semaph 0.4.0 → 0.9.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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +39 -0
  3. data/.semaph +9 -0
  4. data/.semaphore/semaphore.yml +5 -1
  5. data/Gemfile.lock +21 -1
  6. data/README.md +12 -8
  7. data/Rakefile +4 -1
  8. data/lib/semaph.rb +43 -8
  9. data/lib/semaph/{api.rb → client.rb} +24 -3
  10. data/lib/semaph/commands.rb +63 -0
  11. data/lib/semaph/commands/rerun_workflow_command.rb +0 -2
  12. data/lib/semaph/commands/stop_workflow_command.rb +0 -2
  13. data/lib/semaph/formatting.rb +19 -1
  14. data/lib/semaph/model/job.rb +21 -2
  15. data/lib/semaph/model/job_collection.rb +19 -3
  16. data/lib/semaph/model/pipeline.rb +29 -3
  17. data/lib/semaph/model/promotion.rb +31 -0
  18. data/lib/semaph/model/promotion_collection.rb +21 -0
  19. data/lib/semaph/model/workflow.rb +17 -3
  20. data/lib/semaph/shells/organisation/organisation_shell.rb +4 -4
  21. data/lib/semaph/shells/organisation/projects_select_command.rb +6 -0
  22. data/lib/semaph/shells/organisations/organisations_list_command.rb +2 -2
  23. data/lib/semaph/shells/organisations/organisations_select_command.rb +11 -2
  24. data/lib/semaph/shells/organisations/organisations_shell.rb +2 -2
  25. data/lib/semaph/shells/pipeline/job_debug_command.rb +29 -0
  26. data/lib/semaph/shells/pipeline/job_log_command.rb +17 -15
  27. data/lib/semaph/shells/pipeline/job_log_grep_command.rb +5 -11
  28. data/lib/semaph/shells/pipeline/job_show_command.rb +28 -0
  29. data/lib/semaph/shells/pipeline/job_stop_command.rb +28 -0
  30. data/lib/semaph/shells/pipeline/jobs_list_command.rb +4 -2
  31. data/lib/semaph/shells/pipeline/jobs_poll_command.rb +58 -22
  32. data/lib/semaph/shells/pipeline/pipeline_shell.rb +28 -68
  33. data/lib/semaph/shells/pipeline/promote_command.rb +21 -0
  34. data/lib/semaph/shells/pipeline/promotions_list_command.rb +21 -0
  35. data/lib/semaph/shells/project/project_shell.rb +4 -2
  36. data/lib/semaph/shells/project/save_command.rb +26 -0
  37. data/lib/semaph/shells/project/workflows_list_command.rb +11 -17
  38. data/lib/semaph/shells/workflow/pipelines_list_command.rb +3 -1
  39. data/lib/semaph/shells/workflow/workflow_shell.rb +6 -66
  40. data/lib/semaph/version.rb +1 -1
  41. data/semaph.gemspec +1 -0
  42. metadata +30 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c0677122d6857a85e92dc0a74346b4f130f1f715ad9cfede85ffab143540867e
4
- data.tar.gz: c6165a0966dd6cd3088fcece1d56d304188c79552c03a0d48cb3addbe1e4649f
3
+ metadata.gz: 0653a67cbd9a978c6650491d39594eaf22d59b0be26d43bacc7a2f0933d5432c
4
+ data.tar.gz: 1ffb51d996af36938a6fc8b61e26da3db154161b7c420f31a8570a77545d6e1e
5
5
  SHA512:
