amanuensis 1.0.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.
- checksums.yaml +7 -0
- data/.env.sample +10 -0
- data/.gitignore +15 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +248 -0
- data/Rakefile +2 -0
- data/amanuensis.gemspec +36 -0
- data/bin/amanuensis +6 -0
- data/lib/amanuensis.rb +41 -0
- data/lib/amanuensis/builder.rb +52 -0
- data/lib/amanuensis/cli.rb +54 -0
- data/lib/amanuensis/code_manager.rb +6 -0
- data/lib/amanuensis/fake.rb +15 -0
- data/lib/amanuensis/fake/code_manager.rb +18 -0
- data/lib/amanuensis/fake/push.rb +10 -0
- data/lib/amanuensis/fake/tracker.rb +11 -0
- data/lib/amanuensis/file.rb +14 -0
- data/lib/amanuensis/file/push.rb +37 -0
- data/lib/amanuensis/generator.rb +87 -0
- data/lib/amanuensis/github.rb +24 -0
- data/lib/amanuensis/github/code_manager.rb +42 -0
- data/lib/amanuensis/github/push.rb +27 -0
- data/lib/amanuensis/github/tracker.rb +33 -0
- data/lib/amanuensis/issue.rb +4 -0
- data/lib/amanuensis/logger.rb +26 -0
- data/lib/amanuensis/mail.rb +18 -0
- data/lib/amanuensis/mail/push.rb +12 -0
- data/lib/amanuensis/pivotal.rb +17 -0
- data/lib/amanuensis/pivotal/tracker.rb +18 -0
- data/lib/amanuensis/pull.rb +4 -0
- data/lib/amanuensis/push.rb +5 -0
- data/lib/amanuensis/release.rb +4 -0
- data/lib/amanuensis/tracker.rb +7 -0
- data/lib/amanuensis/trello.rb +19 -0
- data/lib/amanuensis/trello/tracker.rb +31 -0
- data/lib/amanuensis/validatable.rb +34 -0
- data/lib/amanuensis/version.rb +26 -0
- data/spec/fixtures/vcr_cassettes/github/amanuensis_generates_a_github_changelog_and_release.yml +550 -0
- data/spec/fixtures/vcr_cassettes/pivotal/amanuensis_generates_a_changelog_from_pivotal_tracker.yml +120 -0
- data/spec/fixtures/vcr_cassettes/trello/amanuensis_generates_a_changelog_from_trello_tracker.yml +359 -0
- data/spec/integrations/file_spec.rb +19 -0
- data/spec/integrations/github_spec.rb +16 -0
- data/spec/integrations/mail_spec.rb +16 -0
- data/spec/integrations/pivotal_spec.rb +16 -0
- data/spec/integrations/trello_spec.rb +18 -0
- data/spec/spec_helper.rb +37 -0
- data/spec/unit/fake_spec.rb +13 -0
- metadata +300 -0
@@ -0,0 +1,54 @@
|
|
1
|
+
module Amanuensis
|
2
|
+
class CLI < Thor
|
3
|
+
|
4
|
+
desc "generate", "Generate a changelog"
|
5
|
+
option :push, type: :array, aliases: :p, default: [:file]
|
6
|
+
option :tracker, type: :string, aliases: :t, default: :github
|
7
|
+
option :code_manager, type: :string, aliases: :c, default: :github
|
8
|
+
option :version, type: :string, aliases: :u, default: :patch
|
9
|
+
option :verbose, type: :boolean, aliases: :v, default: false
|
10
|
+
option :github, type: :hash, aliases: :g
|
11
|
+
option :trello, type: :hash, aliases: :c
|
12
|
+
option :pivotal, type: :hash, aliases: :i
|
13
|
+
option :mail, type: :hash, aliases: :m
|
14
|
+
option :file, type: :hash, aliases: :f
|
15
|
+
def generate
|
16
|
+
Amanuensis.push = options.push
|
17
|
+
Amanuensis.tracker = options.tracker
|
18
|
+
Amanuensis.code_manager = options.code_manager
|
19
|
+
Amanuensis.version = options.version
|
20
|
+
Amanuensis.verbose = options.verbose
|
21
|
+
|
22
|
+
if options.github.present?
|
23
|
+
options.github.each do |key, value|
|
24
|
+
Amanuensis::Github.send "#{key}=", value
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
if options.file.present?
|
29
|
+
options.file.each do |key, value|
|
30
|
+
Amanuensis::File.send "#{key}=", value
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
if options.trello.present?
|
35
|
+
options.trello.each do |key, value|
|
36
|
+
Amanuensis::Trello.send "#{key}=", value
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
if options.pivotal.present?
|
41
|
+
options.pivotal.each do |key, value|
|
42
|
+
Amanuensis::Pivotal.send "#{key}=", value
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
Amanuensis::Mail.pony = options.mail
|
47
|
+
|
48
|
+
Amanuensis.generate
|
49
|
+
rescue ValidationError => e
|
50
|
+
puts e.message
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require_relative 'fake/code_manager'
|
2
|
+
require_relative 'fake/tracker'
|
3
|
+
require_relative 'fake/push'
|
4
|
+
|
5
|
+
module Amanuensis
|
6
|
+
module Fake
|
7
|
+
include Validatable
|
8
|
+
end
|
9
|
+
|
10
|
+
Push.register :fake, Fake::Push.new
|
11
|
+
CodeManager.register :fake, Fake::CodeManager.new
|
12
|
+
Tracker.register :fake, Fake::Tracker.new
|
13
|
+
end
|
14
|
+
|
15
|
+
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Amanuensis
|
2
|
+
module File
|
3
|
+
class Push
|
4
|
+
|
5
|
+
def run(changelog)
|
6
|
+
if ::File.exists?(file_name)
|
7
|
+
prepend(changelog)
|
8
|
+
else
|
9
|
+
create(changelog)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def file_name
|
16
|
+
@file_name ||= File.file_name
|
17
|
+
end
|
18
|
+
|
19
|
+
def create(changelog)
|
20
|
+
f = ::File.new(file_name, 'w')
|
21
|
+
f.write changelog
|
22
|
+
f.close
|
23
|
+
end
|
24
|
+
|
25
|
+
def prepend(changelog)
|
26
|
+
::File.open(file_name, 'r') do |orig|
|
27
|
+
::File.unlink(file_name)
|
28
|
+
::File.open(file_name, 'w') do |new|
|
29
|
+
new.write changelog
|
30
|
+
new.write orig.read
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module Amanuensis
|
2
|
+
class Generator
|
3
|
+
|
4
|
+
def run!
|
5
|
+
valid_configurations!
|
6
|
+
|
7
|
+
CodeManager.use Amanuensis.code_manager.to_sym
|
8
|
+
Tracker.use Amanuensis.tracker.to_sym
|
9
|
+
|
10
|
+
changelog = build_changelog
|
11
|
+
result = push_changelog(changelog)
|
12
|
+
|
13
|
+
create_release if result.all?
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def verbose(message, &block)
|
19
|
+
if Amanuensis.verbose
|
20
|
+
logger.call message, block
|
21
|
+
else
|
22
|
+
block.call
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def logger
|
27
|
+
@logger ||= Logger.new
|
28
|
+
end
|
29
|
+
|
30
|
+
def build_changelog
|
31
|
+
verbose "Build changelog for #{version}" do
|
32
|
+
Builder.new(version, latest_release.created_at).build
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def push_changelog(changelog)
|
37
|
+
Amanuensis.push.map do |type|
|
38
|
+
Push.use type.to_sym
|
39
|
+
|
40
|
+
verbose "Push on #{type}" do
|
41
|
+
Push.run changelog
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def latest_release
|
47
|
+
@latest_release ||= CodeManager.latest_release
|
48
|
+
end
|
49
|
+
|
50
|
+
def create_release
|
51
|
+
verbose 'Create release' do
|
52
|
+
CodeManager.create_release version
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def valid_configurations!
|
57
|
+
verbose 'Valid configuration' do
|
58
|
+
Amanuensis.valid!
|
59
|
+
|
60
|
+
push.map(&:valid!)
|
61
|
+
tracker.valid!
|
62
|
+
code_manager.valid!
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def version
|
67
|
+
@version = Version.new(latest_release.tag).get
|
68
|
+
end
|
69
|
+
|
70
|
+
def push
|
71
|
+
@push ||= Amanuensis.push.map(&method(:classify))
|
72
|
+
end
|
73
|
+
|
74
|
+
def tracker
|
75
|
+
@tracker ||= classify Amanuensis.tracker
|
76
|
+
end
|
77
|
+
|
78
|
+
def code_manager
|
79
|
+
@code_manager ||= classify Amanuensis.code_manager
|
80
|
+
end
|
81
|
+
|
82
|
+
def classify(integration)
|
83
|
+
"Amanuensis::#{integration.to_s.classify}".constantize
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'octokit'
|
2
|
+
|
3
|
+
require_relative 'github/code_manager'
|
4
|
+
require_relative 'github/tracker'
|
5
|
+
require_relative 'github/push'
|
6
|
+
|
7
|
+
module Amanuensis
|
8
|
+
module Github
|
9
|
+
include ActiveSupport::Configurable
|
10
|
+
include Validatable
|
11
|
+
|
12
|
+
config_accessor(:oauth_token)
|
13
|
+
config_accessor(:repo)
|
14
|
+
config_accessor(:file_name) { 'Changelog.md' }
|
15
|
+
|
16
|
+
validate_presence_of :oauth_token, :repo
|
17
|
+
end
|
18
|
+
|
19
|
+
Push.register :github, Github::Push.new
|
20
|
+
CodeManager.register :github, Github::CodeManager.new
|
21
|
+
Tracker.register :github, Github::Tracker.new
|
22
|
+
end
|
23
|
+
|
24
|
+
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Amanuensis
|
2
|
+
module Github
|
3
|
+
class CodeManager
|
4
|
+
|
5
|
+
def latest_release
|
6
|
+
hash = client.latest_release(Github.repo)
|
7
|
+
Release.new hash.created_at, hash.tag_name
|
8
|
+
rescue
|
9
|
+
Release.new Date.new(1900), '0.0.0'
|
10
|
+
end
|
11
|
+
|
12
|
+
def create_release(version)
|
13
|
+
client.create_release(Github.repo, version, {
|
14
|
+
body: "Release generated by amanuensis.",
|
15
|
+
draft: false,
|
16
|
+
prerelease: false
|
17
|
+
})
|
18
|
+
end
|
19
|
+
|
20
|
+
def pulls(from)
|
21
|
+
filter(closed_pulls, from).map do |pull|
|
22
|
+
Pull.new pull['number'], pull['html_url'], pull['title']
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def filter(list, from)
|
29
|
+
list.select { |object| object.closed_at > from.to_time }
|
30
|
+
end
|
31
|
+
|
32
|
+
def closed_pulls
|
33
|
+
client.pull_requests(Github.repo, state: 'closed')
|
34
|
+
end
|
35
|
+
|
36
|
+
def client
|
37
|
+
@client ||= Octokit::Client.new(access_token: Github.oauth_token, auto_paginate: true)
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Amanuensis
|
2
|
+
module Github
|
3
|
+
class Push
|
4
|
+
|
5
|
+
def run(changelog)
|
6
|
+
client = Octokit::Client.new(access_token: Github.oauth_token, auto_paginate: true)
|
7
|
+
|
8
|
+
repo_name = Github.repo
|
9
|
+
default_branch = client.repo(repo_name)[:default_branch]
|
10
|
+
ref = "heads/#{default_branch}"
|
11
|
+
|
12
|
+
content = (client.contents repo_name, path: Github.file_name, ref: ref, accept: 'application/vnd.github.V3.raw' rescue '')
|
13
|
+
|
14
|
+
if content.empty?
|
15
|
+
client.create_content(repo_name, Github.file_name, 'Creating changelog', changelog, branch: default_branch)
|
16
|
+
else
|
17
|
+
content.prepend(changelog)
|
18
|
+
content_object = client.contents repo_name, path: Github.file_name, ref: ref
|
19
|
+
|
20
|
+
client.update_content(repo_name, Github.file_name, 'Updating changelog', content_object.sha, content, branch: default_branch)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Amanuensis
|
2
|
+
module Github
|
3
|
+
class Tracker
|
4
|
+
|
5
|
+
def issues(from)
|
6
|
+
filter(closed_issues, from).map do |issue|
|
7
|
+
Issue.new issue['number'], issue['html_url'], issue['title']
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def filter(list, from)
|
14
|
+
list.select { |object| object.closed_at > from.to_time }
|
15
|
+
end
|
16
|
+
|
17
|
+
def closed_issues
|
18
|
+
client.list_issues(Github.repo, state: 'closed').select do |issue|
|
19
|
+
!issue['html_url'].include?('pull')
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def closed_pulls
|
24
|
+
client.pull_requests(Github.repo, state: 'closed')
|
25
|
+
end
|
26
|
+
|
27
|
+
def client
|
28
|
+
Octokit::Client.new(access_token: Github.oauth_token, auto_paginate: true)
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'benchmark'
|
2
|
+
|
3
|
+
module Amanuensis
|
4
|
+
class Logger
|
5
|
+
|
6
|
+
def call(message, block)
|
7
|
+
formatter.info "#{message}"
|
8
|
+
result = nil
|
9
|
+
|
10
|
+
duration = Benchmark.realtime do
|
11
|
+
result = block.call
|
12
|
+
end
|
13
|
+
|
14
|
+
formatter.info "#{message} ends after #{duration}s"
|
15
|
+
|
16
|
+
result
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def formatter
|
22
|
+
@formatter ||= ::Logger.new(STDOUT)
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'pony'
|
2
|
+
|
3
|
+
require_relative 'mail/push'
|
4
|
+
|
5
|
+
module Amanuensis
|
6
|
+
module Mail
|
7
|
+
include ActiveSupport::Configurable
|
8
|
+
include Validatable
|
9
|
+
|
10
|
+
config_accessor(:pony) {{}}
|
11
|
+
|
12
|
+
validate_presence_of :pony
|
13
|
+
end
|
14
|
+
|
15
|
+
Push.register :mail, Mail::Push.new
|
16
|
+
end
|
17
|
+
|
18
|
+
|