Last active
July 20, 2022 13:25
-
-
Save mikeananev/fa6c1c7513bd66f9f47159cf5bf5cd86 to your computer and use it in GitHub Desktop.
Update Gantt EDN files by data from Jira
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| (ns update-task-data-from-jira | |
| "Update task data in Gantt EDN-files by Jira data" | |
| (:require [babashka.curl :as curl] | |
| [babashka.fs :as fs] | |
| [cheshire.core :as json] | |
| [clojure.string :as string] | |
| [rewrite-clj.zip :as z]) | |
| (:import (java.net URLEncoder))) | |
| (def login (-> (System/getenv) (get "LOGNAME"))) | |
| (def password (string/trim (slurp "/Users/mylogin/.credpwd"))) | |
| (def jql-url "https://jit.mycompany.ru/rest/api/2/search?jql=") | |
| (def task-url "https://jit.mycompany.ru/rest/api/2/issue/") | |
| (defn get-raw-issue | |
| "Get raw Jira issue by key using REST API via curl" | |
| ([issue-key] (get-raw-issue issue-key task-url)) | |
| ([issue-key task-url] (get-raw-issue issue-key task-url login password)) | |
| ([issue-key task-url login password] | |
| (try | |
| (let [resp (curl/get (str task-url issue-key) | |
| {:basic-auth [login password] | |
| :headers {"Accept" "application/json"}})] | |
| (when (= 200 (:status resp)) | |
| (-> resp | |
| :body | |
| (json/parse-string true)))) | |
| (catch Exception e | |
| (println "Exception message" (.getMessage e) "issue:" issue-key))))) | |
| (defn extract-fields | |
| "Returns map of common attributes from raw Jira issue or nil if error" | |
| [raw-issue] | |
| (some->> raw-issue | |
| ((juxt | |
| (fn [x] (-> x :key)) | |
| (fn [x] (-> x :fields :summary)) | |
| (fn [x] (-> x :fields :description)) | |
| (fn [x] (-> x :fields :status :name)) | |
| (fn [x] (-> x :fields :resolution :name)) | |
| (fn [x] (-> x :fields :labels)) | |
| (fn [x] (-> x :fields :created)) | |
| (fn [x] (-> x :fields :updated)) | |
| (fn [x] (-> x :fields :resolutiondate)) | |
| (fn [x] (-> x :fields :customfield_18602)) | |
| (fn [x] (-> x :fields :customfield_18603)) | |
| (fn [x] (-> x :fields :duedate)) | |
| (fn [x] (-> x :fields :assignee :name)))) | |
| (zipmap | |
| [:key :summary :description :status :resolution :labels | |
| :created-at :updated-at :resolved-at :planned-start-at | |
| :planned-end-at :duedate :assignee]))) | |
| (defn jira-rest-search | |
| "Make search request to Jira using REST API via curl | |
| Params: | |
| * jql-url - Jira endpoint for search. Example: https://jira.mydomain.ru/rest/api/2/search?jql= | |
| * jql-query - JQL query request. Example: \"project=ABC AND creator=mylogin\"" | |
| [login password jql-url ^String jql-query] | |
| (let [resp (curl/get (str jql-url (URLEncoder/encode jql-query "UTF-8")) | |
| {:basic-auth [login password] | |
| :headers {"Accept" "application/json"}})] | |
| (when (= 200 (:status resp)) | |
| (-> resp | |
| :body | |
| (json/parse-string true))))) | |
| (defn search | |
| "Make a raw JQL with predefined params: login, password, jql-url" | |
| [jql-query] | |
| (jira-rest-search login password jql-url jql-query)) | |
| (defn task-search | |
| "Make a query for tasks search" | |
| [query-string] | |
| (->> | |
| query-string | |
| search | |
| :issues | |
| (map extract-fields))) | |
| (defn update-task-kv | |
| "Update task key and value in a given zipper node by jira issue data. | |
| Returns task node with modified data." | |
| [task-node task-key new-task-value] | |
| (let [key-loc (-> (z/down task-node) (z/find-value z/right task-key)) | |
| modified-task-node (if (z/sexpr key-loc) | |
| (z/replace (z/next key-loc) new-task-value) ;; replace old value | |
| (-> ;; or insert new pair - :key value | |
| task-node | |
| z/down | |
| z/rightmost | |
| (z/insert-right task-key) | |
| z/right | |
| z/insert-newline-left | |
| (z/insert-right new-task-value) | |
| ))] | |
| (z/up modified-task-node))) | |
| (defn update-task-node | |
| "Try to update task from jira. | |
| Returns task node. Node is modified if success" | |
| [task-node] | |
| (let [value (z/sexpr task-node) | |
| uri (:links-to value) | |
| issue-key (some-> | |
| uri | |
| (string/last-index-of "/") | |
| inc | |
| ((partial subs uri)))] | |
| (if (seq issue-key) | |
| (if-let [jira-issue (extract-fields (get-raw-issue issue-key))] | |
| (-> task-node | |
| (update-task-kv :alias (-> jira-issue :key string/lower-case keyword)) | |
| (update-task-kv :task (-> jira-issue :summary))) | |
| task-node) | |
| task-node))) | |
| (defn update-all-tasks | |
| "Update all tasks in a given EDN file. | |
| Returns nil." | |
| [^String edn-filename] | |
| (let [edn-string (slurp edn-filename) | |
| root-zloc (z/of-string edn-string) | |
| zloc (-> root-zloc (z/find-value z/next :project-content) z/next) | |
| updated-content-string (loop [zloc zloc | |
| next-node (z/down zloc)] | |
| (if (z/end? next-node) | |
| (z/root-string zloc) | |
| (let [value (z/sexpr next-node) | |
| result-node (cond | |
| (and (map? value) (:links-to value)) (update-task-node next-node) | |
| :else next-node)] | |
| (recur result-node (z/right result-node)))))] | |
| (spit edn-filename updated-content-string) | |
| (println "Successfully updated file:" edn-filename))) | |
| (defn update-tasks-in-path | |
| "Find EDN files in a given path and update task attributes: name, alias from Jira" | |
| [^String plan-path] | |
| (if (fs/directory? plan-path) | |
| (let [edn-files (mapv str (fs/glob plan-path "**.edn"))] | |
| (run! update-all-tasks edn-files)) | |
| (do | |
| (println "Updating file" plan-path) | |
| (update-all-tasks plan-path)))) | |
| (println "Updating tasks data from Jira...") | |
| (if (pos-int? (count *command-line-args*)) | |
| (if (fs/exists? (first *command-line-args*)) | |
| (update-tasks-in-path (first *command-line-args*)) | |
| (println "Path is not exist:" (first *command-line-args*))) | |
| (println "Usage: <this-program> <path-to-edn-files>")) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment