bimble 0.0.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. checksums.yaml +8 -8
  2. data/.travis.yml +3 -1
  3. data/CHANGELOG.md +9 -0
  4. data/README.md +10 -2
  5. data/Rakefile +4 -0
  6. data/bimble.gemspec +5 -2
  7. data/bin/bimble +11 -0
  8. data/bin/{generate_oauth_token.rb → generate_github_oauth_token} +0 -0
  9. data/lib/bimble.rb +16 -3
  10. data/lib/bimble/bundler.rb +9 -0
  11. data/lib/bimble/factory.rb +12 -0
  12. data/lib/bimble/git_strategy/clone.rb +40 -0
  13. data/lib/bimble/git_strategy/github_api.rb +57 -0
  14. data/lib/bimble/helpers/github.rb +99 -0
  15. data/lib/bimble/helpers/strings.rb +19 -0
  16. data/lib/bimble/helpers/updater.rb +14 -0
  17. data/lib/bimble/version.rb +1 -1
  18. data/spec/cassettes/Bimble_GitStrategy_GithubApi/should_be_able_to_create_a_new_blob.yml +73 -0
  19. data/spec/cassettes/Bimble_GitStrategy_GithubApi/should_be_able_to_create_a_new_branch_for_a_commit.yml +73 -0
  20. data/spec/cassettes/Bimble_GitStrategy_GithubApi/should_be_able_to_create_a_new_commit_from_a_tree.yml +215 -0
  21. data/spec/cassettes/Bimble_GitStrategy_GithubApi/should_be_able_to_create_a_tree_with_the_new_blob_in_it_given_a_filename.yml +211 -0
  22. data/spec/cassettes/Bimble_GitStrategy_GithubApi/should_be_able_to_fetch_the_default_branch_for_a_repo.yml +72 -0
  23. data/spec/cassettes/Bimble_GitStrategy_GithubApi/should_be_able_to_get_a_blob_sha_for_a_file_on_a_branch.yml +72 -0
  24. data/spec/cassettes/Bimble_GitStrategy_GithubApi/should_be_able_to_get_a_blob_sha_for_files_matching_a_regex_on_a_branch.yml +72 -0
  25. data/spec/cassettes/Bimble_GitStrategy_GithubApi/should_be_able_to_get_a_blob_sha_for_files_matching_a_regexp_on_a_branch.yml +72 -0
  26. data/spec/cassettes/Bimble_GitStrategy_GithubApi/should_be_able_to_get_latest_commit_SHA_on_a_branch.yml +73 -0
  27. data/spec/cassettes/Bimble_GitStrategy_GithubApi/should_be_able_to_get_the_content_of_the_Gemfile_blob.yml +70 -0
  28. data/spec/cassettes/Bimble_GitStrategy_GithubApi/should_be_able_to_open_a_pull_request_back_to_the_default_branch.yml +76 -0
  29. data/spec/cassettes/Bimble_GitStrategy_GithubApi/should_be_able_to_update_Gemfile_lock_and_open_PR_all_in_one_go.yml +567 -0
  30. data/spec/cassettes/github_api_strategy/should_get_all_appropriate_files.yml +342 -0
  31. data/spec/git_strategy_spec.rb +26 -0
  32. data/spec/github_api_spec.rb +70 -0
  33. data/spec/spec_helper.rb +15 -6
  34. metadata +88 -8
  35. data/bin/bimble.rb +0 -52
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- MjU4MGVhZmIwNjFkYTMzM2IxNTdhNTFjMzg4NzMwMTExZTAyYjJlNA==
4
+ ODNlYmJiNGVjMzAwZjk2NTkxNzkzNDYzODI4Zjc1YjExMjY5MWIwZQ==
5
5
  data.tar.gz: !binary |-
6
- YTY3OGUzMTJjZGFkMTljOTIyMmExZDZjODJkMzM3YjU4NTE0NzJiNQ==
6
+ NzU0ZjAzNjhjMjE4MjZkNWQ4YzlhNzVhYWI4YWRmMDc0OTZiOWQ1Yw==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- OWU0MGJmNWFiYTljY2RlMmQ2MzExNDUwNzJjNzkzYzUyNzMxNjdkNmVlMjFm
10
- YzQ2NGJmYWNmZGNjZjM5ODU2NGQwM2VmZDdmZmQ0NjM4YTBiYTczYmEzNjMy
11
- NjlhYzA1NmZiZTdhNTBmNDE2NzYyNGU3N2JmNDI3NGI4OThkNDQ=
9
+ Mzg0MjA1YWY1OTQ4NTE0NjY3NThmMmQ1ZTEzMWZjMTI0MjQwMzQwODUzOTcz
10
+ YzkxZjJlZWI0N2FkN2M3YTBhN2UxNjc4OTk4ZmVhMDQzYWI0ODY3YjgwN2Nh
11
+ YmM3MTE1NmVlYmRmZThiMTIyODkwNWRhZTJmMTUxOGIwODJiOTM=
12
12
  data.tar.gz: !binary |-
