octofart 0.1.0
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 +7 -0
- data/.gitignore +8 -0
- data/.rspec +1 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +62 -0
- data/LICENSE.txt +21 -0
- data/README.md +97 -0
- data/Rakefile +2 -0
- data/bin/console +7 -0
- data/bin/setup +8 -0
- data/lib/octofart.rb +39 -0
- data/lib/octofart/client.rb +56 -0
- data/lib/octofart/config.rb +19 -0
- data/lib/octofart/singleton_class.rb +17 -0
- data/lib/octofart/task_runner.rb +14 -0
- data/lib/octofart/tasks/branch_mapping.rb +26 -0
- data/lib/octofart/tasks/commits.rb +48 -0
- data/lib/octofart/tasks/create_branch.rb +28 -0
- data/lib/octofart/tasks/data_mapping.rb +64 -0
- data/lib/octofart/tasks/pull_request.rb +25 -0
- data/lib/octofart/tasks/update_file.rb +20 -0
- data/lib/octofart/version.rb +3 -0
- data/lib/octofart/workflow.rb +58 -0
- data/octofart.gemspec +25 -0
- data/spec/fixtures/blob.json +1 -0
- data/spec/fixtures/branch.json +6 -0
- data/spec/fixtures/commit.json +9 -0
- data/spec/fixtures/content.json +3 -0
- data/spec/fixtures/filename.json +18 -0
- data/spec/fixtures/pull_request.json +1 -0
- data/spec/fixtures/ref.json +7 -0
- data/spec/fixtures/repo.json +3 -0
- data/spec/fixtures/search.json +18 -0
- data/spec/fixtures/tree.json +3 -0
- data/spec/octofart/client_spec.rb +32 -0
- data/spec/octofart_spec.rb +126 -0
- data/spec/spec_helper.rb +17 -0
- data/spec/support/fixture.rb +3 -0
- metadata +199 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 5bdf2f2e8a547d90e2c509be4452a5c5be758364bed6b619d92a670f175cd220
|
4
|
+
data.tar.gz: 939485afcd11d61fc8397f3e099ce22278c6e828d9f796c27c7488678e69184b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 61168d12b0a187096ce2d30917f667a5a868c8140b1fcbac9f3e08a768fc0970b19869a8ee880252aa514caa4e140090eefb90a035075df819e9e31128037b8b
|
7
|
+
data.tar.gz: 7f4e7fe1cd8697d380e6ff017399bd5913837830252b5418d2b07884912d25c7c3180d1c5a4bdcf6795a3053a5ca318dc10a22aef0ecfb2c800259f0e1a7164e
|
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--require spec_helper
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
octofart (0.1.0)
|
5
|
+
octokit (~> 4.8, >= 4.8.0)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
addressable (2.5.2)
|
11
|
+
public_suffix (>= 2.0.2, < 4.0)
|
12
|
+
coderay (1.1.2)
|
13
|
+
crack (0.4.3)
|
14
|
+
safe_yaml (~> 1.0.0)
|
15
|
+
diff-lcs (1.3)
|
16
|
+
faraday (0.14.0)
|
17
|
+
multipart-post (>= 1.2, < 3)
|
18
|
+
hashdiff (0.3.7)
|
19
|
+
method_source (0.9.0)
|
20
|
+
multipart-post (2.0.0)
|
21
|
+
octokit (4.8.0)
|
22
|
+
sawyer (~> 0.8.0, >= 0.5.3)
|
23
|
+
pry (0.11.3)
|
24
|
+
coderay (~> 1.1.0)
|
25
|
+
method_source (~> 0.9.0)
|
26
|
+
public_suffix (3.0.2)
|
27
|
+
rake (10.5.0)
|
28
|
+
rspec (3.7.0)
|
29
|
+
rspec-core (~> 3.7.0)
|
30
|
+
rspec-expectations (~> 3.7.0)
|
31
|
+
rspec-mocks (~> 3.7.0)
|
32
|
+
rspec-core (3.7.1)
|
33
|
+
rspec-support (~> 3.7.0)
|
34
|
+
rspec-expectations (3.7.0)
|
35
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
36
|
+
rspec-support (~> 3.7.0)
|
37
|
+
rspec-mocks (3.7.0)
|
38
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
39
|
+
rspec-support (~> 3.7.0)
|
40
|
+
rspec-support (3.7.1)
|
41
|
+
safe_yaml (1.0.4)
|
42
|
+
sawyer (0.8.1)
|
43
|
+
addressable (>= 2.3.5, < 2.6)
|
44
|
+
faraday (~> 0.8, < 1.0)
|
45
|
+
webmock (3.3.0)
|
46
|
+
addressable (>= 2.3.6)
|
47
|
+
crack (>= 0.3.2)
|
48
|
+
hashdiff
|
49
|
+
|
50
|
+
PLATFORMS
|
51
|
+
ruby
|
52
|
+
|
53
|
+
DEPENDENCIES
|
54
|
+
bundler (~> 1.16)
|
55
|
+
octofart!
|
56
|
+
pry (~> 0.11, >= 0.11.3)
|
57
|
+
rake (~> 10.0)
|
58
|
+
rspec (~> 3.2)
|
59
|
+
webmock (~> 3.3, >= 3.3.0)
|
60
|
+
|
61
|
+
BUNDLED WITH
|
62
|
+
1.16.1
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2018 Robbie Marcelo
|
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,97 @@
|
|
1
|
+
# Octofart :dash:
|
2
|
+
|
3
|
+
As we continuously create new repositories in our organization, there can be
|
4
|
+
a time when you need to update a single line of code across multiple
|
5
|
+
repositories, hence, this gem aims to solve that problem.
|
6
|
+
|
7
|
+
Octofart (Octokit - Find And Replace Text) provides a DSL that executes a bulk update of code from all repositories within your organization.
|
8
|
+
|
9
|
+
**:warning: WARNING: Use at your own risk! If improperly used, it might send humongous pull requests to different repositories abnormally.**
|
10
|
+
|
11
|
+
## Sample use cases
|
12
|
+
|
13
|
+
- Updating hard-coded ruby versions from multiple repositories (i.e `s/2.4.2/2.5.0`)
|
14
|
+
- Updating typo errors
|
15
|
+
- Renaming class names (i.e `s/FactoryGirl/FactoryBot`)
|
16
|
+
|
17
|
+
## Workflow
|
18
|
+
|
19
|
+
- Octofart takes advantage of Github API to perform full text search of the code.
|
20
|
+
- Response will be parsed and files that matches the mapping will be updated.
|
21
|
+
- Octofart will commit the changes, push it on a new branch, and create a pull request.
|
22
|
+
- The merging of PR can be done by a developer to ensure that the changes are correct.
|
23
|
+
|
24
|
+
## Installation
|
25
|
+
|
26
|
+
Add this line to your application's Gemfile:
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
gem 'octofart'
|
30
|
+
```
|
31
|
+
|
32
|
+
And then execute:
|
33
|
+
|
34
|
+
$ bundle
|
35
|
+
|
36
|
+
Or install it yourself as:
|
37
|
+
|
38
|
+
$ gem install octofart
|
39
|
+
|
40
|
+
## Configuration
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
Octofart.configure do |config|
|
44
|
+
config.github_token = ENV['GITHUB_USER_TOKEN']
|
45
|
+
config.max_retries = 3
|
46
|
+
end
|
47
|
+
```
|
48
|
+
|
49
|
+
## DSL
|
50
|
+
|
51
|
+
```ruby
|
52
|
+
Octofart.workflow {
|
53
|
+
organization "quipper"
|
54
|
+
|
55
|
+
task find: "FactoryGirl",
|
56
|
+
replace: "FactoryBot",
|
57
|
+
message: "Updates FactoryGirl class names to FactoryBot"
|
58
|
+
|
59
|
+
# You can add as many commits as you want
|
60
|
+
task find: "git ocmmit",
|
61
|
+
replace: "git commit",
|
62
|
+
message: "Fixes typo errors of `git commit` from bash scripts"
|
63
|
+
|
64
|
+
pull_request title: "Bulk update ",
|
65
|
+
body: "Please Review, Onii-chan!",
|
66
|
+
branch_name: "rbmrclo-#{Time.now.to_i}"
|
67
|
+
}
|
68
|
+
|
69
|
+
```
|
70
|
+
|
71
|
+
|
72
|
+
## Tests
|
73
|
+
|
74
|
+
```
|
75
|
+
$ bundle exec rspec spec
|
76
|
+
```
|
77
|
+
|
78
|
+
## Development
|
79
|
+
|
80
|
+
After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
81
|
+
|
82
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
83
|
+
|
84
|
+
## Roadmap
|
85
|
+
|
86
|
+
- [ ] Address failure scenarios (i.e when no organization supplied)
|
87
|
+
- [ ] Implement asynchronous execution per tasks (to avoid abuse rate limits)
|
88
|
+
- [ ] Testing coverage
|
89
|
+
- [ ] Refactor / Cleanup code
|
90
|
+
|
91
|
+
## Contributing
|
92
|
+
|
93
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/rbmrclo/octofart.
|
94
|
+
|
95
|
+
## License
|
96
|
+
|
97
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/bin/console
ADDED
data/bin/setup
ADDED
data/lib/octofart.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require "octokit"
|
2
|
+
require "octofart/version"
|
3
|
+
require "octofart/config"
|
4
|
+
require "octofart/client"
|
5
|
+
require "octofart/singleton_class"
|
6
|
+
require "octofart/task_runner"
|
7
|
+
|
8
|
+
require "octofart/tasks/create_branch"
|
9
|
+
require "octofart/tasks/commits"
|
10
|
+
require "octofart/tasks/pull_request"
|
11
|
+
require "octofart/tasks/update_file"
|
12
|
+
require "octofart/tasks/data_mapping"
|
13
|
+
require "octofart/tasks/branch_mapping"
|
14
|
+
|
15
|
+
module Octofart
|
16
|
+
extend SingleForwardable
|
17
|
+
extend SingletonClass
|
18
|
+
|
19
|
+
def_delegators :config, :unique_head_branch_name,
|
20
|
+
:github_token,
|
21
|
+
:max_retries
|
22
|
+
|
23
|
+
def self.client
|
24
|
+
@client ||= Client.new(
|
25
|
+
max_retries: max_retries,
|
26
|
+
access_token: github_token,
|
27
|
+
)
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.configure(&blk)
|
31
|
+
yield(config)
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.config
|
35
|
+
@config ||= Config.new
|
36
|
+
end
|
37
|
+
|
38
|
+
private_class_method :config
|
39
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Octofart
|
2
|
+
class Client
|
3
|
+
|
4
|
+
DEFAULT_ARGS = {
|
5
|
+
connection_options: {
|
6
|
+
request: {
|
7
|
+
open_timeout: 2,
|
8
|
+
timeout: 5,
|
9
|
+
}
|
10
|
+
}
|
11
|
+
}.freeze
|
12
|
+
|
13
|
+
RETRYABLE_ERRORS = [
|
14
|
+
Faraday::ConnectionFailed,
|
15
|
+
Faraday::TimeoutError,
|
16
|
+
Octokit::InternalServerError,
|
17
|
+
Octokit::BadGateway
|
18
|
+
].freeze
|
19
|
+
|
20
|
+
def initialize(max_retries: 1, **args)
|
21
|
+
octokit_args = DEFAULT_ARGS.merge(args)
|
22
|
+
|
23
|
+
@max_retries = max_retries || 1
|
24
|
+
@client = Octokit::Client.new(**octokit_args)
|
25
|
+
end
|
26
|
+
|
27
|
+
def method_missing(method_name, *args, &block)
|
28
|
+
retry_connection_failures do
|
29
|
+
if @client.respond_to?(method_name)
|
30
|
+
mutatable_args = args.map(&:dup)
|
31
|
+
@client.public_send(method_name, *mutatable_args, &block)
|
32
|
+
else
|
33
|
+
super
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def respond_to_missing?(method_name, include_private = false)
|
39
|
+
@client.respond_to?(method_name) || super
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def retry_connection_failures
|
45
|
+
retry_attempt = 0
|
46
|
+
|
47
|
+
begin
|
48
|
+
yield
|
49
|
+
rescue *RETRYABLE_ERRORS
|
50
|
+
retry_attempt += 1
|
51
|
+
retry_attempt <= @max_retries ? retry : raise
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
3
|
+
module Octofart
|
4
|
+
class Config < OpenStruct
|
5
|
+
|
6
|
+
def initialize(args = {})
|
7
|
+
super defaults.merge(args)
|
8
|
+
end
|
9
|
+
|
10
|
+
def defaults
|
11
|
+
@defaults ||= {
|
12
|
+
github_token: nil,
|
13
|
+
max_retries: 1,
|
14
|
+
unique_head_branch_name: "find-and-replace-text"
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require_relative 'workflow'
|
2
|
+
|
3
|
+
module Octofart
|
4
|
+
module SingletonClass
|
5
|
+
|
6
|
+
def workflow(&block)
|
7
|
+
raise ArgumentError, 'Must provide a block' unless block_given?
|
8
|
+
|
9
|
+
Class.new(Workflow) {
|
10
|
+
_init
|
11
|
+
class_eval(&block)
|
12
|
+
_run
|
13
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Octofart
|
2
|
+
module Tasks
|
3
|
+
class BranchMapping
|
4
|
+
|
5
|
+
def run(params)
|
6
|
+
puts "Determining base branch of #{params[:repositories].size} repositories..."
|
7
|
+
|
8
|
+
params[:repositories].each_pair do |repo_name, metadata|
|
9
|
+
next if metadata[:base_branch][:name]
|
10
|
+
puts "Getting base branch of #{repo_name}..."
|
11
|
+
|
12
|
+
base_branch_name ||= Octofart.client.repo(repo_name).default_branch
|
13
|
+
base_branch_latest_sha ||= Octofart.client.branch(repo_name, base_branch_name).commit.sha
|
14
|
+
|
15
|
+
metadata[:base_branch][:name] = base_branch_name
|
16
|
+
metadata[:base_branch][:sha] = base_branch_latest_sha
|
17
|
+
|
18
|
+
puts "Detected `#{base_branch_name}` as default branch of #{repo_name} (HEAD at #{base_branch_latest_sha})"
|
19
|
+
end
|
20
|
+
|
21
|
+
params
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Octofart
|
2
|
+
module Tasks
|
3
|
+
class Commits
|
4
|
+
|
5
|
+
def run(params)
|
6
|
+
params[:repositories].each_pair do |repo_name, metadata|
|
7
|
+
metadata[:tasks].each do |task|
|
8
|
+
tree_sha = new_tree_sha(repo_name, task[:path], task[:blob_sha], metadata[:head_branch][:sha])
|
9
|
+
|
10
|
+
commit_args = [
|
11
|
+
repo_name,
|
12
|
+
task[:message],
|
13
|
+
tree_sha,
|
14
|
+
metadata[:head_branch][:sha]
|
15
|
+
]
|
16
|
+
|
17
|
+
commit = Octofart.client.create_commit(*commit_args)
|
18
|
+
metadata[:head_branch][:sha] = commit.sha # update the commit to latest
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
params
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def head_tree_sha(repo_name, commit_sha)
|
28
|
+
Octofart.client.commit(repo_name, commit_sha).commit.tree.sha
|
29
|
+
end
|
30
|
+
|
31
|
+
def new_tree_sha(repo_name, file_path, blob_sha, latest_commit_sha)
|
32
|
+
opts = {
|
33
|
+
path: file_path,
|
34
|
+
mode: "100644",
|
35
|
+
type: "blob",
|
36
|
+
sha: blob_sha,
|
37
|
+
}
|
38
|
+
|
39
|
+
base_tree_opts = {
|
40
|
+
base_tree: head_tree_sha(repo_name, latest_commit_sha)
|
41
|
+
}
|
42
|
+
|
43
|
+
Octofart.client.create_tree(repo_name, [opts], base_tree_opts).sha
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Octofart
|
2
|
+
module Tasks
|
3
|
+
class CreateBranch
|
4
|
+
|
5
|
+
def run(params)
|
6
|
+
params[:repositories].each_pair do |repo_name, metadata|
|
7
|
+
head_branch_name ||= params[:pull_request][:branch_name]
|
8
|
+
head_branch_name ||= Octofart.unique_head_branch_name
|
9
|
+
metadata[:head_branch][:name] ||= "heads/#{head_branch_name}"
|
10
|
+
|
11
|
+
head_branch =
|
12
|
+
begin
|
13
|
+
Octofart.client.ref(repo_name, metadata[:head_branch][:name])
|
14
|
+
rescue
|
15
|
+
puts "Ref not found, so we'll create one."
|
16
|
+
Octofart.client.create_ref(repo_name, metadata[:head_branch][:name], metadata[:base_branch][:sha])
|
17
|
+
end
|
18
|
+
|
19
|
+
metadata[:head_branch][:sha] = head_branch.object.sha
|
20
|
+
metadata[:head_branch][:ref] = head_branch.ref
|
21
|
+
end
|
22
|
+
|
23
|
+
params
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Octofart
|
2
|
+
module Tasks
|
3
|
+
class DataMapping
|
4
|
+
|
5
|
+
def run(params)
|
6
|
+
params[:tasks].each do |task|
|
7
|
+
items = search(text: task[:find], org: params[:organization])
|
8
|
+
items.each do |item|
|
9
|
+
repo_name = item.repository.full_name
|
10
|
+
|
11
|
+
init_repo_data(repo_name, params[:repositories])
|
12
|
+
|
13
|
+
task_attrs = {
|
14
|
+
path: item.path,
|
15
|
+
task_id: task[:id],
|
16
|
+
repo_name: repo_name,
|
17
|
+
}
|
18
|
+
|
19
|
+
task_args = [
|
20
|
+
params[:repositories],
|
21
|
+
params[:tasks],
|
22
|
+
task_attrs
|
23
|
+
]
|
24
|
+
|
25
|
+
register_task(*task_args)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
clear(params)
|
30
|
+
params
|
31
|
+
end
|
32
|
+
|
33
|
+
def init_repo_data(repo_name, repositories)
|
34
|
+
puts "Initializing metadata for #{repo_name}..."
|
35
|
+
|
36
|
+
repositories[repo_name] ||= {}
|
37
|
+
repositories[repo_name][:tasks] ||= []
|
38
|
+
repositories[repo_name][:base_branch] ||= {}
|
39
|
+
repositories[repo_name][:head_branch] ||= {}
|
40
|
+
|
41
|
+
puts repositories[repo_name]
|
42
|
+
end
|
43
|
+
|
44
|
+
def register_task(repositories, tasks, options = {})
|
45
|
+
puts "Registering task for #{options[:repo_name]}..."
|
46
|
+
|
47
|
+
task = tasks.find { |t| t[:id] == options[:task_id] }
|
48
|
+
repositories[options[:repo_name]][:tasks] << task.merge(path: options[:path])
|
49
|
+
|
50
|
+
puts task
|
51
|
+
end
|
52
|
+
|
53
|
+
def search(text:, org:)
|
54
|
+
Octofart.client.search_code(%Q{#{text} in:file org:#{org}})[:items]
|
55
|
+
end
|
56
|
+
|
57
|
+
def clear(params)
|
58
|
+
params.delete(:items)
|
59
|
+
params.delete(:tasks)
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Octofart
|
2
|
+
module Tasks
|
3
|
+
class PullRequest
|
4
|
+
|
5
|
+
def run(params)
|
6
|
+
params[:repositories].each_pair do |repo_name, metadata|
|
7
|
+
Octofart.client.update_ref(repo_name, metadata[:head_branch][:name], metadata[:head_branch][:sha])
|
8
|
+
|
9
|
+
pull_request_opts = [
|
10
|
+
repo_name,
|
11
|
+
metadata[:base_branch][:name],
|
12
|
+
metadata[:head_branch][:ref],
|
13
|
+
params[:pull_request][:title],
|
14
|
+
params[:pull_request][:body]
|
15
|
+
]
|
16
|
+
|
17
|
+
Octofart.client.create_pull_request(*pull_request_opts)
|
18
|
+
end
|
19
|
+
|
20
|
+
params
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Octofart
|
2
|
+
module Tasks
|
3
|
+
class UpdateFile
|
4
|
+
|
5
|
+
def run(params)
|
6
|
+
params[:repositories].each_pair do |repo_name, metadata|
|
7
|
+
metadata[:tasks].each do |task|
|
8
|
+
file_info = Octofart.client.contents(repo_name, { path: task[:path], branch: metadata[:base_branch][:name]})
|
9
|
+
old_content = Base64.decode64(file_info.content)
|
10
|
+
new_content = old_content.gsub(task[:find], task[:replace])
|
11
|
+
|
12
|
+
task[:blob_sha] = Octofart.client.create_blob(repo_name, Base64.encode64(new_content), "base64")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
params
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Octofart
|
2
|
+
class Workflow
|
3
|
+
class << self
|
4
|
+
|
5
|
+
private :new
|
6
|
+
|
7
|
+
private
|
8
|
+
|
9
|
+
def _init
|
10
|
+
@tasks = []
|
11
|
+
@repositories = {}
|
12
|
+
@pull_request = {}
|
13
|
+
@organization = nil
|
14
|
+
|
15
|
+
nil
|
16
|
+
end
|
17
|
+
|
18
|
+
def task_id
|
19
|
+
@tasks.size + 1
|
20
|
+
end
|
21
|
+
|
22
|
+
def task(find:, replace:, message:)
|
23
|
+
@tasks << { id: task_id, find: find, replace: replace, message: message }
|
24
|
+
end
|
25
|
+
|
26
|
+
def organization(org)
|
27
|
+
@organization = org
|
28
|
+
end
|
29
|
+
|
30
|
+
def pull_request(title:, body:, branch_name: nil)
|
31
|
+
@pull_request[:title] = title
|
32
|
+
@pull_request[:body] = body
|
33
|
+
@pull_request[:branch_name] = branch_name if branch_name
|
34
|
+
@pull_request
|
35
|
+
end
|
36
|
+
|
37
|
+
def metadata
|
38
|
+
@metadata ||= {
|
39
|
+
tasks: @tasks,
|
40
|
+
organization: @organization,
|
41
|
+
repositories: @repositories,
|
42
|
+
pull_request: @pull_request
|
43
|
+
}
|
44
|
+
end
|
45
|
+
|
46
|
+
def _run
|
47
|
+
Octofart::TaskRunner.run metadata, [
|
48
|
+
Octofart::Tasks::DataMapping.new,
|
49
|
+
Octofart::Tasks::BranchMapping.new,
|
50
|
+
Octofart::Tasks::CreateBranch.new,
|
51
|
+
Octofart::Tasks::UpdateFile.new,
|
52
|
+
Octofart::Tasks::Commits.new,
|
53
|
+
Octofart::Tasks::PullRequest.new
|
54
|
+
]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/octofart.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
lib = File.expand_path("../lib", __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require "octofart/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "octofart"
|
7
|
+
spec.version = Octofart::VERSION
|
8
|
+
spec.authors = ["Robbie Marcelo"]
|
9
|
+
spec.email = ["rbmrclo@hotmail.com"]
|
10
|
+
spec.summary = %q{Octokit + Find and Replace Text}
|
11
|
+
spec.description = %q{Automate bulk update of code from repositories within your organization, like the wind. :)}
|
12
|
+
spec.homepage = "https://github.com/rbmrclo/octofart"
|
13
|
+
spec.license = "MIT"
|
14
|
+
spec.files = `git ls-files`.split($\)
|
15
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
16
|
+
spec.require_paths = ["lib", "spec"]
|
17
|
+
|
18
|
+
spec.add_runtime_dependency 'octokit', '~> 4.8', '>= 4.8.0'
|
19
|
+
|
20
|
+
spec.add_development_dependency "bundler", "~> 1.16"
|
21
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
22
|
+
spec.add_development_dependency "rspec", "~> 3.2"
|
23
|
+
spec.add_development_dependency 'webmock', "~> 3.3", ">= 3.3.0"
|
24
|
+
spec.add_development_dependency "pry", "~> 0.11", ">= 0.11.3"
|
25
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
{ "sha": "asd1231231312sha1" }
|
@@ -0,0 +1,18 @@
|
|
1
|
+
{
|
2
|
+
"name": "Gemfile",
|
3
|
+
"path": "Gemfile",
|
4
|
+
"sha": "dbce0c9e2e7efd19139c2c0aeb0110e837812c2f",
|
5
|
+
"size": 291,
|
6
|
+
"url": "https://api.github.com/repos/rbmrclo/rbmrclo/contents/Gemfile?ref=master",
|
7
|
+
"html_url": "https://github.com/rbmrclo/rbmrclo/blob/master/Gemfile",
|
8
|
+
"git_url": "https://api.github.com/repos/rbmrclo/rbmrclo/git/blobs/dbce0c9e2e7efd19139c2c0aeb0110e837812c2f",
|
9
|
+
"download_url": "https://raw.githubusercontent.com/rbmrclo/rbmrclo/master/Gemfile?token=asd",
|
10
|
+
"type": "file",
|
11
|
+
"content": "foobar\n",
|
12
|
+
"encoding": "base64",
|
13
|
+
"_links": {
|
14
|
+
"self": "https://api.github.com/repos/rbmrclo/rbmrclo/contents/Gemfile?ref=master",
|
15
|
+
"git": "https://api.github.com/repos/rbmrclo/rbmrclo/git/blobs/dbce0c9e2e7efd19139c2c0aeb0110e837812c2f",
|
16
|
+
"html": "https://github.com/rbmrclo/rbmrclo/blob/master/Gemfile"
|
17
|
+
}
|
18
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
{}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
{
|
2
|
+
"total_count": 7,
|
3
|
+
"incomplete_results": false,
|
4
|
+
"items": [
|
5
|
+
{
|
6
|
+
"name": "classes.js",
|
7
|
+
"path": "src/attributes/classes.js",
|
8
|
+
"sha": "d7212f9dee2dcc18f084d7df8f417b80846ded5a",
|
9
|
+
"url": "https://api.github.com/repositories/167174/contents/src/attributes/classes.js?ref=825ac3773694e0cd23ee74895fd5aeb535b27da4",
|
10
|
+
"git_url": "https://api.github.com/repositories/167174/git/blobs/d7212f9dee2dcc18f084d7df8f417b80846ded5a",
|
11
|
+
"html_url": "https://github.com/jquery/jquery/blob/825ac3773694e0cd23ee74895fd5aeb535b27da4/src/attributes/classes.js",
|
12
|
+
"repository": {
|
13
|
+
"full_name": "jquery/jquery"
|
14
|
+
},
|
15
|
+
"score": 0.5269679
|
16
|
+
}
|
17
|
+
]
|
18
|
+
}
|
@@ -0,0 +1,32 @@
|
|
1
|
+
RSpec.describe Octofart::Client do
|
2
|
+
let(:access_token) { "t0k3n" }
|
3
|
+
let(:client) { Octofart::Client.new(access_token: access_token) }
|
4
|
+
|
5
|
+
describe "retrying a method that mutates args" do
|
6
|
+
subject { client.contents("some/repo", path: "important_path.json") }
|
7
|
+
|
8
|
+
context "when the request has to be retried" do
|
9
|
+
before do
|
10
|
+
repo_url = "https://api.github.com/repos/some/repo"
|
11
|
+
stub_request(:get, "#{repo_url}/contents/important_path.json").
|
12
|
+
with(headers: {
|
13
|
+
'Accept'=>'application/vnd.github.v3+json',
|
14
|
+
'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
|
15
|
+
'Authorization'=>'token t0k3n',
|
16
|
+
'Content-Type'=>'application/json',
|
17
|
+
'User-Agent'=>'Octokit Ruby Gem 4.8.0'
|
18
|
+
}).to_return(
|
19
|
+
{ status: 502, headers: { "content-type" => "application/json" } },
|
20
|
+
{
|
21
|
+
status: 200,
|
22
|
+
body: fixture("filename.json"),
|
23
|
+
headers: { "content-type" => "application/json" }
|
24
|
+
}
|
25
|
+
)
|
26
|
+
end
|
27
|
+
|
28
|
+
it { expect(subject.name).to eq("Gemfile") }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
RSpec.describe Octofart do
|
2
|
+
describe "#configure" do
|
3
|
+
after(:each) do
|
4
|
+
Octofart.instance_variable_set("@config", nil)
|
5
|
+
end
|
6
|
+
|
7
|
+
let!(:token) { "f00bar" }
|
8
|
+
|
9
|
+
it "enables base branch and github token configurable" do
|
10
|
+
Octofart.configure do |config|
|
11
|
+
config.github_token = token
|
12
|
+
config.max_retries = 3
|
13
|
+
end
|
14
|
+
|
15
|
+
expect(Octofart.github_token).to eq(token)
|
16
|
+
expect(Octofart.max_retries).to eq(3)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "#workflow" do
|
21
|
+
context "when no supplied block" do
|
22
|
+
it "raises an error" do
|
23
|
+
expect { Octofart.workflow }.to raise_error(ArgumentError)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context "when a block is supplied" do
|
28
|
+
subject do
|
29
|
+
Octofart.workflow {
|
30
|
+
organization "foo"
|
31
|
+
task find: "this", replace: "that", message: "test"
|
32
|
+
pull_request body: "test body", title: "test title"
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
let!(:request_headers) do
|
37
|
+
{
|
38
|
+
'Accept'=>'application/vnd.github.v3+json',
|
39
|
+
'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
|
40
|
+
'Content-Type'=>'application/json',
|
41
|
+
'User-Agent'=>'Octokit Ruby Gem 4.8.0'
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
let!(:response_headers) do
|
46
|
+
{ "content-type" => "application/json" }
|
47
|
+
end
|
48
|
+
|
49
|
+
before do
|
50
|
+
@search_stub = stub_request(:get, "https://api.github.com/search/code?q=this%20in:file%20org:foo")
|
51
|
+
.with(headers: request_headers)
|
52
|
+
.to_return(status: 200, body: fixture("search.json"), headers: response_headers)
|
53
|
+
|
54
|
+
@repo_stub = stub_request(:get, "https://api.github.com/repos/jquery/jquery")
|
55
|
+
.with(headers: request_headers)
|
56
|
+
.to_return(status: 200, body: fixture("repo.json"), headers: response_headers)
|
57
|
+
|
58
|
+
@branch_stub = stub_request(:get, "https://api.github.com/repos/jquery/jquery/branches/master")
|
59
|
+
.with(headers: request_headers)
|
60
|
+
.to_return(status: 200, body: fixture("branch.json"), headers: response_headers)
|
61
|
+
|
62
|
+
@ref_stub = stub_request(:get, "https://api.github.com/repos/jquery/jquery/git/refs/heads/find-and-replace-text")
|
63
|
+
.with(headers: request_headers)
|
64
|
+
.to_return(status: 200, body: fixture("ref.json"), headers: response_headers)
|
65
|
+
|
66
|
+
@content_stub = stub_request(:get, "https://api.github.com/repos/jquery/jquery/contents/src/attributes/classes.js?branch=master")
|
67
|
+
.with(headers: request_headers)
|
68
|
+
.to_return(status: 200, body: fixture("content.json"), headers: response_headers)
|
69
|
+
|
70
|
+
@blob_stub = stub_request(:post, "https://api.github.com/repos/jquery/jquery/git/blobs")
|
71
|
+
.with(
|
72
|
+
body: "{\"content\":\"Zm9vYmFy\\n\",\"encoding\":\"base64\"}",
|
73
|
+
headers: request_headers
|
74
|
+
).to_return(status: 200, body: fixture("blob.json"), headers: response_headers)
|
75
|
+
|
76
|
+
@get_commit_stub = stub_request(:get, "https://api.github.com/repos/jquery/jquery/commits/asd")
|
77
|
+
.with(headers: request_headers)
|
78
|
+
.to_return(status: 200, body: fixture("commit.json"), headers: response_headers)
|
79
|
+
|
80
|
+
@tree_stub = stub_request(:post, "https://api.github.com/repos/jquery/jquery/git/trees")
|
81
|
+
.with(
|
82
|
+
body: "{\"base_tree\":\"3rg32342sha1\",\"tree\":[{\"path\":\"src/attributes/classes.js\",\"mode\":\"100644\",\"type\":\"blob\",\"sha\":\"asd1231231312sha1\"}]}",
|
83
|
+
headers: request_headers
|
84
|
+
).to_return(status: 200, body: fixture("tree.json"), headers: response_headers)
|
85
|
+
|
86
|
+
@post_commit_stub = stub_request(:post, "https://api.github.com/repos/jquery/jquery/git/commits")
|
87
|
+
.with(
|
88
|
+
body: "{\"message\":\"test\",\"tree\":\"12321afasha1\",\"parents\":[\"asd\"]}",
|
89
|
+
headers: request_headers
|
90
|
+
).to_return(status: 200, body: fixture("commit.json"), headers: response_headers)
|
91
|
+
|
92
|
+
@patch_ref_stub = stub_request(:patch, "https://api.github.com/repos/jquery/jquery/git/refs/heads/find-and-replace-text")
|
93
|
+
.with(
|
94
|
+
body: "{\"sha\":\"12321jsfsdfssha1\",\"force\":true}",
|
95
|
+
headers: request_headers
|
96
|
+
).to_return(status: 200, body: fixture("ref.json"), headers: response_headers)
|
97
|
+
|
98
|
+
@pull_request_stub = stub_request(:post, "https://api.github.com/repos/jquery/jquery/pulls")
|
99
|
+
.with(
|
100
|
+
body: "{\"base\":\"master\",\"head\":\"123\",\"title\":\"test title\",\"body\":\"test body\"}",
|
101
|
+
headers: request_headers
|
102
|
+
).to_return(status: 200, body: fixture("pull_request.json"), headers: response_headers)
|
103
|
+
end
|
104
|
+
|
105
|
+
it "works" do
|
106
|
+
expect { subject }.not_to raise_error
|
107
|
+
end
|
108
|
+
|
109
|
+
it "sends api requests" do
|
110
|
+
subject
|
111
|
+
|
112
|
+
expect(@search_stub).to have_been_requested
|
113
|
+
expect(@repo_stub).to have_been_requested
|
114
|
+
expect(@branch_stub).to have_been_requested
|
115
|
+
expect(@ref_stub).to have_been_requested
|
116
|
+
expect(@content_stub).to have_been_requested
|
117
|
+
expect(@blob_stub).to have_been_requested
|
118
|
+
expect(@get_commit_stub).to have_been_requested
|
119
|
+
expect(@tree_stub).to have_been_requested
|
120
|
+
expect(@post_commit_stub).to have_been_requested
|
121
|
+
expect(@patch_ref_stub).to have_been_requested
|
122
|
+
expect(@pull_request_stub).to have_been_requested
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
|
2
|
+
|
3
|
+
require "pry"
|
4
|
+
require "octofart"
|
5
|
+
require "webmock/rspec"
|
6
|
+
|
7
|
+
Dir[File.expand_path("support/**/*.rb", __dir__)].each { |f| require f }
|
8
|
+
|
9
|
+
RSpec.configure do |config|
|
10
|
+
config.expect_with :rspec do |c|
|
11
|
+
c.syntax = :expect
|
12
|
+
end
|
13
|
+
|
14
|
+
config.mock_with :rspec do |mocks|
|
15
|
+
mocks.verify_partial_doubles = true
|
16
|
+
end
|
17
|
+
end
|
metadata
ADDED
@@ -0,0 +1,199 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: octofart
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Robbie Marcelo
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-04-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: octokit
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '4.8'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 4.8.0
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '4.8'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 4.8.0
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: bundler
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '1.16'
|
40
|
+
type: :development
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '1.16'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rake
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '10.0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '10.0'
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: rspec
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - "~>"
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '3.2'
|
68
|
+
type: :development
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - "~>"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '3.2'
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: webmock
|
77
|
+
requirement: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - "~>"
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '3.3'
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: 3.3.0
|
85
|
+
type: :development
|
86
|
+
prerelease: false
|
87
|
+
version_requirements: !ruby/object:Gem::Requirement
|
88
|
+
requirements:
|
89
|
+
- - "~>"
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: '3.3'
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: 3.3.0
|
95
|
+
- !ruby/object:Gem::Dependency
|
96
|
+
name: pry
|
97
|
+
requirement: !ruby/object:Gem::Requirement
|
98
|
+
requirements:
|
99
|
+
- - "~>"
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0.11'
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: 0.11.3
|
105
|
+
type: :development
|
106
|
+
prerelease: false
|
107
|
+
version_requirements: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - "~>"
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0.11'
|
112
|
+
- - ">="
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: 0.11.3
|
115
|
+
description: Automate bulk update of code from repositories within your organization,
|
116
|
+
like the wind. :)
|
117
|
+
email:
|
118
|
+
- rbmrclo@hotmail.com
|
119
|
+
executables: []
|
120
|
+
extensions: []
|
121
|
+
extra_rdoc_files: []
|
122
|
+
files:
|
123
|
+
- ".gitignore"
|
124
|
+
- ".rspec"
|
125
|
+
- Gemfile
|
126
|
+
- Gemfile.lock
|
127
|
+
- LICENSE.txt
|
128
|
+
- README.md
|
129
|
+
- Rakefile
|
130
|
+
- bin/console
|
131
|
+
- bin/setup
|
132
|
+
- lib/octofart.rb
|
133
|
+
- lib/octofart/client.rb
|
134
|
+
- lib/octofart/config.rb
|
135
|
+
- lib/octofart/singleton_class.rb
|
136
|
+
- lib/octofart/task_runner.rb
|
137
|
+
- lib/octofart/tasks/branch_mapping.rb
|
138
|
+
- lib/octofart/tasks/commits.rb
|
139
|
+
- lib/octofart/tasks/create_branch.rb
|
140
|
+
- lib/octofart/tasks/data_mapping.rb
|
141
|
+
- lib/octofart/tasks/pull_request.rb
|
142
|
+
- lib/octofart/tasks/update_file.rb
|
143
|
+
- lib/octofart/version.rb
|
144
|
+
- lib/octofart/workflow.rb
|
145
|
+
- octofart.gemspec
|
146
|
+
- spec/fixtures/blob.json
|
147
|
+
- spec/fixtures/branch.json
|
148
|
+
- spec/fixtures/commit.json
|
149
|
+
- spec/fixtures/content.json
|
150
|
+
- spec/fixtures/filename.json
|
151
|
+
- spec/fixtures/pull_request.json
|
152
|
+
- spec/fixtures/ref.json
|
153
|
+
- spec/fixtures/repo.json
|
154
|
+
- spec/fixtures/search.json
|
155
|
+
- spec/fixtures/tree.json
|
156
|
+
- spec/octofart/client_spec.rb
|
157
|
+
- spec/octofart_spec.rb
|
158
|
+
- spec/spec_helper.rb
|
159
|
+
- spec/support/fixture.rb
|
160
|
+
homepage: https://github.com/rbmrclo/octofart
|
161
|
+
licenses:
|
162
|
+
- MIT
|
163
|
+
metadata: {}
|
164
|
+
post_install_message:
|
165
|
+
rdoc_options: []
|
166
|
+
require_paths:
|
167
|
+
- lib
|
168
|
+
- spec
|
169
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - ">="
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
175
|
+
requirements:
|
176
|
+
- - ">="
|
177
|
+
- !ruby/object:Gem::Version
|
178
|
+
version: '0'
|
179
|
+
requirements: []
|
180
|
+
rubyforge_project:
|
181
|
+
rubygems_version: 2.7.3
|
182
|
+
signing_key:
|
183
|
+
specification_version: 4
|
184
|
+
summary: Octokit + Find and Replace Text
|
185
|
+
test_files:
|
186
|
+
- spec/fixtures/blob.json
|
187
|
+
- spec/fixtures/branch.json
|
188
|
+
- spec/fixtures/commit.json
|
189
|
+
- spec/fixtures/content.json
|
190
|
+
- spec/fixtures/filename.json
|
191
|
+
- spec/fixtures/pull_request.json
|
192
|
+
- spec/fixtures/ref.json
|
193
|
+
- spec/fixtures/repo.json
|
194
|
+
- spec/fixtures/search.json
|
195
|
+
- spec/fixtures/tree.json
|
196
|
+
- spec/octofart/client_spec.rb
|
197
|
+
- spec/octofart_spec.rb
|
198
|
+
- spec/spec_helper.rb
|
199
|
+
- spec/support/fixture.rb
|