huborg 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +24 -0
- data/README.md +78 -19
- data/Rakefile +46 -0
- data/huborg.gemspec +3 -0
- data/lib/huborg.rb +244 -20
- data/lib/huborg/version.rb +3 -1
- metadata +45 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bca5b4b64bf1da62ccbb67ce27f6cf459ca1ec65c3989ed1d8fb095cdf8bb956
|
4
|
+
data.tar.gz: 2c44b381a4cdd5cabcae0afa7f35e83dbbd643b5d5f6df2025fcdc5687033736
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e6c8b6fe6e75a86ee922a0e52dc2515aae8a47f01394b04c2c8c17ddf785c04d9f7bf547bf227d8736ae638e2ca3b25d8b53ac9b856a3123e34ce1c6c068508b
|
7
|
+
data.tar.gz: 67bdc6e7138eb137393d34c2ffd9275fe6db99979c93bac6bfb17feb0e47c15f6f1b570f36db7e605bd0e9b40bb6b8482720bde62c5551e41a09ca87626d820b
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
## [v0.2.0](https://github.com/samvera-labs/huborg/tree/v0.2.0) (2020-02-28)
|
4
|
+
|
5
|
+
[Full Changelog](https://github.com/samvera-labs/huborg/compare/v0.1.0...v0.2.0)
|
6
|
+
|
7
|
+
**Implemented enhancements:**
|
8
|
+
|
9
|
+
- Adding release process [\#4](https://github.com/samvera-labs/huborg/pull/4) ([jeremyf](https://github.com/jeremyf))
|
10
|
+
|
11
|
+
**Merged pull requests:**
|
12
|
+
|
13
|
+
- Tweaking documentation [\#5](https://github.com/samvera-labs/huborg/pull/5) ([jeremyf](https://github.com/jeremyf))
|
14
|
+
- Adding Huborg::Client\#synchronize\_mailmap! [\#3](https://github.com/samvera-labs/huborg/pull/3) ([jeremyf](https://github.com/jeremyf))
|
15
|
+
- Adding Huborg::Client\#audit\_license [\#2](https://github.com/samvera-labs/huborg/pull/2) ([jeremyf](https://github.com/jeremyf))
|
16
|
+
- Adding Huborg::Client\#clone\_and\_rebase! [\#1](https://github.com/samvera-labs/huborg/pull/1) ([jeremyf](https://github.com/jeremyf))
|
17
|
+
|
18
|
+
## [v0.1.0](https://github.com/samvera-labs/huborg/tree/v0.1.0) (2020-02-26)
|
19
|
+
|
20
|
+
[Full Changelog](https://github.com/samvera-labs/huborg/commit/cc1ce07147ad552cabf343c8195610bbb8c9376d)
|
21
|
+
|
22
|
+
- Adding Huborg::Client\#push\_template! ([jeremyf](https://github.com/jeremyf))
|
23
|
+
|
24
|
+
\* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)*
|
data/README.md
CHANGED
@@ -45,6 +45,12 @@ client = Huborg::Client.new(org_names: ["samvera", "samvera-labs"])
|
|
45
45
|
client.push_template!(
|
46
46
|
template: "/path/to/file/on/your/system",
|
47
47
|
filename: "relative/path/in/repository"
|
48
|
+
|
49
|
+
# This will clone all repositories from samvera and samvera-labs.
|
50
|
+
# You can expect to see something in `~/git/samvera/hyrax` and
|
51
|
+
# `~/git/samvera-labs/huborg`
|
52
|
+
client.clone_and_rebase!(
|
53
|
+
directory: File.join(ENV["HOME"], "git")
|
48
54
|
)
|
49
55
|
```
|
50
56
|
|
@@ -53,27 +59,47 @@ The above will create a pull request against all repositories in
|
|
53
59
|
named `repository` (in the directory `relative/path/in`). The file's
|
54
60
|
content will be from the file `/path/to/file/on/your/system`.
|
55
61
|
|
56
|
-
|
62
|
+
```ruby
|
63
|
+
require 'huborg'
|
57
64
|
|
58
|
-
|
65
|
+
# NOTE: You will need to include GITHUB_ACCESS_TOKEN in your ENV
|
66
|
+
client = Huborg::Client.new(org_names: ["samvera", "samvera-labs"])
|
67
|
+
client.clone_and_rebase!(
|
68
|
+
directory: File.join(ENV["HOME"], "git")
|
69
|
+
)
|
70
|
+
```
|
71
|
+
|
72
|
+
The above will clone and rebase all repositories from samvera and
|
73
|
+
samvera-labs. The script will skip existing repositories. You can
|
74
|
+
expect to see [Hyrax](https://github.com/samvera/hyrax) cloned into
|
75
|
+
`~/git/samvera/hyrax` and [Huborg](https://github.com/samvera-labs/huborg)
|
76
|
+
cloned into `~/git/samvera-labs/huborg`
|
59
77
|
|
60
78
|
```ruby
|
61
79
|
require 'huborg'
|
62
|
-
|
80
|
+
# NOTE: You will need to include GITHUB_ACCESS_TOKEN in your ENV
|
81
|
+
client = Huborg::Client.new(org_names: ["samvera"])
|
82
|
+
client.audit_license
|
83
|
+
```
|
63
84
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
client.
|
71
|
-
|
72
|
-
filename: "relative/path/in/repository",
|
73
|
-
overwrite: true
|
74
|
-
)
|
85
|
+
The above script leverages Github's API to check each repository's
|
86
|
+
license. Log as an error each repository that does not have a license.
|
87
|
+
|
88
|
+
```ruby
|
89
|
+
require 'huborg'
|
90
|
+
# NOTE: You will need to include GITHUB_ACCESS_TOKEN in your ENV
|
91
|
+
client = Huborg::Client.new(org_names: ["samvera"])
|
92
|
+
client.synchronize_mailmap!(template: '/path/to/my/MAILMAP_TEMPLATE')
|
75
93
|
```
|
76
94
|
|
95
|
+
The above will take the given template (which confirms to [Git's .mailmap
|
96
|
+
file format](https://www.git-scm.com/docs/git-check-mailmap), then
|
97
|
+
iterates on all of the repositories, adding any non-duplicates, then
|
98
|
+
writing back to the template before creating pull requests against
|
99
|
+
each of the organization's non-archived repositories.
|
100
|
+
|
101
|
+
**All of the commands have several parameters, many set to default values.**
|
102
|
+
|
77
103
|
## Prerequisites
|
78
104
|
|
79
105
|
You'll want to have created a [Github OAuth Access Token](https://github.com/octokit/octokit.rb#oauth-access-tokens).
|
@@ -96,11 +122,44 @@ $ export GITHUB_ORG_NAME=their-organization
|
|
96
122
|
$ bundle exec rake test:push_template
|
97
123
|
```
|
98
124
|
|
99
|
-
##
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
125
|
+
## Documentation
|
126
|
+
|
127
|
+
The product owner encourages you to clone this repository and generate the
|
128
|
+
documentation.
|
129
|
+
|
130
|
+
- [ ] `git clone https://github.com/samvera-labs/huborg`
|
131
|
+
- [ ] `cd huborg`
|
132
|
+
- [ ] `git checkout master && git pull --rebase`
|
133
|
+
- [ ] `gem install yard`
|
134
|
+
- [ ] `yard`
|
135
|
+
|
136
|
+
The above process will generate documentation in `./doc`. Open `./doc/index.html`
|
137
|
+
in your browser. (On OSX, try `open ./doc/index.html`).
|
138
|
+
|
139
|
+
## Releasing Huborg
|
140
|
+
|
141
|
+
Huborg uses [Semantic Versioning](https://semver.org/).
|
142
|
+
|
143
|
+
Below is the checklist:
|
144
|
+
|
145
|
+
- [ ] An internet connection
|
146
|
+
- [ ] A [Github Access Token](https://developer.github.com/apps/building-oauth-apps/authorizing-oauth-apps/)
|
147
|
+
- [ ] Your access token exported to `ENV["CHANGELOG_GITHUB_TOKEN"]`
|
148
|
+
- [ ] Verify you are a [huborg gem owner](https://rubygems.org/gems/huborg). If not, Samvera uses
|
149
|
+
[`grant_revoke_gem_authority`](https://github.com/samvera/maintenance/blob/master/script/grant_revoke_gem_authority.rb)
|
150
|
+
to manage the gem owners.
|
151
|
+
- [ ] Verify that you can push changes to https://github.com/samvera-labs/huborg
|
152
|
+
- [ ] Check that you have a clean git index
|
153
|
+
- [ ] Pull down the latest version of master
|
154
|
+
- [ ] Update the Huborg::VERSION (in ./lib/huborg/version.rb); Remember, huborg
|
155
|
+
uses [Semantic Versioning](https://semver.org). (_**NOTE:** Do not commit the version change_)
|
156
|
+
- [ ] Run `bundle exec rake changelog` to generate [CHANGELOG.md](./CHANGELOG.md)
|
157
|
+
- [ ] Review the new Huborg::VERSION CHANGELOG.md entries as they might prompt
|
158
|
+
you to consider a different version (e.g. what you thought was a bug fix
|
159
|
+
release is in fact a minor version release). Look at the changelog from
|
160
|
+
the perspective of a person curious about using this gem.
|
161
|
+
- [ ] Commit your changes with a simple message: "Bumping to v#{Huborg::VERSION}"
|
162
|
+
- [ ] Run `bundle exec rake release`
|
104
163
|
|
105
164
|
# Acknowledgments
|
106
165
|
|
data/Rakefile
CHANGED
@@ -13,4 +13,50 @@ namespace :test do
|
|
13
13
|
filename: "disposable-#{Time.now.utc.to_s.gsub(/\D+/,'')}.rake"
|
14
14
|
)
|
15
15
|
end
|
16
|
+
|
17
|
+
task :clone_and_rebase do
|
18
|
+
require 'huborg'
|
19
|
+
client = Huborg::Client.new(
|
20
|
+
github_access_token: ENV.fetch("GITHUB_ACCESS_TOKEN"),
|
21
|
+
org_names: ENV.fetch("GITHUB_ORG_NAME")
|
22
|
+
)
|
23
|
+
directory = ENV.fetch("DIRECTORY") { File.join(ENV.fetch("HOME"), "git") }
|
24
|
+
client.clone_and_rebase!(directory: directory)
|
25
|
+
end
|
26
|
+
|
27
|
+
task :audit_license do
|
28
|
+
require 'huborg'
|
29
|
+
client = Huborg::Client.new(
|
30
|
+
github_access_token: ENV.fetch("GITHUB_ACCESS_TOKEN"),
|
31
|
+
org_names: ENV.fetch("GITHUB_ORG_NAME")
|
32
|
+
)
|
33
|
+
client.audit_license
|
34
|
+
end
|
35
|
+
|
36
|
+
task :mailmap do
|
37
|
+
require 'huborg'
|
38
|
+
client = Huborg::Client.new(
|
39
|
+
github_access_token: ENV.fetch("GITHUB_ACCESS_TOKEN"),
|
40
|
+
org_names: ENV.fetch("GITHUB_ORG_NAME")
|
41
|
+
)
|
42
|
+
client.synchronize_mailmap!(template: ENV.fetch("MAILMAP_TEMPLATE_FILENAME"))
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
require 'github_changelog_generator/task'
|
48
|
+
desc "Generate CHANGELOG.md based on lib/huborg/version.md (change that to the new version before you run rake changelog)"
|
49
|
+
GitHubChangelogGenerator::RakeTask.new :changelog do |config|
|
50
|
+
begin
|
51
|
+
ENV.fetch("CHANGELOG_GITHUB_TOKEN")
|
52
|
+
rescue KeyError
|
53
|
+
$stderr.puts %(To run `rake changelog` you need to have a CHANGELOG_GITHUB_TOKEN)
|
54
|
+
$stderr.puts %(set in ENV. (`export CHANGELOG_GITHUB_TOKEN="«your-40-digit-github-token»"`))
|
55
|
+
exit!(1)
|
56
|
+
end
|
57
|
+
config.user = 'samvera-labs'
|
58
|
+
config.project = 'huborg'
|
59
|
+
config.since_tag = 'v0.1.0' # The changes before v0.1.0 were not as helpful
|
60
|
+
config.future_release = %(v#{ENV.fetch("FUTURE_RELEASE", Huborg::VERSION)})
|
61
|
+
config.base = 'CHANGELOG.md'
|
16
62
|
end
|
data/huborg.gemspec
CHANGED
@@ -24,4 +24,7 @@ Gem::Specification.new do |spec|
|
|
24
24
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
25
25
|
spec.require_paths = ["lib"]
|
26
26
|
spec.add_dependency "octokit", "~> 4.16"
|
27
|
+
spec.add_dependency "git", "~> 1.6"
|
28
|
+
spec.add_development_dependency "byebug"
|
29
|
+
spec.add_development_dependency "github_changelog_generator"
|
27
30
|
end
|
data/lib/huborg.rb
CHANGED
@@ -1,34 +1,66 @@
|
|
1
1
|
require "huborg/version"
|
2
2
|
require 'octokit'
|
3
|
+
require 'git'
|
4
|
+
require 'fileutils'
|
5
|
+
require 'set'
|
3
6
|
|
7
|
+
# A module for interacting with Github organizations
|
4
8
|
module Huborg
|
9
|
+
# If there's a problem with Huborg, expect to see this error OR an
|
10
|
+
# error from an underlying library.
|
5
11
|
class Error < RuntimeError; end
|
6
12
|
|
7
|
-
# The class that interacts with organizational repositories
|
13
|
+
# The class that interacts with organizational repositories.
|
14
|
+
#
|
15
|
+
# * {#push_template!} - push a file to all repositories
|
16
|
+
# * {#clone_and_rebase!} - download all repositories for the org
|
17
|
+
# * {#audit_license} - tooling to check the licenses of your org
|
18
|
+
# * {#synchronize_mailmap!} - ensure all git .mailmap files are
|
19
|
+
# synchronized
|
8
20
|
class Client
|
9
|
-
|
10
|
-
#
|
21
|
+
# When checking repository names, this pattern will match all repositories.
|
22
|
+
# @see #initialize `#initialize` for details on the repository pattern.
|
11
23
|
DEFAULT_REPOSITORY_PATTERN = %r{\A.*\Z}
|
12
24
|
|
25
|
+
# @since v0.1.0
|
26
|
+
#
|
13
27
|
# @param logger [Logger] used in logging output of processes
|
14
28
|
# @param github_access_token [String] used to connect to the Oktokit::Client.
|
15
29
|
# The given token will need to have permission to interact with
|
16
30
|
# repositories. Defaults to ENV["GITHUB_ACCESS_TOKEN"]
|
17
|
-
# @param org_names [Array<String
|
31
|
+
# @param org_names [Array<String>, String] used as the default list of Github organizations
|
18
32
|
# in which we'll interact.
|
19
33
|
# @param repository_pattern [Regexp] limit the list of repositories to the given pattern; defaults to ALL
|
20
34
|
#
|
21
|
-
# @
|
35
|
+
# @example
|
36
|
+
# # Without configuration options. You'll want ENV["GITHUB_ACCESS_TOKEN"]
|
37
|
+
# # to be assigned.
|
38
|
+
# client = Huborg::Client.new(org_names: ["samvera", "samvera-labs"])
|
39
|
+
#
|
40
|
+
# # With explicit configuration options. Note, we'll be interacting only
|
41
|
+
# # with repositories that contain the case-insensitive word "hyrax" (case-
|
42
|
+
# # insensitivity is declared as the `i` at the end of the regular
|
43
|
+
# # expression).
|
44
|
+
# client = Huborg::Client.new(
|
45
|
+
# logger: Logger.new(STDOUT),
|
46
|
+
# github_access_token: "40-random-characters-for-your-token",
|
47
|
+
# org_names: ["samvera", "samvera-labs"],
|
48
|
+
# repository_patter: %r{hyrax}i
|
49
|
+
# )
|
50
|
+
#
|
51
|
+
# @see https://github.com/octokit/octokit.rb#oauth-access-tokens Octokit's documentation for OAuth Tokens
|
52
|
+
# @see https://developer.github.com/v3/repos/#list-organization-repositories Github's documentation for repository data structures
|
22
53
|
def initialize(logger: default_logger, github_access_token: default_access_token, org_names:, repository_pattern: DEFAULT_REPOSITORY_PATTERN)
|
23
54
|
@logger = logger
|
24
55
|
@client = Octokit::Client.new(access_token: github_access_token)
|
25
56
|
@org_names = Array(org_names)
|
26
57
|
@repository_pattern = repository_pattern
|
27
58
|
end
|
28
|
-
attr_reader :client, :logger, :org_names, :repository_pattern
|
29
59
|
|
30
60
|
private
|
31
61
|
|
62
|
+
attr_reader :client, :logger, :org_names, :repository_pattern
|
63
|
+
|
32
64
|
def default_logger
|
33
65
|
require 'logger'
|
34
66
|
Logger.new(STDOUT)
|
@@ -37,13 +69,15 @@ module Huborg
|
|
37
69
|
def default_access_token
|
38
70
|
ENV.fetch('GITHUB_ACCESS_TOKEN')
|
39
71
|
rescue KeyError => e
|
40
|
-
|
41
|
-
|
72
|
+
message = "You need to provide an OAuth Access Token.\nSee: https://github.com/octokit/octokit.rb#oauth-access-tokens"
|
73
|
+
$stderr.puts message
|
74
|
+
raise Error.new(message)
|
42
75
|
end
|
43
76
|
|
44
77
|
public
|
45
78
|
|
46
79
|
# @api public
|
80
|
+
# @since v0.1.0
|
47
81
|
#
|
48
82
|
# Responsible for pushing the given template file to all of the
|
49
83
|
# organizations repositories. As we are pushing changes to
|
@@ -61,23 +95,178 @@ module Huborg
|
|
61
95
|
# would not want to do that. In the case of a .mailmap, we
|
62
96
|
# would likely want to overwrite.
|
63
97
|
# @todo Verify that the template exists
|
98
|
+
#
|
99
|
+
# @example
|
100
|
+
# client = Huborg::Client.new(
|
101
|
+
# github_access_token: ENV.fetch("GITHUB_ACCESS_TOKEN"),
|
102
|
+
# org_names: ENV.fetch("GITHUB_ORG_NAME")
|
103
|
+
# )
|
104
|
+
# client.push_template!(
|
105
|
+
# template: "/path/to/file/on/your/system",
|
106
|
+
# filename: "relative/path/in/repository"
|
107
|
+
# )
|
108
|
+
# @return [True] if successfully completed
|
64
109
|
def push_template!(template:, filename:, overwrite: false)
|
65
|
-
|
110
|
+
each_github_repository do |repo|
|
66
111
|
push_template_to!(repo: repo, template: template, filename: filename, overwrite: overwrite)
|
67
112
|
end
|
113
|
+
true
|
114
|
+
end
|
115
|
+
|
116
|
+
# @api public
|
117
|
+
# @since v0.2.0
|
118
|
+
#
|
119
|
+
# Responsible for logging (as an error) repositories that do not
|
120
|
+
# have a license.
|
121
|
+
#
|
122
|
+
# @param skip_private [Boolean] do not check private repositories for a
|
123
|
+
# license
|
124
|
+
# @param skip_archived [Boolean] do not check archived repositories
|
125
|
+
# for license
|
126
|
+
# @param allowed_licenses [Array<String>, :all] the licenses which are
|
127
|
+
# allowed, in all other cases, log as an error. This checks
|
128
|
+
# the :key of a license object in Github's API (see
|
129
|
+
# https://api.github.com/licenses)
|
130
|
+
#
|
131
|
+
# @see https://api.github.com/licenses Github's documentation for a list of license keys
|
132
|
+
# @return [True] the task completed without exception (there may be
|
133
|
+
# logged errors)
|
134
|
+
def audit_license(skip_private: true, skip_archived: true, allowed_licenses: :all)
|
135
|
+
license_list = Array(allowed_licenses)
|
136
|
+
each_github_repository do |repo|
|
137
|
+
next if skip_private && repo.private?
|
138
|
+
next if skip_archived && repo.archived?
|
139
|
+
if repo.license
|
140
|
+
logger.info(%(#{repo.fullname} has "#{repo.license.key}"))
|
141
|
+
next if allowed_licenses == :all
|
142
|
+
next if license_list.include?(repo.license.key)
|
143
|
+
logger.error(%(#{repo.full_name} has "#{repo.license.key}" which is not in #{license_list.inspect}))
|
144
|
+
else
|
145
|
+
logger.error("#{repo.full_name} is missing a license")
|
146
|
+
end
|
147
|
+
end
|
148
|
+
true
|
68
149
|
end
|
69
150
|
|
70
|
-
# @api
|
71
|
-
# @
|
151
|
+
# @api public
|
152
|
+
# @since v0.2.0
|
72
153
|
#
|
154
|
+
# Responsible for taking a template that confirms to Git's .mailmap
|
155
|
+
# file format (e.g. https://github.com/samvera/maintenance/blob/master/templates/MAILMAP)
|
156
|
+
# and adding in all .mailmap entries that exist within the
|
157
|
+
# organizations repositories. This merged .mailmap is then pushed
|
158
|
+
# out, via a pull request, to all of the non-archived repositories.
|
159
|
+
#
|
160
|
+
# @param template [String] path to the source template for .mailmap
|
161
|
+
# This does assume that there were prior efforts at
|
162
|
+
# consolidating a .mailmap file. If you don't have this,
|
163
|
+
# pass an empty file.
|
164
|
+
# @param consolidated_template [String] path that we will write our
|
165
|
+
# changes, this file will be pushed to all non-archived
|
166
|
+
# repositories
|
167
|
+
# @return [True] if successfully completed
|
168
|
+
# @see https://www.git-scm.com/docs/git-check-mailmap Git's documentation
|
169
|
+
# for more on git's .mailmap file
|
170
|
+
# @todo Ensure that this doesn't create a pull request if nothing
|
171
|
+
# has changed.
|
172
|
+
def synchronize_mailmap!(template:, consolidated_template: template)
|
173
|
+
mailmap_lines = Set.new
|
174
|
+
File.read(template).split("\n").each do |line|
|
175
|
+
mailmap_lines << line unless line.empty?
|
176
|
+
end
|
177
|
+
|
178
|
+
each_github_repository do |repo|
|
179
|
+
begin
|
180
|
+
mailmap = client.contents(repo.full_name, path: '.mailmap')
|
181
|
+
lines = mailmap.rels[:download].get.data
|
182
|
+
lines.split("\n").each do |line|
|
183
|
+
mailmap_lines << line
|
184
|
+
end
|
185
|
+
rescue Octokit::NotFound
|
186
|
+
next
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
# Write the contents to a file
|
191
|
+
File.open(consolidated_template, "w+") do |file|
|
192
|
+
mailmap_lines.to_a.sort.each do |line|
|
193
|
+
file.puts line
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
each_github_repository do |repo|
|
198
|
+
next if repo.archived?
|
199
|
+
push_template_to!(filename: ".mailmap", template: consolidated_template, repo: repo, overwrite: true)
|
200
|
+
end
|
201
|
+
return true
|
202
|
+
end
|
203
|
+
|
204
|
+
# @api public
|
205
|
+
# @since v0.2.0
|
206
|
+
#
|
207
|
+
# Clone all repositories (that match the {#repository_pattern} for
|
208
|
+
# the given organization(s). Then and rebase any existing repositories.
|
209
|
+
#
|
210
|
+
# @param directory [String] the directory in which to clone the repositories
|
211
|
+
# (as a sub-directory)
|
212
|
+
# @param skip_dirty [Boolean] if the repository already exists there, don't
|
213
|
+
# clone or pull down changes
|
214
|
+
# @param force [Boolean] if we want to obliterate any changes in an existing
|
215
|
+
# repository
|
216
|
+
# @param shallow [Boolean] when true, instead of cloning into a
|
217
|
+
# subdirectory of `org/repo`, clone into `repo`.
|
218
|
+
# @param skip_forked [Boolean] when true, don't clone a repository that is
|
219
|
+
# a fork of some other repository.
|
220
|
+
# @param skip_archived [Boolean] when true, don't clone a repository that is
|
221
|
+
# archived on Github.
|
222
|
+
# @note The Product Owner decided to set `shallow: false` as the default, as
|
223
|
+
# other local scripts run by them made use of those directory
|
224
|
+
# structures.
|
225
|
+
#
|
226
|
+
# @example
|
227
|
+
# client = Huborg::Client.new(
|
228
|
+
# github_access_token: ENV.fetch("GITHUB_ACCESS_TOKEN"),
|
229
|
+
# org_names: ENV.fetch("GITHUB_ORG_NAME")
|
230
|
+
# )
|
231
|
+
# directory = ENV.fetch("DIRECTORY") { File.join(ENV.fetch("HOME"), "git") }
|
232
|
+
# client.clone_and_rebase!(directory: directory)
|
233
|
+
#
|
234
|
+
# Let's say we have a Github Organization "penguin" which has the
|
235
|
+
# repositories "paradigm" and "raft". In the above example, if we
|
236
|
+
# specified the `DIRECTORY` as "/Iceflow", we would end up with the
|
237
|
+
# following local directory tree within /Iceflow:
|
238
|
+
# .
|
239
|
+
# └── penguin
|
240
|
+
# ├── paradigm
|
241
|
+
# └── raft
|
242
|
+
#
|
243
|
+
# In the case of `shallow: true`, we would have the following tree within
|
244
|
+
# /Iceflow:
|
245
|
+
# .
|
246
|
+
# ├── paradigm
|
247
|
+
# └── raft
|
248
|
+
#
|
249
|
+
# @return [True] if successfully completed
|
250
|
+
def clone_and_rebase!(directory:, skip_forked: false, skip_archived: false, skip_dirty: true, force: false, shallow: false)
|
251
|
+
each_github_repository do |repo|
|
252
|
+
next if skip_archived && repo.archived?
|
253
|
+
next if skip_forked && repo.fork?
|
254
|
+
clone_and_rebase_one!(repo: repo, directory: directory, skip_dirty: skip_dirty, force: force, shallow: shallow)
|
255
|
+
end
|
256
|
+
true
|
257
|
+
end
|
258
|
+
|
259
|
+
private
|
260
|
+
|
73
261
|
# Fetch all of the repositories for the initialized :org_names that
|
74
262
|
# match the initialized :repository_pattern
|
75
263
|
#
|
76
|
-
# @yield
|
77
|
-
#
|
78
|
-
# @
|
264
|
+
# @yield [Oktokit::Repository] each repository will be yielded
|
265
|
+
# @yieldparam [Oktokit::Repository]
|
266
|
+
# @see https://developer.github.com/v3/repos/#list-organization-repositories
|
267
|
+
# for the response document
|
79
268
|
# @return [True]
|
80
|
-
def
|
269
|
+
def each_github_repository(&block)
|
81
270
|
# Collect all repositories
|
82
271
|
repos = []
|
83
272
|
org_names.each do |org_name|
|
@@ -91,11 +280,9 @@ module Huborg
|
|
91
280
|
return true
|
92
281
|
end
|
93
282
|
|
94
|
-
private
|
95
|
-
|
96
283
|
# @note Due to an implementation detail in octokit.rb, refs sometimes
|
97
|
-
#
|
98
|
-
#
|
284
|
+
# need to be "heads/master" and "refs/heads/master" as detailed
|
285
|
+
# below
|
99
286
|
# @param repo [#full_name, #archived] Likely the result of Octokit::Client#org
|
100
287
|
# @param template [String] name of the template to push out to all
|
101
288
|
# repositories
|
@@ -148,13 +335,50 @@ module Huborg
|
|
148
335
|
end
|
149
336
|
end
|
150
337
|
|
338
|
+
def clone_and_rebase_one!(repo:, directory:, skip_dirty: true, force: false, shallow: false)
|
339
|
+
repo_path = shallow ? File.join(directory, repo.name) : File.join(directory, repo.full_name)
|
340
|
+
if File.directory?(repo_path)
|
341
|
+
# We already have a directory (hopefully its a git repository)
|
342
|
+
git = Git.open(repo_path)
|
343
|
+
if force
|
344
|
+
logger.info("Forcing and reseting to a clean #{repo_path}")
|
345
|
+
# force clean and remove whole directories that are untracked
|
346
|
+
git.clean(force: true, d: true)
|
347
|
+
# reset any changed files to original state
|
348
|
+
git.reset(hard: true)
|
349
|
+
elsif git.status.changed.any? || git.status.added.any? || git.status.deleted.any?
|
350
|
+
# The repository is dirty but should we skip dirty
|
351
|
+
if skip_dirty
|
352
|
+
logger.info("Skipping #{repo.full_name} as it has a dirty git index")
|
353
|
+
return
|
354
|
+
else
|
355
|
+
logger.info("Staching changes on #{repo_path}")
|
356
|
+
# We'll offer a kindness and stash everything
|
357
|
+
git.add('.', all: true)
|
358
|
+
git.branch.stashes.save("Stashing via #{self.class}#clone_and_rebase!")
|
359
|
+
end
|
360
|
+
end
|
361
|
+
git.branch("master").checkout
|
362
|
+
logger.info("Pulling down master branch from origin for #{repo_path}")
|
363
|
+
git.pull("origin", "master")
|
364
|
+
else
|
365
|
+
parent_directory = File.dirname(repo_path)
|
366
|
+
logger.info("Creating #{parent_directory}")
|
367
|
+
FileUtils.mkdir_p(parent_directory)
|
368
|
+
# We don't have a repository in the given path, so make one
|
369
|
+
logger.info("Cloning #{repo.name} into #{parent_directory}")
|
370
|
+
Git.clone(repo.clone_url, repo.name, path: parent_directory)
|
371
|
+
logger.info("Finished cloning #{repo.name} into #{parent_directory}")
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
151
375
|
# Responsible for fetching an array of the given :rel
|
152
376
|
#
|
153
377
|
# @param rel [Symbol] The name of the related object(s) for the
|
154
378
|
# given org
|
155
379
|
# @param org [Object] An Organization object (provided by Oktokit
|
156
380
|
# object) from which this method fetchs the related :rel
|
157
|
-
|
381
|
+
#
|
158
382
|
# @return [Array<Object>]
|
159
383
|
def fetch_rel_for(rel:, org:)
|
160
384
|
# Build a list of repositories, note per Github's API, these are
|
data/lib/huborg/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: huborg
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeremy Friesen
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-02-
|
11
|
+
date: 2020-02-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: octokit
|
@@ -24,6 +24,48 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '4.16'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: git
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.6'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.6'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: byebug
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: github_changelog_generator
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
27
69
|
description: Make changes to Organization Repositories en-masse.
|
28
70
|
email:
|
29
71
|
- jeremy.n.friesen@gmail.com
|
@@ -32,6 +74,7 @@ extensions: []
|
|
32
74
|
extra_rdoc_files: []
|
33
75
|
files:
|
34
76
|
- ".gitignore"
|
77
|
+
- CHANGELOG.md
|
35
78
|
- CODE_OF_CONDUCT.md
|
36
79
|
- CONTRIBUTING.md
|
37
80
|
- Gemfile
|