semaph 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -1
- data/Gemfile.lock +1 -1
- data/README.md +81 -11
- data/lib/semaph/api.rb +37 -4
- data/lib/semaph/commands/reload_command.rb +5 -4
- data/lib/semaph/commands/rerun_workflow_command.rb +18 -0
- data/lib/semaph/commands/stop_workflow_command.rb +18 -0
- data/lib/semaph/model/job.rb +43 -1
- data/lib/semaph/model/job_collection.rb +17 -4
- data/lib/semaph/model/pipeline.rb +27 -1
- data/lib/semaph/model/pipeline_collection.rb +0 -1
- data/lib/semaph/model/project.rb +1 -1
- data/lib/semaph/model/project_collection.rb +0 -1
- data/lib/semaph/model/workflow.rb +11 -1
- data/lib/semaph/model/workflow_collection.rb +0 -1
- data/lib/semaph/shells/organisation/organisation_shell.rb +13 -9
- data/lib/semaph/shells/organisation/projects_list_command.rb +1 -0
- data/lib/semaph/shells/organisations/organisations_shell.rb +5 -1
- data/lib/semaph/shells/pipeline/jobs_list_command.rb +3 -15
- data/lib/semaph/shells/pipeline/jobs_logs_command.rb +30 -0
- data/lib/semaph/shells/pipeline/jobs_poll_command.rb +37 -0
- data/lib/semaph/shells/pipeline/pipeline_shell.rb +80 -7
- data/lib/semaph/shells/project/project_shell.rb +31 -18
- data/lib/semaph/shells/project/workflows_list_command.rb +1 -0
- data/lib/semaph/shells/project/workflows_select_command.rb +10 -3
- data/lib/semaph/shells/workflow/pipelines_list_command.rb +2 -1
- data/lib/semaph/shells/workflow/pipelines_select_command.rb +9 -3
- data/lib/semaph/shells/workflow/workflow_shell.rb +44 -13
- data/lib/semaph/version.rb +1 -1
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 13271774cf750f1f8eedc2d48de45ceeaa164af2593581cac85fc73e6c371d95
|
4
|
+
data.tar.gz: 3afba979f087aba88acbeeb3a09e46261fda8ba3afae3cf1690ced82d687d420
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a00c84f6e8e357e0a99f921e316b8a36f8c5cf78a8d9befb33f2e8e25f733801024392401b4329d8faf20a690dace3c7b2fe48a1f31bb71dfa4c25f41987156b
|
7
|
+
data.tar.gz: 8c904c17ba321fb240c4bdc1fa8ecb1beac95d6688da8632dd6e7e26446c2c16bd52bca36757eccc389cb06b64d3e1af4fc874ce817d706d632e28eaad2b56b5
|
data/.gitignore
CHANGED
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,28 +1,98 @@
|
|
1
1
|
# Semaph
|
2
2
|
|
3
|
-
|
3
|
+
This is command line shell for interacting with [semaphoreci 2.0](http://docs.semaphoreci.com/).
|
4
|
+
|
5
|
+
It complements the [sem](https://docs.semaphoreci.com/reference/sem-command-line-tool/) tool with some
|
6
|
+
overlap in responsibilities.
|
4
7
|
|
5
|
-
TODO: Delete this and the text above, and describe your gem
|
6
8
|
|
7
9
|
## Installation
|
8
10
|
|
9
|
-
|
11
|
+
gem install semaph
|
12
|
+
|
13
|
+
## Usage
|
14
|
+
|
15
|
+
To set up authentication to semaphoreci, you can just follow the instructions to install and setup
|
16
|
+
[sem](https://docs.semaphoreci.com/reference/sem-command-line-tool/). This will result
|
17
|
+
in your authentication details being written to `~/.sem.yaml`.
|
10
18
|
|
11
|
-
|
12
|
-
|
19
|
+
You should see something like the following in this file:
|
20
|
+
|
21
|
+
```yaml
|
22
|
+
active-context: foo_semaphoreci_com
|
23
|
+
contexts:
|
24
|
+
foo_semaphoreci_com:
|
25
|
+
auth:
|
26
|
+
token: qwerty
|
27
|
+
host: foo.semaphoreci.com
|
13
28
|
```
|
14
29
|
|
15
|
-
|
30
|
+
Now you can run `semaph` and will be presented with a prompt like one of the following:
|
16
31
|
|
17
|
-
|
32
|
+
🏗 >
|
18
33
|
|
19
|
-
|
34
|
+
or
|
20
35
|
|
21
|
-
|
36
|
+
🏗 foo.semaphoreci.com >
|
22
37
|
|
23
|
-
|
38
|
+
This is the first of a series of nested shells. Each shell represents a different context
|
39
|
+
and has different commands available. To see the commands available, execute `help` and
|
40
|
+
to see the details of a particular command, execute `help <command name>`. Once you are
|
41
|
+
familar with the commands for each context, you can type the first couple of characters
|
42
|
+
and then hit tab to complete the rest. For some commands you can also tab complete the
|
43
|
+
parameters. Once you enter a shell, return to the previous shell or exit `semaph`, you can
|
44
|
+
press ctrl-d.
|
45
|
+
|
46
|
+
### organisations shell
|
47
|
+
|
48
|
+
🏗 >
|
49
|
+
|
50
|
+
You will only see this shell if you have multiple sets of credentials in your `~/.sem.yml` file.
|
51
|
+
|
52
|
+
From this shell, you can `list-organisations` you are authenticated to and `select-organisation`
|
53
|
+
to enter a shell for that organisation.
|
54
|
+
|
55
|
+
### organisation shell
|
56
|
+
|
57
|
+
🏗 foo.semaphoreci.com >
|
58
|
+
|
59
|
+
If you have only one set of credentials in `~/.sem.yml` then this will be the initial shell.
|
60
|
+
|
61
|
+
From here you can `list-projects` and then `select-project` to enter a shell for that project.
|
62
|
+
|
63
|
+
If new projects have been added/removed while you are using this shell, you can `reload-projects`.
|
64
|
+
|
65
|
+
### project shell
|
66
|
+
|
67
|
+
🏗 foo.semaphoreci.com my-app >
|
68
|
+
|
69
|
+
From this shell, you will mostly be interested in `list-workflows <branch>` (where 'branch' is any
|
70
|
+
substring of the git branch you want to see workflows for) and then `select-workflow <index>`
|
71
|
+
(where 'index' is the number displayed for each workflow `list-workflows` - tab completion on uuids
|
72
|
+
seemed a bad idea) to enter a shell for that specific workflow.
|
73
|
+
|
74
|
+
You can also `open-github` (opens a web browser for the github project associated with the project), `open-project`
|
75
|
+
(opens the semaphoreci project in a browser) and `reload-workflows` (to see any new/changed workflows).
|
76
|
+
|
77
|
+
### workflow shell
|
78
|
+
|
79
|
+
🏗 foo.semaphoreci.com my-app workflowuuid >
|
80
|
+
|
81
|
+
From this shell, you can `list-pipelines` for the selected workflow. These are the builds usually starting
|
82
|
+
from `semaphore.yml` plus any promotion pipelines that might be executed. You can `select-pipeline` to monitor
|
83
|
+
what's happening with the pipeline.
|
84
|
+
|
85
|
+
You can also `open-github-branch`, `open-github-commit` to see the branch/commit in a browser and
|
86
|
+
`open-workflow`, `open-branch` to see the semaphore branch/workflow in a browser and `reload-pipelines` to see
|
87
|
+
any changes that have happened in semaphore.
|
88
|
+
|
89
|
+
### pipeline shell
|
90
|
+
|
91
|
+
🏗 foo.semaphoreci.com my-app workflowuuid semaphore.yml >
|
92
|
+
|
93
|
+
From this shell, you can `list-jobs` and `reload-jobs`.
|
24
94
|
|
25
|
-
|
95
|
+
Jobs are displayed with a flattened view of blocks and jobs for compactness.
|
26
96
|
|
27
97
|
## Development
|
28
98
|
|
data/lib/semaph/api.rb
CHANGED
@@ -4,12 +4,14 @@ require "json"
|
|
4
4
|
module Semaph
|
5
5
|
# Refer to https://docs.semaphoreci.com/reference/api-v1alpha/
|
6
6
|
class Api
|
7
|
-
attr_reader :host
|
7
|
+
attr_reader :host, :name
|
8
8
|
|
9
9
|
def initialize(token, host)
|
10
10
|
@token = token
|
11
11
|
@host = host
|
12
|
-
@
|
12
|
+
@name = host.split(".").first
|
13
|
+
@host_url = "https://#{host}"
|
14
|
+
@base = "#{@host_url}/api/v1alpha"
|
13
15
|
end
|
14
16
|
|
15
17
|
def projects
|
@@ -20,6 +22,18 @@ module Semaph
|
|
20
22
|
get "plumber-workflows", { project_id: project_id }
|
21
23
|
end
|
22
24
|
|
25
|
+
def workflow(workflow_id)
|
26
|
+
get "plumber-workflows/#{workflow_id}"
|
27
|
+
end
|
28
|
+
|
29
|
+
def stop_workflow(workflow_id)
|
30
|
+
post "plumber-workflows/#{workflow_id}/terminate"
|
31
|
+
end
|
32
|
+
|
33
|
+
def rerun_workflow(workflow_id)
|
34
|
+
post "plumber-workflows/#{workflow_id}/reschedule?request_token=#{workflow_id}"
|
35
|
+
end
|
36
|
+
|
23
37
|
def pipelines(options)
|
24
38
|
get "pipelines", options
|
25
39
|
end
|
@@ -32,13 +46,32 @@ module Semaph
|
|
32
46
|
get "jobs/#{id}"
|
33
47
|
end
|
34
48
|
|
49
|
+
def job_log(id)
|
50
|
+
get_raw "jobs/#{id}/plain_logs.json"
|
51
|
+
end
|
52
|
+
|
35
53
|
private
|
36
54
|
|
55
|
+
def get_raw(path, params = {})
|
56
|
+
url = "#{@host_url}/#{path}"
|
57
|
+
puts url if ENV["SEMAPH_DEBUG"]
|
58
|
+
response = Faraday.get(url, params, { "Authorization" => "Token #{@token}" })
|
59
|
+
check_response(response, url)
|
60
|
+
end
|
61
|
+
|
37
62
|
def get(path, params = {})
|
38
63
|
url = "#{@base}/#{path}"
|
39
64
|
puts url if ENV["SEMAPH_DEBUG"]
|
40
65
|
response = Faraday.get(url, params, headers)
|
41
|
-
check_response(response, url).tap do |hash|
|
66
|
+
JSON.parse(check_response(response, url)).tap do |hash|
|
67
|
+
pp hash if ENV["SEMAPH_DEBUG"]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def post(path, params = {})
|
72
|
+
url = "#{@base}/#{path}"
|
73
|
+
response = Faraday.post(url, params.to_json, headers)
|
74
|
+
JSON.parse(check_response(response, url)).tap do |hash|
|
42
75
|
pp hash if ENV["SEMAPH_DEBUG"]
|
43
76
|
end
|
44
77
|
end
|
@@ -52,7 +85,7 @@ module Semaph
|
|
52
85
|
end
|
53
86
|
|
54
87
|
def check_response(response, url)
|
55
|
-
return
|
88
|
+
return response.body if response.status == 200
|
56
89
|
|
57
90
|
puts "http response #{response.status} received for #{url}:\n#{response.body}"
|
58
91
|
exit 1
|
@@ -3,13 +3,14 @@ module Semaph
|
|
3
3
|
class ReloadCommand
|
4
4
|
attr_reader :help
|
5
5
|
|
6
|
-
def initialize
|
7
|
-
@
|
8
|
-
@help = help
|
6
|
+
def initialize
|
7
|
+
@help = "reload all code"
|
9
8
|
end
|
10
9
|
|
11
10
|
def execute(_whatever)
|
12
|
-
|
11
|
+
Dir["lib/**/*.rb"].each do |path|
|
12
|
+
load path
|
13
|
+
end
|
13
14
|
end
|
14
15
|
end
|
15
16
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require "semaph/shells/workflow/workflow_shell"
|
2
|
+
|
3
|
+
module Semaph
|
4
|
+
module Commands
|
5
|
+
class RerunWorkflowCommand
|
6
|
+
attr_reader :help
|
7
|
+
|
8
|
+
def initialize(workflow)
|
9
|
+
@workflow = workflow
|
10
|
+
@help = "rerun workflow"
|
11
|
+
end
|
12
|
+
|
13
|
+
def execute(_whatever)
|
14
|
+
::Semaph::Shells::Workflow::WorkflowShell.new(@workflow.rerun).push
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require "semaph/shells/workflow/workflow_shell"
|
2
|
+
|
3
|
+
module Semaph
|
4
|
+
module Commands
|
5
|
+
class StopWorkflowCommand
|
6
|
+
attr_reader :help
|
7
|
+
|
8
|
+
def initialize(workflow)
|
9
|
+
@workflow = workflow
|
10
|
+
@help = "stop workflow"
|
11
|
+
end
|
12
|
+
|
13
|
+
def execute(_whatever)
|
14
|
+
@workflow.stop
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/semaph/model/job.rb
CHANGED
@@ -20,6 +20,49 @@ module Semaph
|
|
20
20
|
assign_from_block(raw_block)
|
21
21
|
end
|
22
22
|
|
23
|
+
def log
|
24
|
+
pipeline.workflow.project.client.job_log(id)
|
25
|
+
end
|
26
|
+
|
27
|
+
def description
|
28
|
+
[
|
29
|
+
block_icon,
|
30
|
+
@block_name,
|
31
|
+
job_icon,
|
32
|
+
@name,
|
33
|
+
].compact.join(" ")
|
34
|
+
end
|
35
|
+
|
36
|
+
# block_state can be waiting/running/done
|
37
|
+
# block_result can be passed/failed/canceled/stopped
|
38
|
+
def block_icon
|
39
|
+
return "🟠" if @block_state == "waiting"
|
40
|
+
|
41
|
+
return "🔵" if @block_state == "running"
|
42
|
+
|
43
|
+
return "⚪" if @block_result == "canceled"
|
44
|
+
|
45
|
+
return "⛔" if @block_result == "stopped"
|
46
|
+
|
47
|
+
return "🟢" if @block_result == "passed"
|
48
|
+
|
49
|
+
"🔴"
|
50
|
+
end
|
51
|
+
|
52
|
+
# status can be FINISHED/RUNNING
|
53
|
+
# result can be PASSED/FAILED/STOPPED
|
54
|
+
def job_icon
|
55
|
+
return nil unless @status
|
56
|
+
|
57
|
+
return "🔵" unless @status == "FINISHED"
|
58
|
+
|
59
|
+
return "⛔" if @result == "STOPPED"
|
60
|
+
|
61
|
+
return "🟢" if @result == "PASSED"
|
62
|
+
|
63
|
+
"🔴"
|
64
|
+
end
|
65
|
+
|
23
66
|
private
|
24
67
|
|
25
68
|
def assign_from_job(raw)
|
@@ -37,4 +80,3 @@ module Semaph
|
|
37
80
|
end
|
38
81
|
end
|
39
82
|
end
|
40
|
-
|
@@ -7,7 +7,6 @@ module Semaph
|
|
7
7
|
|
8
8
|
def initialize(pipeline)
|
9
9
|
@pipeline = pipeline
|
10
|
-
reload
|
11
10
|
end
|
12
11
|
|
13
12
|
def reload
|
@@ -16,6 +15,14 @@ module Semaph
|
|
16
15
|
@all = build_jobs(project.client.pipeline(@pipeline.id))
|
17
16
|
end
|
18
17
|
|
18
|
+
def incomplete
|
19
|
+
@all.reject { |job| job.status == "FINISHED" }
|
20
|
+
end
|
21
|
+
|
22
|
+
def failed
|
23
|
+
@all.select { |job| job.result == "FAILED" }
|
24
|
+
end
|
25
|
+
|
19
26
|
private
|
20
27
|
|
21
28
|
def build_jobs(content)
|
@@ -23,12 +30,18 @@ module Semaph
|
|
23
30
|
blocks = content.delete("blocks")
|
24
31
|
blocks.each do |block|
|
25
32
|
jobs = block.delete("jobs").sort_by { |job| job["index"] }
|
26
|
-
|
27
|
-
result << Job.new(@pipeline, block, job)
|
28
|
-
end
|
33
|
+
append_jobs(result, block, jobs)
|
29
34
|
end
|
30
35
|
result
|
31
36
|
end
|
37
|
+
|
38
|
+
def append_jobs(result, block, jobs)
|
39
|
+
if jobs.count.positive?
|
40
|
+
jobs.each { |job| result << Job.new(@pipeline, block, job) }
|
41
|
+
else
|
42
|
+
result << Job.new(@pipeline, block, {})
|
43
|
+
end
|
44
|
+
end
|
32
45
|
end
|
33
46
|
end
|
34
47
|
end
|
@@ -12,10 +12,36 @@ module Semaph
|
|
12
12
|
@yaml = raw["yaml_file_name"]
|
13
13
|
@state = raw["state"]
|
14
14
|
@result = raw["result"]
|
15
|
+
%w[created done pending queuing running stopping].each do |name|
|
16
|
+
extract_time(name)
|
17
|
+
end
|
15
18
|
end
|
16
19
|
|
17
20
|
def job_collection
|
18
|
-
JobCollection.new(self)
|
21
|
+
@job_collection ||= JobCollection.new(self)
|
22
|
+
end
|
23
|
+
|
24
|
+
def description
|
25
|
+
"#{icon} #{yaml}"
|
26
|
+
end
|
27
|
+
|
28
|
+
def icon
|
29
|
+
return "🔵" unless @state == "DONE"
|
30
|
+
|
31
|
+
return "⛔" if @result == "STOPPED"
|
32
|
+
|
33
|
+
return "🟢" if @result == "PASSED"
|
34
|
+
|
35
|
+
"🔴"
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def extract_time(name)
|
41
|
+
key = "#{name}_at"
|
42
|
+
return if raw[key]["seconds"].zero?
|
43
|
+
|
44
|
+
instance_variable_set("@#{key}", Time.at(raw[key]["seconds"]))
|
19
45
|
end
|
20
46
|
end
|
21
47
|
end
|
data/lib/semaph/model/project.rb
CHANGED
@@ -17,7 +17,17 @@ module Semaph
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def pipeline_collection
|
20
|
-
PipelineCollection.new(self)
|
20
|
+
@pipeline_collection ||= PipelineCollection.new(self)
|
21
|
+
end
|
22
|
+
|
23
|
+
def rerun
|
24
|
+
rerun_response = project.client.rerun_workflow(@id)
|
25
|
+
workflow_response = project.client.workflow(rerun_response["wf_id"])
|
26
|
+
Workflow.new(project, workflow_response["workflow"])
|
27
|
+
end
|
28
|
+
|
29
|
+
def stop
|
30
|
+
project.client.stop_workflow(@id)
|
21
31
|
end
|
22
32
|
end
|
23
33
|
end
|
@@ -12,16 +12,20 @@ module Semaph
|
|
12
12
|
include ShellShock::Context
|
13
13
|
|
14
14
|
def initialize(organisation)
|
15
|
-
|
16
|
-
@prompt = "🏗 #{
|
17
|
-
|
18
|
-
|
19
|
-
|
15
|
+
@client = ::Semaph::Api.new(organisation["auth"]["token"], organisation["host"])
|
16
|
+
@prompt = "🏗 #{@client.name} > "
|
17
|
+
add_commands
|
18
|
+
@project_list_command.execute("")
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def add_commands
|
24
|
+
project_collection = ::Semaph::Model::ProjectCollection.new(@client)
|
25
|
+
@project_list_command = ProjectsListCommand.new(project_collection)
|
26
|
+
add_command @project_list_command, "list-projects"
|
20
27
|
add_command ProjectsSelectCommand.new(project_collection), "select-project"
|
21
|
-
add_command
|
22
|
-
::Semaph::Commands::ReloadCommand.new(project_collection, "reload projects"),
|
23
|
-
"reload-projects",
|
24
|
-
)
|
28
|
+
add_command ::Semaph::Commands::ReloadCommand.new, "reload" if ENV["SEMAPH_RELOAD"]
|
25
29
|
end
|
26
30
|
end
|
27
31
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require "semaph/commands/reload_command"
|
1
2
|
require "semaph/shells/organisations/organisations_list_command"
|
2
3
|
require "semaph/shells/organisations/organisations_select_command"
|
3
4
|
require "shell_shock/context"
|
@@ -11,8 +12,11 @@ module Semaph
|
|
11
12
|
def initialize(organisations)
|
12
13
|
@organisations = organisations
|
13
14
|
@prompt = "🏗 > "
|
14
|
-
|
15
|
+
organisations_list_command = OrganisationsListCommand.new(organisations)
|
16
|
+
add_command organisations_list_command, "list-organisations"
|
15
17
|
add_command OrganisationsSelectCommand.new(organisations), "select-organisation"
|
18
|
+
add_command ::Semaph::Commands::ReloadCommand.new, "reload" if ENV["SEMAPH_RELOAD"]
|
19
|
+
organisations_list_command.execute("")
|
16
20
|
end
|
17
21
|
end
|
18
22
|
end
|
@@ -10,23 +10,11 @@ module Semaph
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def execute(_whatever)
|
13
|
-
@job_collection.
|
14
|
-
|
13
|
+
@job_collection.reload
|
14
|
+
@job_collection.all.each_with_index do |job, index|
|
15
|
+
puts "#{index + 1} #{job.description}"
|
15
16
|
end
|
16
17
|
end
|
17
|
-
|
18
|
-
private
|
19
|
-
|
20
|
-
def description(job)
|
21
|
-
[
|
22
|
-
job.block_name,
|
23
|
-
job.block_state,
|
24
|
-
job.block_result,
|
25
|
-
job.name,
|
26
|
-
job.status,
|
27
|
-
job.result,
|
28
|
-
].join(" ")
|
29
|
-
end
|
30
18
|
end
|
31
19
|
end
|
32
20
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Semaph
|
2
|
+
module Shells
|
3
|
+
module Pipeline
|
4
|
+
class JobsLogsCommand
|
5
|
+
attr_reader :usage, :help
|
6
|
+
|
7
|
+
def initialize(job_collection)
|
8
|
+
@job_collection = job_collection
|
9
|
+
@usage = "<job index>"
|
10
|
+
@help = "retrieve log for job"
|
11
|
+
end
|
12
|
+
|
13
|
+
def execute(index_string)
|
14
|
+
index = index_string.to_i - 1
|
15
|
+
|
16
|
+
job = @job_collection.all[index]
|
17
|
+
|
18
|
+
unless job
|
19
|
+
puts "There is no job at position #{index}"
|
20
|
+
return
|
21
|
+
end
|
22
|
+
|
23
|
+
filename = "#{job.id}.log"
|
24
|
+
File.open(filename, "w") { |file| file.puts job.log } unless File.exist?(filename)
|
25
|
+
system("less #{filename}")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Semaph
|
2
|
+
module Shells
|
3
|
+
module Pipeline
|
4
|
+
class JobsPollCommand
|
5
|
+
attr_reader :usage, :help
|
6
|
+
|
7
|
+
def initialize(job_collection)
|
8
|
+
@job_collection = job_collection
|
9
|
+
@help = "poll jobs"
|
10
|
+
@can_notify = !`which terminal-notifier`.chomp.empty?
|
11
|
+
end
|
12
|
+
|
13
|
+
def execute(_whatever)
|
14
|
+
incomplete_jobs = @job_collection.incomplete
|
15
|
+
while incomplete_jobs.count.positive?
|
16
|
+
puts "#{incomplete_jobs.count} incomplete jobs remaining:"
|
17
|
+
incomplete_jobs.each { |job| puts job.description }
|
18
|
+
failed_jobs = @job_collection.failed
|
19
|
+
if failed_jobs.count.positive?
|
20
|
+
puts "Some jobs have already failed:"
|
21
|
+
failed_jobs.each { |job| puts job.description }
|
22
|
+
`terminal-notifier -group semaph -message "#{failed_jobs.count} jobs have failed" -title "Job failures"` if @can_notify
|
23
|
+
return
|
24
|
+
end
|
25
|
+
sleep 20
|
26
|
+
@job_collection.reload
|
27
|
+
incomplete_jobs = @job_collection.incomplete
|
28
|
+
end
|
29
|
+
@job_collection.all.each_with_index do |job, index|
|
30
|
+
puts "#{index + 1} #{job.description}"
|
31
|
+
end
|
32
|
+
`terminal-notifier -group semaph -message "All jobs have completed" -title "Workflow completed"` if @can_notify
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -1,23 +1,96 @@
|
|
1
|
+
require "semaph/commands/reload_command"
|
2
|
+
require "semaph/commands/rerun_workflow_command"
|
1
3
|
require "semaph/shells/pipeline/jobs_list_command"
|
4
|
+
require "semaph/shells/pipeline/jobs_logs_command"
|
5
|
+
require "semaph/shells/pipeline/jobs_poll_command"
|
2
6
|
require "shell_shock/context"
|
3
7
|
|
4
8
|
module Semaph
|
5
9
|
module Shells
|
6
10
|
module Pipeline
|
7
11
|
class PipelineShell
|
12
|
+
attr_reader :pipeline
|
13
|
+
|
8
14
|
include ShellShock::Context
|
9
15
|
|
10
16
|
def initialize(pipeline)
|
11
17
|
@pipeline = pipeline
|
12
|
-
|
13
|
-
|
14
|
-
@
|
15
|
-
|
18
|
+
@prompt = "🏗 #{project.client.name} #{project.name} #{workflow.id} #{pipeline.yaml} > "
|
19
|
+
add_commands
|
20
|
+
@jobs_list_command.execute("")
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def project
|
26
|
+
workflow.project
|
27
|
+
end
|
28
|
+
|
29
|
+
def workflow
|
30
|
+
pipeline.workflow
|
31
|
+
end
|
32
|
+
|
33
|
+
def job_collection
|
34
|
+
pipeline.job_collection
|
35
|
+
end
|
36
|
+
|
37
|
+
def add_commands
|
38
|
+
@jobs_list_command = JobsListCommand.new(job_collection)
|
39
|
+
add_command @jobs_list_command, "list-jobs"
|
40
|
+
add_command JobsPollCommand.new(job_collection), "poll-jobs"
|
41
|
+
add_command JobsLogsCommand.new(job_collection), "jobs-logs"
|
42
|
+
add_command ::Semaph::Commands::RerunWorkflowCommand.new(workflow), "rerun"
|
43
|
+
add_open_branch_command
|
44
|
+
add_open_workflow_command
|
45
|
+
add_github_commands
|
46
|
+
add_command ::Semaph::Commands::ReloadCommand.new, "reload" if ENV["SEMAPH_RELOAD"]
|
47
|
+
end
|
48
|
+
|
49
|
+
def add_open_workflow_command
|
50
|
+
add_command(
|
51
|
+
::Semaph::Commands::VisitUrlCommand.new(
|
52
|
+
"https://#{project.client.host}/workflows/#{workflow.id}",
|
53
|
+
"browse to workflow",
|
54
|
+
),
|
55
|
+
"open-workflow",
|
56
|
+
)
|
57
|
+
end
|
58
|
+
|
59
|
+
def add_open_branch_command
|
60
|
+
add_command(
|
61
|
+
::Semaph::Commands::VisitUrlCommand.new(
|
62
|
+
"https://#{project.client.host}/branches/#{workflow.branch_id}",
|
63
|
+
"browse to branch in semaphore",
|
64
|
+
),
|
65
|
+
"open-branch",
|
66
|
+
)
|
67
|
+
end
|
68
|
+
|
69
|
+
def add_github_commands
|
70
|
+
return unless workflow.project.github_url
|
71
|
+
|
72
|
+
add_github_branch
|
73
|
+
add_github_commit
|
74
|
+
end
|
75
|
+
|
76
|
+
def add_github_branch
|
77
|
+
add_command(
|
78
|
+
::Semaph::Commands::VisitUrlCommand.new(
|
79
|
+
"#{workflow.project.github_url}/tree/#{workflow.branch}",
|
80
|
+
"browse to the branch in github",
|
81
|
+
),
|
82
|
+
"open-github-branch",
|
83
|
+
)
|
84
|
+
end
|
85
|
+
|
86
|
+
def add_github_commit
|
16
87
|
add_command(
|
17
|
-
::Semaph::Commands::
|
18
|
-
|
88
|
+
::Semaph::Commands::VisitUrlCommand.new(
|
89
|
+
"#{workflow.project.github_url}/commit/#{workflow.sha}",
|
90
|
+
"browse to the commit in github",
|
91
|
+
),
|
92
|
+
"open-github-commit",
|
19
93
|
)
|
20
|
-
add_command JobsListCommand.new(job_collection), "list-jobs"
|
21
94
|
end
|
22
95
|
end
|
23
96
|
end
|
@@ -1,5 +1,5 @@
|
|
1
|
-
require "semaph/commands/visit_url_command"
|
2
1
|
require "semaph/commands/reload_command"
|
2
|
+
require "semaph/commands/visit_url_command"
|
3
3
|
require "semaph/shells/project/workflows_list_command"
|
4
4
|
require "semaph/shells/project/workflows_select_command"
|
5
5
|
require "shell_shock/context"
|
@@ -8,30 +8,33 @@ module Semaph
|
|
8
8
|
module Shells
|
9
9
|
module Project
|
10
10
|
class ProjectShell
|
11
|
+
attr_reader :project
|
12
|
+
|
11
13
|
include ShellShock::Context
|
12
14
|
|
13
15
|
def initialize(project)
|
14
|
-
@
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
::Semaph::Commands::ReloadCommand.new(workflow_collection, "reload workflows"),
|
19
|
-
"reload-workflows",
|
20
|
-
)
|
21
|
-
add_command(
|
22
|
-
::Semaph::Commands::VisitUrlCommand.new(
|
23
|
-
"https://#{project.client.host}/projects/#{project.name}",
|
24
|
-
"browse to project",
|
25
|
-
),
|
26
|
-
"open-project",
|
27
|
-
)
|
28
|
-
add_command WorkflowsListCommand.new(workflow_collection), "list-workflows"
|
29
|
-
add_command WorkflowsSelectCommand.new(workflow_collection), "select-workflow"
|
16
|
+
@project = project
|
17
|
+
@prompt = "🏗 #{project.client.name} #{project.name} > "
|
18
|
+
add_commands
|
19
|
+
@workflows_list_command.execute("")
|
30
20
|
end
|
31
21
|
|
32
22
|
private
|
33
23
|
|
34
|
-
def
|
24
|
+
def workflow_collection
|
25
|
+
project.workflow_collection
|
26
|
+
end
|
27
|
+
|
28
|
+
def add_commands
|
29
|
+
add_github_command
|
30
|
+
add_open_project_command
|
31
|
+
@workflows_list_command = WorkflowsListCommand.new(workflow_collection)
|
32
|
+
add_command @workflows_list_command, "list-workflows"
|
33
|
+
add_command WorkflowsSelectCommand.new(workflow_collection), "select-workflow"
|
34
|
+
add_command ::Semaph::Commands::ReloadCommand.new, "reload" if ENV["SEMAPH_RELOAD"]
|
35
|
+
end
|
36
|
+
|
37
|
+
def add_github_command
|
35
38
|
return unless project.github_url
|
36
39
|
|
37
40
|
add_command(
|
@@ -42,6 +45,16 @@ module Semaph
|
|
42
45
|
"open-github",
|
43
46
|
)
|
44
47
|
end
|
48
|
+
|
49
|
+
def add_open_project_command
|
50
|
+
add_command(
|
51
|
+
::Semaph::Commands::VisitUrlCommand.new(
|
52
|
+
"https://#{project.client.host}/projects/#{project.name}",
|
53
|
+
"browse to project",
|
54
|
+
),
|
55
|
+
"open-project",
|
56
|
+
)
|
57
|
+
end
|
45
58
|
end
|
46
59
|
end
|
47
60
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require "semaph/shells/workflow/workflow_shell"
|
2
|
+
require "semaph/shells/pipeline/pipeline_shell"
|
2
3
|
|
3
4
|
module Semaph
|
4
5
|
module Shells
|
@@ -14,9 +15,15 @@ module Semaph
|
|
14
15
|
|
15
16
|
def execute(index_string)
|
16
17
|
index = index_string.to_i - 1
|
17
|
-
|
18
|
-
|
19
|
-
|
18
|
+
|
19
|
+
workflow = @workflow_collection.all[index]
|
20
|
+
|
21
|
+
unless workflow
|
22
|
+
puts "There is no workflow at position #{index}"
|
23
|
+
return
|
24
|
+
end
|
25
|
+
|
26
|
+
::Semaph::Shells::Workflow::WorkflowShell.new(workflow).push
|
20
27
|
end
|
21
28
|
end
|
22
29
|
end
|
@@ -10,8 +10,9 @@ module Semaph
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def execute(_whatever)
|
13
|
+
@pipeline_collection.reload
|
13
14
|
@pipeline_collection.all.each_with_index do |pipeline, index|
|
14
|
-
puts "#{index + 1} #{pipeline.
|
15
|
+
puts "#{index + 1} #{pipeline.description}"
|
15
16
|
end
|
16
17
|
end
|
17
18
|
end
|
@@ -14,9 +14,15 @@ module Semaph
|
|
14
14
|
|
15
15
|
def execute(index_string)
|
16
16
|
index = index_string.to_i - 1
|
17
|
-
|
18
|
-
|
19
|
-
|
17
|
+
|
18
|
+
pipeline = @pipeline_collection.all[index]
|
19
|
+
|
20
|
+
unless pipeline
|
21
|
+
puts "There is no pipeline at position #{index}"
|
22
|
+
return
|
23
|
+
end
|
24
|
+
|
25
|
+
::Semaph::Shells::Pipeline::PipelineShell.new(pipeline).push
|
20
26
|
end
|
21
27
|
end
|
22
28
|
end
|
@@ -1,5 +1,7 @@
|
|
1
|
-
require "semaph/commands/visit_url_command"
|
2
1
|
require "semaph/commands/reload_command"
|
2
|
+
require "semaph/commands/rerun_workflow_command"
|
3
|
+
require "semaph/commands/stop_workflow_command"
|
4
|
+
require "semaph/commands/visit_url_command"
|
3
5
|
require "semaph/shells/workflow/pipelines_list_command"
|
4
6
|
require "semaph/shells/workflow/pipelines_select_command"
|
5
7
|
require "shell_shock/context"
|
@@ -8,15 +10,40 @@ module Semaph
|
|
8
10
|
module Shells
|
9
11
|
module Workflow
|
10
12
|
class WorkflowShell
|
13
|
+
attr_reader :workflow
|
14
|
+
|
11
15
|
include ShellShock::Context
|
12
16
|
|
13
17
|
def initialize(workflow)
|
14
18
|
@workflow = workflow
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
+
@prompt = "🏗 #{project.client.name} #{project.name} #{workflow.id} > "
|
20
|
+
add_commands
|
21
|
+
@list_command.execute("")
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def project
|
27
|
+
@workflow.project
|
28
|
+
end
|
29
|
+
|
30
|
+
def pipeline_collection
|
31
|
+
@workflow.pipeline_collection
|
32
|
+
end
|
33
|
+
|
34
|
+
def add_commands
|
35
|
+
@list_command = PipelinesListCommand.new(pipeline_collection)
|
36
|
+
add_command @list_command, "list-pipelines"
|
19
37
|
add_command PipelinesSelectCommand.new(pipeline_collection), "select-pipeline"
|
38
|
+
add_command ::Semaph::Commands::RerunWorkflowCommand.new(workflow), "rerun"
|
39
|
+
add_command ::Semaph::Commands::StopWorkflowCommand.new(workflow), "stop"
|
40
|
+
add_open_branch_command
|
41
|
+
add_open_workflow_command
|
42
|
+
add_github_commands
|
43
|
+
add_command ::Semaph::Commands::ReloadCommand.new, "reload" if ENV["SEMAPH_RELOAD"]
|
44
|
+
end
|
45
|
+
|
46
|
+
def add_open_workflow_command
|
20
47
|
add_command(
|
21
48
|
::Semaph::Commands::VisitUrlCommand.new(
|
22
49
|
"https://#{project.client.host}/workflows/#{workflow.id}",
|
@@ -24,6 +51,9 @@ module Semaph
|
|
24
51
|
),
|
25
52
|
"open-workflow",
|
26
53
|
)
|
54
|
+
end
|
55
|
+
|
56
|
+
def add_open_branch_command
|
27
57
|
add_command(
|
28
58
|
::Semaph::Commands::VisitUrlCommand.new(
|
29
59
|
"https://#{project.client.host}/branches/#{workflow.branch_id}",
|
@@ -31,18 +61,16 @@ module Semaph
|
|
31
61
|
),
|
32
62
|
"open-branch",
|
33
63
|
)
|
34
|
-
add_github_commands(workflow)
|
35
|
-
add_command(
|
36
|
-
::Semaph::Commands::ReloadCommand.new(pipeline_collection, "reload pipelines"),
|
37
|
-
"reload-pipelines",
|
38
|
-
)
|
39
64
|
end
|
40
65
|
|
41
|
-
|
42
|
-
|
43
|
-
def add_github_commands(workflow)
|
66
|
+
def add_github_commands
|
44
67
|
return unless workflow.project.github_url
|
45
68
|
|
69
|
+
add_github_branch
|
70
|
+
add_github_commit
|
71
|
+
end
|
72
|
+
|
73
|
+
def add_github_branch
|
46
74
|
add_command(
|
47
75
|
::Semaph::Commands::VisitUrlCommand.new(
|
48
76
|
"#{workflow.project.github_url}/tree/#{workflow.branch}",
|
@@ -50,6 +78,9 @@ module Semaph
|
|
50
78
|
),
|
51
79
|
"open-github-branch",
|
52
80
|
)
|
81
|
+
end
|
82
|
+
|
83
|
+
def add_github_commit
|
53
84
|
add_command(
|
54
85
|
::Semaph::Commands::VisitUrlCommand.new(
|
55
86
|
"#{workflow.project.github_url}/commit/#{workflow.sha}",
|
data/lib/semaph/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: semaph
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mark Ryall
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-06-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -91,6 +91,8 @@ files:
|
|
91
91
|
- lib/semaph.rb
|
92
92
|
- lib/semaph/api.rb
|
93
93
|
- lib/semaph/commands/reload_command.rb
|
94
|
+
- lib/semaph/commands/rerun_workflow_command.rb
|
95
|
+
- lib/semaph/commands/stop_workflow_command.rb
|
94
96
|
- lib/semaph/commands/visit_url_command.rb
|
95
97
|
- lib/semaph/formatting.rb
|
96
98
|
- lib/semaph/model/job.rb
|
@@ -108,6 +110,8 @@ files:
|
|
108
110
|
- lib/semaph/shells/organisations/organisations_select_command.rb
|
109
111
|
- lib/semaph/shells/organisations/organisations_shell.rb
|
110
112
|
- lib/semaph/shells/pipeline/jobs_list_command.rb
|
113
|
+
- lib/semaph/shells/pipeline/jobs_logs_command.rb
|
114
|
+
- lib/semaph/shells/pipeline/jobs_poll_command.rb
|
111
115
|
- lib/semaph/shells/pipeline/pipeline_shell.rb
|
112
116
|
- lib/semaph/shells/project/project_shell.rb
|
113
117
|
- lib/semaph/shells/project/workflows_list_command.rb
|