pr_log 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.travis.yml +20 -0
- data/CHANGELOG.md +7 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +150 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/rspec +16 -0
- data/bin/setup +7 -0
- data/exe/prlog +5 -0
- data/lib/pr_log/cli.rb +42 -0
- data/lib/pr_log/command.rb +24 -0
- data/lib/pr_log/configuration.rb +54 -0
- data/lib/pr_log/errors.rb +25 -0
- data/lib/pr_log/fetch_command.rb +41 -0
- data/lib/pr_log/formatter.rb +36 -0
- data/lib/pr_log/gemspec.rb +30 -0
- data/lib/pr_log/github_repository.rb +34 -0
- data/lib/pr_log/injector.rb +22 -0
- data/lib/pr_log/parsed_changelog.rb +23 -0
- data/lib/pr_log/project.rb +52 -0
- data/lib/pr_log/version.rb +3 -0
- data/lib/pr_log.rb +16 -0
- data/pr_log.gemspec +35 -0
- metadata +226 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 219e0119cbee6cea394f2acad2aaff4bb31d74b6
|
4
|
+
data.tar.gz: bf6b1f5ea714216c73f0bfee3967e9f77052b44b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a6d06a0f16cb8fd248d4557dd2047a8f0971115206968e12566bac5332b9ce54579364721754d5141e119cccd6b36ab3c5ef471bd75929470be6f1918665e5c3
|
7
|
+
data.tar.gz: 1541586d7a72ebf774c41160e9589147ff8fa64db79139ad83228754346436435e9797dd27cc6e84f85f7129552ed9693e76a855db885d5fa9a1a90a41118bdf
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- 1.9.3
|
4
|
+
- 2.1.1
|
5
|
+
|
6
|
+
# User container based travis infrastructure which allows caching
|
7
|
+
# features for open source projects.
|
8
|
+
sudo: false
|
9
|
+
cache: bundler
|
10
|
+
|
11
|
+
before_install: gem install bundler -v 1.10.5
|
12
|
+
|
13
|
+
env:
|
14
|
+
global:
|
15
|
+
- PR_LOG_FIXTURE_OAUTH_TOKEN=8909728af9171b43308994050f0c6f57994ace5f
|
16
|
+
|
17
|
+
addons:
|
18
|
+
code_climate:
|
19
|
+
repo_token:
|
20
|
+
secure: "aQtvo+k13pyGi4Hi/7/Hx/wIv5lAlZ0AXrMNy0A4mPF4en6y2jW9yiO0pSMNBAPRmiFrDstarW4IcdtHVQ4vT6XBvcmu4DmYBdfcutrhBBXFXx2IOMtqKpGAib42HQW7lgSwVh2nPTqyVh2fw8TnEYk7Mr1cFK9zQXasFll/yCYtRHquDJxanwYyISw6q8YN7Z9e5M8Sv2Mc7Bu2qtx6QXkEEd8JvxtvXT2vQBdGrzH3Y+gC9hKr2BgJnV9of2Ofu0oFY958nlqxj3dSj9m64wt8xHt4W2fU4FNv4lPCHHotQdWTY2ugzdOA6GhSf76hOO5t/0lQ44eJySgmIzTIWWFUCAzvWpOv7Wj4jrMeoF+MxzQmEu7rUfuu/hFR+dEliQouiMAhBGy6cP8PtzHrUcf3cYaW5GcE57RU/FBb0cyM6QG2vDK0C12bjzpuLrv9dkfizlxPZnwdiuOQWG45sbZgKWv212Dj34jT2rDpfCfovbpse72Pi0FSN4Q04CvHkB/ITP6LGKF5NCmLAewJKOsjUbciPgX7PxnY9ieFLgadenfFQARpRCZaw5Gp7ZEJq+8LAFokW9lDu2HdByRGLDXvv+6yve+Rt5bCT5T+ALboGr0FXaZJ/YCAdL4mUudY/5rW36ZyPQrPpQnnxSe62GzHKCdJhtbhpaEIOubcScQ="
|
data/CHANGELOG.md
ADDED
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# Contributor Code of Conduct
|
2
|
+
|
3
|
+
As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
|
4
|
+
|
5
|
+
We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion.
|
6
|
+
|
7
|
+
Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
|
8
|
+
|
9
|
+
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
|
10
|
+
|
11
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
|
12
|
+
|
13
|
+
This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 Tim Fischbach
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,150 @@
|
|
1
|
+
# PR Log
|
2
|
+
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/pr_log.svg)](http://badge.fury.io/rb/pr_log)
|
4
|
+
[![Dependency Status](https://gemnasium.com/tf/pr_log.svg)](https://gemnasium.com/tf/pr_log)
|
5
|
+
[![Build Status](https://travis-ci.org/tf/pr_log.svg?branch=master)](https://travis-ci.org/tf/pr_log)
|
6
|
+
[![Test Coverage](https://codeclimate.com/github/tf/pr_log/badges/coverage.svg)](https://codeclimate.com/github/tf/pr_log)
|
7
|
+
[![Code Climate](https://codeclimate.com/github/tf/pr_log/badges/gpa.svg)](https://codeclimate.com/github/tf/pr_log)
|
8
|
+
|
9
|
+
Turn GitHub pull requests into changelog entries.
|
10
|
+
|
11
|
+
## Assumptions
|
12
|
+
|
13
|
+
**Changelogs should be written for humans by humans**
|
14
|
+
|
15
|
+
PrLog does not try to auto generate a complete changelog. Instead, it
|
16
|
+
pulls GitHub data to prefill your changelog as a baseline for manual
|
17
|
+
editing. Add prose, order items by priority, insert headers.
|
18
|
+
|
19
|
+
**Merged pull requests fully describe project history**
|
20
|
+
|
21
|
+
PrLog ignores GitHub issues. If a pull request fixes an
|
22
|
+
important issue it can reference it in its title or description.
|
23
|
+
|
24
|
+
**Pull requests are tagged with version milestones**
|
25
|
+
|
26
|
+
PrLog expects pull requests to be assigned to version milestones like
|
27
|
+
`v1.1`. This ensures consistency with the issue tracker and helps
|
28
|
+
limit GitHub API requests to relevant data.
|
29
|
+
|
30
|
+
**Changelogs are written in Markdown**
|
31
|
+
|
32
|
+
Markdown is the de facto standard for formatting files to be
|
33
|
+
displayed on GitHub.
|
34
|
+
|
35
|
+
## Installation
|
36
|
+
|
37
|
+
Install the command line tool:
|
38
|
+
|
39
|
+
$ gem install pr_log
|
40
|
+
|
41
|
+
Generate a
|
42
|
+
[personal access token](https://help.github.com/articles/creating-an-access-token-for-command-line-use/)
|
43
|
+
and place it in a `.pr_log.yml` file in your home directory:
|
44
|
+
|
45
|
+
# ~/.pr_log.yml
|
46
|
+
access_token: "xxx"
|
47
|
+
|
48
|
+
## Usage
|
49
|
+
|
50
|
+
To insert items for new pull requests with milestone `v.1.2` into your
|
51
|
+
`CHANGELOG.md` file run:
|
52
|
+
|
53
|
+
$ prlog fetch --github-repository some/repository --milestone v1.2
|
54
|
+
|
55
|
+
By default, this creates entries of the form:
|
56
|
+
|
57
|
+
- Title of the pull request
|
58
|
+
([#100](https://github.com/some/repository/pull/100)))
|
59
|
+
|
60
|
+
If a pull request URL is already mentioned in the changelog, no entry
|
61
|
+
will be created.
|
62
|
+
|
63
|
+
### Convention over Configuration
|
64
|
+
|
65
|
+
The `fetch` command can also be invoked without command line options:
|
66
|
+
|
67
|
+
$ prlog fetch
|
68
|
+
|
69
|
+
PrLog tries to derive defaults from gemspec information:
|
70
|
+
|
71
|
+
- If the `homepage` attribute mentions the URL of the github
|
72
|
+
repository, it is used to determine the github repository name.
|
73
|
+
- PrLog constructs a milestone name of the form `v%{major}.%{minor}`
|
74
|
+
from the current gem version.
|
75
|
+
|
76
|
+
### Configuration
|
77
|
+
|
78
|
+
To override PrLog's default configuration you can either pass command
|
79
|
+
line options or place a `.pr_log.yml` file inside your project's root
|
80
|
+
or your home directory:
|
81
|
+
|
82
|
+
# .pr_log.yml
|
83
|
+
changelog_file: "HISTORY.md"
|
84
|
+
|
85
|
+
The following configuration options are available:
|
86
|
+
|
87
|
+
- `access_token`: Personal access token to use for GitHub API
|
88
|
+
requests.
|
89
|
+
|
90
|
+
- `changelog_file`: Relative path to the changelog file.
|
91
|
+
|
92
|
+
- `entry_template`: Template string used for new changelog
|
93
|
+
entries. All fields from the
|
94
|
+
[issue search response](https://developer.github.com/v3/search/#search-issues)
|
95
|
+
can be used as interpolations.
|
96
|
+
|
97
|
+
- `github_repository`: Name of the GitHub repository of the form
|
98
|
+
`user/repository`.
|
99
|
+
|
100
|
+
- `insert_after`: Regular expression or string matching the line
|
101
|
+
inside the changelog after which new items shall be inserted.
|
102
|
+
|
103
|
+
- `label_prefixes`: A hash mapping GitHub label names to title
|
104
|
+
prefixes for changelog entries. See below for details.
|
105
|
+
|
106
|
+
- `milestone`: Name of the milestone filter fetched pull requests by.
|
107
|
+
|
108
|
+
- `milestone_format`: Template string used to derive a milestone name
|
109
|
+
from the current gem version. The strings `%{major}`, `%{minor}` and
|
110
|
+
`%{patch}` are replaces with the corresponding numeric component of
|
111
|
+
the current version. Default value: `v%{major}.%{minor}`.
|
112
|
+
|
113
|
+
### Label Prefixes
|
114
|
+
|
115
|
+
Items for pull requests with certain labels can be prefixed with a
|
116
|
+
string automatically. To add a "Bug fix:" prefix to all pull requests
|
117
|
+
with the label `bug`, add the following lines to your configuration file:
|
118
|
+
|
119
|
+
# pr_log.yml
|
120
|
+
label_prefixes:
|
121
|
+
bug: "Bug fix:"
|
122
|
+
|
123
|
+
## Development
|
124
|
+
|
125
|
+
After checking out the repo, run `bin/setup` to install
|
126
|
+
dependencies. You can also run `bin/console` for an interactive prompt
|
127
|
+
that will allow you to experiment.
|
128
|
+
|
129
|
+
### Running the Test Suite
|
130
|
+
|
131
|
+
Ensure the environment variable `PR_LOG_FIXTURE_OAUTH_TOKEN` is set to
|
132
|
+
a valid GitHub access token. Then run `bin/rspec`. The test suite uses
|
133
|
+
[VCR](https://github.com/vcr/vcr) to record and replay requests to the
|
134
|
+
GitHub API. Fixture data used by the test suite comes from the
|
135
|
+
[tf/pr_log_test_fixture](https://github.com/tf/pr_log_test_fixture)
|
136
|
+
repository.
|
137
|
+
|
138
|
+
## Contributing
|
139
|
+
|
140
|
+
Bug reports and pull requests are welcome on GitHub at
|
141
|
+
https://github.com/tf/pr_log. This project is intended to be a safe,
|
142
|
+
welcoming space for collaboration, and contributors are expected to
|
143
|
+
adhere to the [Contributor Covenant](http://contributor-covenant.org)
|
144
|
+
code of conduct.
|
145
|
+
|
146
|
+
## License
|
147
|
+
|
148
|
+
The gem is available as open source under the terms of the
|
149
|
+
[MIT License](http://opensource.org/licenses/MIT).
|
150
|
+
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "pr_log"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/rspec
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# This file was generated by Bundler.
|
4
|
+
#
|
5
|
+
# The application 'rspec' is installed as part of a gem, and
|
6
|
+
# this file is here to facilitate running it.
|
7
|
+
#
|
8
|
+
|
9
|
+
require 'pathname'
|
10
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
|
11
|
+
Pathname.new(__FILE__).realpath)
|
12
|
+
|
13
|
+
require 'rubygems'
|
14
|
+
require 'bundler/setup'
|
15
|
+
|
16
|
+
load Gem.bin_path('rspec-core', 'rspec')
|
data/bin/setup
ADDED
data/exe/prlog
ADDED
data/lib/pr_log/cli.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'thor'
|
2
|
+
|
3
|
+
module PrLog
|
4
|
+
# The main command line interface
|
5
|
+
class Cli < Thor
|
6
|
+
desc 'fetch', 'Insert changelog entries for new pull requests'
|
7
|
+
method_option(:changelog_file,
|
8
|
+
aliases: '-c',
|
9
|
+
desc: 'Path of the changelog file')
|
10
|
+
method_option(:insert_after,
|
11
|
+
aliases: '-i',
|
12
|
+
desc: 'Line to insert new entries after')
|
13
|
+
method_option(:github_repository,
|
14
|
+
aliases: '-r',
|
15
|
+
desc: 'GitHub repository name')
|
16
|
+
method_option(:access_token,
|
17
|
+
aliases: '-t',
|
18
|
+
desc: 'OAuth access token for GitHub API')
|
19
|
+
method_option(:milestone,
|
20
|
+
aliases: '-m',
|
21
|
+
desc: 'Version milestone to filter pull requests')
|
22
|
+
method_option(:milestone_format,
|
23
|
+
desc: 'Pattern to derive milestone from gem version')
|
24
|
+
def fetch
|
25
|
+
FetchCommand.perform(options) do |command|
|
26
|
+
command.on(:fetching) do |milestone, github_repository_name|
|
27
|
+
say_status(:fetching,
|
28
|
+
"pull requests for milestone #{milestone} " \
|
29
|
+
"from #{github_repository_name}")
|
30
|
+
end
|
31
|
+
|
32
|
+
command.on(:inserting) do |pull_requests, changelog_file|
|
33
|
+
say_status(:inserting,
|
34
|
+
"#{pull_requests.size} entries " \
|
35
|
+
"into #{changelog_file}")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
rescue Error => e
|
39
|
+
say_status(:error, e.message, :red)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'events'
|
2
|
+
|
3
|
+
module PrLog
|
4
|
+
# Event emitting command base class
|
5
|
+
class Command < Struct.new(:config)
|
6
|
+
include Events::Emitter
|
7
|
+
|
8
|
+
def self.perform(options)
|
9
|
+
command = new(Configuration.setup(options))
|
10
|
+
yield(command) if block_given?
|
11
|
+
command.perform
|
12
|
+
end
|
13
|
+
|
14
|
+
def perform
|
15
|
+
fail(NotImplementedError)
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def project
|
21
|
+
@project ||= Project.new(config)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'virtus'
|
2
|
+
|
3
|
+
module PrLog
|
4
|
+
# Configuration options
|
5
|
+
class Configuration
|
6
|
+
include Virtus.model
|
7
|
+
|
8
|
+
attribute :changelog_file, String, default: 'CHANGELOG.md'
|
9
|
+
|
10
|
+
attribute :insert_after, Regexp, default: "# CHANGELOG\n"
|
11
|
+
|
12
|
+
attribute :label_prefixes, Hash, default: { bug: 'Bug fix:' }
|
13
|
+
|
14
|
+
attribute :github_repository, String
|
15
|
+
|
16
|
+
attribute :access_token, String
|
17
|
+
|
18
|
+
attribute :milestone, String
|
19
|
+
|
20
|
+
attribute :milestone_format, String, default: 'v%{major}.%{minor}'
|
21
|
+
|
22
|
+
attribute :entry_template, String, default: <<-TEXT.gsub(/^ {6}/, '')
|
23
|
+
- %{title}
|
24
|
+
([#%{number}](%{html_url}))
|
25
|
+
TEXT
|
26
|
+
|
27
|
+
def set(attributes)
|
28
|
+
self.attributes = attributes.reject do |_, value|
|
29
|
+
value.nil?
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def set_from_files
|
34
|
+
CONFIG_FILE_NAMES.each do |config_file_name|
|
35
|
+
next unless File.exist?(config_file_name)
|
36
|
+
self.attributes = YAML.load_file(config_file_name)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.setup(attributes)
|
41
|
+
config = new
|
42
|
+
|
43
|
+
config.set_from_files
|
44
|
+
config.set(attributes)
|
45
|
+
|
46
|
+
config
|
47
|
+
end
|
48
|
+
|
49
|
+
CONFIG_FILE_NAMES = [
|
50
|
+
"#{ENV['HOME']}/.pr_log.yml",
|
51
|
+
'.pr_log.yml'
|
52
|
+
]
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module PrLog
|
2
|
+
class Error < StandardError
|
3
|
+
end
|
4
|
+
|
5
|
+
class InsertPointNotFound < Error
|
6
|
+
end
|
7
|
+
|
8
|
+
class ChangelogFileNotFound < Error
|
9
|
+
end
|
10
|
+
|
11
|
+
class GemspecNotFound < Error
|
12
|
+
end
|
13
|
+
|
14
|
+
class GithubRepositoryRequired < Error
|
15
|
+
end
|
16
|
+
|
17
|
+
class NonGithubHomepage < Error
|
18
|
+
end
|
19
|
+
|
20
|
+
class NoPullRequestsForMilestone < Error
|
21
|
+
end
|
22
|
+
|
23
|
+
class GithubRepositoryNotFound < Error
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'pr_log/command'
|
2
|
+
|
3
|
+
module PrLog
|
4
|
+
# Top level workflow of the fetch command
|
5
|
+
class FetchCommand < Command
|
6
|
+
def perform
|
7
|
+
emit(:fetching, project.milestone, project.github_repository_name)
|
8
|
+
pull_requests = new_pull_requests
|
9
|
+
|
10
|
+
emit(:inserting, pull_requests, config.changelog_file)
|
11
|
+
insert_pull_requests(pull_requests)
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def new_pull_requests
|
17
|
+
pull_requests = project.pull_requests_for_current_milestone
|
18
|
+
|
19
|
+
excluded_issue_numbers = project.issue_numbers_mentioned_in_changelog
|
20
|
+
|
21
|
+
pull_requests.reject do |pull_request|
|
22
|
+
excluded_issue_numbers.include?(pull_request[:number])
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def insert_pull_requests(pull_requests)
|
27
|
+
entries = formatter(pull_requests).entries
|
28
|
+
injector.insert_after(config.insert_after, entries)
|
29
|
+
end
|
30
|
+
|
31
|
+
def formatter(pull_requests)
|
32
|
+
Formatter.new(pull_requests,
|
33
|
+
config.entry_template,
|
34
|
+
config.label_prefixes)
|
35
|
+
end
|
36
|
+
|
37
|
+
def injector
|
38
|
+
Injector.new(config.changelog_file)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module PrLog
|
2
|
+
# Format new pull requests from github search response
|
3
|
+
class Formatter < Struct.new(:pull_requests,
|
4
|
+
:entry_template,
|
5
|
+
:label_prefixes)
|
6
|
+
|
7
|
+
def entries
|
8
|
+
return '' if pull_requests.empty?
|
9
|
+
|
10
|
+
pull_requests.map do |pull_request|
|
11
|
+
entry_template % entry_template_data(pull_request)
|
12
|
+
end.join.prepend("\n")
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def entry_template_data(pull_request)
|
18
|
+
pull_request.merge(title: prefixed_title(pull_request))
|
19
|
+
end
|
20
|
+
|
21
|
+
def prefixed_title(pull_request)
|
22
|
+
[label_prefix(pull_request),
|
23
|
+
format_title(pull_request)].compact.join(' ')
|
24
|
+
end
|
25
|
+
|
26
|
+
def label_prefix(pull_request)
|
27
|
+
pull_request.fetch(:labels, []).map do |label|
|
28
|
+
label_prefixes[label[:name].to_s]
|
29
|
+
end.compact.first
|
30
|
+
end
|
31
|
+
|
32
|
+
def format_title(pull_request)
|
33
|
+
pull_request[:title].capitalize
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module PrLog
|
2
|
+
# Extract default configuration from a gem specification
|
3
|
+
class Gemspec < Struct.new(:specification, :milestone_format)
|
4
|
+
def github_repository
|
5
|
+
unless specification.homepage =~ %r{https?://github.com/}
|
6
|
+
fail(NonGithubHomepage,
|
7
|
+
'Gemspec does not have GitHub hompage URL.')
|
8
|
+
end
|
9
|
+
|
10
|
+
specification.homepage.split('github.com/').last
|
11
|
+
end
|
12
|
+
|
13
|
+
def version_milestone
|
14
|
+
milestone_format % version_components
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def version_components
|
20
|
+
components = specification.version.to_s.split('.')
|
21
|
+
|
22
|
+
[:major, :minor, :patch]
|
23
|
+
.each_with_index
|
24
|
+
.each_with_object({}) do |(name, index), result|
|
25
|
+
|
26
|
+
result[name] = components[index]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'octokit'
|
2
|
+
|
3
|
+
module PrLog
|
4
|
+
# Adapter for Github Api
|
5
|
+
class GithubRepository
|
6
|
+
def initialize(name, access_token)
|
7
|
+
@name = name
|
8
|
+
@client = Octokit::Client.new(access_token: access_token)
|
9
|
+
end
|
10
|
+
|
11
|
+
def pull_requests_with_milestone(milestone)
|
12
|
+
fail_if_empty(get_issues(milestone_query(milestone)))
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def milestone_query(milestone)
|
18
|
+
"repo:#{@name} type:pr is:merged milestone:#{milestone}"
|
19
|
+
end
|
20
|
+
|
21
|
+
def fail_if_empty(result)
|
22
|
+
return result if result.any?
|
23
|
+
|
24
|
+
fail(NoPullRequestsForMilestone,
|
25
|
+
'No pull requests for milestone')
|
26
|
+
end
|
27
|
+
|
28
|
+
def get_issues(query)
|
29
|
+
@client.search_issues(query, per_page: 1000)['items'].map(&:to_hash)
|
30
|
+
rescue Octokit::UnprocessableEntity
|
31
|
+
raise(GithubRepositoryNotFound, 'Github repository not found')
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module PrLog
|
2
|
+
# Injects text into a file
|
3
|
+
class Injector < Struct.new(:destination_file)
|
4
|
+
def insert_after(line, text)
|
5
|
+
unless replace!(/#{line}/, '\0' + text)
|
6
|
+
fail(InsertPointNotFound, "Insert point not found in #{destination_file}.")
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def replace!(regexp, text)
|
13
|
+
content = File.binread(destination_file)
|
14
|
+
|
15
|
+
return false unless content.gsub!(regexp, text)
|
16
|
+
|
17
|
+
File.open(destination_file, 'wb') do |file|
|
18
|
+
file.write(content)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module PrLog
|
2
|
+
# Get mentioned issues from a changelog
|
3
|
+
class ParsedChangelog
|
4
|
+
def initialize(text, options = {})
|
5
|
+
@text = text
|
6
|
+
@github_repository = options.fetch(:github_repository)
|
7
|
+
end
|
8
|
+
|
9
|
+
def mentioned_issue_numbers
|
10
|
+
@text.scan(pull_request_urls_matcher).flatten.map(&:to_i)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def pull_request_urls_matcher
|
16
|
+
%r{#{repository_url_matcher}/pull/(\d+)}
|
17
|
+
end
|
18
|
+
|
19
|
+
def repository_url_matcher
|
20
|
+
%r{https?://github.com/#{@github_repository}}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module PrLog
|
2
|
+
# Parse files from the local project directory
|
3
|
+
class Project < Struct.new(:config)
|
4
|
+
def issue_numbers_mentioned_in_changelog
|
5
|
+
parsed_changelog.mentioned_issue_numbers
|
6
|
+
end
|
7
|
+
|
8
|
+
def milestone
|
9
|
+
config.milestone || gemspec.version_milestone
|
10
|
+
end
|
11
|
+
|
12
|
+
def github_repository_name
|
13
|
+
config.github_repository || gemspec.github_repository
|
14
|
+
|
15
|
+
rescue GemspecNotFound
|
16
|
+
raise(GithubRepositoryRequired,
|
17
|
+
'Could not derive github repository from gemspec.')
|
18
|
+
rescue NonGithubHomepage
|
19
|
+
raise(GithubRepositoryRequired,
|
20
|
+
'Homepage attribute in gemspec is not a GitHub URL.')
|
21
|
+
end
|
22
|
+
|
23
|
+
def pull_requests_for_current_milestone
|
24
|
+
github_repository.pull_requests_with_milestone(milestone)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def github_repository
|
30
|
+
GithubRepository.new(github_repository_name,
|
31
|
+
config.access_token)
|
32
|
+
end
|
33
|
+
|
34
|
+
def parsed_changelog
|
35
|
+
ParsedChangelog.new(File.read(config.changelog_file),
|
36
|
+
github_repository: github_repository_name)
|
37
|
+
rescue Errno::ENOENT
|
38
|
+
raise(ChangelogFileNotFound,
|
39
|
+
"Could not find '#{config.changelog_file}' file.")
|
40
|
+
end
|
41
|
+
|
42
|
+
def gemspec
|
43
|
+
Gemspec.new(Gem::Specification.load(gemspec_path),
|
44
|
+
config.milestone_format)
|
45
|
+
end
|
46
|
+
|
47
|
+
def gemspec_path
|
48
|
+
Dir.glob('*.gemspec').first ||
|
49
|
+
fail(GemspecNotFound, 'Gemspec not found.')
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/lib/pr_log.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'pr_log/cli'
|
2
|
+
require 'pr_log/configuration'
|
3
|
+
require 'pr_log/errors'
|
4
|
+
require 'pr_log/fetch_command'
|
5
|
+
require 'pr_log/formatter'
|
6
|
+
require 'pr_log/gemspec'
|
7
|
+
require 'pr_log/github_repository'
|
8
|
+
require 'pr_log/injector'
|
9
|
+
require 'pr_log/parsed_changelog'
|
10
|
+
require 'pr_log/project'
|
11
|
+
require 'pr_log/version'
|
12
|
+
|
13
|
+
require 'yaml'
|
14
|
+
|
15
|
+
module PrLog
|
16
|
+
end
|
data/pr_log.gemspec
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'pr_log/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'pr_log'
|
8
|
+
spec.version = PrLog::VERSION
|
9
|
+
spec.authors = ['Tim Fischbach']
|
10
|
+
spec.email = ['mail@timfischbach.de']
|
11
|
+
|
12
|
+
spec.summary = 'Turn GitHub pull requests into changelog entries'
|
13
|
+
spec.homepage = 'https://github.com/tf/pr_log'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
17
|
+
f.match(%r{^spec/})
|
18
|
+
end
|
19
|
+
spec.bindir = 'exe'
|
20
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
21
|
+
spec.require_paths = ['lib']
|
22
|
+
|
23
|
+
spec.add_dependency 'thor', '~> 0.19'
|
24
|
+
spec.add_dependency 'octokit', '~> 4.0'
|
25
|
+
spec.add_dependency 'virtus', '~> 1.0'
|
26
|
+
spec.add_dependency 'events'
|
27
|
+
|
28
|
+
spec.add_development_dependency 'bundler', '~> 1.10'
|
29
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
30
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
31
|
+
spec.add_development_dependency 'webmock', '~> 1.21'
|
32
|
+
spec.add_development_dependency 'vcr', '~> 2.9'
|
33
|
+
spec.add_development_dependency 'unindent', '~> 1.0'
|
34
|
+
spec.add_development_dependency 'codeclimate-test-reporter'
|
35
|
+
end
|
metadata
ADDED
@@ -0,0 +1,226 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pr_log
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tim Fischbach
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-07-28 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: thor
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.19'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.19'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: octokit
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '4.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '4.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: virtus
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: events
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: bundler
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.10'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1.10'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rake
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '10.0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '10.0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rspec
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '3.0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '3.0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: webmock
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '1.21'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '1.21'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: vcr
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '2.9'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '2.9'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: unindent
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - "~>"
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '1.0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - "~>"
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '1.0'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: codeclimate-test-reporter
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ">="
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - ">="
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0'
|
167
|
+
description:
|
168
|
+
email:
|
169
|
+
- mail@timfischbach.de
|
170
|
+
executables:
|
171
|
+
- prlog
|
172
|
+
extensions: []
|
173
|
+
extra_rdoc_files: []
|
174
|
+
files:
|
175
|
+
- ".gitignore"
|
176
|
+
- ".rspec"
|
177
|
+
- ".travis.yml"
|
178
|
+
- CHANGELOG.md
|
179
|
+
- CODE_OF_CONDUCT.md
|
180
|
+
- Gemfile
|
181
|
+
- LICENSE.txt
|
182
|
+
- README.md
|
183
|
+
- Rakefile
|
184
|
+
- bin/console
|
185
|
+
- bin/rspec
|
186
|
+
- bin/setup
|
187
|
+
- exe/prlog
|
188
|
+
- lib/pr_log.rb
|
189
|
+
- lib/pr_log/cli.rb
|
190
|
+
- lib/pr_log/command.rb
|
191
|
+
- lib/pr_log/configuration.rb
|
192
|
+
- lib/pr_log/errors.rb
|
193
|
+
- lib/pr_log/fetch_command.rb
|
194
|
+
- lib/pr_log/formatter.rb
|
195
|
+
- lib/pr_log/gemspec.rb
|
196
|
+
- lib/pr_log/github_repository.rb
|
197
|
+
- lib/pr_log/injector.rb
|
198
|
+
- lib/pr_log/parsed_changelog.rb
|
199
|
+
- lib/pr_log/project.rb
|
200
|
+
- lib/pr_log/version.rb
|
201
|
+
- pr_log.gemspec
|
202
|
+
homepage: https://github.com/tf/pr_log
|
203
|
+
licenses:
|
204
|
+
- MIT
|
205
|
+
metadata: {}
|
206
|
+
post_install_message:
|
207
|
+
rdoc_options: []
|
208
|
+
require_paths:
|
209
|
+
- lib
|
210
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
211
|
+
requirements:
|
212
|
+
- - ">="
|
213
|
+
- !ruby/object:Gem::Version
|
214
|
+
version: '0'
|
215
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
216
|
+
requirements:
|
217
|
+
- - ">="
|
218
|
+
- !ruby/object:Gem::Version
|
219
|
+
version: '0'
|
220
|
+
requirements: []
|
221
|
+
rubyforge_project:
|
222
|
+
rubygems_version: 2.2.2
|
223
|
+
signing_key:
|
224
|
+
specification_version: 4
|
225
|
+
summary: Turn GitHub pull requests into changelog entries
|
226
|
+
test_files: []
|