gh-pr-backport 0.1.0.alpha2 → 0.1.0.alpha3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/exe/gh-pr-backport-at-once +6 -0
- data/lib/gh_pr_backport.rb +2 -0
- data/lib/gh_pr_backport/at_once_backporter.rb +94 -0
- data/lib/gh_pr_backport/backporter.rb +2 -21
- data/lib/gh_pr_backport/common.rb +25 -0
- data/lib/gh_pr_backport/version.rb +1 -1
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3fd9ac1d7f61467e3a140371a8ccf44623c929458e5e81653131ecbff31dc12d
|
4
|
+
data.tar.gz: f40d8da0820b9c29eb1e393c17a5a7a7f4ba00eb69fad170e16ffb3e633285f0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5c6feefcaedf0e35e70fc0995553342b980c6e3128c3c7140adc62eb824773e8c7e47d3bfb28d54b8c8ff19c3adeb2cf40caef663025da54558de161a76a5d7e
|
7
|
+
data.tar.gz: 5bbda3418e08593d87ee9c1d21106140f0158af05c182159233f26edf5c4e0aa94d4d1ade4a1d5b767a800c07078fd60f00a98b71cecbfc9d5059ae14f2f6642
|
data/Gemfile.lock
CHANGED
data/lib/gh_pr_backport.rb
CHANGED
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'octokit'
|
2
|
+
|
3
|
+
module GhPrBackport
|
4
|
+
class AtOnceBackporter
|
5
|
+
include GhPrBackport::Common
|
6
|
+
|
7
|
+
def run
|
8
|
+
raise GhPrBackport::DirectoryIsMessy unless clean?
|
9
|
+
create_todo_file
|
10
|
+
open_editor
|
11
|
+
run_todos_from_file
|
12
|
+
end
|
13
|
+
|
14
|
+
def open_editor
|
15
|
+
unless system("#{optional_str ENV['EDITOR'], 'vim'} #{todo_file}")
|
16
|
+
raise 'Editor returned non-zero exit status.'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def run_todos_from_file
|
21
|
+
todo_commits = read_todo_file
|
22
|
+
if todo_commits.empty?
|
23
|
+
puts 'Nothing to do.'
|
24
|
+
return
|
25
|
+
end
|
26
|
+
system("git cherry-pick -m 1 -x #{todo_commits.join(' ')}")
|
27
|
+
end
|
28
|
+
|
29
|
+
def list_todo_prs
|
30
|
+
picked_pr_numbers = list_picked_prs.map { |commit| commit[:pr_number] }.to_set
|
31
|
+
list_merged_prs.select { |commit| !picked_pr_numbers.include?(commit[:pr_number]) }
|
32
|
+
end
|
33
|
+
|
34
|
+
def list_merged_prs
|
35
|
+
parse_log_stream(`git log --merges #{log_format_option} HEAD..origin/HEAD`)
|
36
|
+
.select { |commit| commit[:pr_number] }
|
37
|
+
end
|
38
|
+
|
39
|
+
def list_picked_prs
|
40
|
+
parse_log_stream(`git log #{log_format_option} origin/HEAD..HEAD`)
|
41
|
+
.select { |commit| commit[:pr_number] }
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def git_dir
|
47
|
+
optional_str ENV['GIT_DIR'], '.git'
|
48
|
+
end
|
49
|
+
|
50
|
+
def todo_file
|
51
|
+
File.join(git_dir, '.git-pr-backport-todo')
|
52
|
+
end
|
53
|
+
|
54
|
+
def read_todo_file
|
55
|
+
File.readlines(todo_file)
|
56
|
+
.map(&:strip)
|
57
|
+
.reject { |line| line == '' || line.start_with?('#') }
|
58
|
+
.each_with_index { |line, i| raise "Parse error in line #{i + 1}: #{line}" unless line =~ /^[0-9A-Za-z]+(?:\s|\z)/ }
|
59
|
+
.map { |line| line.split(/\s+/, 2)[0] }
|
60
|
+
end
|
61
|
+
|
62
|
+
def create_todo_file
|
63
|
+
File.write(todo_file, list_todo_prs.map do |commit|
|
64
|
+
"# #{commit[:hash][0..7]} ##{commit[:pr_number]} #{commit[:body].lines[0]} (#{pr_to_link(commit)})"
|
65
|
+
end.join("\n"))
|
66
|
+
end
|
67
|
+
|
68
|
+
def pr_to_link(commit)
|
69
|
+
"#{repo.url}/pull/#{commit[:pr_number]}"
|
70
|
+
end
|
71
|
+
|
72
|
+
def log_format_option
|
73
|
+
# null terminated
|
74
|
+
'--format=format:%H%n%B%x00'
|
75
|
+
end
|
76
|
+
|
77
|
+
def parse_log_stream(stream)
|
78
|
+
stream
|
79
|
+
.split("\0\n")
|
80
|
+
.map { |commit_data| parse_commit_data(commit_data) }
|
81
|
+
.reverse
|
82
|
+
end
|
83
|
+
|
84
|
+
def parse_commit_data(commit_data)
|
85
|
+
hash, subject, body = commit_data.split("\n", 3).map(&:strip)
|
86
|
+
pr_number = subject.match(/\AMerge pull request #([1-9][0-9]*) from/)&.tap { |m| break m[1].to_i }
|
87
|
+
{ hash: hash, pr_number: pr_number, subject: subject, body: body || '' }
|
88
|
+
end
|
89
|
+
|
90
|
+
def optional_str(str, default)
|
91
|
+
str == '' ? default : str || default
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -1,10 +1,11 @@
|
|
1
1
|
require 'uri'
|
2
2
|
|
3
3
|
require 'hashie'
|
4
|
-
require 'octokit'
|
5
4
|
|
6
5
|
module GhPrBackport
|
7
6
|
class Backporter
|
7
|
+
include GhPrBackport::Common
|
8
|
+
|
8
9
|
def initialize(original_pr_number:, staging_branch: nil)
|
9
10
|
@client = client
|
10
11
|
@repo = repo
|
@@ -39,16 +40,6 @@ module GhPrBackport
|
|
39
40
|
end
|
40
41
|
end
|
41
42
|
|
42
|
-
def client
|
43
|
-
client = Octokit::Client.new(access_token: `git config backport.token`.chomp)
|
44
|
-
client.scopes # Validate token. If the token is invalid, then raise an error.
|
45
|
-
client
|
46
|
-
end
|
47
|
-
|
48
|
-
def clean?
|
49
|
-
`git status --porcelain`.chomp.empty?
|
50
|
-
end
|
51
|
-
|
52
43
|
def create_backport_pull_request
|
53
44
|
body = "##{@original.number} のバックポートです\r\n\r\n" +
|
54
45
|
@original.body.lines.map { |l| "> #{l}" }.join
|
@@ -87,16 +78,6 @@ module GhPrBackport
|
|
87
78
|
`git config -f #{path}/.git-pr-release pr-release.branch.staging`.chomp
|
88
79
|
end
|
89
80
|
|
90
|
-
def repo
|
91
|
-
remote = `git config remote.origin.url`.chomp
|
92
|
-
repo_name = if remote.start_with?('git@github.com:')
|
93
|
-
remote.split(':', 2)[1].sub(/.git$/, '')
|
94
|
-
else
|
95
|
-
URI.parse(remote).path.sub(%r{^\/}, '').sub(/.git$/, '')
|
96
|
-
end
|
97
|
-
Octokit::Repository.new(repo_name)
|
98
|
-
end
|
99
|
-
|
100
81
|
def system!(program, *args, error_class)
|
101
82
|
raise error_class unless system(program, *args)
|
102
83
|
true
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'octokit'
|
2
|
+
|
3
|
+
module GhPrBackport
|
4
|
+
module Common
|
5
|
+
def client
|
6
|
+
client = Octokit::Client.new(access_token: `git config backport.token`.chomp)
|
7
|
+
client.scopes # Validate token. If the token is invalid, then raise an error.
|
8
|
+
client
|
9
|
+
end
|
10
|
+
|
11
|
+
def clean?
|
12
|
+
`git status --porcelain`.chomp.empty?
|
13
|
+
end
|
14
|
+
|
15
|
+
def repo
|
16
|
+
remote = `git config remote.origin.url`.chomp
|
17
|
+
repo_name = if remote.start_with?('git@github.com:')
|
18
|
+
remote.split(':', 2)[1].sub(/.git$/, '')
|
19
|
+
else
|
20
|
+
URI.parse(remote).path.sub(%r{^\/}, '').sub(/.git$/, '')
|
21
|
+
end
|
22
|
+
Octokit::Repository.new(repo_name)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gh-pr-backport
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.0.
|
4
|
+
version: 0.1.0.alpha3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Takeru Naito
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-04-
|
11
|
+
date: 2018-04-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -111,6 +111,7 @@ email:
|
|
111
111
|
- takeru.naito@gmail.com
|
112
112
|
executables:
|
113
113
|
- gh-pr-backport
|
114
|
+
- gh-pr-backport-at-once
|
114
115
|
extensions: []
|
115
116
|
extra_rdoc_files: []
|
116
117
|
files:
|
@@ -127,9 +128,12 @@ files:
|
|
127
128
|
- bin/console
|
128
129
|
- bin/setup
|
129
130
|
- exe/gh-pr-backport
|
131
|
+
- exe/gh-pr-backport-at-once
|
130
132
|
- gh-pr-backport.gemspec
|
131
133
|
- lib/gh_pr_backport.rb
|
134
|
+
- lib/gh_pr_backport/at_once_backporter.rb
|
132
135
|
- lib/gh_pr_backport/backporter.rb
|
136
|
+
- lib/gh_pr_backport/common.rb
|
133
137
|
- lib/gh_pr_backport/version.rb
|
134
138
|
homepage: https://github.com/elim/gh-pr-backport
|
135
139
|
licenses:
|