zd_hire 0.0.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 +7 -0
- data/.gitignore +11 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/README.md +22 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/bin/zd_hire +214 -0
- data/lib/zd_hire/config.rb +50 -0
- data/lib/zd_hire/version.rb +3 -0
- data/lib/zd_hire.rb +6 -0
- data/zd_hire.gemspec +27 -0
- metadata +139 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: '0971f5f3780f1088ee0d4c38638decdc2016a8fc'
|
4
|
+
data.tar.gz: 48025579e091a34a92db35c2fe60c08fcb5c6290
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: bb8f4e78d4b0f068a15ef9bd16fd9ebbd5cff7738e477d3c6fee7726efa774f3f2c943ed540b9068a95fc0c9dde0b0c4729c71cd346c211b2be5f7b448cd3f16
|
7
|
+
data.tar.gz: 7e21272192a87eec7d523cfd8739081b5394c9171f3b9441e6c40b9d402e2d618bb3d91d098029df5c166e5e8b1daf62a1d9d5c9a0f4e6620fd4ec3b38cf3d6f
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# ZdHire
|
2
|
+
|
3
|
+
Clone orphaned repositories from a Github origin and copy selected issues to the new repo.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Install the gem and use the command line client:
|
8
|
+
|
9
|
+
```bash
|
10
|
+
$ gem install zd_hire
|
11
|
+
$ zd_hire init
|
12
|
+
```
|
13
|
+
|
14
|
+
This command will start an interactive shell session and will save your github credentials and origin repo configuration at `~/.zd_hire`.
|
15
|
+
|
16
|
+
## Usage
|
17
|
+
|
18
|
+
```bash
|
19
|
+
$ zd_hide clone
|
20
|
+
```
|
21
|
+
|
22
|
+
This command will start an interactive shell session and will guide you setting up the repository copy.
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "zd_hire"
|
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
data/bin/zd_hire
ADDED
@@ -0,0 +1,214 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "zd_hire"
|
5
|
+
require 'commander/import'
|
6
|
+
require 'octokit'
|
7
|
+
|
8
|
+
program :name, 'ZdHire'
|
9
|
+
program :version, ZdHire::VERSION
|
10
|
+
program :description, 'Hire developers using Github'
|
11
|
+
default_command :init
|
12
|
+
|
13
|
+
QUESTIONS = {
|
14
|
+
repo: 'Github Repository(user/repo): ',
|
15
|
+
issues: 'Github Issue Ids: ',
|
16
|
+
target_repo: 'New repository name: '
|
17
|
+
}
|
18
|
+
|
19
|
+
PRIVATE_SECTION_SEPARATOR = '## PRIVATE'
|
20
|
+
EVALUATION_SEPARATOR = '## EVALUATION'
|
21
|
+
DEFAULT_ISSUE_LABEL = 'default_issue'
|
22
|
+
|
23
|
+
def token_validator
|
24
|
+
->(token) {
|
25
|
+
@client = Octokit::Client.new(access_token: token)
|
26
|
+
@client.user rescue false
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
def origin_validator
|
31
|
+
->(repo) {
|
32
|
+
return false if repo !~ /\w+\/\w+/
|
33
|
+
github.repo(repo) rescue false
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
def target_validator
|
38
|
+
->(target) { target != config.origin_repo }
|
39
|
+
end
|
40
|
+
|
41
|
+
def local_origin_validator
|
42
|
+
->(path) { File.directory?(File.expand_path(path)) }
|
43
|
+
end
|
44
|
+
|
45
|
+
def config
|
46
|
+
@config ||= ZdHire::Config.new
|
47
|
+
end
|
48
|
+
|
49
|
+
def github
|
50
|
+
@client ||= Octokit::Client.new(access_token: config.github_token)
|
51
|
+
end
|
52
|
+
|
53
|
+
command :init do |c|
|
54
|
+
c.syntax = 'zd_hire init'
|
55
|
+
c.description = 'Configures ZdHire'
|
56
|
+
c.action do |args, options|
|
57
|
+
if config.valid?
|
58
|
+
say "Current Configuration: #{config.attributes}"
|
59
|
+
if agree('Would you like to exit initialization?(y/n) ', true)
|
60
|
+
exit
|
61
|
+
end
|
62
|
+
end
|
63
|
+
say 'Initializing Configuration'
|
64
|
+
|
65
|
+
if agree('Would you like to create a new Github access token?(y/n) ', true)
|
66
|
+
system "open https://github.com/settings/tokens"
|
67
|
+
end
|
68
|
+
|
69
|
+
config.github_token = ask("Github access token(needs repo, read:org and read:user scopes): ") do |q|
|
70
|
+
q.validate = token_validator
|
71
|
+
q.responses.merge!(not_valid: "Couldn't connect to github with token. Try again.")
|
72
|
+
end
|
73
|
+
|
74
|
+
config.origin_repo = ask("Origin Github Repository(username/repo): ") do |q|
|
75
|
+
q.validate = origin_validator
|
76
|
+
q.responses.merge!(not_valid: "Couldn't retrieve repository with credentials. Use the format 'username/repo'")
|
77
|
+
end
|
78
|
+
|
79
|
+
config.local_path = ask("Local repository path: ") do |q|
|
80
|
+
q.validate = local_origin_validator
|
81
|
+
q.responses.merge!(not_valid: "Couldn't find repo path in local filesystem. E.g (~/Code/myrepo)")
|
82
|
+
end
|
83
|
+
|
84
|
+
config.branch = ask("Default branch to export: ") { |q| q.default = 'master' }
|
85
|
+
config.serialize_to_file
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
command :clone do |c|
|
90
|
+
c.action do |args, options|
|
91
|
+
if config.valid?
|
92
|
+
target = ask(QUESTIONS[:target_repo]) do |q|
|
93
|
+
q.validate = target_validator
|
94
|
+
q.responses.merge!(not_valid: "Target and origin repositories can't be the same")
|
95
|
+
end
|
96
|
+
clone_repository(config.origin_repo, target)
|
97
|
+
else
|
98
|
+
say 'Run `zd_hire init` to configure github keys'
|
99
|
+
end
|
100
|
+
if agree('Would you like to create a Github Project?(y/n) ', true)
|
101
|
+
create_project(target)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def origin_default_issue
|
107
|
+
@df ||= origin_repo_issues.detect{|issue| issue.labels.any?{ |l| l.name == DEFAULT_ISSUE_LABEL} }
|
108
|
+
end
|
109
|
+
|
110
|
+
def evaluation_items(issue)
|
111
|
+
return [] unless issue
|
112
|
+
evaluation_text = issue.body.split(EVALUATION_SEPARATOR).last
|
113
|
+
evaluation_items = evaluation_text.lines.map(&:chomp)
|
114
|
+
evaluation_items.delete('')
|
115
|
+
evaluation_items
|
116
|
+
end
|
117
|
+
|
118
|
+
def evaluation_item_report(issue)
|
119
|
+
default_items = evaluation_items(origin_default_issue)
|
120
|
+
issue_type = issue.title.match(/\[(\w+)\]/)[1] rescue issue.number
|
121
|
+
issue_items = evaluation_items(issue)
|
122
|
+
(issue_items + default_items).compact.map { |item| [issue_type, item].join(', ') }
|
123
|
+
end
|
124
|
+
|
125
|
+
def presentable_issues
|
126
|
+
@presentable ||= origin_repo_issues.reject do |issue|
|
127
|
+
issue.number.to_i == origin_default_issue&.number&.to_i
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def origin_repo_issues(options = {})
|
132
|
+
@rp ||= github.issues(config.origin_repo, options).reject(&:pull_request)
|
133
|
+
end
|
134
|
+
|
135
|
+
def copy_and_report_issues(target)
|
136
|
+
issues = presentable_issues
|
137
|
+
issues.each { |i| say "#{i.number}: #{i.title}" }
|
138
|
+
issue_ids = ask('Type Issue IDs separated by spaces: ', Array).map(&:to_i)
|
139
|
+
selected_issues = issues.select do |issue|
|
140
|
+
issue_ids.include?(issue.number.to_i)
|
141
|
+
end
|
142
|
+
selected_issues.each { |issue| copy_issue(target, issue) }
|
143
|
+
selected_issues.each { |issue| puts evaluation_item_report(issue) }
|
144
|
+
end
|
145
|
+
|
146
|
+
def copy_issue(target, issue)
|
147
|
+
public_body, private_section = issue.body.split(PRIVATE_SECTION_SEPARATOR)
|
148
|
+
unless private_section
|
149
|
+
unless agree("[issue #{issue.number}] Could not identify a private section. Issue may be malformatted. Want to copy anyway?(y/n) ", true)
|
150
|
+
return
|
151
|
+
end
|
152
|
+
end
|
153
|
+
github.create_issue(target, issue.title, public_body)
|
154
|
+
end
|
155
|
+
|
156
|
+
def clone_repository(origin, target)
|
157
|
+
system(
|
158
|
+
[
|
159
|
+
"git clone --depth 1 -b master git@github.com:#{origin}.git #{target}",
|
160
|
+
"cd #{target}",
|
161
|
+
'rm -rf .git'
|
162
|
+
].join(' && ')
|
163
|
+
)
|
164
|
+
end
|
165
|
+
|
166
|
+
def setup_remote(target_dir, remote_repo)
|
167
|
+
system(
|
168
|
+
[
|
169
|
+
"cd #{target_dir}",
|
170
|
+
'git init',
|
171
|
+
'git add .',
|
172
|
+
'git commit -m "first commit"',
|
173
|
+
"git remote add origin #{remote_repo.ssh_url}",
|
174
|
+
'git push -u origin master'
|
175
|
+
].join(' && ')
|
176
|
+
)
|
177
|
+
end
|
178
|
+
|
179
|
+
def create_project(target)
|
180
|
+
user = github.user.login
|
181
|
+
organization = choose("Which Github Organization? \n") do |menu|
|
182
|
+
menu.choices(*([user] + github.organizations.map(&:login)))
|
183
|
+
menu.default = user
|
184
|
+
end
|
185
|
+
project_name = ask('Project name? ') {|q| q.default = target }
|
186
|
+
attrs = repo_attributes
|
187
|
+
attrs[:organization] = organization unless user == organization
|
188
|
+
attrs[:private] = agree('Private repository?(y/n) ', true)
|
189
|
+
|
190
|
+
begin
|
191
|
+
new_repo = github.create_repository(project_name, attrs)
|
192
|
+
|
193
|
+
if agree("Would you like setup the local repo?(y/n) ", true)
|
194
|
+
setup_remote(target, new_repo)
|
195
|
+
end
|
196
|
+
|
197
|
+
if agree("Would you like to select issues to copy(y/n) ", true)
|
198
|
+
copy_and_report_issues(new_repo.full_name)
|
199
|
+
end
|
200
|
+
|
201
|
+
if agree('Would you like to open the project in your browser?(y/n) ', true)
|
202
|
+
system "open #{new_repo.html_url}"
|
203
|
+
end
|
204
|
+
rescue => e
|
205
|
+
say "The repository could not be created: #{e.message}"
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
def repo_attributes
|
210
|
+
{
|
211
|
+
has_issues: true,
|
212
|
+
has_wiki: false
|
213
|
+
}
|
214
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
module ZdHire
|
5
|
+
class Config
|
6
|
+
attr_accessor :github_token, :origin_repo, :local_path, :branch
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
if File.exist?(config_file)
|
10
|
+
begin
|
11
|
+
deserialize_from_file
|
12
|
+
rescue
|
13
|
+
FileUtils.rm(config_file)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def config_file
|
19
|
+
@config_file ||= File.join(File.expand_path('~'), '.zd_hire')
|
20
|
+
end
|
21
|
+
|
22
|
+
def deserialize_from_file
|
23
|
+
self.attributes = YAML.load_file(config_file)
|
24
|
+
end
|
25
|
+
|
26
|
+
def serialize_to_file
|
27
|
+
File.write(config_file, attributes.to_yaml)
|
28
|
+
end
|
29
|
+
|
30
|
+
def attributes
|
31
|
+
{
|
32
|
+
github_token: github_token,
|
33
|
+
origin_repo: origin_repo,
|
34
|
+
local_path: local_path,
|
35
|
+
branch: branch,
|
36
|
+
}
|
37
|
+
end
|
38
|
+
|
39
|
+
def valid?
|
40
|
+
attributes.values.none?(&:nil?)
|
41
|
+
end
|
42
|
+
|
43
|
+
def attributes=(options)
|
44
|
+
self.github_token = options[:github_token]
|
45
|
+
self.origin_repo = options[:origin_repo]
|
46
|
+
self.local_path = options[:local_path]
|
47
|
+
self.branch = options[:branch]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/lib/zd_hire.rb
ADDED
data/zd_hire.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'zd_hire/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "zd_hire"
|
8
|
+
spec.version = ZdHire::VERSION
|
9
|
+
spec.authors = ["Alexandre Angelim"]
|
10
|
+
spec.email = ["angelim@angelim.com.br"]
|
11
|
+
|
12
|
+
spec.summary = %q{Code Challenges made easy}
|
13
|
+
spec.description = %q{Recruit using Gitub}
|
14
|
+
spec.homepage = "http://github.com/angelim/zd_hire"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
17
|
+
spec.bindir = "bin"
|
18
|
+
spec.executables = ["zd_hire"]
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_runtime_dependency 'commander', '~> 4.4', '>= 4.4.3'
|
22
|
+
spec.add_runtime_dependency 'octokit', '~> 4.9', '>= 4.9.0'
|
23
|
+
|
24
|
+
spec.add_development_dependency "bundler", "~> 1.12"
|
25
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
26
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
27
|
+
end
|
metadata
ADDED
@@ -0,0 +1,139 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: zd_hire
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Alexandre Angelim
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-06-16 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: commander
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '4.4'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 4.4.3
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '4.4'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 4.4.3
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: octokit
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '4.9'
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: 4.9.0
|
43
|
+
type: :runtime
|
44
|
+
prerelease: false
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - "~>"
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '4.9'
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: 4.9.0
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: bundler
|
55
|
+
requirement: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - "~>"
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '1.12'
|
60
|
+
type: :development
|
61
|
+
prerelease: false
|
62
|
+
version_requirements: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - "~>"
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '1.12'
|
67
|
+
- !ruby/object:Gem::Dependency
|
68
|
+
name: rake
|
69
|
+
requirement: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - "~>"
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '10.0'
|
74
|
+
type: :development
|
75
|
+
prerelease: false
|
76
|
+
version_requirements: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - "~>"
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '10.0'
|
81
|
+
- !ruby/object:Gem::Dependency
|
82
|
+
name: rspec
|
83
|
+
requirement: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - "~>"
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '3.0'
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - "~>"
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '3.0'
|
95
|
+
description: Recruit using Gitub
|
96
|
+
email:
|
97
|
+
- angelim@angelim.com.br
|
98
|
+
executables:
|
99
|
+
- zd_hire
|
100
|
+
extensions: []
|
101
|
+
extra_rdoc_files: []
|
102
|
+
files:
|
103
|
+
- ".gitignore"
|
104
|
+
- ".rspec"
|
105
|
+
- ".travis.yml"
|
106
|
+
- Gemfile
|
107
|
+
- README.md
|
108
|
+
- Rakefile
|
109
|
+
- bin/console
|
110
|
+
- bin/setup
|
111
|
+
- bin/zd_hire
|
112
|
+
- lib/zd_hire.rb
|
113
|
+
- lib/zd_hire/config.rb
|
114
|
+
- lib/zd_hire/version.rb
|
115
|
+
- zd_hire.gemspec
|
116
|
+
homepage: http://github.com/angelim/zd_hire
|
117
|
+
licenses: []
|
118
|
+
metadata: {}
|
119
|
+
post_install_message:
|
120
|
+
rdoc_options: []
|
121
|
+
require_paths:
|
122
|
+
- lib
|
123
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
124
|
+
requirements:
|
125
|
+
- - ">="
|
126
|
+
- !ruby/object:Gem::Version
|
127
|
+
version: '0'
|
128
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
129
|
+
requirements:
|
130
|
+
- - ">="
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: '0'
|
133
|
+
requirements: []
|
134
|
+
rubyforge_project:
|
135
|
+
rubygems_version: 2.5.2.1
|
136
|
+
signing_key:
|
137
|
+
specification_version: 4
|
138
|
+
summary: Code Challenges made easy
|
139
|
+
test_files: []
|