Skip to content

Commit

Permalink
Migrate prepare hotfix (#21)
Browse files Browse the repository at this point in the history
Co-authored-by: Dominik Kapusta <[email protected]>
  • Loading branch information
kshann and ayoy authored Nov 25, 2024
1 parent 270faa3 commit f8f3d4d
Show file tree
Hide file tree
Showing 7 changed files with 315 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,23 @@ def self.run(params)
options = params.values
options[:asana_user_id] = Helper::AsanaHelper.get_asana_user_id_for_github_handle(options[:github_handle])

release_branch_name, new_version = Helper::DdgAppleAutomationHelper.prepare_release_branch(
params[:platform], params[:version], other_action
)
if params[:is_hotfix]
release_branch_name, new_version = Helper::DdgAppleAutomationHelper.prepare_hotfix_branch(
params[:github_token], params[:platform], other_action, options
)
else
release_branch_name, new_version = Helper::DdgAppleAutomationHelper.prepare_release_branch(
params[:platform], params[:version], other_action
)
end

options[:version] = new_version
options[:release_branch_name] = release_branch_name

release_task_id = Helper::AsanaHelper.create_release_task(options[:platform], options[:version], options[:asana_user_id], options[:asana_access_token])
release_task_id = Helper::AsanaHelper.create_release_task(options[:platform], options[:version], options[:asana_user_id], options[:asana_access_token], is_hotfix: options[:is_hotfix])
options[:release_task_id] = release_task_id

Helper::AsanaHelper.update_asana_tasks_for_internal_release(options)
Helper::AsanaHelper.update_asana_tasks_for_internal_release(options) unless params[:is_hotfix]
end

def self.description
Expand All @@ -49,6 +56,7 @@ def self.details
* pushes the changes to the remote repository,
* creates a new Asana release task based off the provided task template,
* updates the Asana release task with tasks included in the release.
For hotfix releases, the action creates a hotfix branch off the latest public release tag, updates the build number and pushes the changes.
DETAILS
end

Expand All @@ -67,8 +75,13 @@ def self.available_options
type: String),
FastlaneCore::ConfigItem.new(key: :target_section_id,
description: "Section ID in Asana where tasks included in the release should be moved",
optional: false,
type: String)
optional: true,
type: String),
FastlaneCore::ConfigItem.new(key: :is_hotfix,
description: "Is this a hotfix release?",
optional: true,
type: Boolean,
default_value: false)
]
end

Expand Down
14 changes: 7 additions & 7 deletions lib/fastlane/plugin/ddg_apple_automation/helper/asana_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ def self.upload_file_to_asana_task(task_id, file_path, asana_access_token)
end
end

def self.release_template_task_id(platform, is_hotfix: false)
def self.release_template_task_id(platform, is_hotfix)
case platform
when "ios"
is_hotfix ? IOS_HOTFIX_TASK_TEMPLATE_ID : IOS_RELEASE_TASK_TEMPLATE_ID
Expand All @@ -140,7 +140,7 @@ def self.release_template_task_id(platform, is_hotfix: false)
end
end

def self.release_task_name(version, platform, is_hotfix: false)
def self.release_task_name(version, platform, is_hotfix)
case platform
when "ios"
is_hotfix ? "iOS App Hotfix Release #{version}" : "iOS App Release #{version}"
Expand Down Expand Up @@ -173,9 +173,9 @@ def self.release_section_id(platform)
end
end

def self.create_release_task(platform, version, assignee_id, asana_access_token)
template_task_id = release_template_task_id(platform)
task_name = release_task_name(version, platform)
def self.create_release_task(platform, version, assignee_id, asana_access_token, is_hotfix: false)
template_task_id = release_template_task_id(platform, is_hotfix)
task_name = release_task_name(version, platform, is_hotfix)
section_id = release_section_id(platform)

UI.message("Creating release task for #{version}")
Expand Down Expand Up @@ -282,6 +282,7 @@ def self.update_asana_tasks_for_public_release(params)

# Complete tasks that don't require a post-mortem.
UI.message("Completing tasks")
task_ids.delete(params[:release_task_id])
complete_tasks(task_ids, params[:asana_access_token])
UI.message("Done completing tasks")

Expand All @@ -292,7 +293,6 @@ def self.update_asana_tasks_for_public_release(params)

