capistrano-slacky 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 386586f5b65ad40376cdf7e1fcd1bb915445c8142bb1159027da83acbda7fc48
4
- data.tar.gz: e7a7ce2418418b4285401c8b5d737284d9d9b2930ac1c7f9514c33a49b3cb2d7
3
+ metadata.gz: 7d8a000422ee77540816f23c92063aaafbc39d62c1d7328bca687abe74c42976
4
+ data.tar.gz: 96fea627fc2ef504cb8597a3c4c904ac75fda310b142f4e0e700e96659b9a6ea
5
5
  SHA512:
6
- metadata.gz: ab2a70933589f9e2b0f1c664c5f83aa349862d945484b395d411b8c624fc3c089d147ae392e892793cb313419cd91e12b0e40c005f1847af5dfff61d667ef994
7
- data.tar.gz: d84c8b2287b2a08c3b140e09e8dcc9bd51a363909a5e7f18ce9b7a3ee7753c07ca6e6bdc84cde690011879bcbd1ade0f5999b18b1e39ac902a5b85cc50734b8b
6
+ metadata.gz: a2290b5b024df873244e1a0196befec28381519aa5ad8ccdecf5c2d67931e0653cc68fc8c4325809381a038d8fe890ccff88dcfdb6969994337ffc61ad52d7d4
7
+ data.tar.gz: bbca074fb05c97288aecbdf858cfcdb03dabbcd2cc969c183e42d39f17e9f32171cb29f5fe762e6df3301dbaf3fb71d88e703312d37adedc2f4a7b64a9984689
data/CHANGELOG.md CHANGED
@@ -4,11 +4,27 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
- ## [Unreleased]
7
+ ## [0.1.2] - 2021-06-03
8
+ ### Changed
9
+ - Use `I18n.t` instead of `t`. ([@chubchenko][])
10
+ - Use `forwardable` instead of `method_missing` + `respond_to_missing?`. ([@chubchenko][])
11
+ - Use the `On` module to interact with the remote server. ([@chubchenko][])
12
+ - Extracted hooks and defaults from `slacky.rake` into separate files. ([@chubchenko][])
13
+ - Renamed `#to_json` to `#as_json`. ([@chubchenko][])
14
+ - Updated hooks from `before` to `after`. ([@chubchenko][])
15
+ - Added 💯 test coverage. ([@chubchenko][])
16
+
17
+ ### Fixed
18
+ - Use `@env` instance variable instead of missing getter `env`. ([@chubchenko][])
19
+ - Update your SSH regex to match the repository with a dash in the name. ([@chubchenko][])
20
+ - Use `SSHKit::Backend.current.capture` instead of `IO.popen` to perform `git log ..` on the remote server. ([@chubchenko][])
21
+
22
+ ### Security
23
+ - Fix possible command injection during the duration retrieval. ([@chubchenko][])
8
24
 
9
25
  ## [0.1.1] - 2021-05-27
10
26
  ### Fixed
11
- - Fix a bug related to using a `Null` messaging
27
+ - Fix a bug related to using a `Null` messaging. ([@chubchenko][])
12
28
 
13
29
  ## [0.1.0] - 2021-05-26
14
30
  ### Added
@@ -16,5 +32,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
16
32
 
17
33
  [@chubchenko]: https://github.com/chubchenko
18
34
  [Unreleased]: https://github.com/chubchenko/capistrano-slacky/compare/v0.1.1...HEAD
35
+ [0.1.2]: https://github.com/chubchenko/capistrano-slacky/compare/v0.1.1...v0.1.2
19
36
  [0.1.1]: https://github.com/chubchenko/capistrano-slacky/compare/v0.1.0...v0.1.1
20
37
  [0.1.0]: https://github.com/chubchenko/capistrano-slacky/releases/tag/v0.1.0
data/README.md CHANGED
@@ -8,6 +8,7 @@ Send `Capistrano` deployment status to `Slack`.
8
8
 
9
9
  [MIT][3]
10
10
 
11
- [1]: https://github.com/chubchenko/capistrano-slacky/workflows/build/badge.svg
12
- [2]: https://github.com/chubchenko/capistrano-slacky/actions
11
+
12
+ [1]: https://github.com/chubchenko/capistrano-slacky/actions/workflows/build.yml/badge.svg
13
+ [2]: https://github.com/chubchenko/capistrano-slacky/actions/workflows/build.yml
13
14
  [3]: https://choosealicense.com/licenses/mit
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  load File.expand_path("../../tasks/slacky.rake", __FILE__)
4
+ load File.expand_path("../../tasks/hooks.rake", __FILE__)
5
+ load File.expand_path("../../tasks/defaults.rake", __FILE__)
4
6
 
