chandler 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/.rubocop.yml +33 -0
- data/.travis.yml +5 -0
- data/CHANGELOG.md +16 -0
- data/CONTRIBUTING.md +26 -0
- data/Gemfile +4 -0
- data/Guardfile +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +107 -0
- data/Rakefile +17 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/chandler.gemspec +36 -0
- data/exe/chandler +4 -0
- data/lib/chandler.rb +4 -0
- data/lib/chandler/changelog.rb +97 -0
- data/lib/chandler/cli.rb +49 -0
- data/lib/chandler/cli/parser.rb +86 -0
- data/lib/chandler/commands/push.rb +47 -0
- data/lib/chandler/configuration.rb +39 -0
- data/lib/chandler/git.rb +58 -0
- data/lib/chandler/github.rb +67 -0
- data/lib/chandler/logger.rb +86 -0
- data/lib/chandler/logging.rb +17 -0
- data/lib/chandler/refinements/color.rb +41 -0
- data/lib/chandler/refinements/version_format.rb +46 -0
- data/lib/chandler/tasks.rb +30 -0
- data/lib/chandler/version.rb +3 -0
- metadata +241 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1b4381b69c5976f8de750c7756837e6da82031b1
|
4
|
+
data.tar.gz: ff127a8a9970f75de6922b618a913f2bd2fc815f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ff2f30b2a72f70e11f27105e27c12c144e2540d173af10975b11bb554db2a2d5d4b341c578412e3a90923987be5ac7caf3834480d3802d7be52dbe68ec100fa0
|
7
|
+
data.tar.gz: 11e84ada787c62a276c9f9f9345c2b052d51eda75a38c3bc52b10f36189baa10153acf6fffa020f32797aa8a763ba4692ad9628c4a9265fbe65c1553379b8b0b
|
data/.gitignore
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
AllCops:
|
2
|
+
Exclude:
|
3
|
+
- "*.gemspec"
|
4
|
+
|
5
|
+
Metrics/AbcSize:
|
6
|
+
Exclude:
|
7
|
+
- "test/**/*"
|
8
|
+
|
9
|
+
Metrics/MethodLength:
|
10
|
+
Exclude:
|
11
|
+
- "test/**/*"
|
12
|
+
|
13
|
+
Metrics/ClassLength:
|
14
|
+
Exclude:
|
15
|
+
- "test/**/*"
|
16
|
+
|
17
|
+
Style/ClassAndModuleChildren:
|
18
|
+
Enabled: false
|
19
|
+
|
20
|
+
Style/Documentation:
|
21
|
+
Enabled: false
|
22
|
+
|
23
|
+
Style/DoubleNegation:
|
24
|
+
Enabled: false
|
25
|
+
|
26
|
+
Style/HashSyntax:
|
27
|
+
EnforcedStyle: hash_rockets
|
28
|
+
|
29
|
+
Style/SpaceAroundEqualsInParameterDefault:
|
30
|
+
EnforcedStyle: no_space
|
31
|
+
|
32
|
+
Style/StringLiterals:
|
33
|
+
EnforcedStyle: double_quotes
|
data/.travis.yml
ADDED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# chandler Change Log
|
2
|
+
|
3
|
+
All notable changes to this project will be documented in this file.
|
4
|
+
|
5
|
+
chandler is in a pre-1.0 state. This means that its APIs and behavior are subject to breaking changes without deprecation notices. Until 1.0, version numbers will follow a [Semver][]-ish `0.y.z` format, where `y` is incremented when new features or breaking changes are introduced, and `z` is incremented for lesser changes or bug fixes.
|
6
|
+
|
7
|
+
## [Unreleased]
|
8
|
+
|
9
|
+
* Your contribution here!
|
10
|
+
|
11
|
+
## 0.1.0 (2015-06-19)
|
12
|
+
|
13
|
+
* Initial release
|
14
|
+
|
15
|
+
[Semver]: http://semver.org
|
16
|
+
[Unreleased]: https://github.com/mattbrictson/airbrussh/compare/v0.1.0...HEAD
|
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# Contributing to chandler
|
2
|
+
|
3
|
+
Have a feature idea, bug fix, or refactoring suggestion? Contributions are welcome!
|
4
|
+
|
5
|
+
## Pull requests
|
6
|
+
|
7
|
+
1. Check [Issues][] to see if your contribution has already been discussed and/or implemented.
|
8
|
+
2. If not, open an issue to discuss your contribution. I won't accept all changes and do not want to waste your time.
|
9
|
+
3. Once you have the :thumbsup:, fork the repo, make your changes, and open a PR.
|
10
|
+
4. Don't forget to add your contribution and credit yourself in `CHANGELOG.md`!
|
11
|
+
|
12
|
+
## Coding guidelines
|
13
|
+
|
14
|
+
* This project has a coding style enforced by [rubocop][]. Use hash rockets and double-quoted strings, and otherwise try to follow the [Ruby style guide][style].
|
15
|
+
* Writing tests is strongly encouraged! This project uses Minitest.
|
16
|
+
|
17
|
+
## Getting started
|
18
|
+
|
19
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment. To run your checked-out version of chandler, use `bundle exec chandler`.
|
20
|
+
|
21
|
+
To execute chandler's tests and rubocop checks, run `rake`.
|
22
|
+
|
23
|
+
|
24
|
+
[Issues]: https://github.com/mattbrictson/chandler/issues
|
25
|
+
[rubocop]: https://github.com/bbatsov/rubocop
|
26
|
+
[style]: https://github.com/bbatsov/ruby-style-guide
|
data/Gemfile
ADDED
data/Guardfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 Matt Brictson
|
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,107 @@
|
|
1
|
+
# chandler
|
2
|
+
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/chandler.svg)](http://badge.fury.io/rb/chandler)
|
4
|
+
[![Build Status](https://travis-ci.org/mattbrictson/chandler.svg?branch=master)](https://travis-ci.org/mattbrictson/chandler)
|
5
|
+
|
6
|
+
**chandler syncs your CHANGELOG entries to GitHub's release notes so you don't have to enter release notes manually.** For Ruby projects, you can even add chandler to your gem's Rakefile to make this an automatic part of your release process!
|
7
|
+
|
8
|
+
### How does it work?
|
9
|
+
|
10
|
+
chandler scans your git repository for version tags (e.g. `v1.0.2`), parses out the corresponding release notes for those tags from your CHANGELOG, and uploads those notes to the GitHub releases area via the GitHub API.
|
11
|
+
|
12
|
+
### Why go through the trouble?
|
13
|
+
|
14
|
+
GitHub's releases feature is a nice UI for browsing the history of your project and downloading snapshots of each version. It is also structured data that can be queried via GitHub's API, making it a available for third-party integrations. For example, [Sibbell][] can automatically send the release notes out to interested parties whenever you publish a new version.
|
15
|
+
|
16
|
+
Of course, as a considerate developer you also want to have a plain text CHANGELOG that travels with the code, can be collaboratively edited in pull requests, and so on. But that means you need two copies of the same release notes!
|
17
|
+
|
18
|
+
chandler takes the hassle out of maintaining these two separate formats: your CHANGELOG is the authoritative source, and GitHub releases are updated with a simple `chandler` command.
|
19
|
+
|
20
|
+
## Requirements
|
21
|
+
|
22
|
+
* Ruby 2.1 or higher
|
23
|
+
* Your project's CHANGELOG must be in Markdown with version numbers in the headings (similar to the format advocated by [keepachangelog.com](http://keepachangelog.com))
|
24
|
+
* You must be an owner or collaborator of the GitHub repository to update its releases
|
25
|
+
|
26
|
+
## Installation
|
27
|
+
|
28
|
+
### 1. Install the gem
|
29
|
+
|
30
|
+
```
|
31
|
+
gem install chandler
|
32
|
+
```
|
33
|
+
|
34
|
+
### 2. Configure .netrc
|
35
|
+
|
36
|
+
In order to access the GitHub API on your behalf, you must provide chandler with your GitHub credentials. Do this by creating a `~/.netrc` file with your GitHub username and password, like this:
|
37
|
+
|
38
|
+
```
|
39
|
+
machine api.github.com
|
40
|
+
login defunkt
|
41
|
+
password c0d3b4ssssss!
|
42
|
+
```
|
43
|
+
|
44
|
+
For more security, you can use an OAuth access token in place of your password. [Here's how to generate one][access-token].
|
45
|
+
|
46
|
+
|
47
|
+
## Usage
|
48
|
+
|
49
|
+
To push all CHANGELOG entries for all tags to GitHub, just run:
|
50
|
+
|
51
|
+
```
|
52
|
+
chandler push
|
53
|
+
```
|
54
|
+
|
55
|
+
chandler will make educated guesses as to what GitHub repository to use, the location of the CHANGELOG, and the tags that represent releases. To see what will happen without actually making changes, run:
|
56
|
+
|
57
|
+
```
|
58
|
+
chandler push --dry-run
|
59
|
+
```
|
60
|
+
|
61
|
+
To upload only a specific tag, `v1.0.2` for example:
|
62
|
+
|
63
|
+
```
|
64
|
+
chandler push v1.0.2
|
65
|
+
```
|
66
|
+
|
67
|
+
Other command-line options:
|
68
|
+
|
69
|
+
* `--git=/path/to/project/.git` – location of the local git repository (defaults to `.git`)
|
70
|
+
* `--github=username/repo` – GitHub repository to upload to (if unspecified, chandler will guess based on your git remotes)
|
71
|
+
* `--changelog=History.md` – location of the CHANGELOG (defaults to `CHANGELOG.md`)
|
72
|
+
|
73
|
+
|
74
|
+
## Rakefile integration
|
75
|
+
|
76
|
+
If you maintain a Ruby gem and use Bundler's gem tasks (i.e. `rake release`) to publish your gem, then you can use chandler to automate update your GitHub release notes.
|
77
|
+
|
78
|
+
### 1. Update the gemspec
|
79
|
+
|
80
|
+
```ruby
|
81
|
+
spec.add_development_dependency "chandler"
|
82
|
+
```
|
83
|
+
|
84
|
+
### 2. Modify the Rakefile
|
85
|
+
|
86
|
+
```ruby
|
87
|
+
require "bundler/gem_tasks"
|
88
|
+
require "chandler/tasks"
|
89
|
+
|
90
|
+
# Optional: override default chandler configuration
|
91
|
+
Chandler::Tasks.configure do |config|
|
92
|
+
config.changelog_path = "History.md"
|
93
|
+
config.github_repository = "mattbrictson/mygem"
|
94
|
+
end
|
95
|
+
|
96
|
+
# Add chandler as a prerequisite for `rake release`
|
97
|
+
task "release:rubygem_push" => "chandler:push"
|
98
|
+
```
|
99
|
+
|
100
|
+
That's it! Now when you run `rake release`, your GitHub release notes will be updated automatically based on your CHANGELOG entries.
|
101
|
+
|
102
|
+
[Sibbell]: http://sibbell.com
|
103
|
+
[access-token]: https://help.github.com/articles/creating-an-access-token-for-command-line-use/
|
104
|
+
|
105
|
+
## Contributing
|
106
|
+
|
107
|
+
Contributions are welcome! Read [CONTRIBUTING.md](CONTRIBUTING.md) to get started.
|
data/Rakefile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require "rake/testtask"
|
3
|
+
require "rubocop/rake_task"
|
4
|
+
|
5
|
+
$LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
|
6
|
+
require "chandler/tasks"
|
7
|
+
task "release:rubygem_push" => "chandler:push"
|
8
|
+
|
9
|
+
Rake::TestTask.new(:test) do |t|
|
10
|
+
t.libs << "test"
|
11
|
+
t.libs << "lib"
|
12
|
+
t.test_files = FileList["test/**/*_test.rb"]
|
13
|
+
end
|
14
|
+
|
15
|
+
RuboCop::RakeTask.new
|
16
|
+
|
17
|
+
task :default => [:test, :rubocop]
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "chandler"
|
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/setup
ADDED
data/chandler.gemspec
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'chandler/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.required_ruby_version = ">= 2.1.0"
|
8
|
+
|
9
|
+
spec.name = "chandler"
|
10
|
+
spec.version = Chandler::VERSION
|
11
|
+
spec.authors = ["Matt Brictson"]
|
12
|
+
spec.email = ["chandler@mattbrictson.com"]
|
13
|
+
|
14
|
+
spec.summary = "Syncs CHANGELOG entries to GitHub's release notes"
|
15
|
+
spec.homepage = "https://github.com/mattbrictson/chandler"
|
16
|
+
spec.license = "MIT"
|
17
|
+
|
18
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
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 "netrc"
|
24
|
+
spec.add_dependency "octokit", ">= 2.2.0"
|
25
|
+
|
26
|
+
spec.add_development_dependency "bundler", "~> 1.10"
|
27
|
+
spec.add_development_dependency "guard", ">= 2.2.2"
|
28
|
+
spec.add_development_dependency "guard-minitest"
|
29
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
30
|
+
spec.add_development_dependency "rb-fsevent"
|
31
|
+
spec.add_development_dependency "minitest"
|
32
|
+
spec.add_development_dependency "minitest-reporters"
|
33
|
+
spec.add_development_dependency "mocha"
|
34
|
+
spec.add_development_dependency "rubocop"
|
35
|
+
spec.add_development_dependency "terminal-notifier-guard"
|
36
|
+
end
|
data/exe/chandler
ADDED
data/lib/chandler.rb
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
require "chandler/refinements/version_format"
|
2
|
+
|
3
|
+
module Chandler
|
4
|
+
# Responsible for parsing a CHANGELOG into a hash of release notes keyed
|
5
|
+
# by version number. Release notes for a particular version or tag can be
|
6
|
+
# accessed using the `fetch` method.
|
7
|
+
class Changelog
|
8
|
+
using Chandler::Refinements::VersionFormat
|
9
|
+
|
10
|
+
NoMatchingVersion = Class.new(StandardError)
|
11
|
+
|
12
|
+
HEADING_PATTERNS = [
|
13
|
+
/^##\s+.*\n/, # Markdown "atx" style
|
14
|
+
/^###\s+.*\n/,
|
15
|
+
/^==\s+.*\n/, # Rdoc style
|
16
|
+
/^===\s+.*\n/,
|
17
|
+
/^\S.*\n-+\n/ # Markdown "Setext" style
|
18
|
+
].freeze
|
19
|
+
|
20
|
+
attr_reader :path
|
21
|
+
|
22
|
+
def initialize(path:)
|
23
|
+
@path = path
|
24
|
+
end
|
25
|
+
|
26
|
+
# Fetch release notes for the given tag or version number.
|
27
|
+
#
|
28
|
+
# E.g.
|
29
|
+
# fetch("v1.0.1") # => "\nRelease notes for 1.0.1.\n"
|
30
|
+
# fetch("1.0.1") # => "\nRelease notes for 1.0.1.\n"
|
31
|
+
# fetch("blergh") # => Chandler::NoMatchingVersion
|
32
|
+
#
|
33
|
+
def fetch(tag)
|
34
|
+
versions.fetch(tag.version_number) do
|
35
|
+
fail NoMatchingVersion, "Couldn’t find #{tag} in #{path}"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
# Transforms the changelog into a hash where the keys are version numbers
|
42
|
+
# and the values are the release notes for those versions. The values are
|
43
|
+
# *not* stripped of whitespace.
|
44
|
+
#
|
45
|
+
# The version numbers are assumed to be contained at Markdown or Rdoc
|
46
|
+
# headings. The release notes for those version numbers are the text
|
47
|
+
# delimited by those headings. The algorithm tries various styles of these
|
48
|
+
# Markdown and Rdoc headings (see `HEADING_PATTERNS`) until it finds one
|
49
|
+
# that matches.
|
50
|
+
#
|
51
|
+
# The resulting hash entries look like:
|
52
|
+
# { "1.0.1" => "\nRelease notes for 1.0.1.\n" }
|
53
|
+
#
|
54
|
+
def versions
|
55
|
+
@versions ||= begin
|
56
|
+
versions = HEADING_PATTERNS.find do |heading_re|
|
57
|
+
found = versions_at_headings(heading_re)
|
58
|
+
break(found) unless found.empty?
|
59
|
+
end
|
60
|
+
versions || {}
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# rubocop:disable Style/SymbolProc
|
65
|
+
def versions_at_headings(heading_re)
|
66
|
+
sections(heading_re).each_with_object({}) do |(heading, text), versions|
|
67
|
+
tokens = heading.gsub(/[\[\]\(\)`]/, " ").split.map(&:strip)
|
68
|
+
version = tokens.find { |t| t.version? }
|
69
|
+
versions[version.version_number] = text if version
|
70
|
+
end
|
71
|
+
end
|
72
|
+
# rubocop:enable Style/SymbolProc
|
73
|
+
|
74
|
+
# Parses the changelog into a hash, where the keys of the hash are the
|
75
|
+
# Markdown/rdoc headings matching the specified heading regexp, and values
|
76
|
+
# are the content delimited by those headings.
|
77
|
+
#
|
78
|
+
# E.g.
|
79
|
+
# { "## v1.0.1\n" => "\nRelease notes for 1.0.1.\n" }
|
80
|
+
#
|
81
|
+
def sections(heading_re)
|
82
|
+
hash = {}
|
83
|
+
heading = ""
|
84
|
+
remainder = text
|
85
|
+
|
86
|
+
until remainder.empty?
|
87
|
+
hash[heading], heading, remainder = remainder.partition(heading_re)
|
88
|
+
end
|
89
|
+
|
90
|
+
hash
|
91
|
+
end
|
92
|
+
|
93
|
+
def text
|
94
|
+
@text ||= IO.read(path)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
data/lib/chandler/cli.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require "chandler/cli/parser"
|
2
|
+
require "chandler/commands/push"
|
3
|
+
require "chandler/logging"
|
4
|
+
require "forwardable"
|
5
|
+
|
6
|
+
module Chandler
|
7
|
+
# Handles constructing and invoking the appropriate chandler command
|
8
|
+
# based on command line arguments and options provided by the CLI::Parser.
|
9
|
+
# Essentially this is the "router" for the command-line app.
|
10
|
+
#
|
11
|
+
class CLI
|
12
|
+
include Logging
|
13
|
+
extend Forwardable
|
14
|
+
def_delegator :@parser, :args
|
15
|
+
def_delegator :@parser, :config
|
16
|
+
|
17
|
+
def initialize(parser: Chandler::CLI::Parser.new(ARGV))
|
18
|
+
@parser = parser
|
19
|
+
end
|
20
|
+
|
21
|
+
def run
|
22
|
+
command.call
|
23
|
+
end
|
24
|
+
|
25
|
+
def command # rubocop:disable Metrics/MethodLength
|
26
|
+
case (command = args.shift)
|
27
|
+
when "push"
|
28
|
+
push
|
29
|
+
when nil
|
30
|
+
error("Please specify a command")
|
31
|
+
info(@parser.usage)
|
32
|
+
exit(1)
|
33
|
+
else
|
34
|
+
error("Unrecognized command: #{command}")
|
35
|
+
info(@parser.usage)
|
36
|
+
exit(1)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def push
|
43
|
+
Chandler::Commands::Push.new(
|
44
|
+
:tags => args.empty? ? config.git.version_tags : args,
|
45
|
+
:config => config
|
46
|
+
)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require "chandler/configuration"
|
2
|
+
require "chandler/version"
|
3
|
+
require "optparse"
|
4
|
+
|
5
|
+
module Chandler
|
6
|
+
class CLI
|
7
|
+
class Parser
|
8
|
+
attr_reader :args, :config
|
9
|
+
|
10
|
+
def initialize(args, config=Chandler::Configuration.new)
|
11
|
+
@args = args
|
12
|
+
@config = config
|
13
|
+
parse_options
|
14
|
+
end
|
15
|
+
|
16
|
+
def usage
|
17
|
+
option_parser.to_s
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def parse_options
|
23
|
+
unprocessed = []
|
24
|
+
until args.empty?
|
25
|
+
option_parser.order!(args)
|
26
|
+
unprocessed << args.shift
|
27
|
+
end
|
28
|
+
@args = unprocessed.compact
|
29
|
+
end
|
30
|
+
|
31
|
+
def option_parser # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
32
|
+
OptionParser.new do |opts|
|
33
|
+
opts.banner = "Usage: chandler push [tag] [options]"
|
34
|
+
opts.separator("")
|
35
|
+
opts.separator(summary)
|
36
|
+
opts.separator("")
|
37
|
+
|
38
|
+
opts.on("--git=[PATH]", "Path to .git directory") do |p|
|
39
|
+
config.git_path = p
|
40
|
+
end
|
41
|
+
|
42
|
+
opts.on("--github=[URL]",
|
43
|
+
"GitHub repository URL or owner/repo") do |u|
|
44
|
+
config.github_repository = u
|
45
|
+
end
|
46
|
+
|
47
|
+
opts.on("--changelog=[PATH]",
|
48
|
+
"Path to CHANGELOG Markdown file") do |p|
|
49
|
+
config.changelog_path = p
|
50
|
+
end
|
51
|
+
|
52
|
+
opts.on("--dry-run",
|
53
|
+
"Simulate, but don’t actually push to GitHub") do |d|
|
54
|
+
config.dry_run = d
|
55
|
+
end
|
56
|
+
|
57
|
+
opts.on("--debug", "Enable debug output") do |d|
|
58
|
+
config.logger.verbose = d
|
59
|
+
end
|
60
|
+
|
61
|
+
opts.on("-h", "--help", "Show this help message") do
|
62
|
+
puts(opts)
|
63
|
+
exit
|
64
|
+
end
|
65
|
+
|
66
|
+
opts.on("-v", "--version", "Print the chandler version number") do
|
67
|
+
puts("chandler version #{Chandler::VERSION}")
|
68
|
+
exit
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def summary
|
74
|
+
<<-SUMMARY
|
75
|
+
chandler scans your git repository for version tags (e.g. `v1.0.2`), parses out
|
76
|
+
the corresponding release notes for those tags from your CHANGELOG, and uploads
|
77
|
+
those notes to the GitHub releases area via the GitHub API.
|
78
|
+
|
79
|
+
chandler will use reasonable defaults and inferences to configure itself.
|
80
|
+
If chandler doesn’t work for you out of the box, override the configuration
|
81
|
+
using these options.
|
82
|
+
SUMMARY
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require "chandler/logging"
|
2
|
+
require "chandler/refinements/color"
|
3
|
+
require "chandler/refinements/version_format"
|
4
|
+
|
5
|
+
module Chandler
|
6
|
+
module Commands
|
7
|
+
# Iterates over a given array of tags, fetches the corresponding notes
|
8
|
+
# from the CHANGELOG, and creates (or updates) the release notes for that
|
9
|
+
# tag on GitHub.
|
10
|
+
class Push
|
11
|
+
include Logging
|
12
|
+
using Chandler::Refinements::Color
|
13
|
+
using Chandler::Refinements::VersionFormat
|
14
|
+
|
15
|
+
attr_reader :github, :changelog, :tags, :config
|
16
|
+
|
17
|
+
def initialize(tags:, config:)
|
18
|
+
@tags = tags
|
19
|
+
@github = config.github
|
20
|
+
@changelog = config.changelog
|
21
|
+
@config = config
|
22
|
+
end
|
23
|
+
|
24
|
+
def call
|
25
|
+
benchmarking_each_tag do |tag|
|
26
|
+
github.create_or_update_release(
|
27
|
+
:tag => tag,
|
28
|
+
:title => tag.version_number,
|
29
|
+
:description => changelog.fetch(tag).strip
|
30
|
+
)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def benchmarking_each_tag
|
37
|
+
width = tags.map(&:length).max
|
38
|
+
tags.each do |tag|
|
39
|
+
ellipsis = "…".ljust(1 + width - tag.length)
|
40
|
+
benchmark("Push #{tag.blue}#{ellipsis}") do
|
41
|
+
yield(tag)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require "chandler/changelog"
|
2
|
+
require "chandler/git"
|
3
|
+
require "chandler/github"
|
4
|
+
require "chandler/logger"
|
5
|
+
|
6
|
+
module Chandler
|
7
|
+
class Configuration
|
8
|
+
attr_accessor :changelog_path, :git_path, :github_repository, :dry_run
|
9
|
+
attr_accessor :logger
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@changelog_path = "CHANGELOG.md"
|
13
|
+
@git_path = ".git"
|
14
|
+
@logger = Chandler::Logger.new
|
15
|
+
@dry_run = false
|
16
|
+
end
|
17
|
+
|
18
|
+
def dry_run?
|
19
|
+
dry_run
|
20
|
+
end
|
21
|
+
|
22
|
+
def git
|
23
|
+
@git ||= Chandler::Git.new(:path => git_path)
|
24
|
+
end
|
25
|
+
|
26
|
+
def github
|
27
|
+
@github ||=
|
28
|
+
Chandler::GitHub.new(:repository => github_repository, :config => self)
|
29
|
+
end
|
30
|
+
|
31
|
+
def changelog
|
32
|
+
@changelog ||= Chandler::Changelog.new(:path => changelog_path)
|
33
|
+
end
|
34
|
+
|
35
|
+
def github_repository
|
36
|
+
@github_repository || git.origin_remote
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/chandler/git.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require "chandler/refinements/version_format"
|
2
|
+
require "open3"
|
3
|
+
|
4
|
+
module Chandler
|
5
|
+
# Uses the shell to execute git commands against a given .git directory.
|
6
|
+
class Git
|
7
|
+
using Chandler::Refinements::VersionFormat
|
8
|
+
|
9
|
+
Error = Class.new(StandardError)
|
10
|
+
attr_reader :path
|
11
|
+
|
12
|
+
# Initializes the Git object with the path to the `.git` directory of the
|
13
|
+
# desired git repository.
|
14
|
+
#
|
15
|
+
# Chandler::Git.new(:path => "/path/to/my/project/.git")
|
16
|
+
#
|
17
|
+
def initialize(path:)
|
18
|
+
@path = path
|
19
|
+
end
|
20
|
+
|
21
|
+
# Uses `git tag -l` to obtain the list of tags, then returns the subset of
|
22
|
+
# those tags that appear to be version numbers.
|
23
|
+
#
|
24
|
+
# version_tags # => ["v0.0.1", "v0.2.0", "v0.2.1", "v0.3.0"]
|
25
|
+
#
|
26
|
+
# rubocop:disable Style/SymbolProc
|
27
|
+
def version_tags
|
28
|
+
tags = git("tag", "-l").lines.map(&:strip).select { |v| v.version? }
|
29
|
+
tags.sort_by { |t| Gem::Version.new(t.version_number) }
|
30
|
+
end
|
31
|
+
# rubocop:enable Style/SymbolProc
|
32
|
+
|
33
|
+
# Uses `git remote -v` to list the remotes and returns the URL of the
|
34
|
+
# first one labeled "origin".
|
35
|
+
#
|
36
|
+
# origin_remote # => "git@github.com:mattbrictson/chandler.git"
|
37
|
+
#
|
38
|
+
def origin_remote
|
39
|
+
origin = git("remote", "-v").lines.grep(/^origin\s/).first
|
40
|
+
origin && origin.split[1]
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def git(*args)
|
46
|
+
capture("git", "--git-dir", path, *args)
|
47
|
+
end
|
48
|
+
|
49
|
+
def capture(*args)
|
50
|
+
out, err, status = Open3.capture3(*args)
|
51
|
+
return out if status.success?
|
52
|
+
|
53
|
+
message = "Failed to execute: #{args.join(' ')}"
|
54
|
+
message << "\n#{err}" unless err.nil?
|
55
|
+
fail Error, message
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require "octokit"
|
2
|
+
|
3
|
+
module Chandler
|
4
|
+
# A facade for performing GitHub API operations on a given GitHub repository
|
5
|
+
# (specified as a git URL or as `owner/repo` format). Requires that
|
6
|
+
# "~/.netrc" is properly configured with GitHub credentials.
|
7
|
+
#
|
8
|
+
class GitHub
|
9
|
+
MissingCredentials = Class.new(StandardError)
|
10
|
+
|
11
|
+
attr_reader :repository, :config
|
12
|
+
|
13
|
+
def initialize(repository:, config:)
|
14
|
+
@repository = parse_repository(repository)
|
15
|
+
@config = config
|
16
|
+
end
|
17
|
+
|
18
|
+
def create_or_update_release(tag:, title:, description:)
|
19
|
+
return if config.dry_run?
|
20
|
+
|
21
|
+
release = existing_release(tag)
|
22
|
+
return update_release(release, title, description) if release
|
23
|
+
|
24
|
+
create_release(tag, title, description)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def parse_repository(repo)
|
30
|
+
repo[%r{(git@github.com:|://github.com/)(.*)\.git}, 2] || repo
|
31
|
+
end
|
32
|
+
|
33
|
+
def existing_release(tag)
|
34
|
+
release = client.release_for_tag(repository, tag)
|
35
|
+
release.id.nil? ? nil : release
|
36
|
+
rescue Octokit::NotFound
|
37
|
+
nil
|
38
|
+
end
|
39
|
+
|
40
|
+
def update_release(release, title, desc)
|
41
|
+
return if release_unchanged?(release, title, desc)
|
42
|
+
client.update_release(release.url, :name => title, :body => desc)
|
43
|
+
end
|
44
|
+
|
45
|
+
def release_unchanged?(release, title, desc)
|
46
|
+
release.name == title && release.body.to_s.strip == desc.strip
|
47
|
+
end
|
48
|
+
|
49
|
+
def create_release(tag, title, desc)
|
50
|
+
client.create_release(repository, tag, :name => title, :body => desc)
|
51
|
+
end
|
52
|
+
|
53
|
+
def client
|
54
|
+
@client ||= begin
|
55
|
+
octokit = Octokit::Client.new(:netrc => true)
|
56
|
+
octokit.login ? octokit : fail_missing_credentials
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def fail_missing_credentials
|
61
|
+
message = "Couldn’t load GitHub credentials from ~/.netrc.\n"
|
62
|
+
message << "For .netrc instructions, see: "
|
63
|
+
message << "https://github.com/octokit/octokit.rb#using-a-netrc-file"
|
64
|
+
fail MissingCredentials, message
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require "chandler/refinements/color"
|
2
|
+
|
3
|
+
module Chandler
|
4
|
+
# Similar to Ruby's standard Logger, but automatically removes ANSI color
|
5
|
+
# from the logged messages if stdout and stderr do not support it.
|
6
|
+
#
|
7
|
+
class Logger
|
8
|
+
using Chandler::Refinements::Color
|
9
|
+
attr_accessor :stderr, :stdout, :verbose
|
10
|
+
|
11
|
+
def initialize(stderr: $stderr, stdout: $stdout)
|
12
|
+
@stderr = stderr
|
13
|
+
@stdout = stdout
|
14
|
+
@verbose = false
|
15
|
+
end
|
16
|
+
|
17
|
+
def verbose?
|
18
|
+
verbose
|
19
|
+
end
|
20
|
+
|
21
|
+
# Logs a message to stderr. Unless otherwise specified, the message will
|
22
|
+
# be printed in red.
|
23
|
+
def error(message)
|
24
|
+
message = message.red unless message.color?
|
25
|
+
puts(stderr, message)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Logs a message to stdout.
|
29
|
+
def info(message)
|
30
|
+
puts(stdout, message)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Logs a message to stdout, but only if `verbose?` is true.
|
34
|
+
def debug(message=nil)
|
35
|
+
return unless verbose?
|
36
|
+
return puts(stdout, yield) if block_given?
|
37
|
+
puts(stdout, message)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Logs a message to stdout, runs the given block, and then prints the time
|
41
|
+
# it took to run the block.
|
42
|
+
def benchmark(message)
|
43
|
+
start = Time.now
|
44
|
+
print(stdout, "#{message} ")
|
45
|
+
debug("\n")
|
46
|
+
result = yield
|
47
|
+
duration = Time.now - start
|
48
|
+
info("✔".green + format(" %0.3fs", duration).gray)
|
49
|
+
result
|
50
|
+
rescue
|
51
|
+
info("✘".red)
|
52
|
+
raise
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def print(io, message)
|
58
|
+
message = message.strip_color unless color_enabled?
|
59
|
+
io.print(message)
|
60
|
+
end
|
61
|
+
|
62
|
+
def puts(io, message)
|
63
|
+
message = message.strip_color unless color_enabled?
|
64
|
+
io.puts(message)
|
65
|
+
end
|
66
|
+
|
67
|
+
def color_enabled?
|
68
|
+
@color_enabled = determine_color_support if @color_enabled.nil?
|
69
|
+
@color_enabled
|
70
|
+
end
|
71
|
+
|
72
|
+
def determine_color_support
|
73
|
+
if ENV["CLICOLOR_FORCE"] == "1"
|
74
|
+
true
|
75
|
+
elsif ENV["TERM"] == "dumb"
|
76
|
+
false
|
77
|
+
else
|
78
|
+
tty?(stdout) && tty?(stderr)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def tty?(io)
|
83
|
+
io.respond_to?(:tty?) && io.tty?
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Chandler
|
2
|
+
# Assuming self responds to `config`, this mixin provides easy access to
|
3
|
+
# logging methods by delegating to the configured Logger.
|
4
|
+
#
|
5
|
+
module Logging
|
6
|
+
def self.included(target)
|
7
|
+
target.instance_exec do
|
8
|
+
extend Forwardable
|
9
|
+
private def_delegator :config, :logger
|
10
|
+
private def_delegator :logger, :benchmark
|
11
|
+
private def_delegator :logger, :debug
|
12
|
+
private def_delegator :logger, :error
|
13
|
+
private def_delegator :logger, :info
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Chandler
|
2
|
+
module Refinements
|
3
|
+
# Monkey patch String to provide basic ANSI color support.
|
4
|
+
#
|
5
|
+
# "hello".color? # => false
|
6
|
+
# "hello".blue # => "\e[0;34;49mhello\e[0m"
|
7
|
+
# "hello".blue.color? # => true
|
8
|
+
# "hello".blue.strip_color # "hello"
|
9
|
+
#
|
10
|
+
module Color
|
11
|
+
ANSI_CODES = {
|
12
|
+
:red => 31,
|
13
|
+
:green => 32,
|
14
|
+
:blue => 34,
|
15
|
+
:gray => 90,
|
16
|
+
:grey => 90
|
17
|
+
}.freeze
|
18
|
+
|
19
|
+
refine String do
|
20
|
+
# Returns `true` if this String contains ANSI color sequences.
|
21
|
+
def color?
|
22
|
+
self != strip_color
|
23
|
+
end
|
24
|
+
|
25
|
+
# Returns a new String with ANSI color sequences removed.
|
26
|
+
def strip_color
|
27
|
+
gsub(/\e\[[0-9;]*m/, "")
|
28
|
+
end
|
29
|
+
|
30
|
+
# Define red, green, blue, etc. methods that return a copy of the
|
31
|
+
# String that is wrapped in the corresponding ANSI color escape
|
32
|
+
# sequence.
|
33
|
+
ANSI_CODES.each do |name, code|
|
34
|
+
define_method(name) do
|
35
|
+
"\e[0;#{code};49m#{self}\e[0m"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Chandler
|
2
|
+
module Refinements
|
3
|
+
# Monkey patch String to provide conveniences for identifying strings that
|
4
|
+
# represent a version, and converting between between tags (e.g "v1.0.2")
|
5
|
+
# and version numbers ("1.0.2").
|
6
|
+
#
|
7
|
+
module VersionFormat
|
8
|
+
refine String do
|
9
|
+
# Does this string represent a version?
|
10
|
+
#
|
11
|
+
# "1.0.2".version? # => true
|
12
|
+
# "v1.0.2".version? # => true
|
13
|
+
# "nope".version? # => false
|
14
|
+
# "".version? # => false
|
15
|
+
#
|
16
|
+
def version?
|
17
|
+
!!version_number
|
18
|
+
end
|
19
|
+
|
20
|
+
# The version number portion of the string, with the optional "v"
|
21
|
+
# prefix removed.
|
22
|
+
#
|
23
|
+
# "1.0.2".version_number # => "1.0.2"
|
24
|
+
# "v1.0.2".version_number # => "1.0.2"
|
25
|
+
# "nope".version_number # => nil
|
26
|
+
# "".version_number # => nil
|
27
|
+
#
|
28
|
+
def version_number
|
29
|
+
self[/^v?(#{Gem::Version::VERSION_PATTERN})$/, 1]
|
30
|
+
end
|
31
|
+
|
32
|
+
# The version number reformatted as a tag, by prefixing "v".
|
33
|
+
#
|
34
|
+
# "1.0.2".version_tag # => "v1.0.2"
|
35
|
+
# "v1.0.2".version_tag # => "v1.0.2"
|
36
|
+
# "nope".version_tag # => nil
|
37
|
+
# "".version_tag # => nil
|
38
|
+
#
|
39
|
+
def version_tag
|
40
|
+
number = version_number
|
41
|
+
number && "v#{version_number}"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require "bundler/gem_helper"
|
2
|
+
require "chandler/configuration"
|
3
|
+
require "chandler/refinements/version_format"
|
4
|
+
require "chandler/commands/push"
|
5
|
+
|
6
|
+
using Chandler::Refinements::VersionFormat
|
7
|
+
|
8
|
+
namespace :chandler do
|
9
|
+
desc "Push release notes for the current version to GitHub"
|
10
|
+
task "push" do
|
11
|
+
gemspec = Bundler::GemHelper.gemspec
|
12
|
+
push = Chandler::Commands::Push.new(
|
13
|
+
:tags => [gemspec.version.to_s.version_tag],
|
14
|
+
:config => Chandler::Tasks.config
|
15
|
+
)
|
16
|
+
push.call
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
module Chandler
|
21
|
+
module Tasks
|
22
|
+
def self.config
|
23
|
+
@configuration ||= Chandler::Configuration.new
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.configure
|
27
|
+
yield(config)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
metadata
ADDED
@@ -0,0 +1,241 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: chandler
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Matt Brictson
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-06-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: netrc
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: octokit
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 2.2.0
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 2.2.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.10'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.10'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: guard
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 2.2.2
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 2.2.2
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: guard-minitest
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
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: rb-fsevent
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: minitest
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: minitest-reporters
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: mocha
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: rubocop
|
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
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: terminal-notifier-guard
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - ">="
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
type: :development
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - ">="
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: '0'
|
181
|
+
description:
|
182
|
+
email:
|
183
|
+
- chandler@mattbrictson.com
|
184
|
+
executables:
|
185
|
+
- chandler
|
186
|
+
extensions: []
|
187
|
+
extra_rdoc_files: []
|
188
|
+
files:
|
189
|
+
- ".gitignore"
|
190
|
+
- ".rubocop.yml"
|
191
|
+
- ".travis.yml"
|
192
|
+
- CHANGELOG.md
|
193
|
+
- CONTRIBUTING.md
|
194
|
+
- Gemfile
|
195
|
+
- Guardfile
|
196
|
+
- LICENSE.txt
|
197
|
+
- README.md
|
198
|
+
- Rakefile
|
199
|
+
- bin/console
|
200
|
+
- bin/setup
|
201
|
+
- chandler.gemspec
|
202
|
+
- exe/chandler
|
203
|
+
- lib/chandler.rb
|
204
|
+
- lib/chandler/changelog.rb
|
205
|
+
- lib/chandler/cli.rb
|
206
|
+
- lib/chandler/cli/parser.rb
|
207
|
+
- lib/chandler/commands/push.rb
|
208
|
+
- lib/chandler/configuration.rb
|
209
|
+
- lib/chandler/git.rb
|
210
|
+
- lib/chandler/github.rb
|
211
|
+
- lib/chandler/logger.rb
|
212
|
+
- lib/chandler/logging.rb
|
213
|
+
- lib/chandler/refinements/color.rb
|
214
|
+
- lib/chandler/refinements/version_format.rb
|
215
|
+
- lib/chandler/tasks.rb
|
216
|
+
- lib/chandler/version.rb
|
217
|
+
homepage: https://github.com/mattbrictson/chandler
|
218
|
+
licenses:
|
219
|
+
- MIT
|
220
|
+
metadata: {}
|
221
|
+
post_install_message:
|
222
|
+
rdoc_options: []
|
223
|
+
require_paths:
|
224
|
+
- lib
|
225
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
226
|
+
requirements:
|
227
|
+
- - ">="
|
228
|
+
- !ruby/object:Gem::Version
|
229
|
+
version: 2.1.0
|
230
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
231
|
+
requirements:
|
232
|
+
- - ">="
|
233
|
+
- !ruby/object:Gem::Version
|
234
|
+
version: '0'
|
235
|
+
requirements: []
|
236
|
+
rubyforge_project:
|
237
|
+
rubygems_version: 2.4.8
|
238
|
+
signing_key:
|
239
|
+
specification_version: 4
|
240
|
+
summary: Syncs CHANGELOG entries to GitHub's release notes
|
241
|
+
test_files: []
|