     :assoc-fn (fn [previous key val] (assoc previous key (conj (get previous key) val)))]
    ["-h" "--help"]])
 
-;; util
-
-(defn accumulate-build-times [builds]
-  (let [start-times (map :start builds)
-        end-times (map :end builds)]
-    (if (empty? (filter nil? end-times))
-      {:start (apply min start-times)
-       :end (apply max end-times)}
-      {})))
-
-(defn accumulate-builds [builds]
-  (let [outcomes (map :outcome builds)
-        accumulated-outcome (if (every? #(= "pass" %) outcomes)
-                              "pass"
-                              "fail")]
-    (assoc (accumulate-build-times builds)
-           :outcome accumulated-outcome)))
-
-(defn ignore-old-runs-for-rerun-stages [{stage-run :stageRun} builds]
-  (filter #(= stage-run (:actual-stage-run %)) builds))
-
-(defn build-for-job [job-instance]
-  (if-let [jobs-for-accumulation (:jobs-for-accumulation job-instance)]
-    (->> jobs-for-accumulation
-         (map #(merge job-instance %))
-         (map (partial goapi/build-for go-url))
-         (ignore-old-runs-for-rerun-stages job-instance)
-         accumulate-builds)
-    (dissoc (goapi/build-for go-url job-instance)
-            :actual-stage-run)))
-
-(defn job-data-for-instance [jobInstance]
-  (assoc jobInstance :build (build-for-job jobInstance)))
-
-
-(defn job-instances-for-stage-instance [{pipeline-run :pipeline_counter
-                                         stage-run :counter
-                                         jobs :jobs}]
-  (map (fn [{id :id name :name scheduled-date :scheduled_date}]
-         {:jobId id
-          :jobName name
-          :stageRun stage-run
-          :pipelineRun pipeline-run
-          :scheduledDateTime (tc/from-long scheduled-date)})
-       jobs))
-
-(defn job-instance-for-accumulated-stage-instance [{pipeline-run :pipeline_counter
-                                                    stage-run :counter
-                                                    jobs :jobs}]
-  (let [job-instances (map (fn [{id :id name :name}]
-                             {:jobId id :jobName name})
-                           jobs)]
-    {:jobId 0
-     :jobName "accumulated"
-     :stageRun stage-run
-     :pipelineRun pipeline-run
-     :scheduledDateTime (tc/from-long (apply min (map :scheduled_date jobs)))
-     :jobs-for-accumulation job-instances}))
-
-(defn fetch-job-instances-for-stage-instance [accumulate-stages-for-pipelines stage-name stage-instance]
-  (if (contains? accumulate-stages-for-pipelines stage-name)
-    (list (job-instance-for-accumulated-stage-instance stage-instance))
-    (job-instances-for-stage-instance stage-instance)))
-
-(defn job-instances-for-stage [load-builds-from accumulate-stages-for-pipelines {stage-name :stage pipeline :pipeline}]
-  (let [safe-build-start-date (t/minus load-builds-from (t/millis 1))]
-    (->> stage-name
-         (goapi/get-stage-history go-url pipeline)
-         (mapcat (partial fetch-job-instances-for-stage-instance accumulate-stages-for-pipelines pipeline))
-         (take-while #(t/after? (:scheduledDateTime %) safe-build-start-date))
-         (map #(assoc % :stageName stage-name :pipelineName pipeline)))))
-
-
-(defn augment-job-with-inputs [job]
-  (let [pipeline-run (:pipelineRun job)
-        pipeline-name (:pipelineName job)
-        inputs (goapi/get-inputs-for-pipeline-run go-url pipeline-name pipeline-run)]
-    (assoc job :inputs inputs)))
-
-
-(defn select-stages [filter-groups stages]
-  (if (seq filter-groups)
-    (filter #(contains? filter-groups (:group %)) stages)
-    stages))
-
 
 (defn- testsuite? [elem]
   (= :testsuite (:tag elem)))

      (list root)
      (:content root))))

(defn accumulate-junit-xml-results [junit-xml-list]
  (xml/emit-str (apply xml/element (cons :testsuites
                                         (cons {}
                                               (mapcat testsuite-list junit-xml-list))))))

(defn get-all-junit-xml [job-instance]
  (let [jobs (:jobs-for-accumulation job-instance)]
    (->> jobs
         (map #(merge job-instance %))
         (map (partial goapi/get-junit-xml go-url)))))

(defn get-accumulated-junit-xml [job-instance]
  (let [all-junit-xml (get-all-junit-xml job-instance)
        junit-xml-list (remove nil? all-junit-xml)]
    (when-not (empty? junit-xml-list)
      (when-not (= (count junit-xml-list) (count all-junit-xml))
        (let [{pipeline-name :pipelineName
               pipeline-run :pipelineRun
               stage-name :stageName
               stage-run :stageRun} job-instance]
          (log/infof "Unable to accumulate all JUnit XML for jobs of %s %s (%s %s)"
                   pipeline-name stage-name pipeline-run stage-run)))
      (accumulate-junit-xml-results junit-xml-list))))

(defn fetch-junit-xml [job-instance]
  (if (contains? job-instance :jobs-for-accumulation)
    (get-accumulated-junit-xml job-instance)
    (goapi/get-junit-xml go-url job-instance)))

(defn augment-job-instance-with-junit-xml [job-instance]
  (if-let [junit-xml (fetch-junit-xml job-instance)]
    (assoc job-instance
           :junit-xml junit-xml)
    job-instance))

;; upload

(defn make-build-instance [{jobName :jobName stageName :stageName pipelineName :pipelineName
                            stageRun :stageRun pipelineRun :pipelineRun
                            junit-xml :junit-xml
                            inputs :inputs build :build}]
  {:jobName (format "%s %s %s" pipelineName stageName jobName)
   :buildNo (format "%s %s" pipelineRun stageRun)
   :junit-xml junit-xml
   :build (assoc build :inputs inputs)})

(defn buildviz-build-base-url [job-name build-no]
  (format "%s/builds/%s/%s" buildviz-url job-name build-no))

    :id :buildviz-url
    :default "http://localhost:3000"]
   ["-f" "--from DATE" "DATE from which on builds are loaded (by default tries to pick up where the last run finished)"
    :id :sync-start-time
    :parse-fn #(tf/parse date-formatter %)]
   ["-s" "--aggregate PIPELINE" "PIPELINE for which a complete stage will be synced as a job"
    :id :aggregate-jobs-for-pipelines
