tworingtools 4.7.0 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. checksums.yaml +4 -4
  2. data/bin/sync-git +109 -0
  3. data/lib/git_helpers.rb +77 -0
  4. metadata +8 -7
  5. data/bin/sync-forks +0 -90
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ab98c6a76083beb69e5321318a516f318c978c52fae24bf2cb1a7c4ff0f0da56
4
- data.tar.gz: 3e4b33808f476411d426dcc5c01f5cb43769384128f7631b295e0713eccb6626
3
+ metadata.gz: 8a9c273d420e81312cd78a3cfb16705daa66c66cb88333b028a99aeead328b57
4
+ data.tar.gz: bf970bd1d1613d2667f7d5279ec35c5d1bc0ea68b51d07d80bb4246491706320
5
5
  SHA512:
6
- metadata.gz: c88c9a7ff566bdef41e3201b0871466a760fff3f9faf48c1133fda4a136ba1758bb87cbfa0a955380b4e9c90bc3b8fad2a5c95570c774146436fce7d5885bdcb
7
- data.tar.gz: ccec1349aa05d908361c0d35d64b1546748f3d089529a191348c8424facd1e25180adf826bbabfa86d959a377e907e126d692d8c5a0a17dfdd37fceaad4985c8
6
+ metadata.gz: e1acd45a72627aa1c61876360907b65715d55afe06c4c398d711476bc06e79baeb806475c1b46e739cecb57f5a13014273f423ff1d3b0d009987dc5e97143dfd
7
+ data.tar.gz: 6160816443577623849b42d6cd0972b6314dc523bbcdc2295d9501c4d80f6bc1e124831f9aad4d61d27f81dcda68b8bae358869d50f1d4479d06aeedcbc1bb91
data/bin/sync-git ADDED
@@ -0,0 +1,109 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ require 'octokit'
4
+ require 'json'
5
+ require 'optparse'
6
+ require_relative '../lib/echoexec'
7
+ require_relative '../lib/git_helpers'
8
+
9
+ # failure modes
10
+ FURTHER_REQUESTS_REQUIRE_TOKEN = 65
11
+ MISSING_REQUIRED_CREDENTIALS = 66
12
+
13
+ options = {}
14
+ parser = OptionParser.new do |opts|
15
+ opts.banner = <<~BANNER
16
+
17
+ Usage: sync-git [options] <directory>
18
+
19
+ For each of your GitHub forks, clone your forked version, then go in and add a remote
20
+ to the upstream version, and set up local tracking branches for both remotes' default
21
+ branches. Then fast-forward them both, fetch all tags etc.
22
+
23
+ <directory> is the path containing the directories holding your forks, and/or
24
+ to where those you don't yet have should be cloned.
25
+
26
+ Examples:
27
+
28
+ sync-git -u/--username <user> -p/--password <pass> [-o/--one-time-pw <otp>] .
29
+ sync-git -u/--username <user> -t/--token <token> .
30
+ sync-git -u/--username <user> -t/--token -n/--repo-name that-one-repo-I-forked <token> .
31
+
32
+ If you already have a Personal Access Token, provide it in the second form.
33
+ Otherwise, use the first form, which will register a new token for you named
34
+ “sync-git”. Then use that to invoke the program again. This is because
35
+ requests using basic authentication (user/pass) are too rate limited.
36
+
37
+ Options:
38
+
39
+ BANNER
40
+
41
+ opts.on('-uUSERNAME', '--username=USERNAME', 'GitHub username. Required for all invocations.') do |user| options[:username] = user end
42
+ opts.on('-tTOKEN', '--token=TOKEN', 'GitHub personal access token. The primary way to use this program.') do |t| options[:token] = t end
43
+ opts.on('-pPASSWORD', '--password=PASSWORD', 'GitHub password.') do |pass| options[:password] = pass end
44
+ opts.on('-oOTP', '--one-time-pw=OTP', 'GitHub 2FA token, if you have it enabled.') do |otp| options[:otp] = otp end
45
+ opts.on('-rREPO', '--repo-name=REPO', 'The name of a particular repository to sync.') do |repo| options[:repo] = repo end
46
+ opts.on('-v', '--verbose', 'Enable verbose logging.') do options[:verbose] = true end
47
+ end
48
+ parser.parse!
49
+ root_dir_path = ARGV[0]
50
+
51
+ # authenticate the github client, producing a token for callers to use if they try with user/pass, as that is rate limited
52
+ github = nil
53
+ if nil != options[:token] then
54
+ github = Octokit::Client.new(:access_token => options[:token])
55
+ puts 'Running with provided token...'
56
+ elsif nil != options[:username] && nil != options[:password]
57
+ github = Octokit::Client.new \
58
+ :login => options[:username],
59
+ :password => options[:password]
60
+
61
+ headers = Hash.new
62
+ if nil != options[:otp] then
63
+ headers['X-GitHub-OTP'] = options[:otp]
64
+ end
65
+
66
+ token = github.create_authorization \
67
+ :scopes => ["user"],
68
+ :note => "sync-git",
69
+ :headers => headers
70
+
71
+ puts "Created new token, use it to call sync-git again:"
72
+ puts
73
+ puts "\tsync-git -u #{user} -t #{token.token}"
74
+ puts
75
+ exit FURTHER_REQUESTS_REQUIRE_TOKEN
76
+ else
77
+ puts "Must provide either a username/token or username/password/otp combination to authenticate."
78
+ puts parser
79
+ exit MISSING_REQUIRED_CREDENTIALS
80
+ end
81
+
82
+ github.auto_paginate = true
83
+
84
+ repos = github.repos
85
+
86
+ # sync owned repos
87
+ owned_repos = repos.select {|x| !x.fork}
88
+ if options[:repo] != nil then
89
+ owned_repos.select! {|x| x.name == options[:repo]}
90
+ end
91
+ owned_repos.each do |owned_repo|
92
+ puts '---'
93
+ owned_repo_info = github.repo(owned_repo.id)
94
+ sync_repo(owned_repo_info, root_dir_path)
95
+ end
96
+
97
+ # get the list of forks to sync
98
+ forks = repos.select {|x| x.fork}
99
+ if options[:repo] != nil then
100
+ forks.select! {|x| x.name == options[:repo]}
101
+ end
102
+
103
+ # sync the forks
104
+ forks.each do |forked_repo|
105
+ puts '---'
106
+
107
+ forked_repo_info = github.repo(forked_repo.id)
108
+ sync_fork(forked_repo_info, root_dir_path)
109
+ end
@@ -0,0 +1,77 @@
1
+ require 'octokit'
2
+ require_relative 'echoexec'
3
+
4
+ def sync_repo repo_info, root_dir_path
5
+ name = repo_info.name
6
+ ssh_url = repo_info.ssh_url
7
+
8
+ path = "#{root_dir_path}/#{name}"
9
+ already_cloned = Dir.exist?(path)
10
+
11
+ # clone any forks not already cloned
12
+ unless already_cloned then
13
+ echo_and_exec "git clone #{ssh_url} #{path}"
14
+ end
15
+
16
+ # for repos that were cloned previously, update them by fast-forwarding the default branch and fetch all tags
17
+ if already_cloned then
18
+ Dir.chdir path do
19
+ echo_and_exec "git fetch && git fetch --tags && git pull --ff-only"
20
+ end
21
+ end
22
+ end
23
+
24
+
25
+ def sync_fork forked_repo_info, root_dir_path
26
+ upstream_ssh_url = forked_repo_info.source.ssh_url
27
+ original_owner = forked_repo_info.source.owner.login
28
+ name = forked_repo_info.name
29
+ fork_ssh_url = forked_repo_info.ssh_url
30
+
31
+ upstream_remote_name = 'upstream'
32
+ fork_remote_name = 'fork'
33
+ path = "#{root_dir_path}/_Forks/#{original_owner}/#{name}"
34
+ already_cloned = Dir.exist?(path)
35
+
36
+ # clone any forks not already cloned
37
+ unless already_cloned then
38
+ echo_and_exec "git clone #{fork_ssh_url} #{path}"
39
+ end
40
+
41
+ Dir.chdir path do
42
+ # if we just cloned the repo locally, set up both remotes
43
+ unless already_cloned then
44
+ echo_and_exec "git remote add #{upstream_remote_name} #{upstream_ssh_url}"
45
+ echo_and_exec "git remote rename origin #{fork_remote_name}"
46
+ end
47
+
48
+ # get the names of the default branches
49
+ fork_default_branch_name = `git remote show #{fork_remote_name} | grep "HEAD branch" | cut -d ":" -f 2`.strip
50
+ fork_default_local_branch_name = "#{fork_remote_name}_#{fork_default_branch_name}"
51
+ upstream_default_branch_name = `git remote show #{upstream_remote_name} | grep "HEAD branch" | cut -d ":" -f 2`.strip
52
+ upstream_default_local_branch_name = "#{upstream_remote_name}_#{upstream_default_branch_name}"
53
+
54
+ # if we just cloned the repo locally, set local default tracking branches
55
+ unless already_cloned then
56
+ # rename the cloned local default branch to reflect that it's tracking the fork remote's version
57
+ echo_and_exec "git branch -m #{fork_default_branch_name} #{fork_default_local_branch_name}"
58
+
59
+ # set up a local branch to track the upstream remote's default branch
60
+ echo_and_exec "git fetch #{upstream_remote_name}"
61
+ echo_and_exec "git checkout -b #{upstream_default_local_branch_name} #{upstream_remote_name}/#{upstream_default_branch_name}"
62
+
63
+ # push the local upstream default tracking branch to the fork's remote, so it also has a copy alongside it's default branch
64
+ echo_and_exec "git push #{fork_remote_name} HEAD:#{upstream_default_local_branch_name}"
65
+ end
66
+
67
+ # for repos that were cloned previously, update them by fast-forwarding both default branches and fetch all tags
68
+ if already_cloned then
69
+ echo_and_exec "git checkout #{fork_default_local_branch_name}"
70
+ echo_and_exec "git pull --ff-only #{fork_remote_name}"
71
+ echo_and_exec "git fetch --tags #{fork_remote_name}"
72
+
73
+ echo_and_exec "git checkout #{upstream_default_local_branch_name}"
74
+ echo_and_exec "git pull --ff-only #{upstream_remote_name}"
75
+ end
76
+ end
77
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tworingtools
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.7.0
4
+ version: 5.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew McKnight
@@ -11,19 +11,19 @@ cert_chain: []
11
11
  date: 2020-08-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: github_api
