-
Notifications
You must be signed in to change notification settings - Fork 113
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Release and publish scripts v2 (#925)
Working with bash is not the ideal dev experience, so I'm moving our scripts to `thor`! Since `thor` scripts are written with Ruby (which most of our team is experienced with), iterating over them should be easier. I'm also adding new features to the scripts: 1. `release` will create the PR for you 2. `publish` will create the release for you Note: It's really hard to test this since I don't want to create unnecessary releases, but I'm highly confident in the code. Worst-case scenario we can fix bugs while doing the next release
- Loading branch information
1 parent
f5930a3
commit bc7abe0
Showing
2 changed files
with
185 additions
and
180 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,42 @@ | ||
#!/usr/bin/env bash | ||
#!/usr/bin/env ruby | ||
# frozen_string_literal: true | ||
|
||
# Publish gem | ||
bundle exec rake release | ||
require "thor" | ||
require_relative "../lib/primer/view_components/version" | ||
|
||
# Publish NPM | ||
npm publish --access public | ||
# Publishes `primer_view_components` gem and npm package, and creates a new GitHub release. | ||
# | ||
# Usage: | ||
# | ||
# script/publish | ||
class PublishCLI < Thor::Group | ||
include Thor::Actions | ||
|
||
def release_gem | ||
run("bundle exec release") | ||
end | ||
|
||
def release_npm | ||
run("npm publish --access public") | ||
end | ||
|
||
def github_release | ||
run("gh release create v#{version} -n \"#{release_notes}\"") | ||
end | ||
|
||
private | ||
|
||
def release_notes | ||
changelog.gsub(/.*## #{version}/m, "").gsub(/^## .*/m, "").strip | ||
end | ||
|
||
def version | ||
Primer::ViewComponents::VERSION::STRING | ||
end | ||
|
||
def changelog | ||
File.read("CHANGELOG.md") | ||
end | ||
end | ||
|
||
PublishCLI.start(ARGV) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,176 +1,146 @@ | ||
#!/usr/bin/env bash | ||
|
||
if [ $(uname -s) = "Darwin" ]; then | ||
SED_ARGS="-i ''" | ||
else | ||
SED_ARGS="-i" | ||
fi | ||
|
||
fetch() { | ||
git fetch --all | ||
} | ||
|
||
branch_name() { | ||
git symbolic-ref --short HEAD | ||
} | ||
|
||
local_history_is_clean() { | ||
history=$(git rev-list --count --right-only @{u}...HEAD) | ||
[ "$history" == "0" ] | ||
} | ||
|
||
remote_history_is_clean() { | ||
history=$(git rev-list --count --left-only @{u}...HEAD) | ||
[ "$history" == "0" ] | ||
} | ||
|
||
tag_exists_on_remote() { | ||
git rev-parse --quiet --verify refs/tags/v$1.$2.$3 > /dev/null | ||
} | ||
|
||
working_tree_is_clean() { | ||
status=$(git status --porcelain) | ||
[ "$status" == "" ] | ||
} | ||
|
||
create_release_branch() { | ||
git switch -c release-v$1-$2-$3 | ||
} | ||
|
||
update_readme() { | ||
sed $SED_ARGS "/## main/ {a\ | ||
\\ | ||
\\ | ||
## $1.$2.$3 | ||
}" CHANGELOG.md | ||
} | ||
|
||
update_ruby_version() { | ||
# Update version file | ||
sed -E $SED_ARGS \ | ||
-e "s/MAJOR = [0-9]+/MAJOR = $1/g" \ | ||
-e "s/MINOR = [0-9]+/MINOR = $2/g" \ | ||
-e "s/PATCH = [0-9]+/PATCH = $3/g" \ | ||
#!/usr/bin/env ruby | ||
# frozen_string_literal: true | ||
|
||
require "thor" | ||
require_relative "../lib/primer/view_components/version" | ||
|
||
# Prepares a release PR for `primer_view_components`. | ||
# | ||
# Usage: | ||
# | ||
# script/release for a patch release | ||
# script/release --major for a major release | ||
# script/release --minor for a minor release | ||
class ReleaseCLI < Thor::Group | ||
include Thor::Actions | ||
|
||
class_option :major, type: :boolean, desc: "Use this option to bump a major version." | ||
class_option :minor, type: :boolean, desc: "Use this option to bump a minor version." | ||
class_option :patch, type: :boolean, desc: "Use this option to bump a patch version." | ||
|
||
def self.exit_on_failure? | ||
false | ||
end | ||
|
||
def working_tree_is_clean | ||
tree_status = run("git status --porcelain", capture: true).strip | ||
raise "Tree is not clean" unless tree_status.empty? | ||
end | ||
|
||
def must_be_in_main | ||
raise "Must be in the main branch to release" unless current_branch == "main" | ||
end | ||
|
||
def git_fetch | ||
run("git fetch --all") | ||
end | ||
|
||
def remote_history_is_clean | ||
remote_history = run("git rev-list --count --left-only @{u}...HEAD", capture: true).strip | ||
raise "Changes exist on origin not pulled into this branch. Please pull" unless remote_history == "0" | ||
end | ||
|
||
def local_history_is_clean | ||
remote_history = run("git rev-list --count --right-only @{u}...HEAD", capture: true).strip | ||
raise "Changes exist that haven't been pushed to origin. Please pull" unless remote_history == "0" | ||
end | ||
|
||
def tag_exists_on_remote | ||
raise "Tag exists on remote" unless run("git rev-parse --quiet --verify refs/tags/v#{new_version}", capture: true).strip.empty? | ||
end | ||
|
||
def create_release_branch | ||
run("git switch -c #{release_branch}") | ||
end | ||
|
||
def update_readme | ||
gsub_file("CHANGELOG.md", "## main", "## main\n\n## #{new_version}") | ||
end | ||
|
||
def update_ruby_version | ||
major, minor, patch = new_version.split(".") | ||
|
||
gsub_file("lib/primer/view_components/version.rb", /MAJOR = [0-9]+/, "MAJOR = #{major}") | ||
gsub_file("lib/primer/view_components/version.rb", /MINOR = [0-9]+/, "MINOR = #{minor}") | ||
gsub_file("lib/primer/view_components/version.rb", /PATCH = [0-9]+/, "PATCH = #{patch}") | ||
end | ||
|
||
def update_gemfiles | ||
run("bundle") | ||
run("pushd demo") | ||
run("bundle") | ||
run("popd") | ||
end | ||
|
||
def update_npm | ||
run("npm version --no-git-tag-version \"#{new_version}\"") | ||
run("yarn") | ||
end | ||
|
||
def add_changed_files | ||
files_to_add = %w[ | ||
CHANGELOG.md | ||
Gemfile.lock | ||
demo/Gemfile.lock | ||
lib/primer/view_components/version.rb | ||
} | ||
|
||
update_gemfiles() { | ||
# Update Gemfile.lock | ||
bundle | ||
pushd demo | ||
bundle | ||
popd | ||
} | ||
|
||
|
||
update_npm() { | ||
npm version --no-git-tag-version "$1.$2.$3" | ||
yarn | ||
} | ||
|
||
add_changed_files() { | ||
git add \ | ||
CHANGELOG.md \ | ||
Gemfile.lock \ | ||
demo/Gemfile.lock \ | ||
lib/primer/view_components/version.rb \ | ||
app/assets/javascripts \ | ||
package.json \ | ||
yarn.lock | ||
} | ||
|
||
commit() { | ||
git commit -m "release $1.$2.$3" | ||
} | ||
|
||
push() { | ||
git push origin release-v$1-$2-$3 | ||
} | ||
|
||
main() { | ||
version=$(ruby ./lib/primer/view_components/version.rb) | ||
version=(${version//./ }) | ||
major=${version[0]} | ||
minor=${version[1]} | ||
patch=${version[2]} | ||
|
||
echo "===================" | ||
echo "Prerequisite Checks" | ||
echo "===================" | ||
|
||
if ! working_tree_is_clean; then | ||
echo "Error: unclean working tree" | ||
exit 1 | ||
fi | ||
|
||
if [[ "$(branch_name)" != "main" ]]; then | ||
echo "Error: can only make a release on the main branch" | ||
exit 1 | ||
fi | ||
|
||
fetch | ||
if ! remote_history_is_clean; then | ||
echo "Error: changes exist on origin not pulled into this branch. Please pull" | ||
exit 1 | ||
fi | ||
|
||
if ! local_history_is_clean; then | ||
echo "Error: changes exist that haven't been pushed to origin. Please pull" | ||
exit 1 | ||
fi | ||
|
||
echo "Type the number of an option to bump, or pick Manual to enter a version number" | ||
select bump in Major Minor Patch Manual | ||
do | ||
if [ "$bump" == "Major" ]; then | ||
major=$((major + 1)) | ||
minor=0 | ||
patch=0 | ||
elif [ "$bump" == "Minor" ]; then | ||
minor=$((minor + 1)) | ||
patch=0 | ||
elif [ "$bump" == "Patch" ]; then | ||
patch=$((patch + 1)) | ||
else | ||
read -p "What version? (Currently $major.$minor.$patch): " new_version | ||
if [ "$new_version" == "$major.$minor.$patch" ]; then | ||
echo "Error: Cannot be the same version" | ||
exit 1 | ||
fi | ||
|
||
new_version=(${new_version//./ }) | ||
|
||
major=${new_version[0]} | ||
minor=${new_version[1]} | ||
patch=${new_version[2]} | ||
fi | ||
|
||
if tag_exists_on_remote $major $minor $patch; then | ||
echo "Error: tag exists on remote" | ||
exit 1 | ||
fi | ||
|
||
echo "===============================" | ||
echo "Creating release for $major.$minor.$patch" | ||
echo "===============================" | ||
|
||
create_release_branch $major $minor $patch | ||
update_readme $major $minor $patch | ||
update_ruby_version $major $minor $patch | ||
update_gemfiles $major $minor $patch | ||
update_npm $major $minor $patch | ||
add_changed_files $major $minor $patch | ||
commit $major $minor $patch | ||
push $major $minor $patch | ||
|
||
echo "####################################################" | ||
echo "Now, open a PR with this branch and merge it to main." | ||
echo "When the PR has been merged, run script/publish to publish the gem." | ||
echo "Finally, create a GitHub release https://github.com/primer/view_components/releases/new with the changes from CHANGELOG" | ||
echo "####################################################" | ||
|
||
break | ||
done | ||
} | ||
|
||
main | ||
app/assets/javascripts | ||
package.json | ||
yarn.lock | ||
] | ||
|
||
run("git add #{files_to_add.join(' ')}") | ||
end | ||
|
||
def commit_files | ||
run("git commit -m \"release #{new_version}\"") | ||
end | ||
|
||
def push_files | ||
run("git push origin #{release_branch}") | ||
end | ||
|
||
def create_pull_request | ||
@pr_url = run("gh pr create -b "" -t \"Release v#{new_version}\"", capture: true) | ||
end | ||
|
||
def final_message | ||
puts "####################################################" | ||
puts "PR link: #{@pr_url}" | ||
puts "When the PR has been merged, run script/publish to publish the gem." | ||
puts "####################################################" | ||
end | ||
|
||
private | ||
|
||
def current_branch | ||
@current_branch ||= run("git symbolic-ref --short HEAD", capture: true).strip | ||
end | ||
|
||
def current_version | ||
Primer::ViewComponents::VERSION::STRING | ||
end | ||
|
||
def new_version | ||
@new_version ||= case bump | ||
when :major | ||
"#{Primer::ViewComponents::VERSION::MAJOR + 1}.0.0" | ||
when :minor | ||
"#{Primer::ViewComponents::VERSION::MAJOR}.#{Primer::ViewComponents::VERSION::MINOR + 1}.0" | ||
else | ||
"#{Primer::ViewComponents::VERSION::MAJOR}.#{Primer::ViewComponents::VERSION::MINOR}.#{Primer::ViewComponents::VERSION::PATCH + 1}" | ||
end | ||
end | ||
|
||
def bump | ||
return :major if options[:major] | ||
return :minor if options[:minor] | ||
|
||
:patch | ||
end | ||
|
||
def release_branch | ||
"release-v#{new_version}" | ||
end | ||
end | ||
|
||
ReleaseCLI.start(ARGV) |
bc7abe0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs: