capistrano-slacky 0.1.1 → 0.1.2

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 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: