semaph 0.3.0 → 0.8.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 +15 -1
  14. data/lib/semaph/model/job.rb +29 -2
  15. data/lib/semaph/model/job_collection.rb +21 -5
  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/{jobs_logs_command.rb → job_debug_command.rb} +4 -5
  26. data/lib/semaph/shells/pipeline/job_log_command.rb +44 -0
  27. data/lib/semaph/shells/pipeline/job_log_grep_command.rb +28 -0
  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 +57 -22
  32. data/lib/semaph/shells/pipeline/pipeline_shell.rb +29 -67
  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 +3 -16
  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 +32 -7
@@ -0,0 +1,28 @@
1
+ module Semaph
2
+ module Shells
3
+ module Pipeline
4
+ class JobStopCommand
5
+ attr_reader :usage, :help
6
+
7
+ def initialize(job_collection)
8
+ @job_collection = job_collection
9
+ @usage = "<job index>"
10
+ @help = "stop 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
+ job.stop
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -1,3 +1,5 @@
1
+ require "semaph/formatting"
2
+
1
3
  module Semaph
2
4
  module Shells
3
5
  module Pipeline
@@ -9,10 +11,10 @@ module Semaph
9
11
  @help = "list jobs"
10
12
  end
11
13
 
12
- def execute(_whatever)
14
+ def execute(_whatever = nil)
13
15
  @job_collection.reload
14
16
  @job_collection.all.each_with_index do |job, index|
15
- puts "#{index + 1} #{job.description}"
17
+ puts [::Semaph::Formatting.index(index + 1), job.description].join(" ")
16
18
  end
17
19
  end
18
20
  end
@@ -1,35 +1,70 @@
1
+ require "semaph/formatting"
2
+
1
3
  module Semaph
2
4
  module Shells
3
5
  module Pipeline
4
6
  class JobsPollCommand
5
- attr_reader :usage, :help
7
+ attr_reader :usage, :help, :job_collection
6
8
 
7
- def initialize(job_collection)
9
+ def initialize(job_collection, list_command)
8
10
  @job_collection = job_collection
11
+ @list_command = list_command
9
12
  @help = "poll jobs"
10
13
  @can_notify = !`which terminal-notifier`.chomp.empty?
11
14
  end
12
15
 
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
16
+ def execute(_whatever = nil)
17
+ report_and_reload(15) while job_collection.incomplete.count.positive? && job_collection.failed.count.zero?
18
+ report_final
19
+ end
20
+
21
+ private
22
+
23
+ def report_and_reload(period)
24
+ period.times { report_incomplete }
25
+ job_collection.reload
26
+ end
27
+
28
+ def report_final
29
+ @list_command.execute
30
+ failed_job_count = job_collection.failed.count
31
+ notify(
32
+ "Workflow completed",
33
+ "#{job_collection.pipeline.workflow.description} completed with #{failed_job_count} failed jobs",
34
+ failed_job_count.positive?,
35
+ )
36
+ end
37
+
38
+ def report_incomplete
39
+ base = [nil, elapsed, report_ratio, job_collection.pipeline.workflow.description].join(" ")
40
+ erase base
41
+ end
42
+
43
+ def report_ratio
44
+ [
45
+ job_collection.incomplete.count.to_s.rjust(2, "0"),
46
+ job_collection.all.count.to_s.rjust(2, "0"),
47
+ ].join("/")
48
+ end
49
+
50
+ def elapsed
51
+ duration = Time.now.to_i - job_collection.created_at.to_i
52
+ mins = duration / 60
53
+ secs = duration % 60
54
+ [mins.to_s.rjust(2, "0"), secs.to_s.rjust(2, "0")].join(":")
55
+ end
56
+
57
+ def erase(string)
58
+ print string
59
+ print "\b" * string.length
60
+ end
61
+
62
+ def notify(title, message, failed)
63
+ return unless @can_notify
64
+
65
+ sound = failed ? "basso" : "blow"
66
+
67
+ `terminal-notifier -group semaph -message "#{message}" -title "#{title}" -sound #{sound}`
33
68
  end
34
69
  end
35
70
  end
@@ -1,8 +1,13 @@
1
- require "semaph/commands/reload_command"
2
- require "semaph/commands/rerun_workflow_command"
1
+ require "semaph/commands"
2
+ require "semaph/shells/pipeline/job_debug_command"
3
+ require "semaph/shells/pipeline/job_log_command"
4
+ require "semaph/shells/pipeline/job_log_grep_command"
5
+ require "semaph/shells/pipeline/job_show_command"
6
+ require "semaph/shells/pipeline/job_stop_command"
3
7
  require "semaph/shells/pipeline/jobs_list_command"
4
- require "semaph/shells/pipeline/jobs_logs_command"
5
8
  require "semaph/shells/pipeline/jobs_poll_command"