14
+ name: octokit
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0.19'
19
+ version: 4.20.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '0.19'
26
+ version: 4.20.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: json
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -40,7 +40,7 @@ dependencies:
40
40
  version: '2.1'
41
41
  description: |2
42
42
  - xcsims: Delete all simulators and recreate one for each compatible platform and device type pairing.
43
- - sync-forks: Make sure all your GitHub forks are clones into a given directory, and have upstream remotes pointing to the repos that were forked.
43
+ - sync-git: Make sure all your GitHub repos are cloned into a given directory and keep them synced with upstream. Forks are maintained with a remote for both the fork and upstream, both remotes' default branches are tracked in local counterparts, and the upstream default branch is also pushed to the fork.
44
44
  - changetag: Extract changelog entries to write into git tag annotation messages.
45
45
  - prerelease-podspec: Branch and create/push a release candidate tag, modify the podspec to use that version tag, and try linting it.
46
46
  - release-podspec: Create a tag with the version and push it to repo origin, push podspec to CocoaPods trunk.
@@ -52,7 +52,7 @@ email: andrew@tworingsoft.com
52
52
  executables:
53
53
  - clean-rc-tags
54
54
  - xcsims
55
- - sync-forks
55
+ - sync-git
56
56
  - changetag
57
57
  - prerelease-podspec
58
58
  - release-podspec
@@ -69,11 +69,12 @@ files:
69
69
  - bin/prerelease-podspec
70
70
  - bin/release-podspec
71
71
  - bin/revert-failed-release-tag
72
- - bin/sync-forks
72
+ - bin/sync-git
73
73
  - bin/xcsims
74
74
  - lib/echoexec.rb
75
75
  - lib/errors.rb
76
76
  - lib/git_check.rb
77
+ - lib/git_helpers.rb
77
78
  homepage: https://github.com/TwoRingSoft/tools
78
79
  licenses:
79
80
  - MIT
data/bin/sync-forks DELETED
@@ -1,90 +0,0 @@
1
- #! /usr/bin/env ruby
2
-
3
- require 'github_api'
4
- require 'json'
5
- require 'optparse'
6
- require_relative '../lib/echoexec'
7
-
8
- # failure modes
9
- FURTHER_REQUESTS_REQUIRE_TOKEN = 65
10
- MISSING_REQUIRED_CREDENTIALS = 66
11
-
12
- options = {}
13
- parser = OptionParser.new do |opts|
14
- opts.banner = <<~BANNER
15
-
16
- Usage: sync-forks [options] <directory>
17
-
18
- <directory> is the path containing the directories holding your forks, and/or
19
- to where those you don't yet have should be cloned.
20
-
21
- Examples:
22
-
23
- sync-forks -u/--username <user> -p/--password <pass> [-o/--one-time-pw <otp>] .
24
- sync-forks -u/--username <user> -t/--token <token> .
25
- sync-forks -u/--username <user> -t/--token -n/--repo-name that-one-repo-I-forked <token> .
26
-
27
- If you already have a Personal Access Token, provide it in the second form.
28
- Otherwise, use the first form, which will register a new token for you named
29
- “sync-forks”. Then use that to invoke the program again. This is because
30
- requests using basic authentication (user/pass) are too rate limited.
31
-
32
- Options:
33
-
34
- BANNER
35
-
36
- opts.on('-uUSERNAME', '--username=USERNAME', 'GitHub username. Required for all invocations.') do |user| options[:username] = user end
37
- opts.on('-tTOKEN', '--token=TOKEN', 'GitHub personal access token. The primary way to use this program.') do |t| options[:token] = t end
38
- opts.on('-pPASSWORD', '--password=PASSWORD', 'GitHub password.') do |pass| options[:password] = pass end
39
- opts.on('-oOTP', '--one-time-pw=OTP', 'GitHub 2FA token, if you have it enabled.') do |otp| options[:otp] = otp end
40
- opts.on('-rREPO', '--repo-name=REPO', 'The name of a particular repository to sync.') do |repo| options[:repo] = repo end
41
- end
42
- parser.parse!
43
-
44
- github = nil
45
- if nil != options[:token] && nil != options[:username] then
46
- github = Github.new oauth_token: options[:token]
47
- elsif nil != options[:username] && nil != options[:password]
48
- github = Github.new do |config|
49
- config.basic_auth = "#{options[:username]}:#{options[:password]}"
50
- if nil != options[:otp] then
51
- config.connection_options = {headers: {"X-GitHub-OTP" => options[:otp]}}
52
- end
53
- end
54
- token = github.auth.create scopes: ['repo'], note: 'sync-forks3'
55
- puts "Created new token, use it to call sync-forks again:"
56
- puts
57
- puts "\tsync-forks -u #{user} -t #{token.token}"
58
- puts
59
- exit FURTHER_REQUESTS_REQUIRE_TOKEN
60
- else
61
- puts "Must provide either a username/token or username/password/otp combination to authenticate."
62
- puts parser
63
- exit MISSING_REQUIRED_CREDENTIALS
64
- end
65
-
66
- repos = github.repos.list user: options[:username], auto_pagination: true
67
- forks = repos.select {|x| x.fork}
68
-
69
- if options[:repo] != nil then
70
- forks.select! {|x| x.name == options[:repo]}
71
- end
72
-
73
- current_dir = Dir.new(ARGV[0])
74
- Dir.chdir current_dir
75
- forks.each do |forked|
76
- info = github.repos(user: options[:username], repo: forked.name).get
77
- fork_url = info.source.ssh_url
78
- name = forked.name
79
- url = forked.ssh_url
80
-
81
- puts '---'
82
- if current_dir.entries.include? name then
83
- puts "#{name} already exists."
84
- else
85
- echo_and_exec "git clone #{url}"
86
- Dir.chdir "#{name}"
87
- echo_and_exec "git remote add upstream #{fork_url}"
88
- Dir.chdir ".."
89
- end
90
- end