diff --git a/lib/fastlane/plugin/ddg_apple_automation/actions/asana_add_comment_action.rb b/lib/fastlane/plugin/ddg_apple_automation/actions/asana_add_comment_action.rb index 9a5e067..d41420c 100644 --- a/lib/fastlane/plugin/ddg_apple_automation/actions/asana_add_comment_action.rb +++ b/lib/fastlane/plugin/ddg_apple_automation/actions/asana_add_comment_action.rb @@ -23,14 +23,14 @@ def self.run(params) return end - task_id = Fastlane::Actions::AsanaExtractTaskIdAction.run(task_url: task_url) if task_url + task_id = AsanaExtractTaskIdAction.run(task_url: task_url) if task_url if template_name.to_s.empty? text = "#{comment}\n\nWorkflow URL: #{workflow_url}" create_story(asana_access_token, task_id, text: text) else template_file = Helper::DdgAppleAutomationHelper.path_for_asset_file("asana_add_comment/templates/#{template_name}.html") - template_content = Helper::DdgAppleAutomationHelper.load_template_file(template_file) + template_content = Helper::DdgAppleAutomationHelper.load_file(template_file) return unless template_content html_text = process_template_content(template_content) @@ -96,13 +96,6 @@ def self.validate_params(task_id, task_url, comment, template_name, workflow_url end end - def self.load_template_file(template_name) - template_file = Helper::DdgAppleAutomationHelper.path_for_asset_file("asana_add_comment/templates/#{template_name}.html") - File.read(template_file) - rescue StandardError - UI.user_error!("Error: The file '#{template_name}.html' does not exist.") - end - def self.create_story(asana_access_token, task_id, text: nil, html_text: nil) client = Asana::Client.new do |c| c.authentication(:access_token, asana_access_token) diff --git a/lib/fastlane/plugin/ddg_apple_automation/actions/asana_extract_task_assignee_action.rb b/lib/fastlane/plugin/ddg_apple_automation/actions/asana_extract_task_assignee_action.rb index 8e78096..8f23d3b 100644 --- a/lib/fastlane/plugin/ddg_apple_automation/actions/asana_extract_task_assignee_action.rb +++ b/lib/fastlane/plugin/ddg_apple_automation/actions/asana_extract_task_assignee_action.rb @@ -1,7 +1,6 @@ require "fastlane/action" require "fastlane_core/configuration/config_item" -require "httparty" -require "json" +require "asana" require_relative "../helper/ddg_apple_automation_helper" require_relative "../helper/github_actions_helper" @@ -12,16 +11,20 @@ def self.run(params) task_id = params[:task_id] token = params[:asana_access_token] - url = Helper::DdgAppleAutomationHelper::ASANA_API_URL + "/tasks/#{task_id}?opt_fields=assignee" - response = HTTParty.get(url, headers: { 'Authorization' => "Bearer #{token}" }) + client = Asana::Client.new do |c| + c.authentication(:access_token, token) + end - if response.success? - assignee_id = response.parsed_response.dig('data', 'assignee', 'gid') - Helper::GitHubActionsHelper.set_output("asana_assignee_id", assignee_id) - assignee_id - else - UI.user_error!("Failed to fetch task assignee: (#{response.code} #{response.message})") + begin + task = client.tasks.get_task(task_gid: task_id, options: { fields: ["assignee"] }) + rescue StandardError => e + UI.user_error!("Failed to fetch task assignee: #{e}") + return end + + assignee_id = task.assignee["gid"] + Helper::GitHubActionsHelper.set_output("asana_assignee_id", assignee_id) + assignee_id end def self.description diff --git a/lib/fastlane/plugin/ddg_apple_automation/actions/asana_find_release_task_action.rb b/lib/fastlane/plugin/ddg_apple_automation/actions/asana_find_release_task_action.rb index 9aa0aaa..11b14e9 100644 --- a/lib/fastlane/plugin/ddg_apple_automation/actions/asana_find_release_task_action.rb +++ b/lib/fastlane/plugin/ddg_apple_automation/actions/asana_find_release_task_action.rb @@ -1,8 +1,6 @@ require "fastlane/action" require "fastlane_core/configuration/config_item" require "asana" -require "httparty" -require "json" require "octokit" require "time" require_relative "../helper/ddg_apple_automation_helper" diff --git a/lib/fastlane/plugin/ddg_apple_automation/actions/asana_get_release_automation_subtask_id_action.rb b/lib/fastlane/plugin/ddg_apple_automation/actions/asana_get_release_automation_subtask_id_action.rb index 2b2c1ab..8bb1eb5 100644 --- a/lib/fastlane/plugin/ddg_apple_automation/actions/asana_get_release_automation_subtask_id_action.rb +++ b/lib/fastlane/plugin/ddg_apple_automation/actions/asana_get_release_automation_subtask_id_action.rb @@ -1,7 +1,5 @@ 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" @@ -22,16 +20,20 @@ def self.run(params) # 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}" }) + asana_client = Asana::Client.new do |c| + c.authentication(:access_token, token) + end - if response.success? - automation_subtask_id = find_oldest_automation_subtask(response) - 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})") + begin + subtasks = asana_client.tasks.get_subtasks_for_task(task_gid: task_id, options: { fields: ["name", "created_at"] }) + rescue StandardError => e + UI.user_error!("Failed to fetch 'Automation' subtasks for task #{task_id}: #{e}") + return end + + automation_subtask_id = find_oldest_automation_subtask(subtasks)&.gid + Helper::GitHubActionsHelper.set_output("asana_automation_task_id", automation_subtask_id) + automation_subtask_id end def self.description @@ -65,11 +67,10 @@ 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') + def self.find_oldest_automation_subtask(subtasks) + subtasks + .find_all { |task| task.name == 'Automation' } + &.min_by { |task| Time.parse(task.created_at) } end end end diff --git a/lib/fastlane/plugin/ddg_apple_automation/actions/asana_upload_action.rb b/lib/fastlane/plugin/ddg_apple_automation/actions/asana_upload_action.rb index ca181a5..958913a 100644 --- a/lib/fastlane/plugin/ddg_apple_automation/actions/asana_upload_action.rb +++ b/lib/fastlane/plugin/ddg_apple_automation/actions/asana_upload_action.rb @@ -1,6 +1,6 @@ require "fastlane/action" require "fastlane_core/configuration/config_item" -require "httparty" +require "asana" require_relative "../helper/ddg_apple_automation_helper" module Fastlane @@ -11,18 +11,15 @@ def self.run(params) token = params[:asana_access_token] file_name = params[:file_name] - begin - file = File.open(file_name) - url = Helper::DdgAppleAutomationHelper::ASANA_API_URL + "/tasks/#{task_id}/attachments" - response = HTTParty.post(url, - headers: { 'Authorization' => "Bearer #{token}" }, - body: { file: file }) + asana_client = Asana::Client.new do |c| + c.authentication(:access_token, token) + end - unless response.success? - UI.user_error!("Failed to upload file to Asana task: (#{response.code} #{response.message})") - end - rescue StandardError - UI.user_error!("Failed to open file: #{file_name}") + begin + asana_client.tasks.find_by_id(task_id).attach(filename: file_name, mime: "application/octet-stream") + rescue StandardError => e + UI.user_error!("Failed to upload file to Asana task: #{e}") + return end end diff --git a/lib/fastlane/plugin/ddg_apple_automation/helper/ddg_apple_automation_helper.rb b/lib/fastlane/plugin/ddg_apple_automation/helper/ddg_apple_automation_helper.rb index 8cf00f7..f027f3c 100644 --- a/lib/fastlane/plugin/ddg_apple_automation/helper/ddg_apple_automation_helper.rb +++ b/lib/fastlane/plugin/ddg_apple_automation/helper/ddg_apple_automation_helper.rb @@ -6,7 +6,6 @@ module Fastlane module Helper class DdgAppleAutomationHelper - ASANA_API_URL = "https://app.asana.com/api/1.0" ASANA_APP_URL = "https://app.asana.com/0/0" ERROR_ASANA_ACCESS_TOKEN_NOT_SET = "ASANA_ACCESS_TOKEN is not set" ERROR_GITHUB_TOKEN_NOT_SET = "GITHUB_TOKEN is not set" @@ -23,10 +22,10 @@ def self.path_for_asset_file(file) File.expand_path("../assets/#{file}", __dir__) end - def self.load_template_file(template_file) - File.read(template_file) + def self.load_file(file) + File.read(file) rescue StandardError - UI.user_error!("Error: The file '#{template_file}' does not exist.") + UI.user_error!("Error: The file '#{file}' does not exist.") end end end diff --git a/lib/fastlane/plugin/ddg_apple_automation/version.rb b/lib/fastlane/plugin/ddg_apple_automation/version.rb index 2acab82..e6daca4 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.8.0" + VERSION = "0.8.1" end end diff --git a/spec/asana_add_comment_spec.rb b/spec/asana_add_comment_action_spec.rb similarity index 100% rename from spec/asana_add_comment_spec.rb rename to spec/asana_add_comment_action_spec.rb diff --git a/spec/asana_extract_task_assignee_action_spec.rb b/spec/asana_extract_task_assignee_action_spec.rb new file mode 100644 index 0000000..0a5cff8 --- /dev/null +++ b/spec/asana_extract_task_assignee_action_spec.rb @@ -0,0 +1,40 @@ +describe Fastlane::Actions::AsanaExtractTaskAssigneeAction do + describe "#run" do + before do + @asana_client_tasks = double + asana_client = double("asana_client") + allow(Asana::Client).to receive(:new).and_return(asana_client) + allow(asana_client).to receive(:tasks).and_return(@asana_client_tasks) + allow(@asana_client_tasks).to receive(:get_task) + end + + it "returns the assignee ID and sets GHA output when Asana task is assigned" do + allow(Fastlane::Helper::GitHubActionsHelper).to receive(:set_output) + expect(@asana_client_tasks).to receive(:get_task).and_return( + double(assignee: { "gid" => "67890" }) + ) + + expect(test_action("12345")).to eq("67890") + expect(Fastlane::Helper::GitHubActionsHelper).to have_received(:set_output).with("asana_assignee_id", "67890") + end + + it "returns nil when Asana task is not assigned" do + expect(@asana_client_tasks).to receive(:get_task).and_return( + double(assignee: { "gid" => nil }) + ) + + expect(test_action("12345")).to eq(nil) + end + + it "shows error when failed to fetch task assignee" do + expect(@asana_client_tasks).to receive(:get_task).and_raise(StandardError, "API error") + expect(Fastlane::UI).to receive(:user_error!).with("Failed to fetch task assignee: API error") + + test_action("12345") + end + end + + def test_action(task_id) + Fastlane::Actions::AsanaExtractTaskAssigneeAction.run(task_id: task_id) + end +end diff --git a/spec/asana_extract_task_assignee_spec.rb b/spec/asana_extract_task_assignee_spec.rb deleted file mode 100644 index 3258a90..0000000 --- a/spec/asana_extract_task_assignee_spec.rb +++ /dev/null @@ -1,57 +0,0 @@ -describe Fastlane::Actions::AsanaExtractTaskAssigneeAction do - describe "#run" do - it "returns the assignee ID when Asana task is assigned" do - expect(HTTParty).to receive(:get).and_return( - double( - success?: true, - parsed_response: { 'data' => { 'assignee' => { 'gid' => '67890' } } } - ) - ) - - expect(test_action("12345")).to eq("67890") - end - - it "returns nil when Asana task is not assigned" do - expect(HTTParty).to receive(:get).and_return( - double( - success?: true, - parsed_response: { 'data' => { 'assignee' => nil } } - ) - ) - - expect(test_action("12345")).to eq(nil) - end - - it "shows error when failed to fetch task assignee" do - 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 task assignee: (401 Unauthorized)") - - test_action("12345") - end - - it "sets GHA output" do - allow(Fastlane::Helper::GitHubActionsHelper).to receive(:set_output) - - expect(HTTParty).to receive(:get).and_return( - double( - success?: true, - parsed_response: { 'data' => { 'assignee' => { 'gid' => '67890' } } } - ) - ) - - expect(test_action("12345")).to eq("67890") - expect(Fastlane::Helper::GitHubActionsHelper).to have_received(:set_output).with("asana_assignee_id", "67890") - end - end - - def test_action(task_id) - Fastlane::Actions::AsanaExtractTaskAssigneeAction.run(task_id: task_id) - end -end diff --git a/spec/asana_extract_task_id_spec.rb b/spec/asana_extract_task_id_action_spec.rb similarity index 100% rename from spec/asana_extract_task_id_spec.rb rename to spec/asana_extract_task_id_action_spec.rb diff --git a/spec/asana_find_release_task_action_spec.rb b/spec/asana_find_release_task_action_spec.rb index 805a9ab..db6400b 100644 --- a/spec/asana_find_release_task_action_spec.rb +++ b/spec/asana_find_release_task_action_spec.rb @@ -141,9 +141,9 @@ def validate_semver(version) end it "shows error" do + allow(Fastlane::UI).to receive(:user_error!) 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!) find_release_task("1.0.0") diff --git a/spec/asana_get_release_automation_subtask_id_action_spec.rb b/spec/asana_get_release_automation_subtask_id_action_spec.rb new file mode 100644 index 0000000..57fcd17 --- /dev/null +++ b/spec/asana_get_release_automation_subtask_id_action_spec.rb @@ -0,0 +1,45 @@ +describe Fastlane::Actions::AsanaGetReleaseAutomationSubtaskIdAction do + describe "#run" do + before do + @asana_client_tasks = double + asana_client = double("asana_client") + allow(Asana::Client).to receive(:new).and_return(asana_client) + allow(asana_client).to receive(:tasks).and_return(@asana_client_tasks) + allow(@asana_client_tasks).to receive(:get_subtasks_for_task) + end + it "returns the 'Automation' subtask ID and sets GHA output when the subtask exists in the Asana task" do + allow(Fastlane::Helper::GitHubActionsHelper).to receive(:set_output) + expect(Fastlane::Actions::AsanaExtractTaskAssigneeAction).to receive(:run) + expect(@asana_client_tasks).to receive(:get_subtasks_for_task).and_return( + [double(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 + + it "returns the oldest 'Automation' subtask when there are multiple subtasks with that name" do + expect(Fastlane::Actions::AsanaExtractTaskAssigneeAction).to receive(:run) + expect(@asana_client_tasks).to receive(:get_subtasks_for_task).and_return( + [double(gid: "12345", name: "Automation", created_at: "2020-01-01T00:00:00.000Z"), + double(gid: "431", name: "Automation", created_at: "2019-01-01T00:00:00.000Z"), + double(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 + allow(Fastlane::UI).to receive(:user_error!) + expect(Fastlane::Actions::AsanaExtractTaskAssigneeAction).to receive(:run) + expect(@asana_client_tasks).to receive(:get_subtasks_for_task).and_raise(StandardError, "API error") + + test_action("https://app.asana.com/0/0/0") + expect(Fastlane::UI).to have_received(:user_error!).with("Failed to fetch 'Automation' subtasks for task 0: API error") + end + end + + def test_action(task_url) + Fastlane::Actions::AsanaGetReleaseAutomationSubtaskIdAction.run(task_url: task_url) + end +end diff --git a/spec/asana_get_release_automation_subtask_id_spec.rb b/spec/asana_get_release_automation_subtask_id_spec.rb deleted file mode 100644 index 136f1dc..0000000 --- a/spec/asana_get_release_automation_subtask_id_spec.rb +++ /dev/null @@ -1,92 +0,0 @@ -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 "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( - 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 diff --git a/spec/asana_get_user_id_for_github_handle_spec.rb b/spec/asana_get_user_id_for_github_handle_action_spec.rb similarity index 100% rename from spec/asana_get_user_id_for_github_handle_spec.rb rename to spec/asana_get_user_id_for_github_handle_action_spec.rb diff --git a/spec/asana_log_message_spec.rb b/spec/asana_log_message_action_spec.rb similarity index 100% rename from spec/asana_log_message_spec.rb rename to spec/asana_log_message_action_spec.rb diff --git a/spec/asana_upload_action_spec.rb b/spec/asana_upload_action_spec.rb new file mode 100644 index 0000000..78aa58b --- /dev/null +++ b/spec/asana_upload_action_spec.rb @@ -0,0 +1,31 @@ +describe Fastlane::Actions::AsanaUploadAction do + describe "#run" do + before do + @task = double("task") + @asana_client_tasks = double("asana_client_tasks") + asana_client = double("asana_client") + allow(Asana::Client).to receive(:new).and_return(asana_client) + allow(asana_client).to receive(:tasks).and_return(@asana_client_tasks) + end + + it "uploads a file successfully" do + allow(@asana_client_tasks).to receive(:find_by_id).with("123").and_return(@task) + allow(@task).to receive(:attach).with(filename: "path/to/file.txt", mime: "application/octet-stream") + + expect { test_action("123", "path/to/file.txt") }.not_to raise_error + end + + it "shows error if failure" do + allow(@asana_client_tasks).to receive(:find_by_id).with("123").and_return(@task) + allow(@task).to receive(:attach).and_raise(StandardError.new("API Error")) + + expect(Fastlane::UI).to receive(:user_error!).with("Failed to upload file to Asana task: API Error") + test_action("123", "path/to/file.txt") + end + end + + def test_action(task_id, file_name) + Fastlane::Actions::AsanaUploadAction.run(task_id: task_id, + file_name: file_name) + end +end diff --git a/spec/asana_upload_spec.rb b/spec/asana_upload_spec.rb deleted file mode 100644 index 339112a..0000000 --- a/spec/asana_upload_spec.rb +++ /dev/null @@ -1,35 +0,0 @@ -describe Fastlane::Actions::AsanaUploadAction do - describe "#run" do - it "uploads a file successfully" do - allow(HTTParty).to receive(:post).and_return(double(success?: true)) - allow(File).to receive(:open).with("path/to/file.txt").and_return(double) - - expect { test_action("12345", "path/to/file.txt") }.not_to raise_error - end - - it "shows error if HTTP failure" do - allow(HTTParty).to receive(:post).and_return( - double( - success?: false, - code: 500, - message: "Internal Server Error" - ) - ) - allow(File).to receive(:open).with("path/to/file.txt").and_return(double) - - expect(Fastlane::UI).to receive(:user_error!).with("Failed to upload file to Asana task: (500 Internal Server Error)") - test_action("12345", "path/to/file.txt") - end - - it "shows error if file does not exist" do - expect(Fastlane::UI).to receive(:user_error!).with("Failed to open file: path/to/file.txt") - expect(HTTParty).not_to receive(:post) - test_action("12345", "path/to/file.txt") - end - end - - def test_action(task_id, file_name) - Fastlane::Actions::AsanaUploadAction.run(task_id: task_id, - file_name: file_name) - end -end