Skip to content

Commit

Permalink
Improve release workflow on CircleCI (#245)
Browse files Browse the repository at this point in the history
* create release version tag via circleci workflow (WIP)

* add circleci release jobs to deploy workflow

* add actual release related commands to rakefile and circleci

* fix circleci config

* typo

* fix rake config

* fix rake tasks

* create github releases only from release commits

* typo

* no message

* Close github milestone when release tag is added

* create/delete release tags

* delete local release trigger tag after pushing it

* rename release_tag to release_trigger tag

* refactor job filters in circleci config

Co-authored-by: Jochen Pfeiffer <[email protected]>
  • Loading branch information
jjochen and jjochen committed Mar 15, 2020
1 parent b99b006 commit d2055cd
Show file tree
Hide file tree
Showing 2 changed files with 211 additions and 18 deletions.
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:
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:
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:
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:
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

0 comments on commit d2055cd

Please sign in to comment.