semaph 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|