capistrano-fiesta 1.4.1 → 1.5.1

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
  SHA1:
3
- metadata.gz: 0523e553bc6d687b7a7b9a1c712c5d6f9cc5ad6d
4
- data.tar.gz: 00c27fe98e2f058a7ae9ee2711c5c96078e56526
3
+ metadata.gz: 0d2c67bd3f3a7967e8c0d2e21ac1cad88572c1c4
4
+ data.tar.gz: bff17d6f9c990d1196cea630f61acdb4861d6764
5
5
  SHA512:
6
- metadata.gz: d950d568707047a06c9c03971d81ee2d6fc619d2602f7417e929c61a69bc4c2b3447df1991c7c66693013757bac09c7c327e5f77cf661946593c65bde8d00674
7
- data.tar.gz: 7243ef680c5fca0955ff5b81959f85ae8b75c1f5e67dacc0b7e0b802a90ce3015837535ce37bf42ec4418b518d3381313919e472e37858a3f9ab495c94f92ee8
6
+ metadata.gz: 1ef2d2eef7c9c4dcc79e9c1906394b6bbd0eaac76d3f9d9e2a24b2047892e88b473d65dfadae9abce0e4d787f24057b62b0a2c2afb01f441cf5ab9e4b85e70a2
7
+ data.tar.gz: 7c106e2d4245732539088c88f5425228401c8b453e32804de58942d6b7a48fe3113fbafe43ce17a1403f03876cc1750a2dcfd297ea963fc37593a99132731045
@@ -19,6 +19,7 @@ Gem::Specification.new do |spec|
19
19
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
20
  spec.require_paths = ["lib"]
21
21
 
22
+ spec.add_dependency "attr_extras", "~> 5.2"
22
23
  spec.add_dependency "capistrano", "~> 3.1"
23
24
  spec.add_dependency "octokit", "~> 4.1"
24
25
 
