toys-release 0.1.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 +7 -0
- data/.yardopts +11 -0
- data/CHANGELOG.md +5 -0
- data/LICENSE.md +21 -0
- data/README.md +87 -0
- data/docs/guide.md +7 -0
- data/lib/toys/release/version.rb +11 -0
- data/lib/toys-release.rb +23 -0
- data/toys/.data/templates/gh-pages-404.html.erb +25 -0
- data/toys/.data/templates/gh-pages-empty.html.erb +11 -0
- data/toys/.data/templates/gh-pages-gitignore.erb +1 -0
- data/toys/.data/templates/gh-pages-index.html.erb +15 -0
- data/toys/.data/templates/release-hook-on-closed.yml.erb +34 -0
- data/toys/.data/templates/release-hook-on-open.yml.erb +30 -0
- data/toys/.data/templates/release-hook-on-push.yml.erb +32 -0
- data/toys/.data/templates/release-perform.yml.erb +46 -0
- data/toys/.data/templates/release-request.yml.erb +37 -0
- data/toys/.data/templates/release-retry.yml.erb +42 -0
- data/toys/.lib/toys/release/artifact_dir.rb +70 -0
- data/toys/.lib/toys/release/change_set.rb +259 -0
- data/toys/.lib/toys/release/changelog_file.rb +136 -0
- data/toys/.lib/toys/release/component.rb +388 -0
- data/toys/.lib/toys/release/environment_utils.rb +246 -0
- data/toys/.lib/toys/release/performer.rb +346 -0
- data/toys/.lib/toys/release/pull_request.rb +154 -0
- data/toys/.lib/toys/release/repo_settings.rb +855 -0
- data/toys/.lib/toys/release/repository.rb +661 -0
- data/toys/.lib/toys/release/request_logic.rb +217 -0
- data/toys/.lib/toys/release/request_spec.rb +188 -0
- data/toys/.lib/toys/release/semver.rb +112 -0
- data/toys/.lib/toys/release/steps.rb +580 -0
- data/toys/.lib/toys/release/version_rb_file.rb +91 -0
- data/toys/.toys.rb +5 -0
- data/toys/_onclosed.rb +113 -0
- data/toys/_onopen.rb +158 -0
- data/toys/_onpush.rb +57 -0
- data/toys/create-labels.rb +115 -0
- data/toys/gen-gh-pages.rb +146 -0
- data/toys/gen-settings.rb +46 -0
- data/toys/gen-workflows.rb +70 -0
- data/toys/perform.rb +152 -0
- data/toys/request.rb +162 -0
- data/toys/retry.rb +133 -0
- metadata +106 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
desc "Generate GitHub Actions workflow files"
|
|
4
|
+
|
|
5
|
+
long_desc \
|
|
6
|
+
"This tool generates workflow files for GitHub Actions."
|
|
7
|
+
|
|
8
|
+
flag :yes, "--yes", "-y" do
|
|
9
|
+
desc "Automatically answer yes to all confirmations"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
include :exec
|
|
13
|
+
include :terminal, styled: true
|
|
14
|
+
|
|
15
|
+
# Context for ERB templates
|
|
16
|
+
class ErbContext
|
|
17
|
+
def initialize(settings)
|
|
18
|
+
@settings = settings
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def self.get(settings)
|
|
22
|
+
new(settings).instance_eval { binding }
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def run
|
|
27
|
+
require "erb"
|
|
28
|
+
require "toys/release/environment_utils"
|
|
29
|
+
require "toys/release/repo_settings"
|
|
30
|
+
|
|
31
|
+
@utils = Toys::Release::EnvironmentUtils.new(self)
|
|
32
|
+
@settings = Toys::Release::RepoSettings.load_from_environment(@utils)
|
|
33
|
+
|
|
34
|
+
unless @settings.enable_release_automation?
|
|
35
|
+
puts "Release automation disabled in settings."
|
|
36
|
+
unless yes || confirm("Create workflow files anyway? ", default: false)
|
|
37
|
+
@utils.error("Aborted.")
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
@workflows_dir = ::File.join(context_directory, ".github", "workflows")
|
|
42
|
+
files = [
|
|
43
|
+
"release-hook-on-closed.yml",
|
|
44
|
+
"release-hook-on-push.yml",
|
|
45
|
+
"release-perform.yml",
|
|
46
|
+
"release-request.yml",
|
|
47
|
+
"release-retry.yml",
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
files.each { |name| generate(name) }
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def generate(name)
|
|
54
|
+
destination = ::File.join(@workflows_dir, name)
|
|
55
|
+
if ::File.readable?(destination)
|
|
56
|
+
puts "Destination file #{destination} exists.", :yellow, :bold
|
|
57
|
+
return unless yes || confirm("Overwrite? ", default: true)
|
|
58
|
+
else
|
|
59
|
+
return unless yes || confirm("Create file #{destination}? ", default: true)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
template_path = find_data("templates/#{name}.erb")
|
|
63
|
+
raise "Unable to find template #{name}.erb" unless template_path
|
|
64
|
+
erb = ::ERB.new(::File.read(template_path))
|
|
65
|
+
|
|
66
|
+
::File.open(destination, "w") do |file|
|
|
67
|
+
file.write(erb.result(ErbContext.get(@settings)))
|
|
68
|
+
puts "Wrote #{destination}.", :green, :bold
|
|
69
|
+
end
|
|
70
|
+
end
|
data/toys/perform.rb
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
desc "Perform a release"
|
|
4
|
+
|
|
5
|
+
long_desc \
|
|
6
|
+
"This tool performs an official release. It is normally called from a" \
|
|
7
|
+
" GitHub Actions workflow, but can also be executed locally if the" \
|
|
8
|
+
" proper credentials are present.",
|
|
9
|
+
"",
|
|
10
|
+
"Normally, releases should be initiated using the 'request' tool, invoked" \
|
|
11
|
+
" either locally or from GitHub Actions. That tool will automatically" \
|
|
12
|
+
" update the library version and changelog based on the commits since" \
|
|
13
|
+
" the last release, and will open a pull request that you can merge to" \
|
|
14
|
+
" actually perform the release. The 'perform' tool should be used only" \
|
|
15
|
+
" if the version and changelog commits are already committed.",
|
|
16
|
+
"",
|
|
17
|
+
"When invoked, this tool first performs pre-checks including:",
|
|
18
|
+
"* The git workspace must be clean (no new, modified, or deleted files)",
|
|
19
|
+
"* The remote repo must be the correct repo configured in releases.yml",
|
|
20
|
+
"* All GitHub checks for the release to commit must have succeeded",
|
|
21
|
+
"",
|
|
22
|
+
"The tool then performs the necessary release tasks for each component." \
|
|
23
|
+
" It also ensures each version file and changelog are properly formatted" \
|
|
24
|
+
" and match the release version if given."
|
|
25
|
+
|
|
26
|
+
remaining_args :components do
|
|
27
|
+
accept(/^[\w-]+(?:[=:][\w.-]+)?$/)
|
|
28
|
+
desc "Components to release"
|
|
29
|
+
long_desc \
|
|
30
|
+
"Each remaining argument should consist of a component name, and optional" \
|
|
31
|
+
" version number separated by a equal sign, i.e.",
|
|
32
|
+
[" <name>[=<version>]"],
|
|
33
|
+
"",
|
|
34
|
+
"The version to release is determined by the version file and changelog." \
|
|
35
|
+
" The version given on the command line, if provided, is used only for" \
|
|
36
|
+
" verification."
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
flag_group desc: "Flags" do
|
|
40
|
+
flag :dry_run, "--[no-]dry-run" do
|
|
41
|
+
desc "Run in dry-run mode."
|
|
42
|
+
long_desc \
|
|
43
|
+
"Run in dry-run mode, where checks are made and releases are built" \
|
|
44
|
+
" but are not pushed."
|
|
45
|
+
end
|
|
46
|
+
flag :git_remote, "--git-remote=VAL" do
|
|
47
|
+
default "origin"
|
|
48
|
+
desc "The name of the git remote"
|
|
49
|
+
long_desc \
|
|
50
|
+
"The name of the git remote pointing at the canonical repository." \
|
|
51
|
+
" Defaults to 'origin'."
|
|
52
|
+
end
|
|
53
|
+
flag :release_ref, "--release-ref=VAL", "--release-sha=VAL" do
|
|
54
|
+
desc "The commit to use for the release"
|
|
55
|
+
long_desc \
|
|
56
|
+
"Specifies a ref (branch or SHA) for the release. Optional. Defaults" \
|
|
57
|
+
" to the current HEAD."
|
|
58
|
+
end
|
|
59
|
+
flag :enable_prechecks, "--[no-]enable-prechecks" do
|
|
60
|
+
default true
|
|
61
|
+
desc "Enables pre-release checks. Enabled by default."
|
|
62
|
+
end
|
|
63
|
+
flag :release_pr, "--release-pr=VAL" do
|
|
64
|
+
accept ::Integer
|
|
65
|
+
desc "Release pull request number"
|
|
66
|
+
long_desc \
|
|
67
|
+
"Update the given release pull request number. Optional."
|
|
68
|
+
end
|
|
69
|
+
flag :work_dir, "--work-dir=PATH" do
|
|
70
|
+
desc "Set the directory for artifacts and temporary files"
|
|
71
|
+
long_desc \
|
|
72
|
+
"If provided, the given directory path is used for artifacts and" \
|
|
73
|
+
" temporary files, and is left intact after the release so the" \
|
|
74
|
+
" artifacts can be inspected. If omitted, a new temporary directory" \
|
|
75
|
+
" is created, and is automatically deleted after the release."
|
|
76
|
+
end
|
|
77
|
+
flag :yes, "--yes", "-y" do
|
|
78
|
+
desc "Automatically answer yes to all confirmations"
|
|
79
|
+
end
|
|
80
|
+
flag :rubygems_api_key, "--rubygems-api-key=VAL" do
|
|
81
|
+
desc "Set the Rubygems API key"
|
|
82
|
+
long_desc \
|
|
83
|
+
"Use the given Rubygems API key when pushing to Rubygems. Deprecated;" \
|
|
84
|
+
" prefer just setting the `GEM_HOST_API_KEY` environment variable."
|
|
85
|
+
end
|
|
86
|
+
flag :gh_token, "--gh-token=VAL" do
|
|
87
|
+
desc "Set the GitHub token"
|
|
88
|
+
long_desc \
|
|
89
|
+
"Use the given GitHub token when pushing to GitHub. Deprecated; prefer" \
|
|
90
|
+
" just setting the `GITHUB_TOKEN` environment variable."
|
|
91
|
+
end
|
|
92
|
+
flag :enable_releases, "--enable-releases=VAL" do
|
|
93
|
+
desc "Deprecated and unused"
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
include :exec
|
|
98
|
+
include :terminal, styled: true
|
|
99
|
+
|
|
100
|
+
def run
|
|
101
|
+
::Dir.chdir(context_directory)
|
|
102
|
+
require "toys/release/environment_utils"
|
|
103
|
+
require "toys/release/repository"
|
|
104
|
+
require "toys/release/repo_settings"
|
|
105
|
+
require "toys/release/performer"
|
|
106
|
+
|
|
107
|
+
setup_arguments
|
|
108
|
+
setup_performer
|
|
109
|
+
components.each do |component_spec|
|
|
110
|
+
name, version = component_spec.split(/[:=]/, 2)
|
|
111
|
+
confirmation_ui(name, version)
|
|
112
|
+
gem_version = version ? ::Gem::Version.new(version) : nil
|
|
113
|
+
@performer.perform_adhoc_release(name, assert_version: gem_version)
|
|
114
|
+
end
|
|
115
|
+
puts @performer.build_report_text
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def setup_arguments
|
|
119
|
+
[
|
|
120
|
+
:git_remote,
|
|
121
|
+
:release_ref,
|
|
122
|
+
:release_pr,
|
|
123
|
+
:rubygems_api_key,
|
|
124
|
+
:gh_token,
|
|
125
|
+
:work_dir,
|
|
126
|
+
].each do |key|
|
|
127
|
+
set(key, nil) if get(key).to_s.empty?
|
|
128
|
+
end
|
|
129
|
+
set(:dry_run, /^t/i.match?(::ENV["TOYS_RELEASE_DRY_RUN"].to_s)) if dry_run.nil?
|
|
130
|
+
::ENV["GEM_HOST_API_KEY"] = rubygems_api_key if rubygems_api_key
|
|
131
|
+
::ENV["GITHUB_TOKEN"] = gh_token if gh_token
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def setup_performer
|
|
135
|
+
@utils = Toys::Release::EnvironmentUtils.new(self)
|
|
136
|
+
@repo_settings = Toys::Release::RepoSettings.load_from_environment(@utils)
|
|
137
|
+
@repository = Toys::Release::Repository.new(@utils, @repo_settings)
|
|
138
|
+
@repository.git_set_user_info
|
|
139
|
+
@performer = Toys::Release::Performer.new(@repository,
|
|
140
|
+
release_ref: release_ref,
|
|
141
|
+
release_pr: release_pr,
|
|
142
|
+
enable_prechecks: enable_prechecks,
|
|
143
|
+
git_remote: git_remote,
|
|
144
|
+
work_dir: work_dir,
|
|
145
|
+
dry_run: dry_run)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def confirmation_ui(name, version)
|
|
149
|
+
return if yes
|
|
150
|
+
return if confirm("Release #{name} #{version}? ", :bold, default: false)
|
|
151
|
+
@utils.error("Release aborted")
|
|
152
|
+
end
|
data/toys/request.rb
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
desc "Open a release request"
|
|
4
|
+
|
|
5
|
+
long_desc \
|
|
6
|
+
"This tool opens release pull requests for the specified releasable" \
|
|
7
|
+
" components. It analyzes the commits since the last release, and updates" \
|
|
8
|
+
" each component's version and changelog accordingly. This tool is" \
|
|
9
|
+
" normally called from a GitHub Actions workflow, but can also be" \
|
|
10
|
+
" executed locally.",
|
|
11
|
+
"",
|
|
12
|
+
"When invoked, this tool first performs checks including:",
|
|
13
|
+
"* The git workspace must be clean (no new, modified, or deleted files)",
|
|
14
|
+
"* The remote repo must be the correct repo configured in releases.yml",
|
|
15
|
+
"* All GitHub checks for the release commit must have succeeded",
|
|
16
|
+
"",
|
|
17
|
+
"The tool then creates release pull requests for each component:",
|
|
18
|
+
"* It collects all commit messages since the previous release.",
|
|
19
|
+
"* It builds a changelog using properly formatted conventional commit" \
|
|
20
|
+
" messages of type 'fix', 'feat', and 'docs', and any that indicate a" \
|
|
21
|
+
" breaking change.",
|
|
22
|
+
"* Unless a specific version is provided via flags, it infers a new version" \
|
|
23
|
+
" number using the implied semver significance of the commit messages.",
|
|
24
|
+
"* It edits the changelog and version Ruby files and pushes a commit to a" \
|
|
25
|
+
" release branch.",
|
|
26
|
+
"* It opens a release pull request.",
|
|
27
|
+
"",
|
|
28
|
+
"Release pull requests may be edited to modify the version and/or changelog" \
|
|
29
|
+
" before merging. In repositories that have release automation enabled," \
|
|
30
|
+
" the release script will run automatically when a release pull request" \
|
|
31
|
+
" is merged."
|
|
32
|
+
|
|
33
|
+
remaining_args :components do
|
|
34
|
+
accept(/^[\w-]+(?:[=:][\w.-]+)?$/)
|
|
35
|
+
desc "Components to release"
|
|
36
|
+
long_desc \
|
|
37
|
+
"Each remaining argument should consist of a component name, and optional" \
|
|
38
|
+
" version spec separated by a equal sign, i.e.",
|
|
39
|
+
[" <name>[=<version>]"],
|
|
40
|
+
"",
|
|
41
|
+
"The version can be a literal version number, or one of the semver" \
|
|
42
|
+
" change types 'major', 'minor', or 'patch'. It can also be omitted." \
|
|
43
|
+
" If the version is omitted, a semver change type will be inferred" \
|
|
44
|
+
" from the conventional commit message history, and the component will" \
|
|
45
|
+
" be released only if at least one significant releasable commit tag" \
|
|
46
|
+
" (such as 'feat:', 'fix:', or 'docs:') is found.",
|
|
47
|
+
"",
|
|
48
|
+
"Note that any coordination groups are honored. If you release at least" \
|
|
49
|
+
" one component within a group, all components in the group will be" \
|
|
50
|
+
" forced to release with the same version.",
|
|
51
|
+
"",
|
|
52
|
+
"The special name 'all' can be used to specify all components. You can" \
|
|
53
|
+
" also provide a version to force all components to be released with" \
|
|
54
|
+
" that version, e.g. 'all=1.2.3'.",
|
|
55
|
+
"",
|
|
56
|
+
"If no components are provided, all components with releasable changes" \
|
|
57
|
+
" are released. That is, not providing any components is equivalent to" \
|
|
58
|
+
" specifying 'all' without a version."
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
flag :git_remote, "--git-remote=VAL" do
|
|
62
|
+
default "origin"
|
|
63
|
+
desc "The name of the git remote"
|
|
64
|
+
long_desc \
|
|
65
|
+
"The name of the git remote pointing at the canonical repository." \
|
|
66
|
+
" Defaults to 'origin'."
|
|
67
|
+
end
|
|
68
|
+
flag :target_branch, "--release-ref=VAL", "--target-branch=VAL" do
|
|
69
|
+
desc "Target branch for the release"
|
|
70
|
+
long_desc "The target branch for the release request. Defaults to HEAD."
|
|
71
|
+
end
|
|
72
|
+
flag :yes, "--yes", "-y" do
|
|
73
|
+
desc "Automatically answer yes to all confirmations"
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
include :exec
|
|
77
|
+
include :terminal, styled: true
|
|
78
|
+
|
|
79
|
+
def run
|
|
80
|
+
setup
|
|
81
|
+
@utils = Toys::Release::EnvironmentUtils.new(self)
|
|
82
|
+
@repo_settings = Toys::Release::RepoSettings.load_from_environment(@utils)
|
|
83
|
+
@repository = prepare_repository
|
|
84
|
+
@request_spec = build_request_spec
|
|
85
|
+
@request_logic = Toys::Release::RequestLogic.new(@repository, @request_spec)
|
|
86
|
+
@request_logic.verify_component_status
|
|
87
|
+
@request_logic.verify_pull_request_status
|
|
88
|
+
confirmation_ui
|
|
89
|
+
@pull_request = create_pull_request
|
|
90
|
+
result_ui(@pull_request.number)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def setup
|
|
94
|
+
::Dir.chdir(context_directory)
|
|
95
|
+
require "toys/release/environment_utils"
|
|
96
|
+
require "toys/release/repository"
|
|
97
|
+
require "toys/release/repo_settings"
|
|
98
|
+
require "toys/release/request_logic"
|
|
99
|
+
require "toys/release/request_spec"
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def prepare_repository
|
|
103
|
+
repository = Toys::Release::Repository.new(@utils, @repo_settings)
|
|
104
|
+
repository.git_set_user_info
|
|
105
|
+
repository.verify_git_clean
|
|
106
|
+
repository.verify_repo_identity(remote: git_remote)
|
|
107
|
+
set(:target_branch, nil) if get(:target_branch).to_s.empty?
|
|
108
|
+
set(:target_branch, repository.git_prepare_branch(git_remote, branch: target_branch))
|
|
109
|
+
repository.verify_github_checks(ref: target_branch)
|
|
110
|
+
repository
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def build_request_spec
|
|
114
|
+
request_spec = Toys::Release::RequestSpec.new(@utils)
|
|
115
|
+
set(:components, ["all"]) if components.empty?
|
|
116
|
+
components.each do |component_spec|
|
|
117
|
+
component_spec = component_spec.split(/[:=]/)
|
|
118
|
+
name = component_spec[0]
|
|
119
|
+
version = component_spec[1]
|
|
120
|
+
if name == "all"
|
|
121
|
+
@repository.all_components.each do |component|
|
|
122
|
+
request_spec.add(component.name, version: version)
|
|
123
|
+
end
|
|
124
|
+
else
|
|
125
|
+
request_spec.add(name, version: version)
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
request_spec.resolve_versions(@repository, release_ref: target_branch)
|
|
129
|
+
request_spec
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def confirmation_ui
|
|
133
|
+
puts("Opening a request to release the following:", :bold)
|
|
134
|
+
@request_spec.resolved_components.each do |component|
|
|
135
|
+
puts("* #{component.component_name} version #{component.last_version} -> #{component.version}")
|
|
136
|
+
end
|
|
137
|
+
unless yes || confirm("Create release PR? ", :bold, default: true)
|
|
138
|
+
@utils.error("Release aborted")
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def create_pull_request
|
|
143
|
+
release_branch = @request_logic.determine_release_branch
|
|
144
|
+
commit_title = @request_logic.build_commit_title
|
|
145
|
+
commit_details = @request_logic.build_commit_details
|
|
146
|
+
signoff = @repository.settings.signoff_commits?
|
|
147
|
+
@repository.create_branch(release_branch)
|
|
148
|
+
@request_logic.change_files
|
|
149
|
+
@repository.git_commit(commit_title, commit_details: commit_details, signoff: signoff)
|
|
150
|
+
body = @request_logic.build_pr_body
|
|
151
|
+
labels = @request_logic.determine_pr_labels
|
|
152
|
+
@repository.create_pull_request(base_branch: target_branch,
|
|
153
|
+
remote: git_remote,
|
|
154
|
+
title: commit_title,
|
|
155
|
+
body: body,
|
|
156
|
+
labels: labels)
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def result_ui(pr_number)
|
|
160
|
+
repo = @repository.settings.repo_path
|
|
161
|
+
puts("Created pull request: https://github.com/#{repo}/pull/#{pr_number}", :bold)
|
|
162
|
+
end
|
data/toys/retry.rb
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
desc "Releases pending releasable components for a pull request"
|
|
4
|
+
|
|
5
|
+
long_desc \
|
|
6
|
+
"This tool continues the releases associated with a release pull request." \
|
|
7
|
+
" It is normally used to retry or continue releases that aborted due to" \
|
|
8
|
+
" an error. This tool is normally called from a GitHub Actions workflow," \
|
|
9
|
+
" but can also be executed locally if the proper credentials are present."
|
|
10
|
+
|
|
11
|
+
required_arg :release_pr, accept: Integer do
|
|
12
|
+
desc "Release pull request number. Required."
|
|
13
|
+
end
|
|
14
|
+
flag_group desc: "Flags" do
|
|
15
|
+
flag :dry_run, "--[no-]dry-run" do
|
|
16
|
+
desc "Run in dry-run mode."
|
|
17
|
+
long_desc \
|
|
18
|
+
"Run in dry-run mode, where checks are made and releases are built" \
|
|
19
|
+
" but are not pushed."
|
|
20
|
+
end
|
|
21
|
+
flag :gh_pages_dir, "--gh-pages-dir=VAL" do
|
|
22
|
+
desc "The directory to use for the gh-pages branch"
|
|
23
|
+
long_desc \
|
|
24
|
+
"Set to the path of a directory to use as the gh-pages workspace when" \
|
|
25
|
+
" building and pushing gem documentation. If left unset, a temporary" \
|
|
26
|
+
" directory will be created (and removed when finished)."
|
|
27
|
+
end
|
|
28
|
+
flag :git_remote, "--git-remote=VAL" do
|
|
29
|
+
default "origin"
|
|
30
|
+
desc "The name of the git remote"
|
|
31
|
+
long_desc \
|
|
32
|
+
"The name of the git remote pointing at the canonical repository." \
|
|
33
|
+
" Defaults to 'origin'."
|
|
34
|
+
end
|
|
35
|
+
flag :release_ref, "--release-ref=VAL", "--release-sha=VAL" do
|
|
36
|
+
desc "Override the commit for the release"
|
|
37
|
+
long_desc \
|
|
38
|
+
"The SHA or ref to release from. This can be used if additional" \
|
|
39
|
+
" changes are needed to fix the release. If not given, the merge SHA" \
|
|
40
|
+
" of the pull request is used."
|
|
41
|
+
end
|
|
42
|
+
flag :enable_prechecks, "--[no-]enable-prechecks" do
|
|
43
|
+
default true
|
|
44
|
+
desc "Enables pre-release checks. Enabled by default."
|
|
45
|
+
long_desc \
|
|
46
|
+
"Enables pre-release checks. Enabled by default. It may occasionally" \
|
|
47
|
+
" be useful to disable this to repair a broken release, but it is" \
|
|
48
|
+
" generally not recommended."
|
|
49
|
+
end
|
|
50
|
+
flag :yes, "--yes", "-y" do
|
|
51
|
+
desc "Automatically answer yes to all confirmations"
|
|
52
|
+
end
|
|
53
|
+
flag :rubygems_api_key, "--rubygems-api-key=VAL" do
|
|
54
|
+
desc "Set the Rubygems API key"
|
|
55
|
+
long_desc \
|
|
56
|
+
"Use the given Rubygems API key when pushing to Rubygems. Deprecated;" \
|
|
57
|
+
" prefer just setting the `GEM_HOST_API_KEY` environment variable."
|
|
58
|
+
end
|
|
59
|
+
flag :enable_releases, "--enable-releases=VAL" do
|
|
60
|
+
desc "Deprecated and unused"
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
include :exec
|
|
65
|
+
include :terminal, styled: true
|
|
66
|
+
|
|
67
|
+
def run
|
|
68
|
+
::Dir.chdir(context_directory)
|
|
69
|
+
setup_objects
|
|
70
|
+
verify_release_pr
|
|
71
|
+
setup_params
|
|
72
|
+
@repository.at_sha(release_ref) do
|
|
73
|
+
perform_pending_releases
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def setup_objects
|
|
78
|
+
require "toys/release/environment_utils"
|
|
79
|
+
require "toys/release/repository"
|
|
80
|
+
require "toys/release/repo_settings"
|
|
81
|
+
require "toys/release/performer"
|
|
82
|
+
|
|
83
|
+
@utils = Toys::Release::EnvironmentUtils.new(self)
|
|
84
|
+
@repo_settings = Toys::Release::RepoSettings.load_from_environment(@utils)
|
|
85
|
+
@repository = Toys::Release::Repository.new(@utils, @repo_settings)
|
|
86
|
+
@repository.git_set_user_info
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def verify_release_pr
|
|
90
|
+
@pr_info = @repository.load_pr(release_pr)
|
|
91
|
+
@utils.error("Could not load pull request ##{release_pr}") unless @pr_info
|
|
92
|
+
expected_labels = [@repo_settings.release_pending_label, @repo_settings.release_error_label]
|
|
93
|
+
return if @pr_info["labels"].any? { |label| expected_labels.include?(label["name"]) }
|
|
94
|
+
warning = "PR #{release_pr} doesn't have the release pending or release error label."
|
|
95
|
+
if yes
|
|
96
|
+
logger.warn(warning)
|
|
97
|
+
return
|
|
98
|
+
end
|
|
99
|
+
unless confirm("#{warning} Proceed anyway? ", :bold, default: false)
|
|
100
|
+
@utils.error("Release aborted.")
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def setup_params
|
|
105
|
+
[:gh_pages_dir, :rubygems_api_key].each do |key|
|
|
106
|
+
set(key, nil) if get(key).to_s.empty?
|
|
107
|
+
end
|
|
108
|
+
::ENV["GEM_HOST_API_KEY"] = rubygems_api_key if rubygems_api_key
|
|
109
|
+
set(:dry_run, /^t/i.match?(::ENV["TOYS_RELEASE_DRY_RUN"].to_s)) if dry_run.nil?
|
|
110
|
+
set :release_ref, @repository.current_sha(release_ref || @pr_info["merge_commit_sha"])
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def create_performer
|
|
114
|
+
Toys::Release::Performer.new(@repository,
|
|
115
|
+
release_ref: release_ref,
|
|
116
|
+
release_pr: release_pr,
|
|
117
|
+
enable_prechecks: enable_prechecks,
|
|
118
|
+
git_remote: git_remote,
|
|
119
|
+
gh_pages_dir: gh_pages_dir,
|
|
120
|
+
dry_run: dry_run)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def perform_pending_releases
|
|
124
|
+
@repository.wait_github_checks(release_ref) if enable_prechecks
|
|
125
|
+
performer = create_performer
|
|
126
|
+
performer.perform_pr_releases
|
|
127
|
+
performer.report_results
|
|
128
|
+
if performer.error?
|
|
129
|
+
@utils.error("Releases reported failure")
|
|
130
|
+
else
|
|
131
|
+
puts("All releases completed successfully", :bold, :green)
|
|
132
|
+
end
|
|
133
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: toys-release
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Daniel Azuma
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: toys-core
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '0.17'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '0.17'
|
|
26
|
+
description: Toys-Release is a Ruby library release system using GitHub Actions and
|
|
27
|
+
Toys. It interprets conventional commit message format to automate changelog generation
|
|
28
|
+
and library version updating based on semantic versioning, and supports fine tuning
|
|
29
|
+
and approval of releases using GitHub pull requests. Out of the box, Toys-Release
|
|
30
|
+
knows how to tag GitHub releases, build and push gems to Rubygems, and build and
|
|
31
|
+
publish documentation to gh-pages. You can also customize the build pipeline and
|
|
32
|
+
many aspects of its behavior.
|
|
33
|
+
email:
|
|
34
|
+
- dazuma@gmail.com
|
|
35
|
+
executables: []
|
|
36
|
+
extensions: []
|
|
37
|
+
extra_rdoc_files: []
|
|
38
|
+
files:
|
|
39
|
+
- ".yardopts"
|
|
40
|
+
- CHANGELOG.md
|
|
41
|
+
- LICENSE.md
|
|
42
|
+
- README.md
|
|
43
|
+
- docs/guide.md
|
|
44
|
+
- lib/toys-release.rb
|
|
45
|
+
- lib/toys/release/version.rb
|
|
46
|
+
- toys/.data/templates/gh-pages-404.html.erb
|
|
47
|
+
- toys/.data/templates/gh-pages-empty.html.erb
|
|
48
|
+
- toys/.data/templates/gh-pages-gitignore.erb
|
|
49
|
+
- toys/.data/templates/gh-pages-index.html.erb
|
|
50
|
+
- toys/.data/templates/release-hook-on-closed.yml.erb
|
|
51
|
+
- toys/.data/templates/release-hook-on-open.yml.erb
|
|
52
|
+
- toys/.data/templates/release-hook-on-push.yml.erb
|
|
53
|
+
- toys/.data/templates/release-perform.yml.erb
|
|
54
|
+
- toys/.data/templates/release-request.yml.erb
|
|
55
|
+
- toys/.data/templates/release-retry.yml.erb
|
|
56
|
+
- toys/.lib/toys/release/artifact_dir.rb
|
|
57
|
+
- toys/.lib/toys/release/change_set.rb
|
|
58
|
+
- toys/.lib/toys/release/changelog_file.rb
|
|
59
|
+
- toys/.lib/toys/release/component.rb
|
|
60
|
+
- toys/.lib/toys/release/environment_utils.rb
|
|
61
|
+
- toys/.lib/toys/release/performer.rb
|
|
62
|
+
- toys/.lib/toys/release/pull_request.rb
|
|
63
|
+
- toys/.lib/toys/release/repo_settings.rb
|
|
64
|
+
- toys/.lib/toys/release/repository.rb
|
|
65
|
+
- toys/.lib/toys/release/request_logic.rb
|
|
66
|
+
- toys/.lib/toys/release/request_spec.rb
|
|
67
|
+
- toys/.lib/toys/release/semver.rb
|
|
68
|
+
- toys/.lib/toys/release/steps.rb
|
|
69
|
+
- toys/.lib/toys/release/version_rb_file.rb
|
|
70
|
+
- toys/.toys.rb
|
|
71
|
+
- toys/_onclosed.rb
|
|
72
|
+
- toys/_onopen.rb
|
|
73
|
+
- toys/_onpush.rb
|
|
74
|
+
- toys/create-labels.rb
|
|
75
|
+
- toys/gen-gh-pages.rb
|
|
76
|
+
- toys/gen-settings.rb
|
|
77
|
+
- toys/gen-workflows.rb
|
|
78
|
+
- toys/perform.rb
|
|
79
|
+
- toys/request.rb
|
|
80
|
+
- toys/retry.rb
|
|
81
|
+
homepage: https://github.com/dazuma/toys
|
|
82
|
+
licenses:
|
|
83
|
+
- MIT
|
|
84
|
+
metadata:
|
|
85
|
+
changelog_uri: https://dazuma.github.io/toys/gems/toys-release/v0.1.0/file.CHANGELOG.html
|
|
86
|
+
source_code_uri: https://github.com/dazuma/toys/tree/main/toys-release
|
|
87
|
+
bug_tracker_uri: https://github.com/dazuma/toys/issues
|
|
88
|
+
documentation_uri: https://dazuma.github.io/toys/gems/toys-release/v0.1.0
|
|
89
|
+
rdoc_options: []
|
|
90
|
+
require_paths:
|
|
91
|
+
- lib
|
|
92
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - ">="
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: 2.7.0
|
|
97
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
98
|
+
requirements:
|
|
99
|
+
- - ">="
|
|
100
|
+
- !ruby/object:Gem::Version
|
|
101
|
+
version: '0'
|
|
102
|
+
requirements: []
|
|
103
|
+
rubygems_version: 3.6.9
|
|
104
|
+
specification_version: 4
|
|
105
|
+
summary: Release system using GitHub Actions and Toys
|
|
106
|
+
test_files: []
|