Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve release workflow on CircleCI #245

Merged
merged 15 commits into from
Mar 15, 2020
95 changes: 91 additions & 4 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,27 @@ aliases:
branches:
ignore: /.*/

- &filter-major-release-tags-only
filters:
tags:
only: major-release
branches:
ignore: /.*/

- &filter-minor-release-tags-only
filters:
tags:
only: minor-release
branches:
ignore: /.*/

- &filter-patch-release-tags-only
filters:
tags:
only: patch-release
branches:
ignore: /.*/


jobs:

Expand Down Expand Up @@ -207,7 +228,7 @@ jobs:
- store-reports

lint-podspec:
executor: ios12-iphone-xs-max
executor: ios13-iphone-11-pro-max
steps:
- checkout
- setup-gems
Expand All @@ -216,7 +237,7 @@ jobs:
command: bundle exec rake lint_podspec

build-documentation:
executor: ios12-iphone-xs-max
executor: ios13-iphone-11-pro-max
steps:
- checkout
- setup-gems
Expand All @@ -226,7 +247,7 @@ jobs:
command: bundle exec rake generate_documentation

generate-changelog:
executor: ios12-iphone-xs-max
executor: ios13-iphone-11-pro-max
steps:
- checkout
- setup-gems
Expand All @@ -247,8 +268,56 @@ jobs:
- store_test_results:
path: result.xml

create-major-release-pull-request:
jjochen marked this conversation as resolved.
Show resolved Hide resolved
executor: ios13-iphone-11-pro-max
steps:
- checkout
- setup-gems
- setup-cocoapods
- run:
name: Create major release pull request
command: bundle exec rake release_next_version 'major'

create-minor-release-pull-request:
jjochen marked this conversation as resolved.
Show resolved Hide resolved
executor: ios13-iphone-11-pro-max
steps:
- checkout
- setup-gems
- setup-cocoapods
- run:
name: Create minor release pull request
command: bundle exec rake release_next_version 'minor'

create-patch-release-pull-request:
jjochen marked this conversation as resolved.
Show resolved Hide resolved
executor: ios13-iphone-11-pro-max
steps:
- checkout
- setup-gems
- setup-cocoapods
- run:
name: Create patch release pull request
command: bundle exec rake release_next_version 'patch'

create-version-tag:
jjochen marked this conversation as resolved.
Show resolved Hide resolved
executor: ios13-iphone-11-pro-max
steps:
- checkout
- setup-gems
- run:
name: Create version tag on github
command: bundle exec rake create_github_release

close-milestone:
executor: ios13-iphone-11-pro-max
steps:
- checkout
- setup-gems
- run:
name: Close milestone on github
command: bundle exec rake close_github_milestone

push-podspec:
executor: ios12-iphone-xs-max
executor: ios13-iphone-11-pro-max
steps:
- checkout
- setup-gems
Expand All @@ -269,4 +338,22 @@ workflows:
- build-and-test-ios12-iphonexsmax
- build-documentation
- generate-changelog
- create-version-tag:
requires:
- lint-podspec
- swiftlint
- build-and-test-ios13-iphone11promax
- build-and-test-ios12-iphonexsmax
- build-documentation
- generate-changelog
filters:
branches:
only: master

deploy:
jobs:
- close-milestone: *filter-version-tags-only
- push-podspec: *filter-version-tags-only
- create-major-release-pull-request: *filter-major-release-tags-only
- create-minor-release-pull-request: *filter-minor-release-tags-only
- create-patch-release-pull-request: *filter-patch-release-tags-only
134 changes: 120 additions & 14 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -159,18 +159,26 @@ begin

#-- Release ----------------------------------------------------------------#

desc 'Release version'
task :release_version, :version do |task, args|
desc 'Initiate release workflow of type'
task :initiate_release, :type do |task, args|
ensure_clean_git_status
checkout_and_pull_master
ensure_clean_git_status
update_version_in_podspec args.version
update_version_in_example_project args.version
generate_changelog args.version
install_cocoapods
generate_documentation
create_release_branch_and_commit args.version
open_pull_request args.version
create_github_release_trigger_tag args.type
end

desc 'Release next version of type'
task :release_next_version, :type do |task, args|
release_next_version args.type
end

desc 'Release version'
task :release_version, :version do |task, args|
release_version args.version
end

desc 'Delete GitHub release tag of type'
task :delete_github_release_trigger_tag, :type do |task, args|
delete_github_release_trigger_tag args.type
end