5
7
  require_relative "slacky/version"
6
8
  require_relative "slacky/configuration"
@@ -9,24 +11,19 @@ require_relative "slacky/runner"
9
11
  require_relative "slacky/block"
10
12
  require_relative "slacky/facade"
11
13
  require_relative "slacky/command"
14
+ require_relative "slacky/on"
12
15
 
13
16
  module Capistrano
14
17
  module Slacky
15
- module_function
18
+ require "forwardable"
16
19
 
17
- # Delegate any missing method call to the configuration
18
- def method_missing(method_name, *arguments, &block)
19
- return super unless configuration.respond_to?(method_name)
20
+ module_function
20
21
 
21
- configuration.public_send(method_name, *arguments, &block)
22
- end
22
+ extend ::SingleForwardable
23
23
 
24
- # Replace the Object.respond_to?() method
25
- def respond_to_missing?(method_name, include_private = false)
26
- configuration.respond_to?(method_name) || super
27
- end
24
+ def_delegators :configuration, :username, :icon_emoji, :channel, :klass, :slacky?, :repo
25
+ def_delegator :"Capistrano::Slacky::On", :on
28
26
 
29
- # @return [Capistrano::Slacky::Configuration]
30
27
  def configuration
31
28
  @configuration ||= ::Capistrano::Slacky::Configuration.new
32
29
  end
@@ -10,10 +10,10 @@ module Capistrano
10
10
  end
11
11
  end
12
12
 
13
- def to_json
13
+ def as_json
14
14
  {
15
15
  type: :context,
16
- elements: @elements.map(&:to_json)
16
+ elements: @elements.map(&:as_json)
17
17
  }
18
18
  end
19
19
 
@@ -22,7 +22,7 @@ module Capistrano
22
22
  @text = text
23
23
  end
24
24
 