# Construct release announcement task description
UI.message("Preparing release announcement task")
task_ids.delete(params[:release_task_id])
Helper::ReleaseTaskHelper.construct_release_announcement_task_description(params[:version], release_notes, task_ids)
end

Expand Down Expand Up @@ -416,7 +416,7 @@ def self.get_task_ids_from_git_log(from_ref, to_ref = "HEAD")

git_log
.gsub("\n", " ")
.scan(%r{\bTask/Issue URL:.*?https://app\.asana\.com[/0-9f]+\b})
.scan(%r{\bTask/Issue URL:\s*https://app\.asana\.com[/0-9f]+\b})
.map { |task_line| task_line.gsub(/.*(https.*)/, '\1') }
.map { |task_url| extract_asana_task_id(task_url, set_gha_output: false) }
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
require "rexml/document"
require "semantic"
require_relative "github_actions_helper"
require_relative "git_helper"

module Fastlane
UI = FastlaneCore::UI unless Fastlane.const_defined?(:UI)
Expand Down Expand Up @@ -132,6 +133,56 @@ def self.prepare_release_branch(platform, version, other_action)
return release_branch_name, new_version
end

def self.prepare_hotfix_branch(github_token, platform, other_action, options)
client = Octokit::Client.new(access_token: github_token)
latest_public_release = client.latest_release(Helper::GitHelper.repo_name(platform))
version = latest_public_release.tag_name
Helper::GitHubActionsHelper.set_output("last_release", version)
UI.user_error!("Unable to find latest release to hotfix") unless version
source_version = validate_version_exists(version)
new_version = validate_hotfix_version(source_version)
release_branch_name = create_hotfix_branch(platform, source_version, new_version)
increment_build_number(platform, options, other_action)
Helper::GitHubActionsHelper.set_output("release_branch_name", release_branch_name)

return release_branch_name, new_version
end

def self.create_hotfix_branch(platform, source_version, new_version)
branch_name = "#{HOTFIX_BRANCH}/#{new_version}"
UI.message("Creating new hotfix release branch for #{new_version}")

existing_branch = Actions.sh("git", "branch", "--list", branch_name).strip
UI.abort_with_message!("Branch #{branch_name} already exists in this repository. Aborting.") unless existing_branch.empty?
Actions.sh("git", "fetch", "--tags")
Actions.sh("git", "checkout", "-b", branch_name, source_version)
Actions.sh("git", "push", "-u", "origin", branch_name)
branch_name
end

def self.validate_hotfix_version(source_version)
new_version = bump_patch_version(source_version)
UI.important("Release #{source_version} will be hotfixed as #{new_version}.")

if UI.interactive? && !UI.confirm("Do you want to continue?")
UI.abort_with_message!('Aborted by user.')
end

new_version
end

def self.validate_version_exists(version)
user_version = format_version(version)
UI.user_error!("Incorrect version provided: #{version}. Expected x.y.z format.") unless user_version

Actions.sh('git', 'fetch', '--tags')
existing_tag = Actions.sh('git', 'tag', '--list', user_version).chomp
existing_tag = nil if existing_tag.empty?

UI.user_error!("Release #{user_version} not found. Make sure you've passed the version you want to make hotfix for, not the upcoming hotfix version.") unless existing_tag
existing_tag
end

def self.create_release_branch(version)
UI.message("Creating new release branch for #{version}")
release_branch = "#{RELEASE_BRANCH}/#{version}"
Expand Down
2 changes: 1 addition & 1 deletion lib/fastlane/plugin/ddg_apple_automation/version.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module Fastlane
module DdgAppleAutomation
VERSION = "0.11.7"
VERSION = "0.12.0"
end
end
79 changes: 77 additions & 2 deletions spec/asana_helper_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@ def sanitize_asana_html_notes(content)

let(:tag_name) { "7.122.0" }
let(:tag_id) { "7.122.0" }
let(:task_ids) { ["task1", "task2", "task3"] }
let(:task_ids) { ["1234567890", "1234567891", "1234567892"] }
let(:release_notes) { "Release notes content" }

before do
Expand Down Expand Up @@ -400,10 +400,11 @@ def sanitize_asana_html_notes(content)
expect(Fastlane::UI).to have_received(:message).with("Fetching #{tag_name} Asana tag")
expect(Fastlane::UI).to have_received(:success).with("#{tag_name} tag URL: https://app.asana.com/0/#{tag_id}/list")
expect(Fastlane::UI).to have_received(:message).with("Fetching tasks tagged with #{tag_name}")
expect(Fastlane::UI).to have_received(:success).with("#{task_ids.count} task(s) found.")
expect(Fastlane::UI).to have_received(:success).with("3 task(s) found.")
expect(Fastlane::UI).to have_received(:message).with("Moving tasks to Done section")
expect(Fastlane::UI).to have_received(:success).with("All tasks moved to Done section")
expect(Fastlane::UI).to have_received(:message).with("Completing tasks")
expect(task_ids).to eq(["1234567891", "1234567892"]) # Check function removes release task
expect(Fastlane::UI).to have_received(:message).with("Done completing tasks")
expect(Fastlane::UI).to have_received(:message).with("Fetching release notes from Asana release task (https://app.asana.com/0/0/1234567890/f)")
expect(Fastlane::UI).to have_received(:success).with("Release notes: #{release_notes}")
Expand Down Expand Up @@ -515,6 +516,80 @@ def sanitize_asana_html_notes(content)
end
end

describe "#get_task_ids_from_git_log" do
it "extracts Asana task IDs from git log" do
git_log = <<~LOG
commit 1b6f8be812eac431d4e36ec24d4344369f4ce470
Bump version to 1.115.0 (312)
commit ca70d42a7c4e2f1b62f6716eb08d286f2a218c4d
Add attemptCount and maxAttempts to broker config (#3533)
Task/Issue URL:https://app.asana.com/0/72649045549333/1208700893044577/f
Tech Design URL:
https://app.asana.com/0/481882893211075/1208663928051302/f
CC:
**Definition of Done**:
#{' '}
* [ ] Does this PR satisfy our [Definition of
Done](https://app.asana.com/0/1202500774821704/1207634633537039/f)?
commit 7202ff2597d21db57fd6dc9a295e11991c81b3e7
Hide continue setup cards after 1 week (#3471)
#{' '}
Task/Issue URL: https://app.asana.com/0/1202406491309510/1208589738926535/f
commit e83fd007c0bdf054658068a79f5b7ea45d846468
Receive privacy config updates in AddressBarModel on main thread (#3574)
#{' '}
Task/Issue URL:#{' '}
#{' '}
https://app.asana.com/0/1201037661562251/1208804405760977/f
#{' '}
Description:
This privacy config update may update a published value so must be received on main thread.
commit 9587487662876eee3f2606cf5040d4ee80e0c0a7
Add expectation when checking email text field value (#3572)
#{' '}
Task/Issue URL:
Tech Design URL:
CC:
#{' '}
**Description**:
* [x] Does this PR satisfy our [Definition of
Done](https://app.asana.com/0/1202500774821704/1207634633537039/f)?
#{' '}
###### Internal references:
[Pull Request Review
Checklist](https://app.asana.com/0/1202500774821704/1203764234894239/f)
[Software Engineering
Expectations](https://app.asana.com/0/59792373528535/199064865822552)
[Technical Design
Template](https://app.asana.com/0/59792373528535/184709971311943)
[Pull Request
Documentation](https://app.asana.com/0/1202500774821704/1204012835277482/f)
LOG

allow(Fastlane::Helper::AsanaHelper).to receive(:`).with("git log v1.0.0..HEAD").and_return(git_log)

task_ids = Fastlane::Helper::AsanaHelper.get_task_ids_from_git_log("v1.0.0")
expect(task_ids).to eq(["1208700893044577", "1208589738926535", "1208804405760977"])
end

it "returns an empty array if no task IDs are found" do
allow(Fastlane::Helper::AsanaHelper).to receive(:`).with("git log v1.0.0..HEAD").and_return("No tasks here.")

task_ids = Fastlane::Helper::AsanaHelper.get_task_ids_from_git_log("v1.0.0")
expect(task_ids).to eq([])
end
end

describe ".move_tasks_to_section" do
let(:task_ids) { ["task1", "task2", "task3"] }
let(:section_id) { "987654321" }
Expand Down
Loading

0 comments on commit f8f3d4d

Please sign in to comment.