groundskeeper-bitcore 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 22443d1b2eb3e74cb732993ae2162a17d28899f8
4
+ data.tar.gz: f64b1e9362ba9a7025afc5ed6b522f247bd2470b
5
+ SHA512:
6
+ metadata.gz: 8833b8710aad1de7efe9b704a042ea49ae90d541933c302b72e5e1ecab89ed6a8bb2efc6171ab53a2e81502d4bcc87de988076bcb9f0bb4ff4c222ebd0a479b3
7
+ data.tar.gz: 194d6b7558ad5158d94adeaf816c405ba4142ce2fbe8c8bf8ddc27dc65b5a6a21419cda8bc44ce7edd111bf1bf927459e3b33997107bd21b35148cb36c93b831
checksums.yaml.gz.sig ADDED
Binary file
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ groundskeeper-*.gem
data/.rubocop.yml ADDED
@@ -0,0 +1,35 @@
1
+ AllCops:
2
+ Exclude:
3
+ - bin/**/*
4
+ TargetRubyVersion: 2.4
5
+
6
+ AbcSize:
7
+ Exclude:
8
+ - test/**/*
9
+
10
+ BlockLength:
11
+ Exclude:
12
+ - groundskeeper.gemspec
13
+
14
+ ClassLength:
15
+ Exclude:
16
+ - test/**/*
17
+
18
+ EmptyLineBetweenDefs:
19
+ Exclude:
20
+ - test/**/*
21
+
22
+ MethodLength:
23
+ Exclude:
24
+ - test/**/*
25
+
26
+ NestedMethodDefinition:
27
+ Exclude:
28
+ - test/**/*
29
+
30
+ SingleLineMethods:
31
+ Exclude:
32
+ - test/**/*
33
+
34
+ StringLiterals:
35
+ EnforcedStyle: double_quotes
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.4.0
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.3.4
5
+ before_install: gem install bundler -v 1.15.1
data/CHANGELOG.md ADDED
@@ -0,0 +1,30 @@
1
+ # Changelog
2
+
3
+ ## 0.1.1 - 2017-09-14
4
+
5
+ * sign gem and update installation instructions (#37)
6
+ * Update command highlighting (#36)
7
+ * open pull request page in GitHub upon release (#34)
8
+ * add tests to Commands#info method (#32)
9
+ * fix bug preventing loading of project file (#31)
10
+ * refactor and add smoke tests to Application (#30)
11
+ * add tests to Project (#26)
12
+ * refactor/rename some methods; add tests to Git (#25)
13
+ * add code coverage to tests (#23)
14
+ * add version to remote Jira issues; refactor (#21)
15
+ * ask and push the tagged branch to remote (#20)
16
+ * ignore release commits (#19)
17
+ * begin to configure Jira integration (#18)
18
+ * stage, commit, and tag release (#17)
19
+ * detect missing Rails files (#16)
20
+ * create a branch and update the changelog (#10)
21
+ * capture current Rails application version (#8)
22
+ * add release command; calculate next version (#7)
23
+ * print branches which contain latest tag (#6)
24
+
25
+ ## 0.1.0 - 2017-07-18
26
+
27
+ * refactor; capture commits since last tag (#4)
28
+ * add "info" command (#3)
29
+ * add executable `ground` (#2)
30
+ * start scaffolding git and release code (#1)
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at ericcf@northwestern.edu. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ # Specify your gem's dependencies in groundskeeper.gemspec
6
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Eric Carty-Fickes
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,93 @@
1
+ # Groundskeeper
2
+
3
+ The goal of this gem is to manage the workflow related to releasing and
4
+ deploying Rails applications.
5
+
6
+ ## Installation
7
+
8
+ Groundskeeper is cryptographically signed. To be sure this gem hasn't been
9
+ tampered with, add the following public key if you have not already:
10
+
11
+ ```bash
12
+ gem cert --add <(curl -Ls https://raw.github.com/NU-CBITS/groundskeeper/master/certs/ericcf.pem)
13
+ ```
14
+
15
+ Install this gem globally via:
16
+
17
+ ```bash
18
+ gem install groundskeeper -P HighSecurity
19
+ ```
20
+
21
+ The HighSecurity trust profile will verify signed gems and require that all
22
+ dependencies are signed.
23
+
24
+ Note: if you have multiple versions of Ruby installed (via RVM e.g.), you will
25
+ need to install this gem for each of them. In this example, your Rails
26
+ application directory and the groundskeeper source are in the same parent
27
+ directory:
28
+
29
+ ```bash
30
+ gem install ../groundskeeper/groundskeeper-<version>.gem
31
+ ```
32
+
33
+ Additionally, to integrate with Jira you will need to set some environment
34
+ variables. One standard place to do this is in the `~/.bash_profile`:
35
+
36
+ ```bash
37
+ export JIRA_USERNAME="my-username"
38
+ export JIRA_PASSWORD="my-password"
39
+ export JIRA_SITE="https://cbit123.atlassian.net"
40
+ ```
41
+
42
+ Jira integration also depends on a repository that contains metadata for
43
+ projects. Clone it as follows:
44
+
45
+ ```bash
46
+ git clone git@github.com:NU-CBITS/project_details.git ~/.project_details
47
+ ```
48
+
49
+ ## Usage
50
+
51
+ To display tag/release information about a Rails project, use the `info`
52
+ command within a Rails application directory:
53
+
54
+ ```bash
55
+ ground info
56
+ ```
57
+
58
+ To create a new release tag, use the `release` command within a Rails
59
+ application directory:
60
+
61
+ ```bash
62
+ ground release
63
+ ```
64
+
65
+ ## Development
66
+
67
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run
68
+ `rake test` to run the tests. You can also run `bin/console` for an interactive
69
+ prompt that will allow you to experiment.
70
+
71
+ To install this gem onto your local machine, run `bundle exec rake install`. To
72
+ release a new version, update the version number in `version.rb`, and then run
73
+ `bundle exec rake release`, which will create a git tag for the version, push
74
+ git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
75
+
76
+ ## Contributing
77
+
78
+ Bug reports and pull requests are welcome on GitHub at
79
+ https://github.com/NU-CBITS/groundskeeper. This project is intended to be a
80
+ safe, welcoming space for collaboration, and contributors are expected to
81
+ adhere to the [Contributor Covenant](http://contributor-covenant.org) code of
82
+ conduct.
83
+
84
+ ## License
85
+
86
+ The gem is available as open source under the terms of the
87
+ [MIT License](http://opensource.org/licenses/MIT).
88
+
89
+ ## Code of Conduct
90
+
91
+ Everyone interacting in the Groundskeeper project’s codebases, issue trackers,
92
+ chat rooms and mailing lists is expected to follow the
93
+ [code of conduct](https://github.com/NU-CBITS/groundskeeper/blob/master/CODE_OF_CONDUCT.md).
data/Rakefile ADDED
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rake/testtask"
5
+ require "rubocop/rake_task"
6
+
7
+ Rake::TestTask.new(:test) do |t|
8
+ t.libs << "test"
9
+ t.libs << "lib"
10
+ t.test_files = FileList["test/**/*_test.rb"]
11
+ end
12
+
13
+ task :default do
14
+ Rake::Task["test"].invoke
15
+ RuboCop::RakeTask.new
16
+ Rake::Task["rubocop"].invoke
17
+ end
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "groundskeeper"
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(__FILE__)
data/bin/ground ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "groundskeeper"
4
+
5
+ Groundskeeper::Application.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/certs/ericcf.pem ADDED
@@ -0,0 +1,21 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIDhTCCAm2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQ8wDQYDVQQDDAZlcmlj
3
+ Y2YxHDAaBgoJkiaJk/IsZAEZFgxub3J0aHdlc3Rlcm4xEzARBgoJkiaJk/IsZAEZ
4
+ FgNlZHUwHhcNMTcwOTEyMjAwODQzWhcNMTgwOTEyMjAwODQzWjBEMQ8wDQYDVQQD
5
+ DAZlcmljY2YxHDAaBgoJkiaJk/IsZAEZFgxub3J0aHdlc3Rlcm4xEzARBgoJkiaJ
6
+ k/IsZAEZFgNlZHUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDk8FgP
7
+ SIrleTjIXJT/yu+W9nujkvcIMRPbLqKq60KQy/2LANMZ7DiLZRBkg2oSK0D9p8GR
8
+ be30F2DGAOSBZiBTLPDNAQZBpRVGeFpAAOEpREZ8ahaZVTfc8+IYSfxpnW2gaUte
9
+ SfbG5xNcpHkRpwkbZGoq9yFOoaucxfwoz+9QunEFDiCAumn7uRMKHJdqSEpQnFkQ
10
+ 56GKuUvUuq7J+J4M+kwOK6a/4/Y8Bs/qUYH3GHa/0WJwfFLfp3gqhagLcZu40JFe
11
+ mQpX3bAkmojuxyAi7JjXKqFv1LZgxAGca5SC6sECXiTkw9eXInBKzvBN33gOv+Vj
12
+ 9bot70L0EihaqJrnAgMBAAGjgYEwfzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIEsDAd
13
+ BgNVHQ4EFgQUsMK40utpv6yRQ3i0R7avJn3LQ/YwIgYDVR0RBBswGYEXZXJpY2Nm
14
+ QG5vcnRod2VzdGVybi5lZHUwIgYDVR0SBBswGYEXZXJpY2NmQG5vcnRod2VzdGVy
15
+ bi5lZHUwDQYJKoZIhvcNAQEFBQADggEBACvUVV3V8EYqV9DanJS3ywMVnQB5ByP1
16
+ 7TV70+Amnnu196Jp2JGJ27sjeE79VJeBbGyE0rCRUQXlaD2Zh8X6Yy04oWR0YFa8
17
+ DQ3rqVmKTodTJ0K/rmpIMCbwrsyg7QRxfB6cUE+sgPX5ygDmj2gYY+fcw3MoVOif
18
+ QY1i1gFSjcXvx0qnvQLnbD+gbr7D3wpfgFHRbBEDOuNdpFthggUO6eFraVYcsz9u
19
+ 1v/mC2s7Cj+Jv053bCKPjSk2wLLZpHRs40jXgy/NudtouDy2yYlJHxBFfdeRNEk2
20
+ fo8I5WeWdUoEzUI6WlkTjMw3nWezlF0LCGz781P4qvtz0BICgaS41qw=
21
+ -----END CERTIFICATE-----
@@ -0,0 +1,46 @@
1
+ # coding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ lib = File.expand_path("../lib", __FILE__)
5
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
6
+ require "groundskeeper/version"
7
+
8
+ Gem::Specification.new do |spec|
9
+ spec.name = "groundskeeper-bitcore"
10
+ spec.version = Groundskeeper::VERSION
11
+ spec.authors = ["BIT Core"]
12
+ spec.email = ["ericcf@northwestern.edu"]
13
+
14
+ spec.summary = "A gem for managing releases and deployments."
15
+ spec.homepage = "https://github.com/NU-CBITS/groundskeeper.git"
16
+ spec.license = "MIT"
17
+ spec.cert_chain = ["certs/ericcf.pem"]
18
+ if $PROGRAM_NAME.end_with?("gem")
19
+ spec.signing_key = File.expand_path("~/.ssh/gem-private_key.pem")
20
+ end
21
+
22
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the
23
+ # 'allowed_push_host' to allow pushing to a single host or delete this
24
+ # section to allow pushing to any host.
25
+ if spec.respond_to?(:metadata)
26
+ spec.metadata["allowed_push_host"] = "https://rubygems.org"
27
+ else
28
+ raise "RubyGems 2.0 or newer is required to protect against " \
29
+ "public gem pushes."
30
+ end
31
+
32
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
33
+ f.match(%r{^(test|spec|features)/})
34
+ end
35
+ spec.bindir = "bin"
36
+ spec.executables = "ground"
37
+ spec.require_paths = ["lib"]
38
+
39
+ spec.add_dependency "jira-ruby", "~> 1.3"
40
+ spec.add_dependency "thor", "~> 0.19"
41
+
42
+ spec.add_development_dependency "bundler", "~> 1.15"
43
+ spec.add_development_dependency "minitest", "~> 5.0"
44
+ spec.add_development_dependency "rubocop", "~> 0.49.1"
45
+ spec.add_development_dependency "simplecov", "~> 0.14"
46
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "thor"
4
+
5
+ module Groundskeeper
6
+ # Bootstrap this as a Thor application.
7
+ class Application < Thor
8
+ attr_reader :commands
9
+
10
+ def initialize(args = [], local_options = {}, config = {})
11
+ @commands = Commands.build(self)
12
+ super
13
+ end
14
+
15
+ desc "info", "Display revision info"
16
+ def info
17
+ commands.info
18
+ end
19
+
20
+ desc "release", "create a new release"
21
+ def release
22
+ commands.info
23
+ commands.release
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "date"
4
+
5
+ module Groundskeeper
6
+ # The `CHANGELOG.md` file in an application.
7
+ class Changelog
8
+ attr_reader :document, :date
9
+
10
+ FILENAME = "CHANGELOG.md"
11
+ TITLE_EXPRESSION = "# Changelog"
12
+
13
+ def self.build(filename: FILENAME)
14
+ new(
15
+ document: Groundskeeper::Document.new(filename),
16
+ date: Date.today.iso8601
17
+ )
18
+ end
19
+
20
+ def initialize(document:, date:)
21
+ @document = document
22
+ @date = date
23
+ end
24
+
25
+ # rubocop:disable Performance/RedundantMatch,Performance/RegexpMatch
26
+ def update_file(version, changes)
27
+ unless document.match(/(#{TITLE_EXPRESSION})/)
28
+ document.prepend_file("#{TITLE_EXPRESSION}\n\n")
29
+ end
30
+
31
+ document
32
+ .append_to_file(TITLE_EXPRESSION, version_template(version, changes))
33
+ end
34
+ # rubocop:enable Performance/RedundantMatch,Performance/RegexpMatch
35
+
36
+ private
37
+
38
+ def version_template(version, changes)
39
+ ["\n", "## #{version} - #{date}", ""]
40
+ .concat(changes.map { |change| "* #{change}" })
41
+ .join("\n")
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,199 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Groundskeeper
4
+ # Formulas for managing releases.
5
+ # rubocop:disable Metrics/ClassLength
6
+ class Commands
7
+ # rubocop:disable Metrics/MethodLength
8
+ def self.build(console)
9
+ repository = Repository.new
10
+ project = Project.build(repository.name)
11
+ git_hub = GitHub.build(
12
+ username: project.source_control_username,
13
+ repository_name: repository.name
14
+ )
15
+
16
+ new(
17
+ changelog: Changelog.build,
18
+ console: console,
19
+ git: Git.build,
20
+ git_hub: git_hub,
21
+ jira: Jira.build(project.jira_prefix),
22
+ repository: repository,
23
+ project: project,
24
+ version_file: RailsVersion.new
25
+ )
26
+ end
27
+ # rubocop:enable Metrics/MethodLength
28
+
29
+ # rubocop:disable Metrics/ParameterLists
30
+ def initialize(
31
+ changelog: nil,
32
+ console:,
33
+ git: nil,
34
+ git_hub: nil,
35
+ jira: nil,
36
+ project: nil,
37
+ repository: nil,
38
+ version_file:
39
+ )
40
+ @changelog = changelog
41
+ @console = console
42
+ @git = git
43
+ @git_hub = git_hub
44
+ @jira = jira
45
+ @project = project
46
+ @repository = repository
47
+ @version_file = version_file
48
+ @did_checkout_branch = false
49
+ @did_push_to_remote = false
50
+ end
51
+ # rubocop:enable Metrics/ParameterLists
52
+
53
+ # rubocop:disable Metrics/MethodLength
54
+ def info
55
+ return unrecognized_version unless version_file.exists?
56
+
57
+ announce_version
58
+ announce_latest_tag
59
+ console.say(
60
+ "version in current branch: " +
61
+ version_file.current_version,
62
+ :yellow
63
+ )
64
+ console.say(
65
+ "tag contained in: #{git.branches_containing_latest_tag}\n\n",
66
+ :yellow
67
+ )
68
+ end
69
+
70
+ def release
71
+ return unrecognized_version unless version_file.exists?
72
+
73
+ summarize_recent_commits
74
+ ask_next_version
75
+ ask_new_branch
76
+ update_version_file
77
+ update_changelog
78
+ commit_changes_and_tag
79
+ ask_create_jira_version
80
+ ask_push_with_tags
81
+ ask_add_version_to_jira_issues
82
+ open_pull_request_page
83
+ end
84
+ # rubocop:enable Metrics/MethodLength
85
+
86
+ private
87
+
88
+ # collaborators
89
+ attr_reader :changelog, :console, :git, :git_hub, :jira, :project,
90
+ :repository, :version_file
91
+ # state
92
+ attr_reader :next_version, :recent_commits, :did_checkout_branch,
93
+ :did_push_to_remote
94
+
95
+ def announce_version
96
+ console.say("Groundskeeper version #{Groundskeeper::VERSION}\n\n", :bold)
97
+ end
98
+
99
+ def announce_latest_tag
100
+ console.say(
101
+ "latest tag on this repository: " +
102
+ git.latest_tag_name_across_branches,
103
+ :yellow
104
+ )
105
+ end
106
+
107
+ def summarize_recent_commits
108
+ console.say("commits since last tag", :bold)
109
+ @recent_commits = repository.changes_since_latest_tag
110
+ console.say(recent_commits.join("\n"), :green)
111
+ console.say("")
112
+ end
113
+
114
+ def ask_next_version
115
+ type = console.ask(
116
+ "Major, minor, or patch release?",
117
+ :cyan,
118
+ limited_to: %w[M m p]
119
+ )
120
+ @next_version = repository.bumped_semantic_version(type)
121
+ console.say("next tag will be: #{next_version}", :green)
122
+ end
123
+
124
+ def ask_new_branch
125
+ @did_checkout_branch = console.yes?(
126
+ "Checkout new branch #{new_branch_name}? [y, n]",
127
+ :cyan
128
+ )
129
+ git.create_and_checkout_branch(new_branch_name) if did_checkout_branch
130
+ end
131
+
132
+ def update_version_file
133
+ version_file.update_version! next_version
134
+ console.say("# updated version file", :green)
135
+ end
136
+
137
+ def update_changelog
138
+ changelog.update_file(next_version, recent_commits)
139
+ console.say("# updated changelog", :green)
140
+ end
141
+
142
+ def commit_changes_and_tag
143
+ git.add_update
144
+ git.commit(format(Repository::RELEASE_MESSAGE, next_version))
145
+ console.say("# committed changes", :green)
146
+ git.add_tag(next_version)
147
+ console.say("# tagged", :green)
148
+ end
149
+
150
+ def ask_create_jira_version
151
+ create_jira_version =
152
+ console.yes?("Create version #{next_version} in Jira? [y, n]", :cyan)
153
+ jira.create_remote_version(next_jira_version_name) if create_jira_version
154
+ end
155
+
156
+ def ask_push_with_tags
157
+ @did_push_to_remote = console.yes?(
158
+ "Push to remote with tags? [y, n]",
159
+ :cyan
160
+ )
161
+ git.push_with_tags && console.say("# pushed tag") if @did_push_to_remote
162
+ end
163
+
164
+ def ask_add_version_to_jira_issues
165
+ issue_ids = jira.included_issues(recent_commits)
166
+ add_version_to_jira_issues = console.yes?(
167
+ "Add #{next_jira_version_name} to #{issue_ids}? [y, n]",
168
+ :cyan
169
+ )
170
+
171
+ return unless add_version_to_jira_issues
172
+
173
+ jira.add_version_to_remote_issues(next_jira_version_name, issue_ids)
174
+ console.say("# added version to Jira issues", :green)
175
+ end
176
+
177
+ def next_jira_version_name
178
+ "#{repository.name} #{next_version}"
179
+ end
180
+
181
+ def unrecognized_version
182
+ console.say(
183
+ "Unable to find version file, is this a Rails application?",
184
+ :red
185
+ )
186
+ end
187
+
188
+ def open_pull_request_page
189
+ return unless did_checkout_branch && did_push_to_remote
190
+
191
+ git_hub.open_pull_request_page(new_branch_name)
192
+ end
193
+
194
+ def new_branch_name
195
+ "v#{next_version}"
196
+ end
197
+ end
198
+ # rubocop:enable Metrics/ClassLength
199
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Groundskeeper
4
+ # Wraps files.
5
+ class Document
6
+ attr_reader :path
7
+
8
+ def initialize(path)
9
+ @path = File.expand_path(path)
10
+ end
11
+
12
+ def exists?
13
+ File.exist? path
14
+ end
15
+
16
+ # Returns the first captured expression or nil if it is not found.
17
+ def match(expression_with_capture)
18
+ content = read
19
+ match = content.match(expression_with_capture)
20
+
21
+ match[1] if match
22
+ end
23
+
24
+ # Replaces the expression with the provided value in place in the file.
25
+ def gsub_file(expression, value)
26
+ content = read
27
+ content.gsub! expression, value
28
+ write_file content
29
+ end
30
+
31
+ # Inserts the provided value after the expression in place in the file.
32
+ def append_to_file(expression, value)
33
+ content = read
34
+ match = content.match(expression)[0]
35
+ content.gsub! expression, match + value
36
+ write_file content
37
+ end
38
+
39
+ # Inserts the provided value at the beginning of the file.
40
+ def prepend_file(value)
41
+ content = read
42
+ write_file(value + content)
43
+ end
44
+
45
+ def write_file(content)
46
+ File.open(path, "wb") { |file| file.write(content) }
47
+ end
48
+
49
+ def read
50
+ return "" unless exists?
51
+
52
+ File.binread(path)
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Groundskeeper
4
+ # Wraps git executable and adds a few convenience methods on top.
5
+ class Git
6
+ COMMAND = "git"
7
+ # git arguments
8
+ STATUS = "status"
9
+ FETCH_WITH_TAGS = "fetch --tags"
10
+ VERSION = "--version"
11
+ TAGS_ASC = "tag -l --sort=v:refname"
12
+ LATEST_TAG_COMMIT = "#{COMMAND} rev-list --tags --max-count=1"
13
+ LATEST_TAG_NAME = format("describe --tags $(%s)", LATEST_TAG_COMMIT)
14
+ LATEST_TAG_BRANCHES = format("branch --contains $(%s)", LATEST_TAG_COMMIT)
15
+ LATEST_CHANGES = "log %s..HEAD --oneline"
16
+ CREATE_AND_CHECKOUT_BRANCH = "checkout -b %s"
17
+ ADD_UPDATE = "add -u"
18
+ COMMIT = "commit -m \"%s\""
19
+ ADD_TAG = "tag %s"
20
+ PUSH_HEAD_WITH_TAGS = "push origin head --tags"
21
+
22
+ attr_reader :git
23
+
24
+ # Wraps the "git" shell command.
25
+ class Executable
26
+ def execute(arguments)
27
+ `#{COMMAND} #{arguments}`
28
+ end
29
+ end
30
+
31
+ def self.build
32
+ new Executable.new
33
+ end
34
+
35
+ def initialize(git)
36
+ @git = git
37
+ end
38
+
39
+ def status
40
+ git.execute(STATUS)
41
+ end
42
+
43
+ def fetch
44
+ git.execute(FETCH_WITH_TAGS)
45
+ end
46
+
47
+ def version
48
+ semantic_version = /\d+.\d+.\d+/
49
+
50
+ git.execute(VERSION).match(semantic_version)[0]
51
+ end
52
+
53
+ def list_tags
54
+ git.execute(TAGS_ASC)
55
+ end
56
+
57
+ def latest_tag_name_across_branches
58
+ git.execute(LATEST_TAG_NAME).chop
59
+ end
60
+
61
+ def branches_containing_latest_tag
62
+ git.execute(LATEST_TAG_BRANCHES).split("\n").map(&:strip)
63
+ end
64
+
65
+ def raw_changes_since_latest_tag
66
+ latest_changes = format(LATEST_CHANGES, latest_tag_name_across_branches)
67
+
68
+ git.execute(latest_changes).split("\n")
69
+ end
70
+
71
+ def create_and_checkout_branch(name)
72
+ git.execute(format(CREATE_AND_CHECKOUT_BRANCH, name))
73
+ end
74
+
75
+ def add_update
76
+ git.execute(ADD_UPDATE)
77
+ end
78
+
79
+ def commit(message)
80
+ git.execute(format(COMMIT, message))
81
+ end
82
+
83
+ def add_tag(name)
84
+ git.execute(format(ADD_TAG, name))
85
+ end
86
+
87
+ def push_with_tags
88
+ git.execute(PUSH_HEAD_WITH_TAGS)
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Groundskeeper
4
+ # Wraps an interface to GitHub.
5
+ class GitHub
6
+ attr_reader :opener, :username, :repository_name
7
+
8
+ COMMAND = "open"
9
+ URL_BASE = "https://github.com/"
10
+
11
+ # Wraps the "open" shell command.
12
+ class Executable
13
+ def execute(arguments)
14
+ `#{COMMAND} #{arguments}`
15
+ end
16
+ end
17
+
18
+ def self.build(username:, repository_name:)
19
+ new(
20
+ opener: Executable.new,
21
+ username: username,
22
+ repository_name: repository_name
23
+ )
24
+ end
25
+
26
+ def initialize(opener:, username:, repository_name:)
27
+ @opener = opener
28
+ @username = username
29
+ @repository_name = repository_name
30
+ end
31
+
32
+ def open_pull_request_page(branch_name)
33
+ url = "#{URL_BASE}#{username}/#{repository_name}/compare/" \
34
+ "#{branch_name}?expand=1"
35
+
36
+ opener.execute(url)
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "date"
4
+ require "jira-ruby"
5
+
6
+ module Groundskeeper
7
+ # Wraps an interface to Jira.
8
+ class Jira
9
+ attr_reader :client, :prefix
10
+
11
+ ISSUE_PATTERN = "%s-\\d+"
12
+
13
+ # Wraps the jira-ruby Client class.
14
+ class JiraClient
15
+ attr_reader :client
16
+
17
+ def initialize
18
+ @client = JIRA::Client.new(
19
+ username: ENV["JIRA_USERNAME"],
20
+ password: ENV["JIRA_PASSWORD"],
21
+ site: ENV["JIRA_SITE"],
22
+ context_path: "",
23
+ auth_type: :basic,
24
+ read_timeout: 120
25
+ )
26
+ end
27
+
28
+ def create_version(name:, prefix:)
29
+ client.Version
30
+ .build
31
+ .save(name: name, project: prefix)
32
+ end
33
+
34
+ def add_version_to_issue(issue_id:, version_name:)
35
+ client.Issue
36
+ .find(issue_id)
37
+ .save(update: { fixVersions: [{ add: { name: version_name } }] })
38
+ end
39
+ end
40
+
41
+ def self.build(prefix)
42
+ new(
43
+ prefix: prefix,
44
+ client: JiraClient.new
45
+ )
46
+ end
47
+
48
+ def initialize(client: nil, prefix: nil)
49
+ @prefix = prefix
50
+ @client = client
51
+ end
52
+
53
+ # Returns the list of Jira issues found in a set of commit messages.
54
+ def included_issues(changes)
55
+ issue_expression = /#{format(ISSUE_PATTERN, prefix)}/
56
+
57
+ changes.map { |change| change.scan(issue_expression) }.flatten.compact
58
+ end
59
+
60
+ def create_remote_version(name)
61
+ client.create_version(name: name, prefix: prefix)
62
+ end
63
+
64
+ def add_version_to_remote_issues(name, issue_ids)
65
+ issue_ids.each do |issue_id|
66
+ client.add_version_to_issue(issue_id: issue_id, version_name: name)
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "yaml"
4
+
5
+ module Groundskeeper
6
+ # Accesses project details stored in the home directory.
7
+ class Project
8
+ attr_reader :details
9
+
10
+ DETAILS_PATH = "~/.project_details/projects.yml"
11
+ JIRA_PREFIX_KEY = "jira_prefix"
12
+ PROJECT_NAME_KEY = "name"
13
+ SOURCE_CONTROL_USERNAME_KEY = "scm_username"
14
+
15
+ def self.build(repository_name)
16
+ new(
17
+ yaml: Document.new(DETAILS_PATH).read,
18
+ repository_name: repository_name
19
+ )
20
+ end
21
+
22
+ def initialize(yaml:, repository_name:)
23
+ projects = YAML.safe_load(yaml) || {}
24
+ @details = projects[repository_name] || {}
25
+ end
26
+
27
+ def project_name
28
+ details[PROJECT_NAME_KEY] || ""
29
+ end
30
+
31
+ def jira_prefix
32
+ details[JIRA_PREFIX_KEY] || ""
33
+ end
34
+
35
+ def source_control_username
36
+ details[SOURCE_CONTROL_USERNAME_KEY] || ""
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Groundskeeper
4
+ # The `version.rb` file in an application.
5
+ class RailsVersion
6
+ APPLICATION_CONFIG_FILE = "%sconfig/application.rb"
7
+ MODULE_NAME_EXPRESSION = /module (\w+)/
8
+ VERSION_FILE = "%slib/%s/version.rb"
9
+ VERSION_EXPRESSION = /(?<=VERSION = ")([^"]+)(?=")/
10
+
11
+ attr_reader :relative_path, :module_file, :version_file
12
+
13
+ def initialize(relative_path = "")
14
+ @relative_path = relative_path
15
+ find_version_file
16
+ end
17
+
18
+ def current_version
19
+ version_file.match(VERSION_EXPRESSION) || ""
20
+ end
21
+
22
+ def update_version!(value)
23
+ version_file.gsub_file VERSION_EXPRESSION, value
24
+ end
25
+
26
+ def exists?
27
+ version_file.exists?
28
+ end
29
+
30
+ private
31
+
32
+ def find_module_file
33
+ @module_file = Groundskeeper::Document.new(module_file_path)
34
+ end
35
+
36
+ def find_version_file
37
+ find_module_file
38
+ @version_file = Groundskeeper::Document.new(version_file_path)
39
+ end
40
+
41
+ def module_file_path
42
+ format APPLICATION_CONFIG_FILE, relative_path
43
+ end
44
+
45
+ def version_file_path
46
+ format VERSION_FILE, relative_path, project_namespace
47
+ end
48
+
49
+ def project_namespace
50
+ underscore(module_file.match(MODULE_NAME_EXPRESSION))
51
+ end
52
+
53
+ def underscore(word)
54
+ return "" unless word.respond_to?(:gsub)
55
+
56
+ word
57
+ .gsub(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2')
58
+ .gsub(/([a-z\d])([A-Z])/, '\1_\2')
59
+ .downcase
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Groundskeeper
4
+ # A Git repository.
5
+ class Repository
6
+ MAJOR = "major"
7
+ MINOR = "minor"
8
+ PATCH = "patch"
9
+ SEMANTIC_RELEASE_TYPE = { M: MAJOR, m: MINOR, p: PATCH }.freeze
10
+ # git output matching
11
+ ON_BRANCH_MASTER = "On branch master"
12
+ UP_TO_DATE = "Your branch is up-to-date with 'origin/master'"
13
+ UNSTAGED_CHANGES = "Changes not staged for commit"
14
+ # git comment matching
15
+ COMMIT_HASH = /^[^ ]+ /
16
+ RELEASE_MESSAGE = "release version %s"
17
+
18
+ attr_reader :git
19
+
20
+ def initialize(git: nil)
21
+ @git = git || Git.build
22
+ end
23
+
24
+ def clean_directory?
25
+ on_branch_master? && up_to_date? && !unstaged_changes?
26
+ end
27
+
28
+ def on_branch_master?
29
+ git.status.include? ON_BRANCH_MASTER
30
+ end
31
+
32
+ def up_to_date?
33
+ git.status.include? UP_TO_DATE
34
+ end
35
+
36
+ def unstaged_changes?
37
+ git.status.include? UNSTAGED_CHANGES
38
+ end
39
+
40
+ def status
41
+ @status ||= begin
42
+ git.fetch
43
+
44
+ git.status
45
+ end
46
+ end
47
+
48
+ def changes_since_latest_tag
49
+ git
50
+ .raw_changes_since_latest_tag
51
+ .map { |c| c.gsub(COMMIT_HASH, "") }
52
+ .reject { |c| c.match(/#{format(RELEASE_MESSAGE, "")}/) }
53
+ end
54
+
55
+ # rubocop:disable Metrics/MethodLength
56
+ def bumped_semantic_version(type)
57
+ major, minor, patch = git
58
+ .latest_tag_name_across_branches
59
+ .split(".")
60
+ .map(&:to_i)
61
+
62
+ case SEMANTIC_RELEASE_TYPE[type.to_sym]
63
+ when MAJOR
64
+ "#{major + 1}.0.0"
65
+ when MINOR
66
+ "#{major}.#{minor + 1}.0"
67
+ when PATCH
68
+ "#{major}.#{minor}.#{patch + 1}"
69
+ end
70
+ end
71
+ # rubocop:enable Metrics/MethodLength
72
+
73
+ def name
74
+ `pwd`.split("/").last.chop
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Groundskeeper
4
+ VERSION = "0.1.1"
5
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "groundskeeper/application"
4
+ require "groundskeeper/changelog"
5
+ require "groundskeeper/commands"
6
+ require "groundskeeper/document"
7
+ require "groundskeeper/git"
8
+ require "groundskeeper/git_hub"
9
+ require "groundskeeper/jira"
10
+ require "groundskeeper/project"
11
+ require "groundskeeper/rails_version"
12
+ require "groundskeeper/repository"
13
+ require "groundskeeper/version"
14
+
15
+ # :reek:IrresponsibleModule
16
+ module Groundskeeper
17
+ end
data.tar.gz.sig ADDED
@@ -0,0 +1,2 @@
1
+ YN����� �@D����8��vr�F�Ϸ�ܓ�O�7��> ���P}j��
2
+ iZDh4>�3��%ɻ�mr����v3��b��0_Fk��B�u&�y��;�G��3C-ɣ��g�ݕîw捀IR~�w��gm���Q��_=~V5�� �2SU^���%�O��|~ր;�]�f(���
metadata ADDED
@@ -0,0 +1,179 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: groundskeeper-bitcore
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - BIT Core
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain:
11
+ - |
12
+ -----BEGIN CERTIFICATE-----
13
+ MIIDhTCCAm2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQ8wDQYDVQQDDAZlcmlj
14
+ Y2YxHDAaBgoJkiaJk/IsZAEZFgxub3J0aHdlc3Rlcm4xEzARBgoJkiaJk/IsZAEZ
15
+ FgNlZHUwHhcNMTcwOTEyMjAwODQzWhcNMTgwOTEyMjAwODQzWjBEMQ8wDQYDVQQD
16
+ DAZlcmljY2YxHDAaBgoJkiaJk/IsZAEZFgxub3J0aHdlc3Rlcm4xEzARBgoJkiaJ
17
+ k/IsZAEZFgNlZHUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDk8FgP
18
+ SIrleTjIXJT/yu+W9nujkvcIMRPbLqKq60KQy/2LANMZ7DiLZRBkg2oSK0D9p8GR
19
+ be30F2DGAOSBZiBTLPDNAQZBpRVGeFpAAOEpREZ8ahaZVTfc8+IYSfxpnW2gaUte
20
+ SfbG5xNcpHkRpwkbZGoq9yFOoaucxfwoz+9QunEFDiCAumn7uRMKHJdqSEpQnFkQ
21
+ 56GKuUvUuq7J+J4M+kwOK6a/4/Y8Bs/qUYH3GHa/0WJwfFLfp3gqhagLcZu40JFe
22
+ mQpX3bAkmojuxyAi7JjXKqFv1LZgxAGca5SC6sECXiTkw9eXInBKzvBN33gOv+Vj
23
+ 9bot70L0EihaqJrnAgMBAAGjgYEwfzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIEsDAd
24
+ BgNVHQ4EFgQUsMK40utpv6yRQ3i0R7avJn3LQ/YwIgYDVR0RBBswGYEXZXJpY2Nm
25
+ QG5vcnRod2VzdGVybi5lZHUwIgYDVR0SBBswGYEXZXJpY2NmQG5vcnRod2VzdGVy
26
+ bi5lZHUwDQYJKoZIhvcNAQEFBQADggEBACvUVV3V8EYqV9DanJS3ywMVnQB5ByP1
27
+ 7TV70+Amnnu196Jp2JGJ27sjeE79VJeBbGyE0rCRUQXlaD2Zh8X6Yy04oWR0YFa8
28
+ DQ3rqVmKTodTJ0K/rmpIMCbwrsyg7QRxfB6cUE+sgPX5ygDmj2gYY+fcw3MoVOif
29
+ QY1i1gFSjcXvx0qnvQLnbD+gbr7D3wpfgFHRbBEDOuNdpFthggUO6eFraVYcsz9u
30
+ 1v/mC2s7Cj+Jv053bCKPjSk2wLLZpHRs40jXgy/NudtouDy2yYlJHxBFfdeRNEk2
31
+ fo8I5WeWdUoEzUI6WlkTjMw3nWezlF0LCGz781P4qvtz0BICgaS41qw=
32
+ -----END CERTIFICATE-----
33
+ date: 2017-09-15 00:00:00.000000000 Z
34
+ dependencies:
35
+ - !ruby/object:Gem::Dependency
36
+ name: jira-ruby
37
+ requirement: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '1.3'
42
+ type: :runtime
43
+ prerelease: false
44
+ version_requirements: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: '1.3'
49
+ - !ruby/object:Gem::Dependency
50
+ name: thor
51
+ requirement: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '0.19'
56
+ type: :runtime
57
+ prerelease: false
58
+ version_requirements: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: '0.19'
63
+ - !ruby/object:Gem::Dependency
64
+ name: bundler
65
+ requirement: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '1.15'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - "~>"
75
+ - !ruby/object:Gem::Version
76
+ version: '1.15'
77
+ - !ruby/object:Gem::Dependency
78
+ name: minitest
79
+ requirement: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - "~>"
82
+ - !ruby/object:Gem::Version
83
+ version: '5.0'
84
+ type: :development
85
+ prerelease: false
86
+ version_requirements: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - "~>"
89
+ - !ruby/object:Gem::Version
90
+ version: '5.0'
91
+ - !ruby/object:Gem::Dependency
92
+ name: rubocop
93
+ requirement: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - "~>"
96
+ - !ruby/object:Gem::Version
97
+ version: 0.49.1
98
+ type: :development
99
+ prerelease: false
100
+ version_requirements: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - "~>"
103
+ - !ruby/object:Gem::Version
104
+ version: 0.49.1
105
+ - !ruby/object:Gem::Dependency
106
+ name: simplecov
107
+ requirement: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - "~>"
110
+ - !ruby/object:Gem::Version
111
+ version: '0.14'
112
+ type: :development
113
+ prerelease: false
114
+ version_requirements: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - "~>"
117
+ - !ruby/object:Gem::Version
118
+ version: '0.14'
119
+ description:
120
+ email:
121
+ - ericcf@northwestern.edu
122
+ executables:
123
+ - ground
124
+ extensions: []
125
+ extra_rdoc_files: []
126
+ files:
127
+ - ".gitignore"
128
+ - ".rubocop.yml"
129
+ - ".ruby-version"
130
+ - ".travis.yml"
131
+ - CHANGELOG.md
132
+ - CODE_OF_CONDUCT.md
133
+ - Gemfile
134
+ - LICENSE.txt
135
+ - README.md
136
+ - Rakefile
137
+ - bin/console
138
+ - bin/ground
139
+ - bin/setup
140
+ - certs/ericcf.pem
141
+ - groundskeeper.gemspec
142
+ - lib/groundskeeper.rb
143
+ - lib/groundskeeper/application.rb
144
+ - lib/groundskeeper/changelog.rb
145
+ - lib/groundskeeper/commands.rb
146
+ - lib/groundskeeper/document.rb
147
+ - lib/groundskeeper/git.rb
148
+ - lib/groundskeeper/git_hub.rb
149
+ - lib/groundskeeper/jira.rb
150
+ - lib/groundskeeper/project.rb
151
+ - lib/groundskeeper/rails_version.rb
152
+ - lib/groundskeeper/repository.rb
153
+ - lib/groundskeeper/version.rb
154
+ homepage: https://github.com/NU-CBITS/groundskeeper.git
155
+ licenses:
156
+ - MIT
157
+ metadata:
158
+ allowed_push_host: https://rubygems.org
159
+ post_install_message:
160
+ rdoc_options: []
161
+ require_paths:
162
+ - lib
163
+ required_ruby_version: !ruby/object:Gem::Requirement
164
+ requirements:
165
+ - - ">="
166
+ - !ruby/object:Gem::Version
167
+ version: '0'
168
+ required_rubygems_version: !ruby/object:Gem::Requirement
169
+ requirements:
170
+ - - ">="
171
+ - !ruby/object:Gem::Version
172
+ version: '0'
173
+ requirements: []
174
+ rubyforge_project:
175
+ rubygems_version: 2.6.8
176
+ signing_key:
177
+ specification_version: 4
178
+ summary: A gem for managing releases and deployments.
179
+ test_files: []
metadata.gz.sig ADDED
@@ -0,0 +1,3 @@
1
+ z#Vg!Kj�*�-�@�/.�u���M]�3�Coe�*�n�WZq^�RY!,���Ӫ.���3�,��)�k�0:��%(B�����H?�@ $�'�K�Mra�*�`DO��)
2
+ �M/��Y,�����~kh�������Q��GD"�����Qၔn�l�������tlq���D,�P�TSH�'_� �MrO�r� 9�I$Ra)_]���MC-��F1�6j����36G�̶ѥU�r—��� �F�
3
+ %