capistrano-fiesta 1.4.1 → 1.5.1

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