9
+ require "semaph/shells/pipeline/promote_command"
10
+ require "semaph/shells/pipeline/promotions_list_command"
6
11
  require "shell_shock/context"
7
12
 
8
13
  module Semaph
@@ -15,82 +20,39 @@ module Semaph
15
20
 
16
21
  def initialize(pipeline)
17
22
  @pipeline = pipeline
23
+ workflow = pipeline.workflow
24
+ project = workflow.project
18
25
  @prompt = "🏗 #{project.client.name} #{project.name} #{workflow.id} #{pipeline.yaml} > "
26
+ add_command ::Semaph::Commands::ReloadCommand.new, "reload" if ENV["SEMAPH_RELOAD"]
19
27
  add_commands
20
- @jobs_list_command.execute("")
28
+ jobs_list_command.execute
21
29
  end
22
30
 
23
31
  private
24
32
 
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
33
  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
- )
34
+ ::Semaph::Commands.workflow_commands(self, pipeline.workflow)
35
+ add_job_collection_commands(pipeline.job_collection)
36
+ add_command PromoteCommand.new(pipeline), "promote"
37
+ add_command PromotionsListCommand.new(pipeline.promotion_collection), "list-promotions"
57
38
  end
58
39
 
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
- )
40
+ def add_job_collection_commands(job_collection)
41
+ add_command JobsPollCommand.new(job_collection, jobs_list_command), "poll"
42
+ add_command JobLogCommand.new(job_collection), "log"
43
+ add_command JobDebugCommand.new(job_collection), "debug"
44
+ add_command JobShowCommand.new(job_collection), "show"
45
+ add_command JobStopCommand.new(job_collection), "stop"
46
+ add_command JobLogGrepCommand.new(job_collection, :all), "grep-all-logs"
47
+ add_command JobLogGrepCommand.new(job_collection, :failed), "grep-failed-logs"
67
48
  end
68
49
 
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
50
+ def jobs_list_command
51
+ return @jobs_list_command if @jobs_list_command
85
52
 
86
- def add_github_commit
87
- add_command(
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",
93
- )
53
+ @jobs_list_command = JobsListCommand.new(pipeline.job_collection)
54
+ add_command @jobs_list_command, "list-jobs", "ls"
55
+ @jobs_list_command
94
56
  end
95
57
  end
96
58
  end
@@ -0,0 +1,21 @@
1
+ module Semaph
2
+ module Shells
3
+ module Pipeline
4
+ class PromoteCommand
5
+ attr_reader :usage, :help
6
+
7
+ def initialize(pipeline)
8
+ @pipeline = pipeline
9
+ @usage = "<promotion name>"
10
+ @help = "promote pipeline"
11
+ end
12
+
13
+ def execute(name)
14
+ @pipeline.promote(name.chomp.strip)
15
+ rescue ::Semaph::Client::RequestException => e
16
+ puts e.message
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ module Semaph
2
+ module Shells
3
+ module Pipeline
4
+ class PromotionsListCommand
5
+ attr_reader :usage, :help
6
+
7
+ def initialize(promotion_collection)
8
+ @promotion_collection = promotion_collection
9
+ @help = "list promotions"
10
+ end
11
+
12
+ def execute(_whatever)
13
+ @promotion_collection.reload
14
+ @promotion_collection.all.each_with_index do |promotion, index|
15
+ puts "#{index + 1} #{promotion.description}"
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,5 +1,6 @@
1
1
  require "semaph/commands/reload_command"
2
2
  require "semaph/commands/visit_url_command"
3
+ require "semaph/shells/project/save_command"
3
4
  require "semaph/shells/project/workflows_list_command"
4
5
  require "semaph/shells/project/workflows_select_command"
5
6
  require "shell_shock/context"
@@ -28,9 +29,10 @@ module Semaph
28
29
  def add_commands
29
30
  add_github_command
30
31
  add_open_project_command
32
+ add_command SaveCommand.new(project), "save"
31
33
  @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 @workflows_list_command, "list-workflows", "ls"
35
+ add_command WorkflowsSelectCommand.new(workflow_collection), "select-workflow", "cd"
34
36
  add_command ::Semaph::Commands::ReloadCommand.new, "reload" if ENV["SEMAPH_RELOAD"]
35
37
  end
36
38
 
@@ -0,0 +1,26 @@
1
+ require "yaml"
2
+
3
+ module Semaph
4
+ module Shells
5
+ module Project
6
+ class SaveCommand
7
+ attr_reader :help, :project
8
+
9
+ def initialize(project)
10
+ @project = project
11
+ @help = "save current project as default for this folder"
12
+ end
13
+
14
+ def execute(_ignored)
15
+ config = {
16
+ host: project.client.host,
17
+ project: project.raw,
18
+ }
19
+ File.open(".semaph", "w") do |file|
20
+ file.puts config.to_yaml
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -1,9 +1,9 @@
1
+ require "semaph/formatting"
2
+
1
3
  module Semaph
