+
+ #{pipeline.commit?.title}
+
+
+
+
♨︎ #{@controller.toHHMMSS(pipeline.duration)}
+
/ ABS #{@controller.toHHMMSS(pipeline.elapsed)}
+
+
#{@asUniqueNames(alwaysSuccess)}
+
+ #{@asUniqueNames(unstable)}
+
+
+ #{@asUniqueNames(alwaysFailed)}
+
+
#{total.length}
+
#{alwaysSuccess.length}
+
#{unstable.length}
+
#{alwaysFailed.length}
+
+
#{pipeline.user?.name}
+
+ "
+ else
+ "
+
+
+ #{pipeline.id}
+ #{pipeline.sha}
+ #{pipeline.commit?.message}
+
+
+
+
+ "
+
+ confirmed: (pipeline) =>
+ @cancel()
+ @controller.updatePipeline(pipeline, @projectPath);
+
+ cancelled: ->
+ @panel.hide()
+
+module.exports = PipelineSelectorView
diff --git a/lib/status-bar-view.coffee b/lib/status-bar-view.coffee
index a9aaff3..d0a9cd2 100644
--- a/lib/status-bar-view.coffee
+++ b/lib/status-bar-view.coffee
@@ -9,6 +9,10 @@ class StatusBarView extends HTMLElement
@stages = {}
@statuses = {}
@tooltips = []
+ @controller = null
+
+ setController: (controller) =>
+ @controller = controller
activate: => @displayed = false
deactivate: =>
@@ -59,8 +63,10 @@ class StatusBarView extends HTMLElement
@disposeTooltips()
status = document.createElement('div')
status.classList.add('inline-block')
- icon = document.createElement('span')
+ icon = document.createElement('a')
icon.classList.add('icon', 'icon-gitlab')
+ icon.onclick = (e) =>
+ @controller.openGitlabCICD(project);
@tooltips.push atom.tooltips.add icon, {
title: "GitLab project #{project}"
}
@@ -85,10 +91,12 @@ class StatusBarView extends HTMLElement
@disposeTooltips()
status = document.createElement('div')
status.classList.add('inline-block')
- icon = document.createElement('span')
+ icon = document.createElement('a')
icon.classList.add('icon', 'icon-gitlab')
+ icon.onclick = (e) =>
+ @controller.openGitlabCICD(project);
@tooltips.push atom.tooltips.add icon, {
- title: "GitLab project #{project}"
+ title: "GitLab project #{project} #{stages[0]?.pipeline} on branch #{stages[0]?.jobs[0]?.ref}"
}
status.appendChild icon
if stages.length is 0
@@ -99,29 +107,48 @@ class StatusBarView extends HTMLElement
}
status.appendChild e
else
+ icon.onclick = (e) =>
+ @controller.openPipeline(project, stages);
+
+ allPipeline = document.createElement('span')
+ allPipeline.classList.add('icon', 'icon-inbox')
+ @tooltips.push atom.tooltips.add allPipeline, {
+ title: "Open all pipeline selector"
+ }
+ allPipeline.onclick = (e) =>
+ @controller.openAllPipelineSelector(project);
+ status.appendChild allPipeline
+
+ pipeline = document.createElement('span')
+ pipeline.classList.add('icon', "gitlab-#{stages[0]?.pipelineStatus}")
+ pipeline.innerHTML = "#{stages[0]?.pipeline} "
+ pipeline.onclick = (e) =>
+ @controller.openPipelineSelector(project);
+ @tooltips.push atom.tooltips.add pipeline, {
+ title: "Open branch pipeline selector"
+ }
+ status.appendChild pipeline
+
stages.forEach((stage) =>
- e = document.createElement('span')
- switch
- when stage.status is 'success'
- e.classList.add('icon', 'gitlab-success')
- when stage.status is 'failed'
- e.classList.add('icon', 'gitlab-failed')
- when stage.status is 'running'
- e.classList.add('icon', 'gitlab-running')
- when stage.status is 'pending'
- e.classList.add('icon', 'gitlab-pending')
- when stage.status is 'skipped'
- e.classList.add('icon', 'gitlab-skipped')
- when stage.status is 'canceled'
- e.classList.add('icon', 'gitlab-canceled')
- when stage.status is 'created'
- e.classList.add('icon', 'gitlab-created')
- when stage.status is 'manual'
- e.classList.add('icon', 'gitlab-manual')
+ failedJobs = stage.jobs.filter( (job) -> job.status is 'failed' )
+
+ e = document.createElement('a')
+ e.classList.add('icon', "gitlab-#{stage.status}")
+ e.onclick = (e) =>
+ @controller.openJobSelector(project, stage);
@tooltips.push atom.tooltips.add e, {
- title: "#{stage.name}: #{stage.status}"
+ title: "#{stage.name}: #{stage.status} | #{failedJobs.length} failed jobs out of #{stage.jobs.length} | Click to individually select a job's log to download."
}
status.appendChild e
+ if failedJobs.length > 0
+ e = document.createElement('a')
+ e.classList.add('icon', "gitlab-artifact")
+ e.onclick = (e) =>
+ @controller.openFailedLogs(project, stage.jobs);
+ @tooltips.push atom.tooltips.add e, {
+ title: "Download all failed logs (#{failedJobs.length}) from the stage #{stage.name}"
+ }
+ status.appendChild e
)
@setchild(status)
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..d83303e
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,345 @@
+{
+ "name": "gitlab-integration",
+ "version": "0.4.4",
+ "lockfileVersion": 1,
+ "requires": true,
+ "dependencies": {
+ "assertion-error": {
+ "version": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.0.2.tgz",
+ "integrity": "sha1-E8pRXYYgbaC6xm6DTdOX2HWBCUw=",
+ "dev": true
+ },
+ "atom-space-pen-views": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/atom-space-pen-views/-/atom-space-pen-views-2.2.0.tgz",
+ "integrity": "sha1-plsskg7QL3JAFPp9Plw9ePv1mZc=",
+ "requires": {
+ "fuzzaldrin": "2.1.0",
+ "space-pen": "5.1.2"
+ }
+ },
+ "chai": {
+ "version": "https://registry.npmjs.org/chai/-/chai-3.5.0.tgz",
+ "integrity": "sha1-TQJjewZ/6Vi9v906QOxW/vc3Mkc=",
+ "dev": true,
+ "requires": {
+ "assertion-error": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.0.2.tgz",
+ "deep-eql": "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz",
+ "type-detect": "https://registry.npmjs.org/type-detect/-/type-detect-1.0.0.tgz"
+ }
+ },
+ "d": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/d/-/d-0.1.1.tgz",
+ "integrity": "sha1-2hhMU10Y2O57oqoim5FACfrhEwk=",
+ "requires": {
+ "es5-ext": "0.10.37"
+ }
+ },
+ "debug": {
+ "version": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=",
+ "dev": true,
+ "requires": {
+ "ms": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz"
+ }
+ },
+ "deep-eql": {
+ "version": "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz",
+ "integrity": "sha1-71WKyrjeJSBs1xOQbXTlaTDrafI=",
+ "dev": true,
+ "requires": {
+ "type-detect": "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz"
+ },
+ "dependencies": {
+ "type-detect": {
+ "version": "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz",
+ "integrity": "sha1-C6XsKohWQORw6k6FBZcZANrFiCI=",
+ "dev": true
+ }
+ }
+ },
+ "deep-equal": {
+ "version": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz",
+ "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=",
+ "dev": true
+ },
+ "emissary": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/emissary/-/emissary-1.3.3.tgz",
+ "integrity": "sha1-phjZLWgrIy0xER3DYlpd9mF5lgY=",
+ "requires": {
+ "es6-weak-map": "0.1.4",
+ "mixto": "1.0.0",
+ "property-accessors": "1.1.3",
+ "underscore-plus": "1.6.6"
+ }
+ },
+ "encoding": {
+ "version": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz",
+ "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=",
+ "requires": {
+ "iconv-lite": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz"
+ }
+ },
+ "es5-ext": {
+ "version": "0.10.37",
+ "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.37.tgz",
+ "integrity": "sha1-DudB0Ui4AGm6J9AgOTdWryV978M=",
+ "requires": {
+ "es6-iterator": "2.0.3",
+ "es6-symbol": "3.1.1"
+ },
+ "dependencies": {
+ "d": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz",
+ "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=",
+ "requires": {
+ "es5-ext": "0.10.37"
+ }
+ },
+ "es6-iterator": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
+ "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=",
+ "requires": {
+ "d": "1.0.0",
+ "es5-ext": "0.10.37",
+ "es6-symbol": "3.1.1"
+ }
+ },
+ "es6-symbol": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz",
+ "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=",
+ "requires": {
+ "d": "1.0.0",
+ "es5-ext": "0.10.37"
+ }
+ }
+ }
+ },
+ "es6-iterator": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-0.1.3.tgz",
+ "integrity": "sha1-1vWLjE/EE8JJtLqhl2j45NfIlE4=",
+ "requires": {
+ "d": "0.1.1",
+ "es5-ext": "0.10.37",
+ "es6-symbol": "2.0.1"
+ }
+ },
+ "es6-symbol": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-2.0.1.tgz",
+ "integrity": "sha1-dhtcZ8/U8dGK+yNPaR1nhoLLO/M=",
+ "requires": {
+ "d": "0.1.1",
+ "es5-ext": "0.10.37"
+ }
+ },
+ "es6-weak-map": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-0.1.4.tgz",
+ "integrity": "sha1-cGzvnpmqI2undmwjnIueKG6n0ig=",
+ "requires": {
+ "d": "0.1.1",
+ "es5-ext": "0.10.37",
+ "es6-iterator": "0.1.3",
+ "es6-symbol": "2.0.1"
+ }
+ },
+ "fuzzaldrin": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fuzzaldrin/-/fuzzaldrin-2.1.0.tgz",
+ "integrity": "sha1-kCBMPi/appQbso0WZF1BgGOpDps="
+ },
+ "git-up": {
+ "version": "https://registry.npmjs.org/git-up/-/git-up-2.0.9.tgz",
+ "integrity": "sha1-IZv9J8gtrurYSVvrOG3Bjq5jY20=",
+ "requires": {
+ "is-ssh": "https://registry.npmjs.org/is-ssh/-/is-ssh-1.3.0.tgz",
+ "parse-url": "https://registry.npmjs.org/parse-url/-/parse-url-1.3.11.tgz"
+ }
+ },
+ "git-url-parse": {
+ "version": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-7.0.1.tgz",
+ "integrity": "sha1-Gj3/xuqp42NN7txY4g2eMxBtPUE=",
+ "requires": {
+ "git-up": "https://registry.npmjs.org/git-up/-/git-up-2.0.9.tgz"
+ }
+ },
+ "grim": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/grim/-/grim-1.5.0.tgz",
+ "integrity": "sha1-sysI71Z88YUvgXWe2caLDXE5ajI=",
+ "requires": {
+ "emissary": "1.3.3"
+ }
+ },
+ "iconv-lite": {
+ "version": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz",
+ "integrity": "sha1-90aPYBNfXl2tM5nAqBvpoWA6CCs="
+ },
+ "is-ssh": {
+ "version": "https://registry.npmjs.org/is-ssh/-/is-ssh-1.3.0.tgz",
+ "integrity": "sha1-6+oRaaJhTaOSpjdANmw84EnY3/Y=",
+ "requires": {
+ "protocols": "https://registry.npmjs.org/protocols/-/protocols-1.4.6.tgz"
+ }
+ },
+ "is-stream": {
+ "version": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
+ "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ="
+ },
+ "isomorphic-fetch": {
+ "version": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz",
+ "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=",
+ "requires": {
+ "node-fetch": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz",
+ "whatwg-fetch": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz"
+ }
+ },
+ "jquery": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/jquery/-/jquery-2.1.4.tgz",
+ "integrity": "sha1-IoveaYoMYUMdwmMKahVPFYkNIxc="
+ },
+ "json-stringify-safe": {
+ "version": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
+ "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
+ "dev": true
+ },
+ "lodash": {
+ "version": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz",
+ "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=",
+ "dev": true
+ },
+ "minimist": {
+ "version": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
+ "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
+ "dev": true
+ },
+ "mixto": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/mixto/-/mixto-1.0.0.tgz",
+ "integrity": "sha1-wyDvYbUvKJj1IuF9i7xtUG2EJbY="
+ },
+ "mkdirp": {
+ "version": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
+ "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
+ "dev": true,
+ "requires": {
+ "minimist": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz"
+ }
+ },
+ "moment": {
+ "version": "2.20.1",
+ "resolved": "https://registry.npmjs.org/moment/-/moment-2.20.1.tgz",
+ "integrity": "sha512-Yh9y73JRljxW5QxN08Fner68eFLxM5ynNOAw2LbIB1YAGeQzZT8QFSUvkAz609Zf+IHhhaUxqZK8dG3W/+HEvg=="
+ },
+ "ms": {
+ "version": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ },
+ "nock": {
+ "version": "https://registry.npmjs.org/nock/-/nock-9.1.4.tgz",
+ "integrity": "sha1-XN2onF7/rtD0SEhvATW/ex578dw=",
+ "dev": true,
+ "requires": {
+ "chai": "https://registry.npmjs.org/chai/-/chai-3.5.0.tgz",
+ "debug": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "deep-equal": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz",
+ "json-stringify-safe": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
+ "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz",
+ "mkdirp": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
+ "propagate": "https://registry.npmjs.org/propagate/-/propagate-0.4.0.tgz",
+ "qs": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz",
+ "semver": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz"
+ }
+ },
+ "node-fetch": {
+ "version": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz",
+ "integrity": "sha1-mA9vcthSEaU0fGsrwYxbhMPrR+8=",
+ "requires": {
+ "encoding": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz",
+ "is-stream": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz"
+ }
+ },
+ "parse-url": {
+ "version": "https://registry.npmjs.org/parse-url/-/parse-url-1.3.11.tgz",
+ "integrity": "sha1-V8FUKKuKiSsfQ4aWRccR0OFEtVQ=",
+ "requires": {
+ "is-ssh": "https://registry.npmjs.org/is-ssh/-/is-ssh-1.3.0.tgz",
+ "protocols": "https://registry.npmjs.org/protocols/-/protocols-1.4.6.tgz"
+ }
+ },
+ "percentile": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/percentile/-/percentile-1.2.0.tgz",
+ "integrity": "sha1-+jsFwf/TVbNSKFKYNOX6N/C9Rl0="
+ },
+ "propagate": {
+ "version": "https://registry.npmjs.org/propagate/-/propagate-0.4.0.tgz",
+ "integrity": "sha1-8/zKCm/gZzanulcpZgaWF8EwtIE=",
+ "dev": true
+ },
+ "property-accessors": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/property-accessors/-/property-accessors-1.1.3.tgz",
+ "integrity": "sha1-Hd6EAkYxhlkJ7zBwM2VoDF+SixU=",
+ "requires": {
+ "es6-weak-map": "0.1.4",
+ "mixto": "1.0.0"
+ }
+ },
+ "protocols": {
+ "version": "https://registry.npmjs.org/protocols/-/protocols-1.4.6.tgz",
+ "integrity": "sha1-+LsmPqG1/Xp2BNJri+Ob13Z4v4o="
+ },
+ "qs": {
+ "version": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz",
+ "integrity": "sha1-NJzfbu+J7EXBLX1es/wMhwNDptg=",
+ "dev": true
+ },
+ "semver": {
+ "version": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz",
+ "integrity": "sha1-4FnAnYVx8FQII3M0M1BdOi8AsY4=",
+ "dev": true
+ },
+ "space-pen": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/space-pen/-/space-pen-5.1.2.tgz",
+ "integrity": "sha1-Ivu+EOCwROe3pHsCPamdlLWE748=",
+ "requires": {
+ "grim": "1.5.0",
+ "jquery": "2.1.4",
+ "underscore-plus": "1.6.6"
+ }
+ },
+ "type-detect": {
+ "version": "https://registry.npmjs.org/type-detect/-/type-detect-1.0.0.tgz",
+ "integrity": "sha1-diIXzAbbJY7EiQihKY6LlRIejqI=",
+ "dev": true
+ },
+ "underscore": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz",
+ "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag="
+ },
+ "underscore-plus": {
+ "version": "1.6.6",
+ "resolved": "https://registry.npmjs.org/underscore-plus/-/underscore-plus-1.6.6.tgz",
+ "integrity": "sha1-ZezeG9xEGjXYnmUP1w3PE65Dmn0=",
+ "requires": {
+ "underscore": "1.6.0"
+ }
+ },
+ "whatwg-fetch": {
+ "version": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz",
+ "integrity": "sha1-nITsLc9oGH/wC8ZOEnS0QhduHIQ="
+ }
+ }
+}
diff --git a/package.json b/package.json
index e94b638..bcb3196 100644
--- a/package.json
+++ b/package.json
@@ -21,8 +21,11 @@
}
},
"dependencies": {
+ "atom-space-pen-views": "^2.2.0",
+ "git-url-parse": "^7.0.0",
"isomorphic-fetch": "^2.2.1",
- "git-url-parse": "^7.0.0"
+ "moment": "^2.20.1",
+ "percentile": "^1.2.0"
},
"devDependencies": {
"nock": "^9.0.14"
diff --git a/styles/icons.less b/styles/icons.less
index f663c7f..35da178 100644
--- a/styles/icons.less
+++ b/styles/icons.less
@@ -20,6 +20,15 @@
border-style: solid;
}
+.gitlab-avatar {
+ width: 16px !important;
+ height: 16px !important;
+ vertical-align: -4px;
+ margin: 0;
+ padding: 0;
+ .gitlab-round;
+}
+
.gitlab-created:before {
.gitlab-icon(created);
border-color: #c4c4c4;
@@ -69,6 +78,12 @@
.gitlab-round;
}
+.gitlab-artifact:before {
+ .gitlab-icon(download);
+ border-color: #2e2e2e;
+ fill: #2e2e2e;
+}
+
.gitlab-canceled:before {
.gitlab-icon(canceled);
border-color: #2e2e2e;
@@ -97,3 +112,29 @@
width: 12px !important;
height: 16px;
}
+
+.progress-variant(@type) {
+ @text-color-name: "text-color-@{type}";
+
+ &::-webkit-progress-value {
+ background-color: @@text-color-name;
+ }
+}
+
+progress {
+ &.progress-info {
+ .progress-variant(info);
+ }
+
+ &.progress-success {
+ .progress-variant(success);
+ }
+
+ &.progress-warning {
+ .progress-variant(warning);
+ }
+
+ &.progress-error {
+ .progress-variant(error);
+ }
+}