25
- def to_json
25
+ def as_json
26
26
  {
27
27
  type: :mrkdwn,
28
28
  text: @text
@@ -8,7 +8,7 @@ module Capistrano
8
8
  @text = text
9
9
  end
10
10
 
11
- def to_json
11
+ def as_json
12
12
  {
13
13
  type: :header,
14
14
  text: {
@@ -8,9 +8,9 @@ module Capistrano
8
8
  @blocks = blocks.flatten
9
9
  end
10
10
 
11
- def to_json
11
+ def as_json
12
12
  {
13
- blocks: @blocks.map(&:to_json)
13
+ blocks: @blocks.map(&:as_json)
14
14
  }
15
15
  end
16
16
  end
@@ -10,10 +10,10 @@ module Capistrano
10
10
  end
11
11
  end
12
12
 
13
- def to_json
13
+ def as_json
14
14
  {
15
15
  type: :section,
16
- fields: @fields.map(&:to_json)
16
+ fields: @fields.map(&:as_json)
17
17
  }
18
18
  end
19
19
 
@@ -22,7 +22,7 @@ module Capistrano
22
22
  @text = text
23
23
  end
24
24
 
25
- def to_json
25
+ def as_json
26
26
  {
27
27
  type: :mrkdwn, text: @text
28
28
  }
@@ -5,7 +5,13 @@ module Capistrano
5
5
  module Command
6
6
  class Diff
7
7
  def self.call(previous:, current:)
8
- new(previous: previous, current: current).call
8
+ output = nil
9
+
10
+ ::Capistrano::Slacky.on(within: :repository) do
11
+ output = new(previous: previous, current: current).call
12
+ end
13
+
14
+ output
9
15
  end
10
16
 
11
17
  def initialize(previous:, current:)
@@ -14,15 +20,15 @@ module Capistrano
14
20
  end
15
21
 
16
22
  def call
17
- diff = ::IO.popen(
18
- ["git", "log", "--oneline", "--first-parent", "#{previous}..#{current}"]
19
- ).readlines
23
+ log = ::SSHKit::Backend.current.capture(
24
+ :git, :log, "--oneline", "--first-parent", "#{previous}..#{current}"
25
+ ).split("\n")
20
26
 
21
- diff.map.with_index(1) do |line, index|
27
+ log.map.with_index(1) do |line, index|
22
28
  sha, commit = line.match(/^(\w+) (.*+?)/).captures
23
29
 
24
30
  if /^Merge pull request/.match?(commit)
25
- commit = ::IO.popen(["git", "log", "-1", sha, '--pretty=format:"%b"']).readline
31
+ commit = ::SSHKit::Backend.current.capture(:git, :log, "-1", sha, '--pretty=format:"%b"')
26
32
  end
27
33
 
28
34
  Message.new(index: index, sha: sha, commit: commit)
@@ -5,7 +5,7 @@ module Capistrano
5
5
  module Command
6
6
  class Duration
7
7
  def self.call(pid: $PID)
8
- `ps -p #{pid} -o etime=`.strip
8
+ ::IO.popen(["ps", "-p", pid.to_s, "-o", "etime="]).readline.strip
9
9
  end
10
10
  end
11
11
  end
@@ -37,14 +37,14 @@ module Capistrano
37
37
 
38
38
  def repo
39
39
  @repo ||= Repo.new(
40
- remote: env.fetch(:repo_url)
40
+ remote: @env.fetch(:repo_url)
41
41
  )
42
42
  end
43
43
 
44
44
  private
45
45
 
46
46
  def data
47
- @data ||= env.fetch(:slacky, {})
47
+ @data ||= @env.fetch(:slacky, {})
48
48
  end
49
49
 
50
50
  class Repo
@@ -64,7 +64,7 @@ module Capistrano
64
64
  end
65
65
 
66
66
  def ssh?
67
- @remote.match?(/((git|ssh|http(s)?)|(git@[\w.]+))(:(\/)?)([\w.@:\/-~]+)(\.git)(\/)?/)
67
+ @remote.match?(/((git|ssh|http(s)?)|(git@[\w.]+))(:(\/)?)([\w.@:\/~-]+)(\.git)(\/)?/)
68
68
  end
69
69
  end
70
70
 
@@ -8,9 +8,9 @@ module Capistrano
8
8
  @env = env
9
9
 
10
10
  super(
11
- t("slacky.stage"), "`#{stage}`",
12
- t("slacky.branch"), "`#{branch}`",
13
- t("slacky.duration"), "`#{duration}`",
11
+ ::I18n.t("slacky.stage", scope: "capistrano"), "`#{stage}`",
12
+ ::I18n.t("slacky.branch", scope: "capistrano"), "`#{branch}`",
13
+ ::I18n.t("slacky.duration", scope: "capistrano"), "`#{duration}`",
14
14
  )
15
15
  end
16
16
 
@@ -11,25 +11,17 @@ module Capistrano
11
11
  ).call
12
12
  end
13
13
 
14
- attr_accessor :difference
15
-
16
14
  def initialize(previous:, current:)
17
- ref = self
18
-
19
- on(::Capistrano::Configuration.env.primary(:app)) do
20
- within repo_path do
21
- ref.difference = ::Capistrano::Slacky::Command::Diff.call(
22
- previous: previous,
23
- current: current
24
- )
25
- end
26
- end
15
+ @difference = ::Capistrano::Slacky::Command::Diff.call(
16
+ previous: previous,
17
+ current: current
18
+ )
27
19
  end
28
20
 
29
21
  def call
30
22
  if difference.empty?
31
23
  return ::Capistrano::Slacky::Block::Context.new(
32
- t("slacky.nothing_has_changed_since_the_previous_release")
24
+ ::I18n.t("slacky.nothing_has_changed_since_the_previous_release", scope: "capistrano")
33
25
  )
34
26
  end
35
27
 
@@ -39,6 +31,10 @@ module Capistrano
39
31
  )
40
32
  end
41
33
  end
34
+
35
+ private
36
+
37
+ attr_reader :difference
42
38
  end
43
39
  end
44
40
  end
@@ -6,7 +6,7 @@ module Capistrano
6
6
  class DeployedBy < ::Capistrano::Slacky::Block::Context
7
7
  def initialize(env:)
8
8
  super(
9
- t("slacky.deployed_by", deployer: env.fetch(:local_user))
9
+ ::I18n.t("slacky.deployed_by", scope: "capistrano", deployer: env.fetch(:local_user))
10
10
  )
11
11
  end
12
12
  end
@@ -6,7 +6,7 @@ module Capistrano
6
6
  class Exception < ::Capistrano::Slacky::Block::Context
7
7
  DefaultException = ::Class.new(::StandardError) do
8
8
  def initialize
9
- super(t("slacky.something_went_wrong"))
9
+ super(::I18n.t("slacky.something_went_wrong", scope: "capistrano"))
10
10
  end
11
11
  end
12
12
 
@@ -39,7 +39,7 @@ module Capistrano
39
39
  }.freeze