13
- YzA2MWI3ZWMzODc4NmU4M2I0MWZjZTA3NzAxZjE0MTA5ZTJiY2MzZmZkN2Ni
14
- ZDIwNWZhNDE1OTc1NWUxYjA3MDgwNzBhNGRjNjE5NmEyNmE1Y2Q1NDIwZTlh
15
- YjcwNmM4MjU1ZjU1YjQ1Y2JhNzgwMTI0ZmJiMGExMjI1MTRjMGY=
13
+ ODZhY2FiOTgyNmFkNGNlYTE3M2E3YTQ3NWIxMjY1OTczMzQyNjQ4NWVjMDI2
14
+ MThiMWUwNDAyNjM2MTFhZDVkNzYwYmNmY2JjNjJlZmM2MjhhNDBlYzlkNjdj
15
+ NjNmYWQwNTg2OTk3OWJkZjMwMzQ2ZTAwZGQzNDUzZTQ5NzgzOGU=
data/.travis.yml CHANGED
@@ -15,4 +15,6 @@ deploy:
15
15
  gem: bimble
16
16
  on:
17
17
  tags: true
18
- repo: theodi/bimble
18
+ repo: theodi/bimble
19
+ env:
20
+ - GITHUB_OAUTH_TOKEN=abc123
data/CHANGELOG.md ADDED
@@ -0,0 +1,9 @@
1
+ # Changelog
2
+
3
+ ## 1.0.0
4
+
5
+ Use github API to get and commit files instead of a full clone
6
+
7
+ ## 0.0.1
8
+
9
+ First gemmed version. Uses a local clone.
data/README.md CHANGED
@@ -1,3 +1,11 @@
1
+ [![Build Status](http://img.shields.io/travis/theodi/bimble.svg)](https://travis-ci.org/theodi/bimble)
2
+ [![Dependency Status](http://img.shields.io/gemnasium/theodi/bimble.svg)](https://gemnasium.com/theodi/bimble)
3
+ [![Coverage Status](http://img.shields.io/coveralls/theodi/bimble.svg)](https://coveralls.io/r/theodi/bimble)
4
+ [![Code Climate](http://img.shields.io/codeclimate/github/theodi/bimble.svg)](https://codeclimate.com/github/theodi/bimble)
5
+ [![Gem Version](http://img.shields.io/gem/v/bimble.svg)](https://rubygems.org/gems/bimble)
6
+ [![License](http://img.shields.io/:license-mit-blue.svg)](http://theodi.mit-license.org)
7
+ [![Badges](http://img.shields.io/:badges-7/7-ff6799.svg)](https://github.com/pikesley/badger)
8
+
1
9
  # Bimble
2
10
 
3
11
  A gem and executable to check out a repo, run bundle update, then commit and open a PR.
@@ -31,7 +39,7 @@ You need to be able to clone via SSH from the user the script will run as.
31
39
  Then:
32
40
 
33
41
  ```
34
- bimble.rb git@github.com:{user}/{repo}.git
42
+ bimble git@github.com:{user}/{repo}.git
35
43
  ```
36
44
 
37
45
  Once the bundle is updated, `Gemfile.lock` **only** will be committed on a new
@@ -49,7 +57,7 @@ The following environment variables should be set in a `.env` file in order to u
49
57
 
50
58
  GITHUB_OAUTH_TOKEN='your-oauth-token-for-your-app'
51
59
 
52
- To generate this token, run `./generate_oauth_token.rb` and follow the instructions. You'll need
60
+ To generate this token, run `generate_github_oauth_token` and follow the instructions. You'll need
53
61
  to be on a machine with a web browser.
54
62
 
55
63
  ## Contributing
data/Rakefile CHANGED
@@ -1,3 +1,7 @@
1
1
  require "bundler/gem_tasks"
2
2
 
3
+ require 'rspec/core/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
3
7
  task :default => :spec
data/bimble.gemspec CHANGED
@@ -22,11 +22,14 @@ Gem::Specification.new do |spec|
22
22
  spec.add_dependency 'dotenv'
23
23
  spec.add_dependency 'github_api'
24
24
  spec.add_dependency 'launchy'
25
+ spec.add_dependency 'memoist'
25
26
 
26
27
  spec.add_development_dependency "bundler", "~> 1.3"
27
28
  spec.add_development_dependency "rake"
28
29
  spec.add_development_dependency "rspec"
29
- spec.add_development_dependency "travis"
30
30
  spec.add_development_dependency "coveralls"
31
-
31
+ spec.add_development_dependency "vcr"
32
+ spec.add_development_dependency "webmock"
33
+ spec.add_development_dependency "pry"
34
+
32
35
  end
data/bin/bimble ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'dotenv'
4
+ require 'bimble'
5
+
6
+ Dotenv.load
7
+
8
+ bimble = Bimble.create(:github_api,
9
+ git_url: ARGV[0],
10
+ github_oauth_token: ENV['GITHUB_OAUTH_TOKEN'])
11
+ puts bimble.update
data/lib/bimble.rb CHANGED
@@ -1,5 +1,18 @@
1
- require "bimble/version"
2
-
3
1
  module Bimble
4
- # Your code goes here...
2
+
3
+ module Helpers
4
+ end
5
+
6
+ module GitStrategy
7
+ end
8
+
5
9
  end
10
+
11
+ require "bimble/version"
12
+ require "bimble/helpers/github"
13
+ require "bimble/helpers/strings"
14
+ require "bimble/helpers/updater"
15
+ require "bimble/git_strategy/clone"
16
+ require "bimble/git_strategy/github_api"
17
+ require "bimble/factory"
18
+ require "bimble/bundler"
@@ -0,0 +1,9 @@
1
+ module Bimble
2
+
3
+ def self.bundle_update
4
+ if File.exists?("Gemfile")
5
+ `bundle update`
6
+ end
7
+ end
8
+
9
+ end
@@ -0,0 +1,12 @@
1
+ module Bimble
2
+
3
+ def self.create(strategy, options)
4
+ case strategy
5
+ when :clone
6
+ Bimble::GitStrategy::Clone.new(options[:git_url], options[:github_oauth_token])
7
+ when :github_api
8
+ Bimble::GitStrategy::GithubApi.new(options[:git_url], options[:github_oauth_token])
9
+ end
10
+ end
11
+
12
+ end
@@ -0,0 +1,40 @@
1
+ require 'git'
2
+
3
+ class Bimble::GitStrategy::Clone
4
+
5
+ include Bimble::Helpers::Strings
6
+ include Bimble::Helpers::Github
7
+ include Bimble::Helpers::Updater
8
+
9
+ def initialize(git_url, oauth_token)
10
+ @git_url = git_url
11
+ @oauth_token = oauth_token
12
+ end
13
+
14
+ def in_working_copy
15
+ Dir.mktmpdir do |tmpdir|
16
+ @repository = Git.clone(@git_url, tmpdir)
17
+ @default_branch = @repository.branch
18
+ Dir.chdir(tmpdir) do
19
+ yield
20
+ end
21
+ end
22
+ end
23
+
24
+ def lockfile_changed?
25
+ @repository.status.changed.keys.include? "Gemfile.lock"
26
+ end
27
+
28
+ def commit_to_new_branch
29
+ @repository.branch(branch_name).create
30
+ @repository.checkout(branch_name)
31
+ @repository.add("Gemfile.lock")
32
+ @repository.commit(commit_message)
33
+ @repository.push("origin", branch_name)
34
+ end
35
+
36
+ def default_branch
37
+ @default_branch
38
+ end
39
+
40
+ end
@@ -0,0 +1,57 @@
1
+ class Bimble::GitStrategy::GithubApi
2
+
3
+ include Bimble::Helpers::Strings
4
+ include Bimble::Helpers::Github
5
+ include Bimble::Helpers::Updater
6
+
7
+ def initialize(git_url, oauth_token)
8
+ @git_url = git_url
9
+ @oauth_token = oauth_token
10
+ end
11
+
12
+ def in_working_copy
13
+ Dir.mktmpdir do |tmpdir|
14
+ # Get files
15
+ files = get_files("Gemfile.*").merge(get_files(".*gemspec"))
16
+ Dir.chdir(tmpdir) do
17
+ # Write files
18
+ files.each_pair do |name, content|
19
+ File.open(name, 'w') {|f| f.write(content) }
20
+ end
21
+ # Store md5 of lockfile
22
+ @original_md5 = Digest::MD5.hexdigest(File.read("Gemfile.lock"))
23
+ # Do the business
24
+ yield
25
+ end
26
+ end
27
+ end
28
+
29
+ def get_files(name)
30
+ blobs = blob_shas(default_branch, name)
31
+ Hash[blobs.map{|x| [x[0], blob_content(x[1])]}]
32
+ end
33
+
34
+ def lock_md5
35
+ Digest::MD5.hexdigest(File.read("Gemfile.lock"))
36
+ end
37
+
38
+ def lockfile_changed?
39
+ lock_md5 != @original_md5
40
+ end
41
+
42
+ def get_file(name)
43
+ get_files(name)[name]
44
+ end
45
+
46
+ def commit_to_new_branch
47
+ commit_file("Gemfile.lock", File.read("Gemfile.lock"))
48
+ end
49
+
50
+ def commit_file(name, content)
51
+ blob_sha = create_blob(content)
52
+ tree_sha = add_blob_to_tree(blob_sha, name)
53
+ commit_sha = commit(tree_sha)
54
+ create_branch(branch_name, commit_sha)
55
+ end
56
+
57
+ end
@@ -0,0 +1,99 @@
1
+ require 'base64'
2
+ require 'github_api'
3
+ require 'memoist'
4
+
5
+ module Bimble::Helpers::Github
6
+
7
+ extend Memoist
8
+
9
+ GITHUB_REPO_REGEX = /github.com[:\/]([^\/]*)\/([^\.]*)/
10
+
11
+ def github
12
+ Github.new oauth_token: @oauth_token
13
+ end
14
+ memoize :github
15
+
16
+ def user
17
+ match = @git_url.match GITHUB_REPO_REGEX
18
+ match ? match[1] : nil
19
+ end
20
+ memoize :user
21
+
22
+ def repo
23
+ match = @git_url.match GITHUB_REPO_REGEX
24
+ match ? match[2] : nil
25
+ end
26
+ memoize :repo
27
+
28
+ def default_branch
29
+ repository = github.repos.get user, repo
30
+ repository.default_branch
31
+ end
32
+ memoize :default_branch
33
+
34
+ def latest_commit(branch_name)
35
+ branch_data = github.repos.branch user, repo, branch_name
36
+ branch_data['commit']['sha']
37
+ end
38
+ memoize :latest_commit
39
+
40
+ def tree(branch)
41
+ github.git_data.trees.get user, repo, branch
42
+ end
43
+ memoize :tree
44
+
45
+ def blob_shas(branch, path)
46
+ tree = tree branch
47
+ Hash[tree['tree'].select{|x| x['path'] =~ /^#{path}$/ && x['type'] == 'blob'}.map{|x| [x.path, x.sha]}]
48
+ end
49
+ memoize :blob_shas
50
+
51
+ def blob_content(sha)
52
+ blob = github.git_data.blobs.get user, repo, sha
53
+ if blob['encoding'] == 'base64'
54
+ Base64.decode64(blob['content'])
55
+ else
56
+ blob['content']
57
+ end
58
+ end
59
+ memoize :blob_content
60
+
61
+
62
+ def create_blob(content)
63
+ blob = github.git_data.blobs.create user, repo, "content" => content, "encoding" => "utf-8"
64
+ blob['sha']
65
+ end
66
+
67
+ def add_blob_to_tree(sha, filename)
68
+ tree = tree default_branch
69
+ new_tree = github.git_data.trees.create user, repo, "base_tree" => tree['sha'], "tree" => [
70
+ "path" => filename,
71
+ "mode" => "100644",
72
+ "type" => "blob",
73
+ "sha" => sha
74
+ ]
75
+ new_tree['sha']
76
+ end
77
+
78
+ def commit(sha)
79
+ parent = latest_commit(default_branch)
80
+ commit = github.git_data.commits.create user, repo, "message" => commit_message,
81
+ "parents" => [parent],
82
+ "tree" => sha
83
+ commit['sha']
84
+ end
85
+
86
+ def create_branch(name, sha)
87
+ branch = github.git_data.references.create user, repo, "ref" => "refs/heads/#{name}", "sha" => sha
88
+ branch['ref']
89
+ end
90
+
91
+ def open_pr(head, base)
92
+ github.pull_requests.create user, repo,
93
+ "title" => pull_request_title,
94
+ "body" => pull_request_body,
95
+ "head" => head,
96
+ "base" => base
97
+ end
98
+
99
+ end
@@ -0,0 +1,19 @@
1
+ module Bimble::Helpers::Strings
2
+
3
+ def branch_name
4
+ "update-dependencies-#{Date.today.to_s}"
5
+ end
6
+
7
+ def commit_message
8
+ "automatically updated dependencies"
9
+ end
10
+
11
+ def pull_request_title
12
+ "Updated dependencies"
13
+ end
14
+
15
+ def pull_request_body
16
+ "Automatically updated by Bimble"
17
+ end
18
+
19
+ end
@@ -0,0 +1,14 @@
1
+ module Bimble::Helpers::Updater
2
+
3
+ def update
4
+ in_working_copy do
5
+ Bimble.bundle_update
6
+ if lockfile_changed?
7
+ commit_to_new_branch
8
+ @pr = open_pr(branch_name, default_branch) if @oauth_token
9
+ end
10
+ end
11
+ @pr ? @pr['html_url'] : nil
12
+ end
13
+
14
+ end
@@ -1,3 +1,3 @@
1
1
  module Bimble
2
- VERSION = "0.0.1"
2
+ VERSION = "1.0.0"
3
3
  end
@@ -0,0 +1,73 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: https://api.github.com/repos/Floppy/bimble-test/git/blobs?access_token=<GITHUB_OAUTH_TOKEN>
6
+ body:
7
+ encoding: UTF-8
8
+ string: "{\"content\":\"new blob content\",\"encoding\":\"utf-8\"}"
9
+ headers:
10
+ Accept:
11
+ - application/vnd.github.v3+json,application/vnd.github.beta+json;q=0.5,application/json;q=0.1
12
+ Accept-Charset:
13
+ - utf-8
14
+ User-Agent:
15
+ - Github Ruby Gem 0.11.3
16
+ Content-Type:
17
+ - application/json
18
+ Authorization:
19
+ - Token token="<GITHUB_OAUTH_TOKEN>"
20
+ Accept-Encoding:
21
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
22
+ response:
23
+ status:
24
+ code: 201
25
+ message: Created
26
+ headers:
27
+ Server:
28
+ - GitHub.com
29
+ Date:
30
+ - Tue, 11 Mar 2014 14:20:58 GMT
31
+ Content-Type:
32
+ - application/json; charset=utf-8
33
+ Status:
34
+ - 201 Created
35
+ X-Ratelimit-Limit:
36
+ - '5000'
37
+ X-Ratelimit-Remaining:
38
+ - '4563'
39
+ X-Ratelimit-Reset:
40
+ - '1394548554'
41
+ Cache-Control:
42
+ - private, max-age=60, s-maxage=60
43
+ Etag:
44
+ - "\"f1f8f95824fcfe41a55cf713ac0c9b16\""
45
+ X-Oauth-Scopes:
46
+ - repo
47
+ X-Accepted-Oauth-Scopes:
48
+ - ''
49
+ Location:
50
+ - https://api.github.com/repos/Floppy/bimble-test/git/blobs/28b552e7359c5c3bbe947749aab70d18e3ea554b
51
+ Vary:
52
+ - Accept, Authorization, Cookie, X-GitHub-OTP
53
+ X-Github-Media-Type:
54
+ - github.v3; format=json
55
+ X-Content-Type-Options:
56
+ - nosniff
57
+ Content-Length:
58
+ - '157'
59
+ Access-Control-Allow-Credentials:
60
+ - 'true'
61
+ Access-Control-Expose-Headers:
62
+ - ETag, Link, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset,
63
+ X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval
64
+ Access-Control-Allow-Origin:
65
+ - "*"
66
+ X-Github-Request-Id:
67
+ - 519F8646:7B0C:1ADBBE8:531F1BCA
68
+ body:
69
+ encoding: UTF-8
70
+ string: "{\"sha\":\"28b552e7359c5c3bbe947749aab70d18e3ea554b\",\"url\":\"https://api.github.com/repos/Floppy/bimble-test/git/blobs/28b552e7359c5c3bbe947749aab70d18e3ea554b\"}"
71
+ http_version:
72
+ recorded_at: Tue, 11 Mar 2014 14:20:59 GMT
73
+ recorded_with: VCR 2.8.0