modulesync 2.2.0 → 2.3.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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +18 -3
- data/.github/workflows/release.yml +2 -4
- data/.gitignore +1 -0
- data/.rubocop.yml +14 -8
- data/.rubocop_todo.yml +25 -17
- data/.simplecov +46 -0
- data/CHANGELOG.md +32 -0
- data/Gemfile +1 -1
- data/bin/msync +17 -1
- data/features/cli.feature +12 -6
- data/features/execute.feature +51 -0
- data/features/hook.feature +5 -8
- data/features/push.feature +46 -0
- data/features/reset.feature +57 -0
- data/features/step_definitions/git_steps.rb +29 -1
- data/features/support/env.rb +9 -0
- data/features/update/bump_version.feature +8 -12
- data/features/update/dot_sync.feature +52 -0
- data/features/update/pull_request.feature +180 -0
- data/features/update.feature +74 -103
- data/lib/modulesync/cli/thor.rb +12 -0
- data/lib/modulesync/cli.rb +122 -28
- data/lib/modulesync/git_service/base.rb +63 -0
- data/lib/modulesync/git_service/factory.rb +28 -0
- data/lib/modulesync/{pr → git_service}/github.rb +23 -21
- data/lib/modulesync/git_service/gitlab.rb +62 -0
- data/lib/modulesync/git_service.rb +96 -0
- data/lib/modulesync/hook.rb +11 -13
- data/lib/modulesync/renderer.rb +3 -6
- data/lib/modulesync/repository.rb +71 -25
- data/lib/modulesync/settings.rb +0 -1
- data/lib/modulesync/source_code.rb +28 -2
- data/lib/modulesync/util.rb +4 -4
- data/lib/modulesync.rb +104 -66
- data/modulesync.gemspec +7 -4
- data/spec/helpers/faker/puppet_module_remote_repo.rb +16 -1
- data/spec/spec_helper.rb +1 -23
- data/spec/unit/modulesync/git_service/factory_spec.rb +16 -0
- data/spec/unit/modulesync/git_service/github_spec.rb +81 -0
- data/spec/unit/modulesync/git_service/gitlab_spec.rb +90 -0
- data/spec/unit/modulesync/git_service_spec.rb +201 -0
- data/spec/unit/modulesync/source_code_spec.rb +22 -0
- data/spec/unit/modulesync_spec.rb +0 -12
- metadata +74 -12
- data/lib/modulesync/pr/gitlab.rb +0 -54
- data/spec/unit/modulesync/pr/github_spec.rb +0 -49
- data/spec/unit/modulesync/pr/gitlab_spec.rb +0 -81
data/lib/modulesync/cli.rb
CHANGED
@@ -7,31 +7,34 @@ require 'modulesync/util'
|
|
7
7
|
|
8
8
|
module ModuleSync
|
9
9
|
module CLI
|
10
|
+
def self.prepare_options(cli_options, **more_options)
|
11
|
+
options = CLI.defaults
|
12
|
+
options.merge! Util.symbolize_keys(cli_options)
|
13
|
+
options.merge! more_options
|
14
|
+
|
15
|
+
Util.symbolize_keys options
|
16
|
+
end
|
17
|
+
|
10
18
|
def self.defaults
|
11
19
|
@defaults ||= Util.symbolize_keys(Util.parse_config(Constants::MODULESYNC_CONF_FILE))
|
12
20
|
end
|
13
21
|
|
14
22
|
class Hook < Thor
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
+
option :hook_args,
|
24
|
+
:aliases => '-a',
|
25
|
+
:desc => 'Arguments to pass to msync in the git hook'
|
26
|
+
option :branch,
|
27
|
+
:aliases => '-b',
|
28
|
+
:desc => 'Branch name to pass to msync in the git hook',
|
29
|
+
:default => CLI.defaults[:branch]
|
23
30
|
desc 'activate', 'Activate the git hook.'
|
24
31
|
def activate
|
25
|
-
|
26
|
-
config[:hook] = 'activate'
|
27
|
-
ModuleSync.hook(config)
|
32
|
+
ModuleSync.hook CLI.prepare_options(options, hook: 'activate')
|
28
33
|
end
|
29
34
|
|
30
35
|
desc 'deactivate', 'Deactivate the git hook.'
|
31
36
|
def deactivate
|
32
|
-
|
33
|
-
config[:hook] = 'deactivate'
|
34
|
-
ModuleSync.hook(config)
|
37
|
+
ModuleSync.hook CLI.prepare_options(options, hook: 'deactivate')
|
35
38
|
end
|
36
39
|
end
|
37
40
|
|
@@ -39,7 +42,7 @@ module ModuleSync
|
|
39
42
|
class_option :project_root,
|
40
43
|
:aliases => '-c',
|
41
44
|
:desc => 'Path used by git to clone modules into.',
|
42
|
-
:default => CLI.defaults[:project_root]
|
45
|
+
:default => CLI.defaults[:project_root]
|
43
46
|
class_option :git_base,
|
44
47
|
:desc => 'Specify the base part of a git URL to pull from',
|
45
48
|
:default => CLI.defaults[:git_base] || 'git@github.com:'
|
@@ -53,11 +56,11 @@ module ModuleSync
|
|
53
56
|
class_option :negative_filter,
|
54
57
|
:aliases => '-x',
|
55
58
|
:desc => 'A regular expression to skip repositories.'
|
56
|
-
class_option :
|
57
|
-
:aliases => '-
|
58
|
-
:desc => '
|
59
|
-
|
60
|
-
:default =>
|
59
|
+
class_option :verbose,
|
60
|
+
:aliases => '-v',
|
61
|
+
:desc => 'Verbose mode',
|
62
|
+
:type => :boolean,
|
63
|
+
:default => false
|
61
64
|
|
62
65
|
desc 'update', 'Update the modules in managed_modules.yml'
|
63
66
|
option :message,
|
@@ -67,7 +70,7 @@ module ModuleSync
|
|
67
70
|
option :configs,
|
68
71
|
:aliases => '-c',
|
69
72
|
:desc => 'The local directory or remote repository to define the list of managed modules,' \
|
70
|
-
|
73
|
+
' the file templates, and the default values for template variables.'
|
71
74
|
option :managed_modules_conf,
|
72
75
|
:desc => 'The file name to define the list of managed modules'
|
73
76
|
option :remote_branch,
|
@@ -104,7 +107,7 @@ module ModuleSync
|
|
104
107
|
:default => CLI.defaults[:pr_labels] || []
|
105
108
|
option :pr_target_branch,
|
106
109
|
:desc => 'Target branch for the pull/merge request',
|
107
|
-
:default => CLI.defaults[:pr_target_branch]
|
110
|
+
:default => CLI.defaults[:pr_target_branch]
|
108
111
|
option :offline,
|
109
112
|
:type => :boolean,
|
110
113
|
:desc => 'Do not run any Git commands. Allows the user to manage Git outside of ModuleSync.',
|
@@ -130,17 +133,108 @@ module ModuleSync
|
|
130
133
|
:type => :boolean,
|
131
134
|
:aliases => '-F',
|
132
135
|
:desc => 'Produce a failure exit code when there are warnings' \
|
133
|
-
|
136
|
+
' (only has effect when --skip_broken is enabled)',
|
134
137
|
:default => false
|
135
|
-
|
138
|
+
option :branch,
|
139
|
+
:aliases => '-b',
|
140
|
+
:desc => 'Branch name to make the changes in.' \
|
141
|
+
' Defaults to the default branch of the upstream repository, but falls back to "master".',
|
142
|
+
:default => CLI.defaults[:branch]
|
136
143
|
def update
|
137
|
-
config =
|
138
|
-
config = Util.symbolize_keys(config)
|
144
|
+
config = CLI.prepare_options(options)
|
139
145
|
raise Thor::Error, 'No value provided for required option "--message"' unless config[:noop] \
|
140
146
|
|| config[:message] \
|
141
147
|
|| config[:offline]
|
142
|
-
|
143
|
-
ModuleSync.update
|
148
|
+
|
149
|
+
ModuleSync.update config
|
150
|
+
end
|
151
|
+
|
152
|
+
desc 'execute [OPTIONS] -- COMMAND..', 'Execute the command in each managed modules'
|
153
|
+
long_desc <<~DESC
|
154
|
+
Execute the command in each managed modules.
|
155
|
+
|
156
|
+
COMMAND can be an absolute or a relative path.
|
157
|
+
|
158
|
+
To ease running local commands, a relative path is expanded with the current user directory but only if the target file exists.
|
159
|
+
|
160
|
+
Example: `msync exec custom-scripts/true` will run "$PWD/custom-scripts/true" in each repository.
|
161
|
+
|
162
|
+
As side effect, you can shadow system binary if a local file is present:
|
163
|
+
\x5 `msync exec true` will run "$PWD/true", not `/bin/true` if "$PWD/true" exists.
|
164
|
+
DESC
|
165
|
+
|
166
|
+
option :configs,
|
167
|
+
:aliases => '-c',
|
168
|
+
:desc => 'The local directory or remote repository to define the list of managed modules,' \
|
169
|
+
' the file templates, and the default values for template variables.'
|
170
|
+
option :managed_modules_conf,
|
171
|
+
:desc => 'The file name to define the list of managed modules'
|
172
|
+
option :branch,
|
173
|
+
:aliases => '-b',
|
174
|
+
:desc => 'Branch name to make the changes in.',
|
175
|
+
:default => CLI.defaults[:branch]
|
176
|
+
option :fail_fast,
|
177
|
+
:type => :boolean,
|
178
|
+
:desc => 'Abort the run after a command execution failure',
|
179
|
+
:default => CLI.defaults[:fail_fast].nil? ? true : CLI.defaults[:fail_fast]
|
180
|
+
def execute(*command_args)
|
181
|
+
raise Thor::Error, 'COMMAND is a required argument' if command_args.empty?
|
182
|
+
|
183
|
+
ModuleSync.execute CLI.prepare_options(options, command_args: command_args)
|
184
|
+
end
|
185
|
+
|
186
|
+
desc 'reset', 'Reset local repositories to a well-known state'
|
187
|
+
long_desc <<~DESC
|
188
|
+
Reset local repository to a well-known state:
|
189
|
+
\x5 * Switch local repositories to specified branch
|
190
|
+
\x5 * Fetch and prune repositories unless running with `--offline` option
|
191
|
+
\x5 * Hard-reset any changes to specified source branch, technically any git refs, e.g. `main`, `origin/wip`
|
192
|
+
\x5 * Clean all extra local files
|
193
|
+
|
194
|
+
Note: If a repository is not already cloned, it will operate the following to reach to well-known state:
|
195
|
+
\x5 * Clone the repository
|
196
|
+
\x5 * Switch to specified branch
|
197
|
+
DESC
|
198
|
+
option :configs,
|
199
|
+
:aliases => '-c',
|
200
|
+
:desc => 'The local directory or remote repository to define the list of managed modules,' \
|
201
|
+
' the file templates, and the default values for template variables.'
|
202
|
+
option :managed_modules_conf,
|
203
|
+
:desc => 'The file name to define the list of managed modules'
|
204
|
+
option :branch,
|
205
|
+
:aliases => '-b',
|
206
|
+
:desc => 'Branch name to make the changes in.',
|
207
|
+
:default => CLI.defaults[:branch]
|
208
|
+
option :offline,
|
209
|
+
:type => :boolean,
|
210
|
+
:desc => 'Only proceed local operations',
|
211
|
+
:default => false
|
212
|
+
option :source_branch,
|
213
|
+
:desc => 'Branch to reset from (e.g. origin/wip)'
|
214
|
+
def reset
|
215
|
+
ModuleSync.reset CLI.prepare_options(options)
|
216
|
+
end
|
217
|
+
|
218
|
+
desc 'push', 'Push all available commits from branch to remote'
|
219
|
+
option :configs,
|
220
|
+
:aliases => '-c',
|
221
|
+
:desc => 'The local directory or remote repository to define the list of managed modules,' \
|
222
|
+
' the file templates, and the default values for template variables.'
|
223
|
+
option :managed_modules_conf,
|
224
|
+
:desc => 'The file name to define the list of managed modules'
|
225
|
+
option :branch,
|
226
|
+
:aliases => '-b',
|
227
|
+
:desc => 'Branch name to push',
|
228
|
+
:default => CLI.defaults[:branch]
|
229
|
+
option :remote_branch,
|
230
|
+
:desc => 'Remote branch to push to (e.g. maintenance)'
|
231
|
+
def push
|
232
|
+
ModuleSync.push CLI.prepare_options(options)
|
233
|
+
end
|
234
|
+
|
235
|
+
desc 'clone', 'Clone repositories that need to'
|
236
|
+
def clone
|
237
|
+
ModuleSync.clone CLI.prepare_options(options)
|
144
238
|
end
|
145
239
|
|
146
240
|
desc 'hook', 'Activate or deactivate a git hook.'
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module ModuleSync
|
2
|
+
module GitService
|
3
|
+
# Generic class for git services
|
4
|
+
class Base
|
5
|
+
def open_pull_request(repo_path:, namespace:, title:, message:, source_branch:, target_branch:, labels:, noop:) # rubocop:disable Metrics/ParameterLists
|
6
|
+
unless source_branch != target_branch
|
7
|
+
raise ModuleSync::Error,
|
8
|
+
"Unable to open a pull request with the same source and target branch: '#{source_branch}'"
|
9
|
+
end
|
10
|
+
|
11
|
+
_open_pull_request(
|
12
|
+
repo_path: repo_path,
|
13
|
+
namespace: namespace,
|
14
|
+
title: title,
|
15
|
+
message: message,
|
16
|
+
source_branch: source_branch,
|
17
|
+
target_branch: target_branch,
|
18
|
+
labels: labels,
|
19
|
+
noop: noop,
|
20
|
+
)
|
21
|
+
end
|
22
|
+
|
23
|
+
# This method attempts to guess the git service endpoint based on remote
|
24
|
+
def self.guess_endpoint_from(remote:)
|
25
|
+
hostname = extract_hostname(remote)
|
26
|
+
return nil if hostname.nil?
|
27
|
+
|
28
|
+
"https://#{hostname}"
|
29
|
+
end
|
30
|
+
|
31
|
+
# This method extracts hostname from URL like:
|
32
|
+
#
|
33
|
+
# - ssh://[user@]host.xz[:port]/path/to/repo.git/
|
34
|
+
# - git://host.xz[:port]/path/to/repo.git/
|
35
|
+
# - [user@]host.xz:path/to/repo.git/
|
36
|
+
# - http[s]://host.xz[:port]/path/to/repo.git/
|
37
|
+
# - ftp[s]://host.xz[:port]/path/to/repo.git/
|
38
|
+
#
|
39
|
+
# Returns nil if
|
40
|
+
# - /path/to/repo.git/
|
41
|
+
# - file:///path/to/repo.git/
|
42
|
+
# - any invalid URL
|
43
|
+
def self.extract_hostname(url)
|
44
|
+
return nil if url.start_with?('/') || url.start_with?('file://') # local path (e.g. file:///path/to/repo)
|
45
|
+
|
46
|
+
unless url.start_with?(%r{[a-z]+://}) # SSH notation does not contain protocol (e.g. user@server:path/to/repo/)
|
47
|
+
pattern = /^(?<user>.*@)?(?<hostname>[\w|.]*):(?<repo>.*)$/ # SSH path (e.g. user@server:repo)
|
48
|
+
return url.match(pattern)[:hostname] if url.match?(pattern)
|
49
|
+
end
|
50
|
+
|
51
|
+
URI.parse(url).host
|
52
|
+
rescue URI::InvalidURIError
|
53
|
+
nil
|
54
|
+
end
|
55
|
+
|
56
|
+
protected
|
57
|
+
|
58
|
+
def _open_pull_request(repo_path:, namespace:, title:, message:, source_branch:, target_branch:, labels:, noop:) # rubocop:disable Metrics/ParameterLists
|
59
|
+
raise NotImplementedError
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module ModuleSync
|
2
|
+
module GitService
|
3
|
+
# Git service's factory
|
4
|
+
module Factory
|
5
|
+
def self.instantiate(type:, endpoint:, token:)
|
6
|
+
raise MissingCredentialsError, <<~MESSAGE if token.nil?
|
7
|
+
A token is required to use services from #{type}:
|
8
|
+
Please set environment variable: "#{type.upcase}_TOKEN" or set the token entry in module options.
|
9
|
+
MESSAGE
|
10
|
+
|
11
|
+
klass(type: type).new token, endpoint
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.klass(type:)
|
15
|
+
case type
|
16
|
+
when :github
|
17
|
+
require 'modulesync/git_service/github'
|
18
|
+
ModuleSync::GitService::GitHub
|
19
|
+
when :gitlab
|
20
|
+
require 'modulesync/git_service/gitlab'
|
21
|
+
ModuleSync::GitService::GitLab
|
22
|
+
else
|
23
|
+
raise NotImplementedError, "Unknown git service: '#{type}'"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -1,28 +1,30 @@
|
|
1
|
+
require 'modulesync/git_service'
|
2
|
+
require 'modulesync/git_service/base'
|
1
3
|
require 'octokit'
|
2
|
-
require 'modulesync/util'
|
3
4
|
|
4
5
|
module ModuleSync
|
5
|
-
module
|
6
|
+
module GitService
|
6
7
|
# GitHub creates and manages pull requests on github.com or GitHub
|
7
8
|
# Enterprise installations.
|
8
|
-
class GitHub
|
9
|
+
class GitHub < Base
|
9
10
|
def initialize(token, endpoint)
|
11
|
+
super()
|
12
|
+
|
10
13
|
Octokit.configure do |c|
|
11
14
|
c.api_endpoint = endpoint
|
12
15
|
end
|
13
16
|
@api = Octokit::Client.new(:access_token => token)
|
14
17
|
end
|
15
18
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
head = "#{namespace}:#{
|
20
|
-
target_branch = options[:pr_target_branch] || 'master'
|
19
|
+
private
|
20
|
+
|
21
|
+
def _open_pull_request(repo_path:, namespace:, title:, message:, source_branch:, target_branch:, labels:, noop:) # rubocop:disable Metrics/ParameterLists
|
22
|
+
head = "#{namespace}:#{source_branch}"
|
21
23
|
|
22
|
-
if
|
24
|
+
if noop
|
23
25
|
$stdout.puts \
|
24
|
-
"Using no-op. Would submit PR '#{
|
25
|
-
"- merges #{
|
26
|
+
"Using no-op. Would submit PR '#{title}' to '#{repo_path}' " \
|
27
|
+
"- merges '#{source_branch}' into '#{target_branch}'"
|
26
28
|
return
|
27
29
|
end
|
28
30
|
|
@@ -32,25 +34,25 @@ module ModuleSync
|
|
32
34
|
:head => head)
|
33
35
|
unless pull_requests.empty?
|
34
36
|
# Skip creating the PR if it exists already.
|
35
|
-
$stdout.puts "Skipped! #{pull_requests.length} PRs found for branch #{
|
37
|
+
$stdout.puts "Skipped! #{pull_requests.length} PRs found for branch '#{source_branch}'"
|
36
38
|
return
|
37
39
|
end
|
38
40
|
|
39
|
-
pr_labels = ModuleSync::Util.parse_list(options[:pr_labels])
|
40
41
|
pr = @api.create_pull_request(repo_path,
|
41
42
|
target_branch,
|
42
|
-
|
43
|
-
|
44
|
-
|
43
|
+
source_branch,
|
44
|
+
title,
|
45
|
+
message)
|
45
46
|
$stdout.puts \
|
46
|
-
"Submitted PR '#{
|
47
|
-
"- merges #{
|
47
|
+
"Submitted PR '#{title}' to '#{repo_path}' " \
|
48
|
+
"- merges #{source_branch} into #{target_branch}"
|
48
49
|
|
49
50
|
# We only assign labels to the PR if we've discovered a list > 1. The labels MUST
|
50
51
|
# already exist. We DO NOT create missing labels.
|
51
|
-
return if
|
52
|
-
|
53
|
-
|
52
|
+
return if labels.empty?
|
53
|
+
|
54
|
+
$stdout.puts "Attaching the following labels to PR #{pr['number']}: #{labels.join(', ')}"
|
55
|
+
@api.add_labels_to_an_issue(repo_path, pr['number'], labels)
|
54
56
|
end
|
55
57
|
end
|
56
58
|
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'gitlab'
|
2
|
+
require 'modulesync/git_service'
|
3
|
+
require 'modulesync/git_service/base'
|
4
|
+
|
5
|
+
module ModuleSync
|
6
|
+
module GitService
|
7
|
+
# GitLab creates and manages merge requests on gitlab.com or private GitLab
|
8
|
+
# installations.
|
9
|
+
class GitLab < Base
|
10
|
+
def initialize(token, endpoint)
|
11
|
+
super()
|
12
|
+
|
13
|
+
@api = Gitlab::Client.new(
|
14
|
+
:endpoint => endpoint,
|
15
|
+
:private_token => token,
|
16
|
+
)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.guess_endpoint_from(remote:)
|
20
|
+
endpoint = super
|
21
|
+
return nil if endpoint.nil?
|
22
|
+
|
23
|
+
endpoint += '/api/v4'
|
24
|
+
endpoint
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def _open_pull_request(repo_path:, namespace:, title:, message:, source_branch:, target_branch:, labels:, noop:) # rubocop:disable Metrics/ParameterLists, Lint/UnusedMethodArgument
|
30
|
+
if noop
|
31
|
+
$stdout.puts \
|
32
|
+
"Using no-op. Would submit MR '#{title}' to '#{repo_path}' " \
|
33
|
+
"- merges #{source_branch} into #{target_branch}"
|
34
|
+
return
|
35
|
+
end
|
36
|
+
|
37
|
+
merge_requests = @api.merge_requests(repo_path,
|
38
|
+
:state => 'opened',
|
39
|
+
:source_branch => source_branch,
|
40
|
+
:target_branch => target_branch)
|
41
|
+
unless merge_requests.empty?
|
42
|
+
# Skip creating the MR if it exists already.
|
43
|
+
$stdout.puts "Skipped! #{merge_requests.length} MRs found for branch '#{source_branch}'"
|
44
|
+
return
|
45
|
+
end
|
46
|
+
|
47
|
+
mr = @api.create_merge_request(repo_path,
|
48
|
+
title,
|
49
|
+
:source_branch => source_branch,
|
50
|
+
:target_branch => target_branch,
|
51
|
+
:labels => labels)
|
52
|
+
$stdout.puts \
|
53
|
+
"Submitted MR '#{title}' to '#{repo_path}' " \
|
54
|
+
"- merges '#{source_branch}' into '#{target_branch}'"
|
55
|
+
|
56
|
+
return if labels.empty?
|
57
|
+
|
58
|
+
$stdout.puts "Attached the following labels to MR #{mr.iid}: #{labels.join(', ')}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module ModuleSync
|
2
|
+
class Error < StandardError; end
|
3
|
+
|
4
|
+
# Namespace for Git service classes (ie. GitHub, GitLab)
|
5
|
+
module GitService
|
6
|
+
class MissingCredentialsError < Error; end
|
7
|
+
|
8
|
+
class UnguessableTypeError < Error; end
|
9
|
+
|
10
|
+
def self.configuration_for(sourcecode:)
|
11
|
+
type = type_for(sourcecode: sourcecode)
|
12
|
+
|
13
|
+
{
|
14
|
+
type: type,
|
15
|
+
endpoint: endpoint_for(sourcecode: sourcecode, type: type),
|
16
|
+
token: token_for(sourcecode: sourcecode, type: type),
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
# This method attempts to guess git service's type (ie. gitlab or github)
|
21
|
+
# It process in this order
|
22
|
+
# 1. use module specific configuration entry (ie. a specific entry named `gitlab` or `github`)
|
23
|
+
# 2. guess using remote url (ie. looking for `github` or `gitlab` string)
|
24
|
+
# 3. use environment variables (ie. check if GITHUB_TOKEN or GITLAB_TOKEN is set)
|
25
|
+
# 4. fail
|
26
|
+
def self.type_for(sourcecode:)
|
27
|
+
return :github unless sourcecode.options[:github].nil?
|
28
|
+
return :gitlab unless sourcecode.options[:gitlab].nil?
|
29
|
+
return :github if sourcecode.repository_remote.include? 'github'
|
30
|
+
return :gitlab if sourcecode.repository_remote.include? 'gitlab'
|
31
|
+
|
32
|
+
if ENV['GITLAB_TOKEN'].nil? && ENV['GITHUB_TOKEN'].nil?
|
33
|
+
raise UnguessableTypeError, <<~MESSAGE
|
34
|
+
Unable to guess Git service type without GITLAB_TOKEN or GITHUB_TOKEN sets.
|
35
|
+
MESSAGE
|
36
|
+
end
|
37
|
+
|
38
|
+
unless ENV['GITLAB_TOKEN'].nil? || ENV['GITHUB_TOKEN'].nil?
|
39
|
+
raise UnguessableTypeError, <<~MESSAGE
|
40
|
+
Unable to guess Git service type with both GITLAB_TOKEN and GITHUB_TOKEN sets.
|
41
|
+
|
42
|
+
Please set the wanted one in configuration (ie. add `gitlab:` or `github:` key)
|
43
|
+
MESSAGE
|
44
|
+
end
|
45
|
+
|
46
|
+
return :github unless ENV['GITHUB_TOKEN'].nil?
|
47
|
+
return :gitlab unless ENV['GITLAB_TOKEN'].nil?
|
48
|
+
|
49
|
+
raise NotImplementedError
|
50
|
+
end
|
51
|
+
|
52
|
+
# This method attempts to find git service's endpoint based on sourcecode and type
|
53
|
+
# It process in this order
|
54
|
+
# 1. use module specific configuration (ie. `base_url`)
|
55
|
+
# 2. use environment variable dependending on type (e.g. GITLAB_BASE_URL)
|
56
|
+
# 3. guess using the git remote url
|
57
|
+
# 4. fail
|
58
|
+
def self.endpoint_for(sourcecode:, type:)
|
59
|
+
endpoint = sourcecode.options.dig(type, :base_url)
|
60
|
+
|
61
|
+
endpoint ||= case type
|
62
|
+
when :github
|
63
|
+
ENV['GITHUB_BASE_URL']
|
64
|
+
when :gitlab
|
65
|
+
ENV['GITLAB_BASE_URL']
|
66
|
+
end
|
67
|
+
|
68
|
+
endpoint ||= GitService::Factory.klass(type: type).guess_endpoint_from(remote: sourcecode.repository_remote)
|
69
|
+
|
70
|
+
raise NotImplementedError, <<~MESSAGE if endpoint.nil?
|
71
|
+
Unable to guess endpoint for remote: '#{sourcecode.repository_remote}'
|
72
|
+
Please provide `base_url` option in configuration file
|
73
|
+
MESSAGE
|
74
|
+
|
75
|
+
endpoint
|
76
|
+
end
|
77
|
+
|
78
|
+
# This method attempts to find the token associated to provided sourcecode and type
|
79
|
+
# It process in this order:
|
80
|
+
# 1. use module specific configuration (ie. `token`)
|
81
|
+
# 2. use environment variable depending on type (e.g. GITLAB_TOKEN)
|
82
|
+
# 3. fail
|
83
|
+
def self.token_for(sourcecode:, type:)
|
84
|
+
token = sourcecode.options.dig(type, :token)
|
85
|
+
|
86
|
+
token ||= case type
|
87
|
+
when :github
|
88
|
+
ENV['GITHUB_TOKEN']
|
89
|
+
when :gitlab
|
90
|
+
ENV['GITLAB_TOKEN']
|
91
|
+
end
|
92
|
+
|
93
|
+
token
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
data/lib/modulesync/hook.rb
CHANGED
@@ -6,20 +6,20 @@ module ModuleSync
|
|
6
6
|
|
7
7
|
def initialize(hook_file, options = [])
|
8
8
|
@hook_file = hook_file
|
9
|
-
@namespace = options[
|
10
|
-
@branch = options[
|
11
|
-
@args = options[
|
9
|
+
@namespace = options[:namespace]
|
10
|
+
@branch = options[:branch]
|
11
|
+
@args = options[:hook_args]
|
12
12
|
end
|
13
13
|
|
14
14
|
def content(arguments)
|
15
|
-
|
16
|
-
#!/usr/bin/env bash
|
15
|
+
<<~CONTENT
|
16
|
+
#!/usr/bin/env bash
|
17
17
|
|
18
|
-
current_branch=\`git symbolic-ref HEAD | sed -e 's,.*/\(.*\),\1,'\`
|
19
|
-
git_dir=\`git rev-parse --show-toplevel\`
|
20
|
-
message=\`git log -1 --format=%B\`
|
21
|
-
msync -m "\$message" #{arguments}
|
22
|
-
CONTENT
|
18
|
+
current_branch=\`git symbolic-ref HEAD | sed -e 's,.*/\(.*\),\1,'\`
|
19
|
+
git_dir=\`git rev-parse --show-toplevel\`
|
20
|
+
message=\`git log -1 --format=%B\`
|
21
|
+
msync -m "\$message" #{arguments}
|
22
|
+
CONTENT
|
23
23
|
end
|
24
24
|
|
25
25
|
def activate
|
@@ -28,9 +28,7 @@ CONTENT
|
|
28
28
|
hook_args << "-b #{branch}" if branch
|
29
29
|
hook_args << args if args
|
30
30
|
|
31
|
-
File.
|
32
|
-
file.write(content(hook_args.join(' ')))
|
33
|
-
end
|
31
|
+
File.write(hook_file, content(hook_args.join(' ')))
|
34
32
|
end
|
35
33
|
|
36
34
|
def deactivate
|
data/lib/modulesync/renderer.rb
CHANGED
@@ -12,7 +12,7 @@ module ModuleSync
|
|
12
12
|
|
13
13
|
def self.build(target_name)
|
14
14
|
template_file = if !File.exist?("#{target_name}.erb") && File.exist?(target_name)
|
15
|
-
|
15
|
+
$stderr.puts "Warning: using '#{target_name}' as template without '.erb' suffix"
|
16
16
|
target_name
|
17
17
|
else
|
18
18
|
"#{target_name}.erb"
|
@@ -32,11 +32,8 @@ module ModuleSync
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def self.sync(template, target_name)
|
35
|
-
|
36
|
-
|
37
|
-
File.open(target_name, 'w') do |file|
|
38
|
-
file.write(template)
|
39
|
-
end
|
35
|
+
FileUtils.mkdir_p(File.dirname(target_name))
|
36
|
+
File.write(target_name, template)
|
40
37
|
end
|
41
38
|
end
|
42
39
|
end
|