groundskeeper-bitcore 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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
+ %