2
4
  module Shells
3
5
  module Project
4
6
  class WorkflowsListCommand
5
- TIME_FORMAT = "%Y-%m-%d %H:%M:%S".freeze
6
-
7
7
  attr_reader :usage, :help
8
8
 
9
9
  def initialize(workflow_collection)
@@ -17,22 +17,9 @@ module Semaph
17
17
  @workflow_collection.all.each_with_index do |workflow, index|
18
18
  next unless workflow.branch.include?(branch)
19
19
 
20
- puts description(index, workflow)
20
+ puts [::Semaph::Formatting.index(index + 1), workflow.description].join(" ")
21
21
  end
22
22
  end
23
-
24
- private
25
-
26
- def description(index, workflow)
27
- [
28
- index + 1,
29
- workflow.created_at.strftime(TIME_FORMAT),
30
- "SHA",
31
- workflow.sha,
32
- "on branch",
33
- workflow.branch,
34
- ].join(" ")
35
- end
36
23
  end
37
24
  end
38
25
  end
@@ -1,3 +1,5 @@
1
+ require "semaph/formatting"
2
+
1
3
  module Semaph
2
4
  module Shells
3
5
  module Workflow
@@ -12,7 +14,7 @@ module Semaph
12
14
  def execute(_whatever)
13
15
  @pipeline_collection.reload
14
16
  @pipeline_collection.all.each_with_index do |pipeline, index|
15
- puts "#{index + 1} #{pipeline.description}"
17
+ puts [::Semaph::Formatting.index(index + 1), pipeline.description].join(" ")
16
18
  end
17
19
  end
18
20
  end
@@ -1,7 +1,4 @@
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"
1
+ require "semaph/commands"
5
2
  require "semaph/shells/workflow/pipelines_list_command"
6
3
  require "semaph/shells/workflow/pipelines_select_command"
7
4
  require "shell_shock/context"
@@ -16,6 +13,7 @@ module Semaph
16
13
 
17
14
  def initialize(workflow)
18
15
  @workflow = workflow
16
+ project = @workflow.project
19
17
  @prompt = "🏗 #{project.client.name} #{project.name} #{workflow.id} > "
20
18
  add_commands
21
19
  @list_command.execute("")
@@ -23,71 +21,13 @@ module Semaph
23
21
 
24
22
  private
25
23
 
26
- def project
27
- @workflow.project
28
- end
29
-
30
- def pipeline_collection
31
- @workflow.pipeline_collection
32
- end
33
-
34
24
  def add_commands
25
+ pipeline_collection = @workflow.pipeline_collection
35
26
  @list_command = PipelinesListCommand.new(pipeline_collection)
36
- add_command @list_command, "list-pipelines"
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
27
+ add_command @list_command, "list-pipelines", "ls"
28
+ add_command PipelinesSelectCommand.new(pipeline_collection), "select-pipeline", "cd"
43
29
  add_command ::Semaph::Commands::ReloadCommand.new, "reload" if ENV["SEMAPH_RELOAD"]
44
- end
45
-
46
- def add_open_workflow_command
47
- add_command(
48
- ::Semaph::Commands::VisitUrlCommand.new(
49
- "https://#{project.client.host}/workflows/#{workflow.id}",
50
- "browse to workflow",
51
- ),
52
- "open-workflow",
53
- )
54
- end
55
-
56
- def add_open_branch_command
57
- add_command(
58
- ::Semaph::Commands::VisitUrlCommand.new(
59
- "https://#{project.client.host}/branches/#{workflow.branch_id}",
60
- "browse to branch in semaphore",
61
- ),
62
- "open-branch",
63
- )
64
- end
65
-
66
- def add_github_commands
67
- return unless workflow.project.github_url
68
-
69
- add_github_branch
70
- add_github_commit
71
- end
72
-
73
- def add_github_branch
74
- add_command(
75
- ::Semaph::Commands::VisitUrlCommand.new(
76
- "#{workflow.project.github_url}/tree/#{workflow.branch}",
77
- "browse to the branch in github",
78
- ),
79
- "open-github-branch",
80
- )
81
- end
82
-
83
- def add_github_commit
84
- add_command(
85
- ::Semaph::Commands::VisitUrlCommand.new(
86
- "#{workflow.project.github_url}/commit/#{workflow.sha}",
87
- "browse to the commit in github",
88
- ),
89
- "open-github-commit",
90
- )
30
+ ::Semaph::Commands.workflow_commands(self, workflow)
91
31
  end
92
32
  end
93
33
  end