@@ -0,0 +1,32 @@
1
+ require "attr_extras/explicit"
2
+ require "capistrano/fiesta/slack_dummy"
3
+
4
+ module Capistrano
5
+ module Fiesta
6
+ class Announcement
7
+ extend AttrExtras.mixin
8
+ pattr_initialize :text, :config
9
+
10
+ def post
11
+ client.post(options)
12
+ text
13
+ end
14
+
15
+ private
16
+
17
+ def options
18
+ config.merge(payload: payload)
19
+ end
20
+
21
+ def payload
22
+ config.fetch(:payload, {}).merge(text: text)
23
+ end
24
+
25
+ def client
26
+ Slackistrano
27
+ rescue NameError
28
+ SlackDummy.new
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,15 @@
1
+ module Capistrano
2
+ module Fiesta
3
+ class AutoComposedStory < Story
4
+ SCREENSHOT_TAG = "#"
5
+
6
+ def release_note
7
+ release_note_in_body
8
+ end
9
+
10
+ def images
11
+ pr.body.to_s.scan(/https?:\/\/\S*\.(?:png|jpg|gif)#{SCREENSHOT_TAG}/i)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -1,11 +1,11 @@
1
+ require "attr_extras/explicit"
1
2
  require "tempfile"
2
3
 
3
4
  module Capistrano
4
5
  module Fiesta
5
6
  class Editor
6
- def initialize(content)
7
- @content = content
8
- end
7
+ extend AttrExtras.mixin
8
+ pattr_initialize :content, [:comment]
9
9
 
10
10
  def compose
11
11
  create_temp_file
@@ -16,7 +16,8 @@ module Capistrano
16
16
  private
17
17
 
18
18
  def create_temp_file
19
- file << @content
19
+ file << content
20
+ file << "# #{comment}\n\n" if comment
20
21
  file.close
21
22
  end
22
23
 
@@ -37,7 +38,7 @@ module Capistrano
37
38
  end
38
39
 
39
40
  def file
40
- @file ||= Tempfile.new(['fiesta', '.md'])
41
+ @_file ||= Tempfile.new(["fiesta", ".md"])
41
42
  end
42
43
  end
43
44
  end
@@ -4,6 +4,11 @@ require "yaml"
4
4
  module Capistrano
5
5
  module Fiesta
6
6
  class Github
7
+
8
+ def self.client
9
+ new.client
10
+ end
11
+
7
12
  def client
8
13
  Octokit::Client.new(config)
9
14
  end
@@ -0,0 +1,32 @@
1
+ require "attr_extras/explicit"
2
+
3
+ module Capistrano
4
+ module Fiesta
5
+ class Release
6
+ extend AttrExtras.mixin
7
+ pattr_initialize [:repo, :name, :stories]
8
+
9
+ def post
10
+ github.create_release(repo, tag, name: name, body: body)
11
+ end
12
+
13
+ private
14
+
15
+ def name
16
+ @name ||= Time.now.to_i.to_s
17
+ end
18
+
19
+ def tag
20
+ "release-#{name}"
21
+ end
22
+
23
+ def body
24
+ stories.map(&:to_markdown).join("\n")
25
+ end
26
+
27
+ def github
28
+ @_github ||= Github.client
29
+ end
30
+ end
31
+ end
32
+ end
@@ -1,44 +1,72 @@
1
- Encoding.default_internal = Encoding.default_external = 'utf-8'
1
+ Encoding.default_internal = Encoding.default_external = "utf-8"
2
2
 
3
+ require "attr_extras/explicit"
4
+ require "capistrano/fiesta/announcement"
3
5
  require "capistrano/fiesta/github"
4
- require "capistrano/fiesta/draft"
6
+ require "capistrano/fiesta/template"
5
7
  require "capistrano/fiesta/editor"
6
8
  require "capistrano/fiesta/logger"
7
- require "capistrano/fiesta/slack_dummy"
8
9
  require "capistrano/fiesta/story"
10
+ require "capistrano/fiesta/auto_composed_story"
11
+ require "capistrano/fiesta/release"
9
12
 
10
13
  module Capistrano
11
14
  module Fiesta
12
15
  class Report
13
- attr_reader :stories
16
+ extend AttrExtras.mixin
17
+ pattr_initialize :github_url, [:last_release, :comment, :auto_compose]
18
+ attr_query :auto_compose?
14
19
 
15
- def initialize(github_url, last_release: nil, comment: nil)
16
- @github_url, @last_release, @comment = github_url, last_release, comment
17
- @stories = merged_pull_requests.map { |pr| Story.new(pr) }
20
+ def announce(config = {})
21
+ return Logger.warn("Announcement blank, nothing posted to Slack") if nothing_to_announce?
22
+ Announcement.new(text, config).post
18
23
  end
19
24
 
20
- def announce(options = {})
21
- text = editor.compose if stories.any?
22
- return Logger.warn('Announcement blank, nothing posted to Slack') if text.nil? || text.empty?
23
- options[:payload] = options.fetch(:payload, {}).merge(text: text)
24
- chat.post(options)
25
- text
25
+ def create_release(name = nil)
26
+ return Logger.warn "No new stories, skipping GitHub release" if stories.none?
27
+ Release.new(repo: repo, name: name, stories: stories).post
26
28
  end
27
29
 
28
- def create_release(name = nil)
29
- return Logger.warn 'No new stories, skipping GitHub release' if stories.none?
30
- name ||= Time.now.to_i.to_s
31
- github.create_release(repo, "release-#{name}", name: name, body: stories.map(&:to_markdown).join("\n"))
30
+ def stories
31
+ @_stories ||= fetch_stories
32
32
  end
33
33
 
34
34
  private
35
35
 
36
+ def fetch_stories
37
+ if auto_compose?
38
+ merged_pull_requests.map { |pr| AutoComposedStory.new(pr) }
39
+ else
40
+ merged_pull_requests.map { |pr| Story.new(pr) }
41
+ end
42
+ end
43
+
44
+ def nothing_to_announce?
45
+ stories.none? || text.nil? || text.empty?
46
+ end
47
+
48
+ def text
49
+ @_text ||= render_text
50
+ end
51
+
52
+ def render_text
53
+ if auto_compose?
54
+ template
55
+ else
56
+ editor.compose
57
+ end
58
+ end
59
+
36
60
  def editor
37
- Editor.new(draft.render)
61
+ Editor.new(template, comment: comment)
38
62
  end
39
63
 
40
- def draft
41
- Draft.new(comment: @comment, stories: stories)
64
+ def template
65
+ Template.new(stories_with_release_notes).render
66
+ end
67
+
68
+ def stories_with_release_notes
69
+ stories.find_all(&:release_note)
42
70
  end
43
71
 
44
72
  def merged_pull_requests
@@ -49,21 +77,17 @@ module Capistrano
49
77
  end
50
78
 
51
79
  def repo
52
- @github_url.match(/github.com[:\/](\S+\/\S+)\.git/)[1]
80
+ github_url.match(/github.com[:\/](\S+\/\S+)\.git/)[1]
53
81
  end
54
82
 
55
83
  def last_released_at
56
- Time.parse(@last_release + 'Z00:00').iso8601 if @last_release
84
+ if last_release
85
+ Time.parse(last_release + "Z00:00").iso8601
86
+ end
57
87
  end
58
88
 
59
89
  def github
60
- @github ||= Github.new.client
61
- end
62
-
63
- def chat
64
- Slackistrano
65
- rescue NameError
66
- SlackDummy.new
90
+ @_github ||= Github.client
67
91
  end
68
92
  end
69
93
  end
@@ -1,20 +1,21 @@
1
+ require "attr_extras/explicit"
2
+
1
3
  module Capistrano
2
4
  module Fiesta
3
5
  class Story
4
- def initialize(pr)
5
- @pr = pr
6
- end
6
+ extend AttrExtras.mixin
7
+ pattr_initialize :pr
7
8
 
8
9
  def release_note
9
10
  (release_note_in_body || title).strip
10
11
  end
11
12
 
12
13
  def images
13
- @pr.body.to_s.scan(/https?:\/\/\S*\.(?:png|jpg|gif)/i)
14
+ pr.body.to_s.scan(/https?:\/\/\S*\.(?:png|jpg|gif)/i)
14
15
  end
15
16
 
16
17
  def url
17
- @pr.html_url
18
+ pr.html_url
18
19
  end
19
20
 
20
21
  def to_markdown
@@ -24,11 +25,11 @@ module Capistrano
24
25
  private
25
26
 
26
27
  def title
27
- @pr.title.to_s.sub(/\[Delivers #\S+\]\z/, '')
28
+ @_title ||= pr.title.to_s.sub(/\[Delivers #\S+\]\z/, "")
28
29
  end
29
30
 
30
31
  def release_note_in_body
31
- @pr.body.to_s[/_Release\snote\:(.+)_/m, 1]
32
+ @_release_note_in_body ||= pr.body.to_s[/_Release\snote\:?\s(.+)_/m, 1]
32
33
  end
33
34
  end
34
35
  end
@@ -0,0 +1,21 @@
1
+ require "attr_extras/explicit"
2
+ require "erb"
3
+
4
+ module Capistrano
5
+ module Fiesta
6
+ class Template
7
+ extend AttrExtras.mixin
8
+ pattr_initialize :stories
9
+
10
+ def render
11
+ ERB.new(File.read(erb), nil, "-").result(binding)
12
+ end
13
+
14
+ private
15
+
16
+ def erb
17
+ File.join(File.expand_path("../../templates", __FILE__), "draft.erb")
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,5 +1,5 @@
1
1
  module Capistrano
2
2
  module Fiesta
3
- VERSION = "1.4.1"
3
+ VERSION = "1.5.1"
4
4
  end
5
5
  end
@@ -1,40 +1,61 @@
1
1
  namespace :fiesta do
2
- desc 'Run a fiesta report and announce it'
2
+ desc "Generate a fiesta report and announce it"
3
3
  task :run do
4
- invoke 'fiesta:generate'
5
- invoke 'fiesta:announce'
4
+ if master_branch?
5
+ invoke "fiesta:generate"
6
+ invoke "fiesta:announce"
7
+ end
6
8
  end
7
9
 
8
- desc 'Generate a fiesta report'
10
+ desc "Generate a fiesta report"
9
11
  task :generate do
10
12
  run_locally do
11
- set :fiesta_report, Capistrano::Fiesta::Report.new(repo_url, last_release: last_release, comment: fetch(:fiesta_comment))
12
- info "Deploying #{report.stories.size} new story(ies)"
13
+ set :fiesta_report, build_report
13
14
  end
14
15
  end
15
16
 
16
- desc 'Announce a fiesta report'
17
+ desc "Announce a fiesta report"
17
18
  task :announce do
18
19
  run_locally do
19
20
  report.announce(slack_params)
20
- report.create_release fetch(:release_timestamp) if fetch(:branch) == 'master'
21
+ report.create_release(timestamp)
21
22
  Capistrano::Fiesta::Logger.logs.each { |log| warn log }
22
23
  end
23
24
  end
24
25
 
26
+ def build_report
27
+ Capistrano::Fiesta::Report.new(repo_url, report_options)
28
+ end
29
+
25
30
  def report
26
31
  fetch(:fiesta_report)
27
32
  end
28
33
 
34
+ def report_options
35
+ {
36
+ last_release: last_release,
37
+ comment: fetch(:fiesta_comment),
38
+ auto_compose: fetch(:fiesta_auto_compose)
39
+ }
40
+ end
41
+
29
42
  def last_release
30
43
  last_release = nil
31
44
  on roles(:web).first do
32
45
  last_release_path = capture("readlink #{current_path}")
33
- last_release = last_release_path.split('/').last
46
+ last_release = last_release_path.split("/").last
34
47
  end
35
48
  last_release
36
49
  end
37
50
 
51
+ def master_branch?
52
+ fetch(:branch) == "master"
53
+ end
54
+
55
+ def timestamp
56
+ fetch(:release_timestamp)
57
+ end
58
+
38
59
  def slack_params
39
60
  {
40
61
  team: fetch(:slack_team),
@@ -42,13 +63,13 @@ namespace :fiesta do
42
63
  webhook: fetch(:slack_webhook),
43
64
  via_slackbot: fetch(:slack_via_slackbot),
44
65
  payload: {
45
- channel: fetch(:fiesta_slack_channel) || 'releases',
46
- username: fetch(:fiesta_slack_username) || 'New Releases',
47
- icon_emoji: ':tada:'
66
+ channel: fetch(:fiesta_slack_channel) || "releases",
67
+ username: fetch(:fiesta_slack_username) || "New Releases",
68
+ icon_emoji: ":tada:"
48
69
  }
49
70
  }
50
71
  end
51
72
  end
52
73
 
53
- before 'deploy:starting', 'fiesta:generate'
54
- after 'deploy:finished', 'fiesta:announce'
74
+ before "deploy:starting", "fiesta:generate"
75
+ after "deploy:finished", "fiesta:announce"
@@ -1,7 +1,3 @@
1
- <% if comment -%>
2
- # <%= comment %>
3
-
4
- <% end -%>
5
1
  <% stories.each do |story| -%>
6
2
  • <%= story.release_note %>
7
3
  <% story.images.each do |image| -%>
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: capistrano-fiesta
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.1
4
+ version: 1.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jens Balvig
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-05-22 00:00:00.000000000 Z
11
+ date: 2017-06-08 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: attr_extras
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '5.2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '5.2'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: capistrano
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -169,13 +183,16 @@ files:
169
183
  - capistrano-fiesta.gemspec
170
184
  - lib/capistrano-fiesta.rb
171
185
  - lib/capistrano/fiesta.rb
172
- - lib/capistrano/fiesta/draft.rb
186
+ - lib/capistrano/fiesta/announcement.rb
187
+ - lib/capistrano/fiesta/auto_composed_story.rb
173
188
  - lib/capistrano/fiesta/editor.rb
174
189
  - lib/capistrano/fiesta/github.rb
175
190
  - lib/capistrano/fiesta/logger.rb
191
+ - lib/capistrano/fiesta/release.rb
176
192
  - lib/capistrano/fiesta/report.rb
177
193
  - lib/capistrano/fiesta/slack_dummy.rb
178
194
  - lib/capistrano/fiesta/story.rb
195
+ - lib/capistrano/fiesta/template.rb
179
196
  - lib/capistrano/fiesta/version.rb
180
197
  - lib/capistrano/tasks/fiesta.rake
181
198
  - lib/capistrano/templates/draft.erb
@@ -1,23 +0,0 @@
1
- require "erb"
2
-
3
- module Capistrano
4
- module Fiesta
5
- class Draft
6
- attr_reader :comment, :stories
7
-
8
- def initialize(comment:, stories: [])
9
- @comment, @stories = comment, stories
10
- end
11
-
12
- def render
13
- ERB.new(File.read(template), nil, '-').result(binding)
14
- end
15
-
16
- private
17
-
18
- def template
19
- File.join(File.expand_path('../../templates', __FILE__), 'draft.erb')
20
- end
21
- end
22
- end
23
- end