Skip to content

Commit

Permalink
Add partial spec
Browse files Browse the repository at this point in the history
  • Loading branch information
ayoy committed Sep 3, 2024
1 parent bf58868 commit c5bfb87
Show file tree
Hide file tree
Showing 2 changed files with 208 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,19 +37,20 @@ def self.run(params)
setup_constants(platform)

latest_marketing_version = find_latest_marketing_version(github_token)
release_task_id = find_release_task(latest_marketing_version, platform, asana_access_token)
release_task_id = find_release_task(latest_marketing_version, asana_access_token)

release_task_url = "#{Helper::DdgAppleAutomationHelper::ASANA_APP_URL}/#{release_task_id}/f"
release_branch = "release/#{latest_marketing_version}"
UI.success("Found #{latest_marketing_version} release task: #{release_task_url}")

Helper::GitHubActionsHelper.set_output("release_branch", "release/#{latest_marketing_version}")
Helper::GitHubActionsHelper.set_output("release_branch", release_branch)
Helper::GitHubActionsHelper.set_output("release_task_id", release_task_id)
Helper::GitHubActionsHelper.set_output("release_task_url", release_task_url)

{
release_task_id: release_task_id,
release_task_url: release_task_url,
release_branch: "release/#{latest_marketing_version}"
release_branch: release_branch
}
end

Expand All @@ -58,13 +59,29 @@ def self.find_latest_marketing_version(github_token)

# NOTE: `client.latest_release` returns release marked as "latest", i.e. a public release
latest_internal_release = client.releases(@constants[:repo_name], { per_page: 1 }).first
tag_name = latest_internal_release['tag_name']
version = tag_name&.split("-")&.first
Fastlane::UI.user_error!("Failed to fetch latest release") if version.nil?

version = extract_version_from_tag_name(latest_internal_release&.tag_name)
if version.to_s.empty?
Fastlane::UI.user_error!("Failed to find latest marketing version")
return
end
unless self.validate_semver(version)
Fastlane::UI.user_error!("Invalid marketing version: #{version}, expected format: MAJOR.MINOR.PATCH")
return
end
version
end

def self.find_release_task(version, platform, asana_access_token)
def self.extract_version_from_tag_name(tag_name)
tag_name&.split("-")&.first
end

def self.validate_semver(version)
# we only need basic "x.y.z" validation here
version.match?(/\A\d+\.\d+\.\d+\z/)
end

def self.find_release_task(version, asana_access_token)
release_task_name = "#{@constants[:release_task_prefix]} #{version}"
# `completed_since=now` returns only incomplete tasks
url = Helper::DdgAppleAutomationHelper::ASANA_API_URL + "/sections/#{@constants[:release_section_id]}/tasks?opt_fields=name,created_at&limit=100&completed_since=now"
Expand All @@ -77,10 +94,16 @@ def self.find_release_task(version, platform, asana_access_token)
loop do
response = HTTParty.get(url, headers: { 'Authorization' => "Bearer #{asana_access_token}" })

find_hotfix_task_in_response(response)
release_task_id ||= find_release_task_in_response(response, release_task_name)
unless response.success?
UI.user_error!("Failed to fetch release task: (#{response.code} #{response.message})")
return
end
parsed_response = response.parsed_response

url = response.dig('next_page', 'uri')
find_hotfix_task_in_response(parsed_response)
release_task_id ||= find_release_task_in_response(parsed_response, release_task_name)

url = parsed_response.dig('next_page', 'uri')

# Don't return as soon as release task is found, as we want to ensure there's no hotfix task
break if url.nil?
Expand All @@ -98,17 +121,6 @@ def self.find_release_task_in_response(response, release_task_name)
release_task_id
end

def self.find_hotfix_task_in_response(response)
hotfix_task_id = response['data']
&.find { |task| task['name']&.start_with?(@constants[:hotfix_task_prefix]) }
&.dig('gid')

if hotfix_task_id
UI.user_error!("Found active hotfix task: #{Helper::DdgAppleAutomationHelper::ASANA_API_URL}/#{hotfix_task_id}")
return
end
end

# Only consider release tasks created in the last 5 days.
# - We don't want to bump internal release automatically for release tasks that are open for more than a week.
# - The automatic check is only done Tuesday-Friday. If the release task is still open next Tuesday, it's unexpected,
Expand All @@ -124,6 +136,17 @@ def self.ensure_task_not_too_old(release_task_id, created_at)
end
end

def self.find_hotfix_task_in_response(response)
hotfix_task_id = response['data']
&.find { |task| task['name']&.start_with?(@constants[:hotfix_task_prefix]) }
&.dig('gid')

if hotfix_task_id
UI.user_error!("Found active hotfix task: #{Helper::DdgAppleAutomationHelper::ASANA_API_URL}/#{hotfix_task_id}")
return
end
end

def self.description
"Finds an active release task in Asana"
end
Expand Down
164 changes: 164 additions & 0 deletions spec/asana_find_release_task_action_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
describe Fastlane::Actions::AsanaFindReleaseTaskAction do
describe "#run" do
describe "when it finds the release task" do
it "returns release task ID, URL and release branch" do
expect(Fastlane::Actions::AsanaFindReleaseTaskAction).to receive(:find_latest_marketing_version).and_return("1.0.0")
expect(Fastlane::Actions::AsanaFindReleaseTaskAction).to receive(:find_release_task).and_return("1234567890")
allow(Fastlane::UI).to receive(:success)
allow(Fastlane::Helper::GitHubActionsHelper).to receive(:set_output)

expect(test_action("ios")).to eq({
release_task_id: "1234567890",
release_task_url: "https://app.asana.com/0/0/1234567890/f",
release_branch: "release/1.0.0"
})

expect(Fastlane::UI).to have_received(:success).with("Found 1.0.0 release task: https://app.asana.com/0/0/1234567890/f")
expect(Fastlane::Helper::GitHubActionsHelper).to have_received(:set_output).with("release_branch", "release/1.0.0")
expect(Fastlane::Helper::GitHubActionsHelper).to have_received(:set_output).with("release_task_id", "1234567890")
expect(Fastlane::Helper::GitHubActionsHelper).to have_received(:set_output).with("release_task_url", "https://app.asana.com/0/0/1234567890/f")
end
end

def test_action(platform)
Fastlane::Actions::AsanaFindReleaseTaskAction.run(platform: platform)
end
end

describe "#find_latest_marketing_version" do
it "returns the latest marketing version" do
client = double
allow(Octokit::Client).to receive(:new).and_return(client)
allow(client).to receive(:releases).and_return([double(tag_name: '1.0.0')])

expect(test_action).to eq("1.0.0")
end

describe "when there is no latest release" do
it "shows error" do
client = double
allow(Octokit::Client).to receive(:new).and_return(client)
allow(client).to receive(:releases).and_return([])
allow(Fastlane::UI).to receive(:user_error!)

test_action

expect(Fastlane::UI).to have_received(:user_error!).with("Failed to find latest marketing version")
end
end

describe "when latest release is not a valid semver" do
it "shows error" do
client = double
allow(Octokit::Client).to receive(:new).and_return(client)
allow(client).to receive(:releases).and_return([double(tag_name: '1.0')])
allow(Fastlane::UI).to receive(:user_error!)

test_action

expect(Fastlane::UI).to have_received(:user_error!).with("Invalid marketing version: 1.0, expected format: MAJOR.MINOR.PATCH")
end
end

def test_action
Fastlane::Actions::AsanaFindReleaseTaskAction.find_latest_marketing_version("token")
end
end

describe "#extract_version_from_tag_name" do
it "returns the version from the tag name" do
expect(test_action("1.0.0")).to eq("1.0.0")
expect(test_action("v1.0.0")).to eq("v1.0.0")
expect(test_action("1.105.0-251")).to eq("1.105.0")
end

def test_action(tag_name)
Fastlane::Actions::AsanaFindReleaseTaskAction.extract_version_from_tag_name(tag_name)
end
end

describe "#validate_semver" do
it "validates semantic version" do
expect(test_action("1.0.0")).to be_truthy
expect(test_action("0.0.0")).to be_truthy
expect(test_action("7.136.1")).to be_truthy

expect(test_action("v1.0.0")).to be_falsy
expect(test_action("7.1")).to be_falsy
expect(test_action("1.105.0-251")).to be_falsy
expect(test_action("1005")).to be_falsy
end

def test_action(version)
Fastlane::Actions::AsanaFindReleaseTaskAction.validate_semver(version)
end
end

describe "#find_release_task" do
before do
Fastlane::Actions::AsanaFindReleaseTaskAction.setup_constants("ios")
end

describe "when release task is found" do
before do
expect(HTTParty).to receive(:get).and_return(
double(
success?: true,
parsed_response: { 'data' => {}, 'next_page' => nil }
)
)
end

it "returns the release task ID" do
expect(Fastlane::Actions::AsanaFindReleaseTaskAction).to receive(:find_hotfix_task_in_response)
expect(Fastlane::Actions::AsanaFindReleaseTaskAction).to receive(:find_release_task_in_response).and_return("1234567890")

expect(test_action("1.0.0")).to eq("1234567890")
end
end

describe "when fetching tasks in section fails" do
before do
expect(HTTParty).to receive(:get).and_return(
double(
success?: false,
code: 401,
message: "Unauthorized"
)
)
end

it "shows error" do
expect(Fastlane::Actions::AsanaFindReleaseTaskAction).not_to receive(:find_hotfix_task_in_response)
expect(Fastlane::Actions::AsanaFindReleaseTaskAction).not_to receive(:find_release_task_in_response)
allow(Fastlane::UI).to receive(:user_error!)

test_action("1.0.0")

expect(Fastlane::UI).to have_received(:user_error!).with("Failed to fetch release task: (401 Unauthorized)")
end
end

def test_action(version)
Fastlane::Actions::AsanaFindReleaseTaskAction.find_release_task(version, "token")
end
end

describe "#find_release_task_in_response" do
def test_action(response, release_task_name)
Fastlane::Actions::AsanaFindReleaseTaskAction.find_release_task_in_response(response, release_task_name)
end
end

describe "#ensure_task_not_too_old" do
def test_action(version, platform)
Fastlane::Actions::AsanaFindReleaseTaskAction.ensure_task_not_too_old(version, platform, "token")
end
end

describe "#find_hotfix_task_in_response" do
def test_action(response)
Fastlane::Actions::AsanaFindReleaseTaskAction.find_hotfix_task_in_response(response)
end
end
end

0 comments on commit c5bfb87

Please sign in to comment.