From 870a93c879a8ce2c82f61ac943f6fb893ee3dd2b Mon Sep 17 00:00:00 2001 From: Dominik Kapusta Date: Fri, 30 Aug 2024 00:11:39 +0200 Subject: [PATCH 1/3] Add AsanaGetReleaseAutomationSubtaskIdAction --- ...asana_get_release_automation_subtask_id.rb | 69 ++++++++++++++++ .../plugin/ddg_apple_automation/version.rb | 2 +- ..._get_release_automation_subtask_id_spec.rb | 80 +++++++++++++++++++ 3 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 lib/fastlane/plugin/ddg_apple_automation/actions/asana_get_release_automation_subtask_id.rb create mode 100644 spec/asana_get_release_automation_subtask_id_spec.rb diff --git a/lib/fastlane/plugin/ddg_apple_automation/actions/asana_get_release_automation_subtask_id.rb b/lib/fastlane/plugin/ddg_apple_automation/actions/asana_get_release_automation_subtask_id.rb new file mode 100644 index 0000000..a33366d --- /dev/null +++ b/lib/fastlane/plugin/ddg_apple_automation/actions/asana_get_release_automation_subtask_id.rb @@ -0,0 +1,69 @@ +require "fastlane/action" +require "fastlane_core/configuration/config_item" +require "httparty" +require "json" +require "time" +require_relative "../helper/ddg_apple_automation_helper" +require_relative "../helper/github_actions_helper" +require_relative "asana_extract_task_id_action" +require_relative "asana_extract_task_assignee_action" + +module Fastlane + module Actions + class AsanaGetReleaseAutomationSubtaskIdAction < Action + def self.run(params) + task_url = params[:task_url] + token = params[:asana_access_token] + + task_id = AsanaExtractTaskIdAction.run(task_url: task_url, asana_access_token: token) + AsanaExtractTaskAssigneeAction.run(task_id: task_id, asana_access_token: token) + + url = Helper::DdgAppleAutomationHelper::ASANA_API_URL + "/tasks/#{task_id}/subtasks?opt_fields=name,created_at" + response = HTTParty.get(url, headers: { 'Authorization' => "Bearer #{token}" }) + + if response.success? + data = response.parsed_response['data'] + automation_subtask_id = data + .find_all { |hash| hash['name'] == 'Automation' } + &.min_by { |x| Time.parse(x['created_at']) } # Get the oldest 'Automation' subtask + &.dig('gid') + Helper::GitHubActionsHelper.set_output("asana_automation_task_id", automation_subtask_id) + automation_subtask_id + else + UI.user_error!("Failed to fetch 'Automation' subtask: (#{response.code} #{response.message})") + end + end + + def self.description + "This action finds 'Automation' subtask for the release task in Asana specified by the URL given as parameter" + end + + def self.authors + ["DuckDuckGo"] + end + + def self.return_value + "The 'Automation' task ID for the specified release task" + end + + def self.details + # Optional: + "" + end + + def self.available_options + [ + FastlaneCore::ConfigItem.asana_access_token, + FastlaneCore::ConfigItem.new(key: :task_url, + description: "Asana task URL", + optional: false, + type: String) + ] + end + + def self.is_supported?(platform) + true + end + end + end +end diff --git a/lib/fastlane/plugin/ddg_apple_automation/version.rb b/lib/fastlane/plugin/ddg_apple_automation/version.rb index d0ec1d0..557ed75 100644 --- a/lib/fastlane/plugin/ddg_apple_automation/version.rb +++ b/lib/fastlane/plugin/ddg_apple_automation/version.rb @@ -1,5 +1,5 @@ module Fastlane module DdgAppleAutomation - VERSION = "0.2.0" + VERSION = "0.3.0" end end diff --git a/spec/asana_get_release_automation_subtask_id_spec.rb b/spec/asana_get_release_automation_subtask_id_spec.rb new file mode 100644 index 0000000..47d6c78 --- /dev/null +++ b/spec/asana_get_release_automation_subtask_id_spec.rb @@ -0,0 +1,80 @@ +describe Fastlane::Actions::AsanaGetReleaseAutomationSubtaskIdAction do + describe "#run" do + it "returns the 'Automation' subtask ID when it exists in the Asana task" do + expect(Fastlane::Actions::AsanaExtractTaskAssigneeAction).to receive(:run) + expect(HTTParty).to receive(:get).and_return( + double( + success?: true, + parsed_response: { 'data' => [ + { 'gid' => '12345', 'name' => 'Automation', 'created_at' => '2020-01-01T00:00:00.000Z' } + ] } + ) + ) + + expect(test_action("https://app.asana.com/0/0/0")).to eq("12345") + end + + it "returns the oldest 'Automation' subtask when there are multiple subtasks with that name" do + expect(Fastlane::Actions::AsanaExtractTaskAssigneeAction).to receive(:run) + expect(HTTParty).to receive(:get).and_return( + double( + success?: true, + parsed_response: { 'data' => [ + { 'gid' => '12345', 'name' => 'Automation', 'created_at' => '2020-01-01T00:00:00.000Z' }, + { 'gid' => '431', 'name' => 'Automation', 'created_at' => '2019-01-01T00:00:00.000Z' }, + { 'gid' => '12460', 'name' => 'Automation', 'created_at' => '2020-01-05T00:00:00.000Z' } + ] } + ) + ) + + expect(test_action("https://app.asana.com/0/0/0")).to eq("431") + end + + it "returns nil when 'Automation' subtask does not exist in the Asana task" do + expect(Fastlane::Actions::AsanaExtractTaskAssigneeAction).to receive(:run) + expect(HTTParty).to receive(:get).and_return( + double( + success?: true, + parsed_response: { 'data' => [] } + ) + ) + + expect(test_action("https://app.asana.com/0/0/0")).to eq(nil) + end + + it "shows error when failed to fetch task subtasks" do + expect(Fastlane::Actions::AsanaExtractTaskAssigneeAction).to receive(:run) + expect(HTTParty).to receive(:get).and_return( + double( + success?: false, + code: 401, + message: "Unauthorized" + ) + ) + + expect(Fastlane::UI).to receive(:user_error!).with("Failed to fetch 'Automation' subtask: (401 Unauthorized)") + + test_action("https://app.asana.com/0/0/0") + end + + it "sets GHA output" do + allow(Fastlane::Helper::GitHubActionsHelper).to receive(:set_output) + expect(Fastlane::Actions::AsanaExtractTaskAssigneeAction).to receive(:run) + expect(HTTParty).to receive(:get).and_return( + double( + success?: true, + parsed_response: { 'data' => [ + { 'gid' => '12345', 'name' => 'Automation', 'created_at' => '2020-01-01T00:00:00.000Z' } + ] } + ) + ) + + expect(test_action("https://app.asana.com/0/0/0")).to eq("12345") + expect(Fastlane::Helper::GitHubActionsHelper).to have_received(:set_output).with("asana_automation_task_id", "12345") + end + end + + def test_action(task_url) + Fastlane::Actions::AsanaGetReleaseAutomationSubtaskIdAction.run(task_url: task_url) + end +end From 12f6ec24844a681d2d6a5e6a048b03dbc4508a7e Mon Sep 17 00:00:00 2001 From: Dominik Kapusta Date: Fri, 30 Aug 2024 11:40:17 +0200 Subject: [PATCH 2/3] Add documentation about extracting assignee ID --- .../actions/asana_get_release_automation_subtask_id.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/fastlane/plugin/ddg_apple_automation/actions/asana_get_release_automation_subtask_id.rb b/lib/fastlane/plugin/ddg_apple_automation/actions/asana_get_release_automation_subtask_id.rb index a33366d..7fa1e92 100644 --- a/lib/fastlane/plugin/ddg_apple_automation/actions/asana_get_release_automation_subtask_id.rb +++ b/lib/fastlane/plugin/ddg_apple_automation/actions/asana_get_release_automation_subtask_id.rb @@ -16,6 +16,9 @@ def self.run(params) token = params[:asana_access_token] task_id = AsanaExtractTaskIdAction.run(task_url: task_url, asana_access_token: token) + + # Fetch release task assignee and set GHA output + # TODO: To be reworked for local execution AsanaExtractTaskAssigneeAction.run(task_id: task_id, asana_access_token: token) url = Helper::DdgAppleAutomationHelper::ASANA_API_URL + "/tasks/#{task_id}/subtasks?opt_fields=name,created_at" From 84a819f9de3a3f4651b2311b7c0ef65b36706cef Mon Sep 17 00:00:00 2001 From: Dominik Kapusta Date: Mon, 2 Sep 2024 10:24:00 +0200 Subject: [PATCH 3/3] Extract finding subtask into a separate method and improve handling broken responses --- .../asana_get_release_automation_subtask_id.rb | 18 +++++++++++------- ...a_get_release_automation_subtask_id_spec.rb | 12 ++++++++++++ 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/lib/fastlane/plugin/ddg_apple_automation/actions/asana_get_release_automation_subtask_id.rb b/lib/fastlane/plugin/ddg_apple_automation/actions/asana_get_release_automation_subtask_id.rb index 7fa1e92..2b2c1ab 100644 --- a/lib/fastlane/plugin/ddg_apple_automation/actions/asana_get_release_automation_subtask_id.rb +++ b/lib/fastlane/plugin/ddg_apple_automation/actions/asana_get_release_automation_subtask_id.rb @@ -17,19 +17,16 @@ def self.run(params) task_id = AsanaExtractTaskIdAction.run(task_url: task_url, asana_access_token: token) - # Fetch release task assignee and set GHA output - # TODO: To be reworked for local execution + # Fetch release task assignee and set GHA output. + # This is to match current GHA action behavior. + # TODO: To be reworked for local execution. AsanaExtractTaskAssigneeAction.run(task_id: task_id, asana_access_token: token) url = Helper::DdgAppleAutomationHelper::ASANA_API_URL + "/tasks/#{task_id}/subtasks?opt_fields=name,created_at" response = HTTParty.get(url, headers: { 'Authorization' => "Bearer #{token}" }) if response.success? - data = response.parsed_response['data'] - automation_subtask_id = data - .find_all { |hash| hash['name'] == 'Automation' } - &.min_by { |x| Time.parse(x['created_at']) } # Get the oldest 'Automation' subtask - &.dig('gid') + automation_subtask_id = find_oldest_automation_subtask(response) Helper::GitHubActionsHelper.set_output("asana_automation_task_id", automation_subtask_id) automation_subtask_id else @@ -67,6 +64,13 @@ def self.available_options def self.is_supported?(platform) true end + + def self.find_oldest_automation_subtask(response) + response.parsed_response['data'] + &.find_all { |hash| hash['name'] == 'Automation' } + &.min_by { |x| Time.parse(x['created_at']) } # Get the oldest 'Automation' subtask + &.dig('gid') + end end end end diff --git a/spec/asana_get_release_automation_subtask_id_spec.rb b/spec/asana_get_release_automation_subtask_id_spec.rb index 47d6c78..136f1dc 100644 --- a/spec/asana_get_release_automation_subtask_id_spec.rb +++ b/spec/asana_get_release_automation_subtask_id_spec.rb @@ -42,6 +42,18 @@ expect(test_action("https://app.asana.com/0/0/0")).to eq(nil) end + it "returns nil when response is empty" do + expect(Fastlane::Actions::AsanaExtractTaskAssigneeAction).to receive(:run) + expect(HTTParty).to receive(:get).and_return( + double( + success?: true, + parsed_response: {} + ) + ) + + expect(test_action("https://app.asana.com/0/0/0")).to eq(nil) + end + it "shows error when failed to fetch task subtasks" do expect(Fastlane::Actions::AsanaExtractTaskAssigneeAction).to receive(:run) expect(HTTParty).to receive(:get).and_return(