desc 'Push podspec'
Expand All @@ -181,9 +189,15 @@ begin

desc 'Create release on github'
task :create_github_release do
version = version_from_podspec

unless is_release_commit_for_version version
puts "Not a release commit."
next
end

title "Creating release on github"
repo = "jjochen/JJFloatingActionButton"
version = version_from_podspec
body = changelog_for_version version
options = {
:name => version,
Expand All @@ -201,6 +215,29 @@ begin
puts "#{release.name} created."
end

desc 'Close milestone on github'
task :close_github_milestone do
title "Closing milestone on github"

repo = "jjochen/JJFloatingActionButton"
version = version_from_podspec

puts "repo: #{repo}"
puts "version: #{version}"

client = Octokit::Client.new :access_token => ENV['JJ_GITHUB_TOKEN']
open_milestones = client.list_milestones repo, {:state => 'open'}
open_milestones.each do |milestone|
next unless milestone.title == version

number = milestone.number
puts "number: #{number}"

client.update_milestone repo, number, {:state => 'closed'}
puts "#{milestone.title} closed."
end
end

desc 'Update github releases'
task :update_github_releases do
title "Updating releases on github"
Expand Down Expand Up @@ -272,6 +309,30 @@ def check_parameter(parameter)
end
end

def increment_semver(semver, increment_type = "patch")
if not (/\d+\.\d+\.\d+/).match(semver)
raise "Your semantic version must match the format 'X.X.X'."
end
if not ["patch", "minor", "major"].include?(increment_type)
raise "Only 'patch', 'minor', and 'major' are supported increment types."
end

major, minor, patch = semver.split(".")
case increment_type
when "patch"
patch = patch.to_i + 1
when "minor"
minor = minor.to_i + 1
patch = 0
when "major"
major = major.to_i + 1
minor = 0
patch = 0
end

return "#{major}.#{minor}.#{patch}"
end

def install_gems
title 'Installing gems'
sh 'bundle install'
Expand Down Expand Up @@ -306,6 +367,26 @@ def xcodebuild_test(destination)
" | xcpretty --report junit && exit ${PIPESTATUS[0]}"
end

def release_next_version(type)
version = version_from_podspec
new_version = increment_semver(version, type)
release_version new_version
delete_github_release_trigger_tag(type)
end

def release_version(version)
ensure_clean_git_status
checkout_and_pull_master
ensure_clean_git_status
update_version_in_podspec version
update_version_in_example_project version
generate_changelog version
install_cocoapods
generate_documentation
create_release_branch_and_commit version
open_pull_request version
end

def ensure_clean_git_status
title "Ensuring clean git status"
unless `git diff --shortstat 2> /dev/null | tail -n1` == ''
Expand All @@ -314,6 +395,11 @@ def ensure_clean_git_status
end
end

def is_release_commit_for_version(version)
commit_message = `git log -1 --pretty=%B 2> /dev/null`
return commit_message.match(/^Release #{version} \(.*\)$/)
end

def checkout_and_pull_master
title "Checkout and pull master"
sh "git checkout master"
Expand Down Expand Up @@ -390,7 +476,7 @@ def changelog_for_version(version)
end
end
if changelog.nil? || changelog.empty?
error_message "changelog for version #{verion} not found."
error_message "changelog for version #{version} not found."
exit 1
end
return changelog
Expand All @@ -406,6 +492,27 @@ def create_release_branch_and_commit(version)
sh "git push --set-upstream origin #{release_branch}"
end

def release_trigger_tag(type)
if not ["patch", "minor", "major"].include?(type)
raise "Only 'patch', 'minor', and 'major' are supported types. '#{type}' is not."
end
return "#{type}-release"
end

def create_github_release_trigger_tag(type)
title "Creating release tag"
tag = release_trigger_tag(type)
sh "git tag -a #{tag} -m 'Initiating #{type} release'"
sh "git push --set-upstream origin #{tag}"
sh "git tag -ad#{tag}"
end

def delete_github_release_trigger_tag(type)
title "Deleting release tag"
tag = release_trigger_tag(type)
sh "git push origin --delete #{tag} || true"
end

def open_pull_request(version)
title "Opening pull request"
check_parameter(version)
Expand All @@ -429,5 +536,4 @@ def open_pull_request(version)
puts "release label added."

sh "open #{pull_request.html_url}"
end

end