tworingtools 4.7.0 → 5.0.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.
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