40
40
 
41
41
  def initialize(text)
42
- super(t("slacky.#{text}", emoji: EMOJI_MAP.fetch(text).sample))
42
+ super(::I18n.t("slacky.#{text}", scope: "capistrano", emoji: EMOJI_MAP.fetch(text).sample))
43
43
  end
44
44
  end
45
45
  end
@@ -8,9 +8,10 @@ module Capistrano
8
8
  @env = env
9
9
 
10
10
  super(
11
- t("slacky.revision", repository_url: ::Capistrano::Slacky.repo.url,
12
- current: current,
13
- previous: previous)
11
+ I18n.t("slacky.revision", scope: "capistrano",
12
+ repository_url: ::Capistrano::Slacky.repo.url,
13
+ current: current,
14
+ previous: previous)
14
15
  )
15
16
  end
16
17
 
@@ -9,19 +9,15 @@ module Capistrano
9
9
 
10
10
  module_function
11
11
 
12
- def uri(role: Hook.role)
12
+ def uri
13
13
  output = nil
14
14
 
15
- on(role) do
16
- output = capture(:cat, File.join(shared_path, DEFAULT_HOOK_FILE))
15
+ ::Capistrano::Slacky.on(within: :shared) do
16
+ output = ::SSHKit::Backend.current.capture(:cat, DEFAULT_HOOK_FILE)
17
17
  end
18
18
 
19
19
  URI(output)
20
20
  end
21
-
22
- def role
23
- ::Capistrano::Configuration.env.primary(:app)
24
- end
25
21
  end
26
22
 
27
23
  private_constant :Hook
@@ -10,7 +10,7 @@ module Capistrano
10
10
  def self.for(env:)
11
11
  klass =
12
12
  if ::Capistrano::Slacky.slacky?
13
- (::Capistrano::Slacky.klass || Default)
13
+ (::Capistrano::Slacky.klass || ::Capistrano::Slacky::Messaging::Default)
14
14
  else
15
15
  Null
16
16
  end
@@ -11,7 +11,7 @@ module Capistrano
11
11
  ::Capistrano::Slacky::Facade::Revision.new(env: env),
12
12
  ::Capistrano::Slacky::Facade::Changelog.for(env: env),
13
13
  ::Capistrano::Slacky::Facade::DeployedBy.new(env: env)
14
- ).to_json
14
+ ).as_json
15
15
  end
16
16
 
17
17
  def payload_for_reverted
@@ -20,7 +20,7 @@ module Capistrano
20
20
  ::Capistrano::Slacky::Facade::Body.new(env: env),
21
21
  ::Capistrano::Slacky::Facade::Revision.new(env: env),
22
22
  ::Capistrano::Slacky::Facade::DeployedBy.new(env: env)
23
- ).to_json
23
+ ).as_json
24
24
  end
25
25
 
26
26
  def payload_for_failed
@@ -29,7 +29,13 @@ module Capistrano
29
29
  ::Capistrano::Slacky::Facade::Body.new(env: env),
30
30
  ::Capistrano::Slacky::Facade::Exception.new,
31
31
  ::Capistrano::Slacky::Facade::DeployedBy.new(env: env)
32
- ).to_json
32
+ ).as_json
33
+ end
34
+
35
+ private
36
+
37
+ def deploying?
38
+ env.fetch(:deploying, false)
33
39
  end
34
40
  end
35
41
  end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Capistrano
4
+ module Slacky
5
+ module On
6
+ class Path
7
+ extend ::Capistrano::DSL
8
+ end
9
+
10
+ PATH_MAP = {
11
+ repository: -> { Path.repo_path },
12
+ shared: -> { Path.shared_path }
13
+ }.freeze
14
+
15
+ private_constant :PATH_MAP
16
+
17
+ module_function
18
+
19
+ def on(within:, &block)
20
+ ::Capistrano::DSL.on(::Capistrano::Configuration.env.primary(:app)) do
21
+ ::SSHKit::Backend.current.within(PATH_MAP.fetch(within).call, &block)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -6,7 +6,7 @@ require_relative "fanout"
6
6
  module Capistrano