6
- metadata.gz: d2ea65f9d5fdaf2b4b0597dc3fd0205eaa7fad89b596dff1fcf6619c6d39d11c80c9b5f9acd4e375049c6e16a91bcc4df5708cfd6e1725e834c80576d1442dbf
7
- data.tar.gz: 2505c4088ef17b9efdaa9c9d2dfc80159e459dfcc5f097d4761b69b2e390cb3371b611d9a913783812b5b1dd7435063ac8db3de2fb58f90168822068bcdc2ebf
6
+ metadata.gz: e7f196dfd55567cbd4621c0b2223b0367020d0c1d104560b108fc03a73846ccb56bbbca248321b0fb0c02c2ad4122c3093fe8280336440a2fc80c555bc191a5a
7
+ data.tar.gz: 59b468eccf7a64f79d4ea8317df870f24c4d3271d08a3616b992c9994fb4838276865ffc3fc47805795dec5f921323d53864a75c529e4852c9ac3cbe0f4b4ebd
@@ -1,3 +1,42 @@
1
+ Layout/EmptyLinesAroundAttributeAccessor:
2
+ Enabled: true
3
+
4
+ Layout/SpaceAroundMethodCallOperator:
5
+ Enabled: true
6
+
7
+ Lint/DeprecatedOpenSSLConstant:
8
+ Enabled: true
9
+
10
+ Lint/MixedRegexpCaptureTypes:
11
+ Enabled: true
12
+
13
+ Lint/RaiseException:
14
+ Enabled: true
15
+
16
+ Lint/StructNewOverride:
17
+ Enabled: true
18
+
19
+ Style/ExponentialNotation:
20
+ Enabled: true
21
+
22
+ Style/HashEachMethods:
23
+ Enabled: true
24
+
25
+ Style/HashTransformKeys:
26
+ Enabled: true
27
+
28
+ Style/HashTransformValues:
29
+ Enabled: true
30
+
31
+ Style/RedundantRegexpCharacterClass:
32
+ Enabled: true
33
+
34
+ Style/RedundantRegexpEscape:
35
+ Enabled: true
36
+
37
+ Style/SlicingWithRange:
38
+ Enabled: true
39
+
1
40
  Style/Documentation:
2
41
  Enabled: false
3
42
 
data/.semaph ADDED
@@ -0,0 +1,9 @@
1
+ ---
2
+ :host: markryall.semaphoreci.com
3
+ :project:
4
+ spec:
5
+ repository:
6
+ url: git@github.com:markryall/semaph.git
7
+ metadata:
8
+ name: semaph
9
+ id: e75c6c57-2665-4e45-9cab-560508eb0b22
@@ -16,4 +16,8 @@ blocks:
16
16
  - name: Build
17
17
  commands:
18
18
  - checkout
19
- - echo "done"
19
+ - sem-version ruby $(grep ruby .tool-versions | cut -d ' ' -f 2)
20
+ - cache restore $(git ls-tree HEAD Gemfile.lock | cut -f3 -d$' ' | cut -f1 -d$'\t')
21
+ - bundle install --deployment --path vendor/bundle
22
+ - cache store $(git ls-tree HEAD Gemfile.lock | cut -f3 -d$' ' | cut -f1 -d$'\t') vendor/bundle
23
+ - bundle exec rake
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- semaph (0.4.0)
4
+ semaph (0.9.0)
5
5
  faraday
6
6
  rainbow
7
7
  shell_shock
@@ -9,18 +9,37 @@ PATH
9
9
  GEM
10
10
  remote: https://rubygems.org/
11
11
  specs:
12
+ ast (2.4.0)
12
13
  coderay (1.1.2)
13
14
  faraday (1.0.1)
14
15
  multipart-post (>= 1.2, < 3)
15
16
  method_source (1.0.0)
16
17
  minitest (5.14.1)
17
18
  multipart-post (2.1.1)
19
+ parallel (1.19.1)
20
+ parser (2.7.1.3)
21
+ ast (~> 2.4.0)
18
22
  pry (0.13.1)
19
23
  coderay (~> 1.1)
20
24
  method_source (~> 1.0)
21
25
  rainbow (3.0.0)
22
26
  rake (12.3.3)
27
+ regexp_parser (1.7.0)
28
+ rexml (3.2.4)
29
+ rubocop (0.85.0)
30
+ parallel (~> 1.10)
31
+ parser (>= 2.7.0.1)
32
+ rainbow (>= 2.2.2, < 4.0)
33
+ regexp_parser (>= 1.7)
34
+ rexml
35
+ rubocop-ast (>= 0.0.3)
36
+ ruby-progressbar (~> 1.7)
37
+ unicode-display_width (>= 1.4.0, < 2.0)
38
+ rubocop-ast (0.0.3)
39
+ parser (>= 2.7.0.1)
40
+ ruby-progressbar (1.10.1)
23
41
  shell_shock (0.0.5)
42
+ unicode-display_width (1.7.0)
24
43
 
25
44
  PLATFORMS
26
45
  ruby
@@ -29,6 +48,7 @@ DEPENDENCIES
29
48
  minitest (~> 5.0)
30
49
  pry
31
50
  rake (~> 12.0)
51
+ rubocop
32
52
  semaph!
33
53
 
34
54
  BUNDLED WITH
data/README.md CHANGED
@@ -60,8 +60,6 @@ If you have only one set of credentials in `~/.sem.yml` then this will be the in
60
60
 
61
61
  From here you can `list-projects` and then `select-project` to enter a shell for that project.
62
62
 
63
- If new projects have been added/removed while you are using this shell, you can `reload-projects`.
64
-
65
63
  ### project shell
66
64
 
67
65
  🏗 foo.semaphoreci.com my-app >
@@ -71,8 +69,8 @@ substring of the git branch you want to see workflows for) and then `select-work
71
69
  (where 'index' is the number displayed for each workflow `list-workflows` - tab completion on uuids
72
70
  seemed a bad idea) to enter a shell for that specific workflow.
73
71
 
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).
72
+ You can also `open-github` (opens a web browser for the github project associated with the project) and `open-project`
73
+ (opens the semaphoreci project in a browser).
76
74
 
77
75
  ### workflow shell
78
76
 
@@ -83,16 +81,22 @@ from `semaphore.yml` plus any promotion pipelines that might be executed. You c
83
81
  what's happening with the pipeline.
84
82
 
85
83
  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.
84
+ `open-workflow`, `open-branch` to see the semaphore branch/workflow in a browser.
88
85
 
89
86
  ### pipeline shell
90
87
 
91
88
  🏗 foo.semaphoreci.com my-app workflowuuid semaphore.yml >
92
89
 
93
- From this shell, you can `list-jobs` and `reload-jobs`.
90
+ From this shell, you can `list-jobs`, `poll-jobs`, `job-log` and `grep-logs`.
91
+
92
+ Job polling will stop as soon as any one job has failed and send a system notification
93
+ (as long as `terminal-notifier` is installed).
94
+
95
+ You can look at the log for a specific job (by the index presented in `list-jobs`) using `less`.
96
+
97
+ You can grep across all jobs (using `ag`) with `grep-logs` which will download the logs for all completed jobs.
94
98
 
95
- Jobs are displayed with a flattened view of blocks and jobs for compactness.
99
+ You can also open the same browser views in semaphoreci and github from this shell.
96
100
 
97
101
  ## Development
98
102
 
data/Rakefile CHANGED
@@ -1,5 +1,6 @@
1
1
  require "bundler/gem_tasks"
2
2
  require "rake/testtask"
3
+ require "rubocop/rake_task"
3
4
 
4
5
  Rake::TestTask.new(:test) do |t|
5
6
  t.libs << "test"
@@ -7,4 +8,6 @@ Rake::TestTask.new(:test) do |t|
7
8
  t.test_files = FileList["test/**/*_test.rb"]
8
9
  end
9
10
 
10
- task default: :test
11
+ RuboCop::RakeTask.new(:cop)
12
+
13
+ task default: %i[cop test]
@@ -1,22 +1,57 @@
1
+ require "semaph/client"
2
+ require "semaph/model/project"
1
3
  require "semaph/version"
2
4
  require "semaph/shells/organisations/organisations_shell"
3
5
  require "semaph/shells/organisation/organisation_shell"
6
+ require "semaph/shells/project/project_shell"
4
7
  require "yaml"
5
8
 
6
9
  module Semaph
7
10
  class Error < StandardError; end
8
11
 
9
12
  def self.console
10
- yaml_path = File.join(File.expand_path("~"), ".sem.yaml")
11
- raise "Please install the sem tool and authenticate to semaphoreci.com" unless File.exist?(yaml_path)
12
-
13
- sem_config = YAML.load_file(yaml_path)
14
- contexts = sem_config["contexts"]
13
+ organisations = load_organisations
14
+ config = load_config
15
15
 
16
- if contexts.count == 1
17
- Shells::Organisation::OrganisationShell.new(contexts.values.first).push
16
+ if config
17
+ console_with_config(organisations, config)
18
+ elsif organisations.count == 1
19
+ Shells::Organisation::OrganisationShell.new(organisations.first).push
18
20
  else
19
- Shells::Organisations::OrganisationsShell.new(contexts).push
21
+ Shells::Organisations::OrganisationsShell.new(organisations).push
22
+ end
23
+ end
24
+
25
+ def self.console_with_config(organisations, config)
26
+ organisation = organisations.find { |o| o["host"] == config[:host] }
27
+
28
+ Shells::Project::ProjectShell.new(
29
+ Model::Project.new(
30
+ ::Semaph::Client.new(
31
+ organisation["auth"]["token"],
32
+ organisation["host"],
33
+ ),
34
+ config[:project],
35
+ ),
36
+ ).push
37
+ end
38
+
39
+ def self.load_organisations
40
+ yaml_path = File.join(File.expand_path("~"), ".sem.yaml")
41
+
42
+ unless File.exist?(yaml_path)
43
+ unless organisations
44
+ puts "Please install the sem tool and authenticate to semaphoreci.com"
45
+ exit 1
46
+ end
20
47
  end
48
+
49
+ YAML.load_file(yaml_path)["contexts"].values
50
+ end
51
+
52
+ def self.load_config
53
+ return nil unless File.exist?(".semaph")
54
+
55
+ YAML.load_file(".semaph")
21
56
  end
22
57
  end
@@ -3,7 +3,17 @@ require "json"
3
3
 
4
4
  module Semaph
5
5
  # Refer to https://docs.semaphoreci.com/reference/api-v1alpha/
6
- class Api
6
+ class Client
7
+ class RequestException < RuntimeError
8
+ attr_reader :url, :response
9
+
10
+ def initialize(url, response)
11
+ @url = url
12
+ @response = response
13
+ super("http response #{response.status} received for #{url}:\n#{response.body}")
14
+ end
15
+ end
16
+
7
17
  attr_reader :host, :name
8
18
 
9
19
  def initialize(token, host)
@@ -42,10 +52,22 @@ module Semaph
42
52
  get "pipelines/#{id}", { detailed: true }
43
53
  end
44
54
 
55
+ def promotions(pipeline_id)
56
+ get "promotions", { pipeline_id: pipeline_id }
57
+ end
58
+
59
+ def promote(pipeline_id, name)
60
+ post "promotions", { pipeline_id: pipeline_id, name: name }
61
+ end
62
+
45
63
  def job(id)
46
64
  get "jobs/#{id}"
47
65
  end
48
66
 
67
+ def stop_job(id)
68
+ post "jobs/#{id}/stop"
69
+ end
70
+
49
71
  def job_log(id)
50
72
  get_raw "jobs/#{id}/plain_logs.json"
51
73
  end
@@ -87,8 +109,7 @@ module Semaph
87
109
  def check_response(response, url)
88
110
  return response.body if response.status == 200
89
111
 
90
- puts "http response #{response.status} received for #{url}:\n#{response.body}"
91
- exit 1
112
+ raise RequestException.new(url, response)
92
113
  end
93
114
  end
94
115
  end
@@ -0,0 +1,63 @@
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"
5
+
6
+ module Semaph
7
+ module Commands
8
+ def self.workflow_commands(shell, workflow)
9
+ shell.add_command ::Semaph::Commands::RerunWorkflowCommand.new(workflow), "rerun"
10
+ shell.add_command ::Semaph::Commands::StopWorkflowCommand.new(workflow), "stop"
11
+ add_open_workflow_command(shell, workflow)
12
+ add_open_branch_command(shell, workflow)
13
+ add_github_commands(shell, workflow)
14
+ end
15
+
16
+ def self.add_open_workflow_command(shell, workflow)
17
+ shell.add_command(
18
+ ::Semaph::Commands::VisitUrlCommand.new(
19
+ "https://#{workflow.project.client.host}/workflows/#{workflow.id}",
20
+ "browse to workflow",
21
+ ),
22
+ "open-workflow",
23
+ )
24
+ end
25
+
26
+ def self.add_open_branch_command(shell, workflow)
27
+ shell.add_command(
28
+ ::Semaph::Commands::VisitUrlCommand.new(
29
+ "https://#{workflow.project.client.host}/branches/#{workflow.branch_id}",
30
+ "browse to branch in semaphore",
31
+ ),
32
+ "open-branch",
33
+ )
34
+ end
35
+
36
+ def self.add_github_commands(shell, workflow)
37
+ return unless workflow.project.github_url
38
+
39
+ add_github_branch(shell, workflow)
40
+ add_github_commit(shell, workflow)
41
+ end
42
+
43
+ def self.add_github_branch(shell, workflow)
44
+ shell.add_command(
45
+ ::Semaph::Commands::VisitUrlCommand.new(
46
+ "#{workflow.project.github_url}/tree/#{workflow.branch}",
47
+ "browse to the branch in github",
48
+ ),
49
+ "open-github-branch",
50
+ )
51
+ end
52
+
53
+ def self.add_github_commit(shell, workflow)
54
+ shell.add_command(
55
+ ::Semaph::Commands::VisitUrlCommand.new(
56
+ "#{workflow.project.github_url}/commit/#{workflow.sha}",
57
+ "browse to the commit in github",
58
+ ),
59
+ "open-github-commit",
60
+ )
61
+ end
62
+ end
63
+ end
@@ -1,5 +1,3 @@
1
- require "semaph/shells/workflow/workflow_shell"
2
-
3
1
  module Semaph
4
2
  module Commands
5
3
  class RerunWorkflowCommand
@@ -1,5 +1,3 @@
1
- require "semaph/shells/workflow/workflow_shell"
2
-
3
1
  module Semaph
4
2
  module Commands
5
3
  class StopWorkflowCommand
@@ -1,9 +1,27 @@
1
+ require "rainbow"
2
+
1
3
  module Semaph
2
4
  module Formatting
3
- TIME_FORMAT = "%Y-%m-%d %H:%M:%S".freeze
5
+ TIME_FORMAT = "%m-%d %H:%M".freeze
4
6
 
5
7
  def self.time(time)
6
8
  time.strftime(TIME_FORMAT)
7
9
  end
10
+
11
+ def self.hours_minutes_seconds(total_seconds)
12
+ seconds = total_seconds % 60
13
+ minutes = (total_seconds / 60) % 60
14
+ hours = total_seconds / (60 * 60)
15
+
16
+ format("%02<hours>d:%02<minutes>d:%02<seconds>d", hours: hours, minutes: minutes, seconds: seconds)
17
+ end
18
+
19
+ def self.index(number)
20
+ Rainbow(number.to_s.rjust(2)).yellow
21
+ end
22
+
23
+ def self.length(collection)
24
+ Rainbow(collection.length.to_s).cyan
25
+ end
8
26
  end
9
27
  end
@@ -1,3 +1,5 @@
1
+ require "fileutils"
2
+
1
3
  module Semaph
2
4
  module Model
3
5
  class Job
@@ -20,8 +22,25 @@ module Semaph
20
22
  assign_from_block(raw_block)
21
23
  end
22
24
 
23
- def log
24
- pipeline.workflow.project.client.job_log(id)
25
+ def stop
26
+ pipeline.workflow.project.client.stop_job(id)
27
+ end
28
+
29
+ def show
30
+ pp pipeline.workflow.project.client.job(id)
31
+ end
32
+
33
+ def write_log(base)
34
+ FileUtils.mkdir_p(base)
35
+ filename = "#{base}/#{id}.log"
36
+ return filename if File.exist?(filename)
37
+
38
+ puts "retrieving log for job #{id}"
39
+ File.open(filename, "w") do |file|
40
+ file.puts pipeline.workflow.project.client.job_log(id)
41
+ end
42
+
43
+ filename
25
44
  end
26
45
 
27
46
  def description