gitomator-github 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 48039cc1c1db7659a763068cbba64b83eba5db2c
4
+ data.tar.gz: e73d715a625a98e08145314f312fc03dfb3eaab6
5
+ SHA512:
6
+ metadata.gz: ec36dac4420f30b9f940e170df89ca9aea7c0152338151e1deed2cf00c79198f30a4cfd6400ad3fe02357a82799ded98f5a6b27535cfa7e38f91963e8d50d29b
7
+ data.tar.gz: 04359cb8cb41e088ca37afa6db42a214912f2a5af8602d0ffd6b4a0ee22c2037e7bca5fd2fc6d4b8255a933ac1c41cd4781187d2be9e5cc5fa757fec149ad524
data/.gitignore ADDED
@@ -0,0 +1,56 @@
1
+
2
+ # Created by https://www.gitignore.io/api/ruby
3
+
4
+ ### Ruby ###
5
+ *.gem
6
+ *.rbc
7
+ /.config
8
+ /coverage/
9
+ /InstalledFiles
10
+ /pkg/
11
+ /spec/reports/
12
+ /spec/examples.txt
13
+ /test/tmp/
14
+ /test/version_tmp/
15
+ /tmp/
16
+
17
+ # Used by dotenv library to load environment variables.
18
+ # .env
19
+
20
+ ## Specific to RubyMotion:
21
+ .dat*
22
+ .repl_history
23
+ build/
24
+ *.bridgesupport
25
+ build-iPhoneOS/
26
+ build-iPhoneSimulator/
27
+
28
+ ## Specific to RubyMotion (use of CocoaPods):
29
+ #
30
+ # We recommend against adding the Pods directory to your .gitignore. However
31
+ # you should judge for yourself, the pros and cons are mentioned at:
32
+ # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
33
+ #
34
+ # vendor/Pods/
35
+
36
+ ## Documentation cache and generated files:
37
+ /.yardoc/
38
+ /_yardoc/
39
+ /doc/
40
+ /rdoc/
41
+
42
+ ## Environment normalization:
43
+ /.bundle/
44
+ /vendor/bundle
45
+ /lib/bundler/man/
46
+
47
+ # for a library or gem, you might want to ignore these files since the code is
48
+ # intended to run in multiple environments; otherwise, check them in:
49
+ Gemfile.lock
50
+ .ruby-version
51
+ .ruby-gemset
52
+
53
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
54
+ .rvmrc
55
+
56
+ # End of https://www.gitignore.io/api/ruby
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ ruby-2.2.2
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in gitomator-github.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Joey Freund
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,10 @@
1
+ > **IMPORTANT:** All Gitomator projects are currently in pre-alpha stage, which means that:
2
+ >
3
+ > * Some parts are not implemented
4
+ > * API's may change significantly
5
+ > * There are not a lot of tests
6
+ >
7
+
8
+ # Gitomator::Github
9
+
10
+ See https://gitomator.github.io/
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ begin
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new
6
+ rescue LoadError
7
+ end
8
+
9
+ task :test => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "gitomator/github"
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
data/bin/setup ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'gitomator/github/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "gitomator-github"
8
+ spec.version = Gitomator::Github::VERSION
9
+ spec.authors = ["Joey Freund"]
10
+ spec.email = ["joeyfreund@gmail.com"]
11
+
12
+ spec.summary = %q{Gitomator GitHub provider}
13
+ spec.description = %q{Automate the management of GitHub organizations}
14
+ spec.homepage = "https://github.com/gitomator/gitomator-github"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "bin"
19
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_development_dependency "bundler", "~> 1.11"
23
+ spec.add_development_dependency "rake", "~> 10.0"
24
+ spec.add_development_dependency "rspec"
25
+
26
+ spec.add_runtime_dependency 'octokit', '~> 4.2'
27
+ spec.add_runtime_dependency 'gitomator', '>= 0.1.1'
28
+ end
@@ -0,0 +1,28 @@
1
+ require 'gitomator/github'
2
+ require 'gitomator/util/repo/name_resolver'
3
+
4
+
5
+ module Gitomator
6
+ module GitHub
7
+ class BaseProvider
8
+
9
+
10
+ #
11
+ # @param github_client [Octokit::Client]
12
+ # @param github_organization [String]
13
+ #
14
+ def initialize(github_client, github_organization=nil)
15
+ @gh = github_client
16
+ @org = github_organization
17
+ @repo_name_resolver = Gitomator::Util::Repo::NameResolver.new(@org)
18
+ end
19
+
20
+
21
+ def name
22
+ :github
23
+ end
24
+
25
+
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,402 @@
1
+ require 'gitomator/github'
2
+ require 'gitomator/github/base_provider'
3
+ require 'gitomator/github/model/hosted_repo'
4
+ require 'gitomator/github/model/pull_request'
5
+ require 'gitomator/github/model/team'
6
+ require 'gitomator/github/model/user'
7
+ require 'gitomator/util/repo/name_resolver'
8
+
9
+
10
+ module Gitomator
11
+ module GitHub
12
+ class HostingProvider < Gitomator::GitHub::BaseProvider
13
+
14
+ #
15
+ # @param config [Hash<String,Object>]
16
+ # @return [Gitomator::GitHub::HostingProvider] GitHub hosting provider.
17
+ #
18
+ def self.from_config(config = {})
19
+ org = config['organization'] || config[:organization]
20
+ return new(Gitomator::GitHub::github_client_from_config(config), org)
21
+ end
22
+
23
+
24
+ #=========================================================================
25
+
26
+ #
27
+ # @param github_client [Octokit::Client]
28
+ # @param github_organization [String]
29
+ # @param opts [Hash]
30
+ #
31
+ def initialize(github_client, github_organization=nil)
32
+ super
33
+ # GitHub API doesn't have a straight forward way to get a team by name, so we'll keep an in-memory cache
34
+ @name2team_cache = {}
35
+ end
36
+
37
+ def name
38
+ :github
39
+ end
40
+
41
+
42
+ # ------------ Helper Methods, Dealing With Naming Conventions -------
43
+
44
+ def repo_name_full(repo_name)
45
+ @repo_name_resolver.full_name(repo_name)
46
+ end
47
+
48
+ #---------------------------------------------------------------------
49
+
50
+ def _fetch_teams
51
+ with_auto_paginate do
52
+ @name2team_cache = @gh.org_teams(@org).map {|t| [t.name, t]} .to_h
53
+ end
54
+ end
55
+
56
+
57
+ #---------------------------- REPO -----------------------------------
58
+
59
+ SUPPORTED_CREATE_OPTS = [:description, :homepage, :private, :has_issues,
60
+ :has_wiki, :has_downloads, :auto_init]
61
+ #
62
+ # @option opts [String] :description
63
+ # @option opts [String] :homepage
64
+ # @option opts [Boolean] :private
65
+ # @option opts [Boolean] :has_issues
66
+ # @option opts [Boolean] :has_wiki
67
+ # @option opts [Boolean] :has_downloads
68
+ # @option opts [Boolean] :auto_init
69
+ #
70
+ def create_repo(name, opts = {})
71
+ opts = opts.select {|k,_| SUPPORTED_CREATE_OPTS.include? k }
72
+
73
+ # Decide whether this is an organization-repo or a user-repo ...
74
+ org = @repo_name_resolver.namespace(name)
75
+ unless org.nil? || org == @gh.user.login
76
+ opts[:organization] = org
77
+ end
78
+
79
+ return Gitomator::GitHub::Model::HostedRepo.new(
80
+ @gh.create_repo(@repo_name_resolver.name_only(name), opts)
81
+ )
82
+ end
83
+
84
+
85
+ def read_repo(name)
86
+ begin
87
+ return Gitomator::GitHub::Model::HostedRepo.new(@gh.repo repo_name_full(name))
88
+ rescue Octokit::NotFound
89
+ return nil
90
+ end
91
+ end
92
+
93
+
94
+ SUPPORTED_UPDATE_OPTS = [:name, :description, :homepage, :private,
95
+ :has_issues, :has_wiki, :has_downloads,
96
+ :default_branch]
97
+ #
98
+ # @option opts [String] :name — Name of the repo
99
+ # @option opts [String] :description — Description of the repo
100
+ # @option opts [String] :homepage — Home page of the repo
101
+ # @option opts [Boolean] :private — true makes the repository private, and false makes it public.
102
+ # @option opts [Boolean] :has_issues — true enables issues for this repo, false disables issues.
103
+ # @option opts [Boolean] :has_wiki — true enables wiki for this repo, false disables wiki.
104
+ # @option opts [Boolean] :has_downloads — true enables downloads for this repo, false disables downloads.
105
+ # @option opts [String] :default_branch — Update the default branch for this repository.
106
+ #
107
+ def update_repo(name, opts = {})
108
+ opts = opts.select {|k,_| SUPPORTED_UPDATE_OPTS.include? k }
109
+ unless opts.empty?
110
+ return Gitomator::GitHub::Model::HostedRepo.new(
111
+ @gh.edit_repository repo_name_full(name), opts)
112
+ end
113
+ end
114
+
115
+
116
+ def delete_repo(name)
117
+ @gh.delete_repo repo_name_full(name)
118
+ end
119
+
120
+ #
121
+ # For opts see http://www.rubydoc.info/gems/octokit/Octokit%2FClient%2FSearch%3Asearch_issues
122
+ #
123
+ def search_repos(query, opts = {})
124
+ gh_repos = nil
125
+ with_auto_paginate do
126
+ gh_repos = @gh.search_repos("#{query} user:#{@org}", opts).items
127
+ end
128
+
129
+ gh_repos.map {|r| Gitomator::GitHub::Model::HostedRepo.new(r)}
130
+ end
131
+
132
+
133
+ #---------------------------- TEAMS ----------------------------------
134
+
135
+ def create_team(name, opts = {})
136
+ Gitomator::GitHub::Model::Team.new(@gh.create_team(@org, {name: name}))
137
+ end
138
+
139
+ def read_team(name)
140
+ unless @name2team_cache.has_key? name
141
+ _fetch_teams()
142
+ end
143
+ if @name2team_cache[name]
144
+ Gitomator::GitHub::Model::Team.new(@name2team_cache[name])
145
+ else
146
+ return nil
147
+ end
148
+ end
149
+
150
+ #
151
+ # opts:
152
+ # - :name (String)
153
+ # - :permission (String, one of 'pull', 'push' or 'admin')
154
+ #
155
+ def update_team(name, opts)
156
+ unless @name2team_cache.has_key? name
157
+ _fetch_teams()
158
+ end
159
+ raise "No such team, '#{name}'" unless @name2team_cache.has_key? name
160
+
161
+ t = @gh.update_team(@name2team_cache[name].id, opts)
162
+ @name2team_cache[name] = t
163
+ return Gitomator::GitHub::Model::Team.new(t)
164
+ end
165
+
166
+ def delete_team(name)
167
+ unless @name2team_cache.has_key? name
168
+ _fetch_teams()
169
+ end
170
+ if @name2team_cache.has_key? name
171
+ @gh.delete_team @name2team_cache[name].id
172
+ @name2team_cache.delete(name)
173
+ return true
174
+ end
175
+ return false
176
+ end
177
+
178
+
179
+ def search_teams(query, opts={})
180
+ result = @name2team_cache.select {|k,_| k.downcase.include? query} .values
181
+ if result.empty?
182
+ _fetch_teams()
183
+ result = @name2team_cache.select {|k,_| k.downcase.include? query} .values
184
+ end
185
+ return result.map {|t| Gitomator::GitHub::Model::Team.new(t)}
186
+ end
187
+
188
+
189
+ #---------------------------------------------------------------------
190
+
191
+ def set_user_permission(user, repo, permission)
192
+ permission = _strinigify_permission(permission)
193
+ if permission.nil?
194
+ @gh.remove_collab(repo_name_full(repo), user)
195
+ else
196
+ @gh.add_collab(repo_name_full(repo), user, {permission: permission})
197
+ end
198
+ end
199
+
200
+
201
+ def set_team_permission(team, repo, permission)
202
+ permission = _strinigify_permission(permission)
203
+
204
+ t = read_team(team)
205
+ raise "No such team, #{team}" if t.nil?
206
+
207
+ if permission.nil?
208
+ @gh.remove_team_repo(t.id, repo_name_full(repo))
209
+ else
210
+ @gh.add_team_repo(t.id, repo_name_full(repo),
211
+ {
212
+ permission: permission,
213
+ accept: 'application/vnd.github.ironman-preview+json'
214
+ }
215
+ )
216
+ end
217
+ end
218
+
219
+
220
+ def _strinigify_permission(permission)
221
+ if permission.nil?
222
+ return nil
223
+ end
224
+
225
+ case permission.to_s
226
+ when 'read' || 'pull'
227
+ return 'pull'
228
+ when 'write' || 'push'
229
+ return 'push'
230
+ else
231
+ raise "Invalid permission '#{permission}'"
232
+ end
233
+ end
234
+
235
+
236
+
237
+ #--------------------------- Team Membership -------------------------
238
+
239
+ #----------- Helpers ---------
240
+
241
+ def gitomator_role_2_github_role(role)
242
+ if ['admin', 'maintainer'].include? role.to_s.downcase
243
+ return 'maintainer'
244
+ else
245
+ return 'member'
246
+ end
247
+ end
248
+
249
+ def github_role_2_gitomator_role(role)
250
+ role == 'maintainer' ? 'admin' : role
251
+ end
252
+
253
+ def team_id(team_name)
254
+ team = read_team(team_name)
255
+ raise "No such team, #{team_name}" if team.nil?
256
+ return team.id
257
+ end
258
+
259
+ #-----------------------------
260
+
261
+
262
+ def create_team_membership(team_name, user_name, role='member')
263
+ @gh.add_team_membership(team_id(team_name), user_name,
264
+ { :role => gitomator_role_2_github_role(role) }
265
+ )
266
+ return role
267
+ end
268
+
269
+
270
+ def read_team_membership(team_name, user_name)
271
+ begin
272
+ m = @gh.team_membership(team_id(team_name), user_name)
273
+ return m.nil? ? nil : m.role
274
+ rescue Octokit::NotFound
275
+ return nil
276
+ end
277
+ end
278
+
279
+
280
+ def update_team_membership(team_name, user_name, role)
281
+ @gh.add_team_membership(team_id(team_name), user_name,
282
+ { :role => gitomator_role_2_github_role(role) } )
283
+ return role
284
+ end
285
+
286
+
287
+ def delete_team_membership(team_name, user_name)
288
+ @gh.remove_team_membership(team_id(team_name), user_name)
289
+ end
290
+
291
+
292
+ #---------------------------------------------------------------------
293
+
294
+ def with_auto_paginate
295
+ raise "You must supply a block" unless block_given?
296
+ begin
297
+ @gh.auto_paginate = true # We want to get all team members
298
+ yield
299
+ ensure
300
+ @gh.auto_paginate = nil # We don't want to hit GitHub's API rate-limit
301
+ end
302
+ end
303
+
304
+
305
+ def search_users(query, opts={})
306
+
307
+ # If the team's name is specified ...
308
+ gh_users = nil
309
+ if opts[:team_name]
310
+ team = read_team(opts[:team_name])
311
+ gh_users = with_auto_paginate { @gh.team_members(team.id) }
312
+ else
313
+ gh_users = with_auto_paginate { @gh.org_members(@org) }
314
+ end
315
+
316
+ result = gh_users.map { |u| Gitomator::GitHub::Model::User.new(u) }
317
+
318
+ if query.is_a?(String) && (! query.empty?)
319
+ result = result.select {|u| u.username.include? query }
320
+ elsif query.is_a? Regexp
321
+ result = result.select {|u| query.match(u.username) }
322
+ end
323
+
324
+ return result
325
+ end
326
+
327
+
328
+ #---------------------------------------------------------------------
329
+
330
+
331
+ #
332
+ # @param src (String) of the following format 'org/repo:branch'.
333
+ # @param dst (String) of the following format 'org/repo:branch'.
334
+ #
335
+ def create_pull_request(src, dst, opts = {})
336
+
337
+ def extract_org_repo_and_branch(src_or_dst)
338
+ match = src_or_dst.match(/(.+)\/(.+):(.+)/i)
339
+ raise "Invalid src/dst, #{src_or_dst} (expected: `org_or_user/repo:branch`)" if match.nil?
340
+ return match.captures
341
+ end
342
+
343
+ src_org, src_repo, src_branch = extract_org_repo_and_branch(src)
344
+ dst_org, dst_repo, dst_branch = extract_org_repo_and_branch(dst)
345
+
346
+ unless src_repo == dst_repo
347
+ raise "Cannot create pull-request from #{src} to #{dst} (must be the same repo or a fork)."
348
+ end
349
+
350
+ Gitomator::GitHub::Model::PullRequest.new(
351
+ @gh.create_pull_request("#{dst_org}/#{dst_repo}", dst_branch,
352
+ (src_org == dst_org ? '' : "#{src_org}:") + src_branch,
353
+ opts[:title] || 'New Pull Request',
354
+ opts[:body] || 'Pull-request created using Gitomator.'
355
+ )
356
+ )
357
+ end
358
+
359
+
360
+ def read_pull_request(dst_repo, id)
361
+ begin
362
+ return Gitomator::GitHub::Model::PullRequest.new(
363
+ @gh.pull_request(repo_name_full(dst_repo), id))
364
+ rescue Octokit::NotFound
365
+ return nil
366
+ end
367
+ end
368
+
369
+
370
+ #
371
+ # @param opts [Hash]
372
+ # => @param :state [Symbol] One of :open, :close or :all (default: :open)
373
+ #
374
+ def read_pull_requests(dst_repo, opts = {})
375
+ @gh.pulls(repo_name_full(dst_repo), opts)
376
+ .map {|pr| Gitomator::GitHub::Model::PullRequest.new(pr, @gh)}
377
+ end
378
+
379
+
380
+ def merge_pull_request(dst_repo, id, message='')
381
+ Gitomator::GitHub::Model::PullRequest.new(
382
+ @gh.merge_pull_request(repo_name_full(dst_repo), id, message), @gh)
383
+ end
384
+
385
+ def close_pull_request(dst_repo, id)
386
+ Gitomator::GitHub::Model::PullRequest.new(
387
+ @gh.close_pull_request(repo_name_full(dst_repo), id), @gh)
388
+ end
389
+
390
+ def open_pull_request(dst_repo, id)
391
+ Gitomator::GitHub::Model::PullRequest.new(
392
+ @gh.update_pull_request(repo_name_full(dst_repo), id, {state: :open}), @gh)
393
+ end
394
+
395
+
396
+ #---------------------------------------------------------------------
397
+
398
+
399
+
400
+ end
401
+ end
402
+ end
@@ -0,0 +1,43 @@
1
+ module Gitomator
2
+ module GitHub
3
+ module Model
4
+ class HostedRepo
5
+
6
+
7
+ #
8
+ # @param gh_repo [Sawyer::Resource]
9
+ #
10
+ def initialize(gh_repo)
11
+ @r = gh_repo
12
+ end
13
+
14
+
15
+ def name
16
+ @r.name
17
+ end
18
+
19
+ def full_name
20
+ @r.full_name
21
+ end
22
+
23
+ def url
24
+ @r.clone_url
25
+ end
26
+
27
+ def properties
28
+ return {
29
+ :description => @r.description,
30
+ :homepage => @r.homepage,
31
+ :private => @r.private?,
32
+ :has_issues => @r.has_issues?,
33
+ :has_wiki => @r.has_wiki?,
34
+ :has_downloads => @r.has_downloads?,
35
+ :default_branch => @r.default_branch
36
+ }
37
+ end
38
+
39
+
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,81 @@
1
+ require 'gitomator/github/model/hosted_repo'
2
+
3
+ module Gitomator
4
+ module GitHub
5
+ module Model
6
+ class PullRequest
7
+
8
+
9
+ #
10
+ # @param gh_pull_request [Sawyer::Resource]
11
+ # @param octokit [Octokit::Client]
12
+ #
13
+ def initialize(gh_pull_request, octokit)
14
+ @r = gh_pull_request
15
+ @octokit = octokit
16
+ end
17
+
18
+
19
+ def id
20
+ @r.number
21
+ end
22
+
23
+ def title
24
+ @r.title
25
+ end
26
+
27
+ def created_by
28
+ @r.user.login
29
+ end
30
+
31
+ def created_at
32
+ @r.created_at
33
+ end
34
+
35
+ # @return [String] One of 'open', 'close'
36
+ #
37
+ def state
38
+ @r.state
39
+ end
40
+
41
+ #
42
+ # @return true/false/nil
43
+ #
44
+ def mergeable?
45
+ # In Octokit, the two methods `pull_request` and `pull_requests` return
46
+ # different type of objects (the one returned by `pull_requests` is missing
47
+ # the mergeable? method)
48
+ if (not @r.respond_to? :mergeable?)
49
+ @r = @octokit.pull_request(@r.base.repo.full_name, @r.number)
50
+ end
51
+
52
+ if @r.mergeable_state == 'clean'
53
+ return @r.mergeable?
54
+ else
55
+ return nil
56
+ end
57
+ end
58
+
59
+ # The "source repo"
60
+ def head_repo
61
+ Gitomator::GitHub::Model::HostedRepo.new(@r.head.repo)
62
+ end
63
+
64
+ def head_branch
65
+ @r.head.label.split(':').last
66
+ end
67
+
68
+ # The "destination repo"
69
+ def base_repo
70
+ Gitomator::GitHub::Model::HostedRepo.new(@r.base.repo)
71
+ end
72
+
73
+ def base_branch
74
+ @r.base.label.split(':').last
75
+ end
76
+
77
+
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,26 @@
1
+ module Gitomator
2
+ module GitHub
3
+ module Model
4
+ class Team
5
+
6
+
7
+ #
8
+ # @param gh_team [Sawyer::Resource]
9
+ #
10
+ def initialize(gh_team)
11
+ @r = gh_team
12
+ end
13
+
14
+ def id
15
+ @r.id
16
+ end
17
+
18
+ def name
19
+ @r.name
20
+ end
21
+
22
+
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,21 @@
1
+ module Gitomator
2
+ module GitHub
3
+ module Model
4
+ class User
5
+
6
+
7
+ #
8
+ # @param gh_user [Sawyer::Resource]
9
+ #
10
+ def initialize(gh_user)
11
+ @r = gh_user
12
+ end
13
+
14
+ def username
15
+ @r.login
16
+ end
17
+
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,95 @@
1
+ require 'gitomator/github'
2
+ require 'gitomator/github/base_provider'
3
+
4
+
5
+ module Gitomator
6
+ module GitHub
7
+ class TaggingProvider < Gitomator::GitHub::BaseProvider
8
+
9
+
10
+ # ---------------------- Static Factory Methods --------------------------
11
+
12
+ #
13
+ # @param config [Hash<String,Object>]
14
+ # @return [Gitomator::GitHub::HostingProvider] GitHub hosting provider.
15
+ #
16
+ def self.from_config(config = {})
17
+ return new(Gitomator::GitHub::github_client_from_config(config),
18
+ config['organization'])
19
+ end
20
+
21
+ #-------------------------------------------------------------------------
22
+
23
+
24
+ def add_tags(repo, issue_or_pr_id, *tags)
25
+ @gh.add_labels_to_an_issue(@repo_name_resolver.full_name(repo),
26
+ issue_or_pr_id, tags
27
+ ).map { |r| r.to_h }
28
+ end
29
+
30
+ def remove_tag(repo, id_or_name, tag)
31
+ @gh.remove_label(@repo_name_resolver.full_name(repo), id_or_name, tag)
32
+ .map { |r| r.to_h } # Make the result a regular Ruby Hash
33
+ end
34
+
35
+
36
+ def tags(repo, id_or_name)
37
+ repo = @repo_name_resolver.full_name(repo)
38
+ @gh.labels_for_issue(repo, id_or_name).map {|r| r.name }
39
+ end
40
+
41
+
42
+ #
43
+ # @return Enumerable of object identifiers.
44
+ #
45
+ def search(repo, label)
46
+ if label.is_a? String
47
+ q = "repo:#{@repo_name_resolver.full_name(repo)} type:issue|pr label:\"#{label}\""
48
+ @gh.search_issues(q)
49
+ .items.map {|item| item.number} # Make the result an array of issue/or id's
50
+ else
51
+ raise "Unimplemented! Search only supports a single tag at the moment."
52
+ end
53
+
54
+ end
55
+
56
+
57
+ def metadata(repo, tag=nil)
58
+ repo = @repo_name_resolver.full_name(repo)
59
+
60
+ if tag
61
+ begin
62
+ @gh.label(repo, tag).to_h # Return metadata (Hash<Symbol,String>)
63
+ rescue Octokit::NotFound
64
+ return nil
65
+ end
66
+ else
67
+ @gh.labels(repo).map {|r| [r.name, r.to_h]}.to_h # Return Hash<String,Hash<Symbol,String>>, mapping tags to their metadata
68
+ end
69
+ end
70
+
71
+
72
+
73
+ def set_metadata(repo, tag, metadata)
74
+ repo = @repo_name_resolver.full_name(repo)
75
+ color = metadata[:color] || metadata['color']
76
+ raise "The only supported metadata property is 'color'" if color.nil?
77
+ # TODO: Validate the color string (6-char-long Hex string. Any other formats supproted by GitHub?)
78
+
79
+ if metadata(repo, tag).nil?
80
+ @gh.add_label(repo, tag, color).to_h
81
+ else
82
+ @gh.update_label(repo, tag, {:color => color}).to_h
83
+ end
84
+
85
+ end
86
+
87
+
88
+ def delete_metadata(repo, tag)
89
+ @gh.delete_label!(@repo_name_resolver.full_name(repo), tag)
90
+ end
91
+
92
+
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,5 @@
1
+ module Gitomator
2
+ module Github
3
+ VERSION = "0.1.1"
4
+ end
5
+ end
@@ -0,0 +1,31 @@
1
+ require "gitomator/github/version"
2
+
3
+ module Gitomator
4
+ module GitHub
5
+
6
+
7
+ def self.github_client_from_config(config = {})
8
+ # Convert keys yo strings (to handle keys whose type is Symbol)
9
+ config = config.map {|k,v| [k.to_s, v]} .to_h
10
+
11
+ opts = {}
12
+
13
+ if config['access_token']
14
+ opts[:access_token] = config['access_token']
15
+ elsif config['username'] && config['password']
16
+ opts[:login] = config['username']
17
+ opts[:password] = config['password']
18
+ elsif config['client_id'] && config['client_secret']
19
+ opts[:client_id] = config['client_id']
20
+ opts[:client_secret] = config['client_secret']
21
+ else
22
+ raise "Invalid GitHub hosting configuration - #{config}"
23
+ end
24
+
25
+ require 'octokit'
26
+ return Octokit::Client.new(opts)
27
+ end
28
+
29
+
30
+ end
31
+ end
metadata ADDED
@@ -0,0 +1,134 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gitomator-github
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Joey Freund
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-12-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.11'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.11'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
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: octokit
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '4.2'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '4.2'
69
+ - !ruby/object:Gem::Dependency
70
+ name: gitomator
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: 0.1.1
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 0.1.1
83
+ description: Automate the management of GitHub organizations
84
+ email:
85
+ - joeyfreund@gmail.com
86
+ executables:
87
+ - console
88
+ - setup
89
+ extensions: []
90
+ extra_rdoc_files: []
91
+ files:
92
+ - ".gitignore"
93
+ - ".ruby-version"
94
+ - Gemfile
95
+ - LICENSE.txt
96
+ - README.md
97
+ - Rakefile
98
+ - bin/console
99
+ - bin/setup
100
+ - gitomator-github.gemspec
101
+ - lib/gitomator/github.rb
102
+ - lib/gitomator/github/base_provider.rb
103
+ - lib/gitomator/github/hosting_provider.rb
104
+ - lib/gitomator/github/model/hosted_repo.rb
105
+ - lib/gitomator/github/model/pull_request.rb
106
+ - lib/gitomator/github/model/team.rb
107
+ - lib/gitomator/github/model/user.rb
108
+ - lib/gitomator/github/tagging_provider.rb
109
+ - lib/gitomator/github/version.rb
110
+ homepage: https://github.com/gitomator/gitomator-github
111
+ licenses:
112
+ - MIT
113
+ metadata: {}
114
+ post_install_message:
115
+ rdoc_options: []
116
+ require_paths:
117
+ - lib
118
+ required_ruby_version: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ version: '0'
123
+ required_rubygems_version: !ruby/object:Gem::Requirement
124
+ requirements:
125
+ - - ">="
126
+ - !ruby/object:Gem::Version
127
+ version: '0'
128
+ requirements: []
129
+ rubyforge_project:
130
+ rubygems_version: 2.6.2
131
+ signing_key:
132
+ specification_version: 4
133
+ summary: Gitomator GitHub provider
134
+ test_files: []