7
7
  module Slacky
8
8
  class Runner
9
- def self.call(env:, action:)
9
+ def self.call(action:, env: ::Capistrano::Configuration.env)
10
10
  payload = ::Capistrano::Slacky::Payload.new(
11
11
  env: env, action: action
12
12
  )
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Capistrano
4
4
  module Slacky
5
- VERSION = "0.1.1"
5
+ VERSION = "0.1.2"
6
6
  end
7
7
  end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :load do
4
+ task :defaults do
5
+ append :linked_files, "config/slacky.yml"
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ after :'deploy:finishing', :'slacky:updated'
4
+ after :'deploy:finishing_rollback', :'slacky:reverted'
5
+ after :'deploy:failed', :'slacky:failed'
@@ -3,40 +3,26 @@
3
3
  namespace :slacky do
4
4
  desc "Slacky after a successful deployment"
5
5
  task :updated do
6
- Capistrano::Slacky::Runner.call(
7
- env: self, action: :updated
8
- )
6
+ Capistrano::Slacky::Runner.call(action: :updated)
9
7
  end
10
8
 
11
9
  desc "Slacky after successful rollback"
12
10
  task :reverted do
13
- Capistrano::Slacky::Runner.call(
14
- env: self, action: :reverted
15
- )
11
+ Capistrano::Slacky::Runner.call(action: :reverted)
16
12
  end
17
13
 
18
14
  desc "Slacky after failure deployment or rollback"
19
15
  task :failed do
20
- Capistrano::Slacky::Runner.call(
21
- env: self, action: :failed
22
- )
16
+ Capistrano::Slacky::Runner.call(action: :failed)
23
17
  end
24
18
 
25
- # task :ping do
26
- # [:updated, :reverted, :failed].each do |action|
27
- # Capistrano::Slacky::Runner.call(
28
- # env: self, action: action
29
- # )
30
- # end
31
- # end
32
- end
33
-
34
- before :'deploy:finishing', :'slacky:updated'
35
- before :'deploy:finishing_rollback', :'slacky:reverted'
36
- before :'deploy:failed', :'slacky:failed'
19
+ desc "Slacky all slackable task (updated, reverted, failed)"
20
+ task :ping do
21
+ ask(:previous_revision) unless env.any?(:previous_revision)
22
+ ask(:current_revision) unless env.any?(:current_revision)
37
23
 
38
- namespace :load do
39
- task :defaults do
40
- append :linked_files, "config/slacky.yml"
24
+ [:updated, :reverted, :failed].each do |action|
25
+ Capistrano::Slacky::Runner.call(action: action)
26
+ end
41
27
  end
42
28
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: capistrano-slacky
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Artem Chubchenko
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-05-27 00:00:00.000000000 Z
11
+ date: 2021-06-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: capistrano
@@ -72,20 +72,6 @@ dependencies:
72
72
  - - "~>"
73
73
  - !ruby/object:Gem::Version
74
74
  version: '0.21'
75
- - !ruby/object:Gem::Dependency
76
- name: webmock
77
- requirement: !ruby/object:Gem::Requirement
78
- requirements:
79
- - - "~>"
80
- - !ruby/object:Gem::Version
81
- version: '3.12'
82
- type: :development
83
- prerelease: false
84
- version_requirements: !ruby/object:Gem::Requirement
85
- requirements:
86
- - - "~>"
87
- - !ruby/object:Gem::Version
88
- version: '3.12'
89
75
  description: Send Capistrano deployment status to Slack via the incoming webhooks
90
76
  integration
91
77
  email: artem.chubchenko@gmail.com
@@ -121,9 +107,12 @@ files:
121
107
  - lib/capistrano/slacky/messaging/base.rb
122
108
  - lib/capistrano/slacky/messaging/default.rb
123
109
  - lib/capistrano/slacky/messaging/null.rb
110
+ - lib/capistrano/slacky/on.rb
124
111
  - lib/capistrano/slacky/payload.rb
125
112
  - lib/capistrano/slacky/runner.rb
126
113
  - lib/capistrano/slacky/version.rb
114
+ - lib/tasks/defaults.rake
115
+ - lib/tasks/hooks.rake
127
116
  - lib/tasks/slacky.rake
128
117
  homepage: https://github.com/chubchenko/capistrano-slacky
129
118
  licenses: