From 4a6f8106a0a420276cf2209f77eca004fef10aa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacek=20=C5=81yp?= Date: Fri, 6 Sep 2024 14:08:08 +0200 Subject: [PATCH] Asana log message (#6) --- .../actions/asana_add_comment_action.rb | 10 +- ...na_get_user_id_for_github_handle_action.rb | 2 +- .../actions/asana_log_message_action.rb | 97 +++++++++++++++++++ .../helper/ddg_apple_automation_helper.rb | 6 ++ .../plugin/ddg_apple_automation/version.rb | 2 +- spec/asana_add_comment_spec.rb | 26 +++-- ...sana_get_user_id_for_github_handle_spec.rb | 6 +- spec/asana_log_message_spec.rb | 76 +++++++++++++++ 8 files changed, 206 insertions(+), 19 deletions(-) create mode 100644 lib/fastlane/plugin/ddg_apple_automation/actions/asana_log_message_action.rb create mode 100644 spec/asana_log_message_spec.rb 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 d2698ad..9a5e067 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 @@ -13,7 +13,8 @@ def self.run(params) task_url = params[:task_url] template_name = params[:template_name] comment = params[:comment] - workflow_url = params[:workflow_url] + + workflow_url = ENV.fetch('WORKFLOW_URL', '') begin validate_params(task_id, task_url, comment, template_name, workflow_url) @@ -28,7 +29,8 @@ def self.run(params) text = "#{comment}\n\nWorkflow URL: #{workflow_url}" create_story(asana_access_token, task_id, text: text) else - template_content = load_template_file(template_name) + template_file = Helper::DdgAppleAutomationHelper.path_for_asset_file("asana_add_comment/templates/#{template_name}.html") + template_content = Helper::DdgAppleAutomationHelper.load_template_file(template_file) return unless template_content html_text = process_template_content(template_content) @@ -71,10 +73,6 @@ def self.available_options FastlaneCore::ConfigItem.new(key: :template_name, description: "Name of a template file (without extension) for the comment. Templates can be found in assets/asana_add_comment/templates subdirectory. The file is processed before being sent to Asana", - optional: true, - type: String), - FastlaneCore::ConfigItem.new(key: :workflow_url, - description: "Workflow URL to include in the comment", optional: true, type: String) ] diff --git a/lib/fastlane/plugin/ddg_apple_automation/actions/asana_get_user_id_for_github_handle_action.rb b/lib/fastlane/plugin/ddg_apple_automation/actions/asana_get_user_id_for_github_handle_action.rb index 4660e2a..6be093e 100644 --- a/lib/fastlane/plugin/ddg_apple_automation/actions/asana_get_user_id_for_github_handle_action.rb +++ b/lib/fastlane/plugin/ddg_apple_automation/actions/asana_get_user_id_for_github_handle_action.rb @@ -15,7 +15,7 @@ def self.run(params) asana_user_id = user_mapping[github_handle] if asana_user_id.nil? || asana_user_id.to_s.empty? - UI.warning("Asana User ID not found for GitHub handle: #{github_handle}") + UI.message("Asana User ID not found for GitHub handle: #{github_handle}") else Helper::GitHubActionsHelper.set_output("asana_user_id", asana_user_id) asana_user_id diff --git a/lib/fastlane/plugin/ddg_apple_automation/actions/asana_log_message_action.rb b/lib/fastlane/plugin/ddg_apple_automation/actions/asana_log_message_action.rb new file mode 100644 index 0000000..9a12a92 --- /dev/null +++ b/lib/fastlane/plugin/ddg_apple_automation/actions/asana_log_message_action.rb @@ -0,0 +1,97 @@ +require "fastlane/action" +require "fastlane_core/configuration/config_item" +require "asana" +require_relative "../helper/ddg_apple_automation_helper" +require_relative "asana_add_comment_action" +require_relative "asana_get_release_automation_subtask_id_action" +require_relative "asana_get_user_id_for_github_handle_action" +require_relative "asana_extract_task_id_action" +require_relative "asana_extract_task_assignee_action" + +module Fastlane + module Actions + class AsanaLogMessageAction < Action + def self.run(params) + token = params[:asana_access_token] + task_url = params[:task_url] + template_name = params[:template_name] + comment = params[:comment] + is_scheduled_release = params[:is_scheduled_release] + github_handle = params[:github_handle] + + automation_subtask_id = AsanaGetReleaseAutomationSubtaskIdAction.run(task_url: task_url, asana_access_token: token) + + if is_scheduled_release + task_id = AsanaExtractTaskIdAction.run(task_url: task_url) + assignee_id = AsanaExtractTaskAssigneeAction.run(task_id: task_id, asana_access_token: token) + else + if github_handle.to_s.empty? + UI.user_error!("Github handle cannot be empty for manual release") + return + end + assignee_id = AsanaGetUserIdForGithubHandleAction.run(github_handle: github_handle, asana_access_token: token) + end + + asana_client = Asana::Client.new do |c| + c.authentication(:access_token, token) + end + + begin + asana_client.tasks.add_followers_for_task(task_gid: automation_subtask_id, followers: [assignee_id]) + rescue StandardError => e + UI.user_error!("Failed to add user #{assignee_id} as collaborator on task #{automation_subtask_id}: #{e}") + end + + AsanaAddCommentAction.run(task_id: automation_subtask_id, comment: comment, template_name: template_name, asana_access_token: token) + end + + def self.description + "Add a Message to Asana Release Automation Task" + end + + def self.authors + ["DuckDuckGo"] + end + + def self.return_value + "" + end + + def self.details + "Adds a comment about release progress to the Asana release task's 'Automation' subtask" + end + + def self.available_options + [ + FastlaneCore::ConfigItem.asana_access_token, + FastlaneCore::ConfigItem.new(key: :task_url, + description: "Asana release task URL", + optional: false, + type: String), + FastlaneCore::ConfigItem.new(key: :comment, + description: "Comment to add to the Asana task", + optional: true, + type: String), + FastlaneCore::ConfigItem.new(key: :template_name, + description: "Name of a template file (without extension) for the comment. Templates can be found in assets/asana_add_comment/templates subdirectory. + The file is processed before being sent to Asana", + optional: true, + type: String), + FastlaneCore::ConfigItem.new(key: :github_handle, + description: "Github user handle", + optional: true, + type: String), + FastlaneCore::ConfigItem.new(key: :is_scheduled_release, + description: "Indicates whether the release was scheduled or started manually", + optional: true, + type: Boolean, + default_value: false) + ] + end + + def self.is_supported?(platform) + true + end + end + 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 d0f8320..8cf00f7 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 @@ -22,6 +22,12 @@ def self.asana_task_url(task_id) 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) + rescue StandardError + UI.user_error!("Error: The file '#{template_file}' does not exist.") + 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 42b314c..2acab82 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.7.0" + VERSION = "0.8.0" end end diff --git a/spec/asana_add_comment_spec.rb b/spec/asana_add_comment_spec.rb index 3bc8a48..f5fc15c 100644 --- a/spec/asana_add_comment_spec.rb +++ b/spec/asana_add_comment_spec.rb @@ -7,19 +7,21 @@ asana_client = double("Asana::Client") allow(Asana::Client).to receive(:new).and_return(asana_client) allow(asana_client).to receive(:stories).and_return(@asana_client_stories) + + ENV["WORKFLOW_URL"] = "http://www.example.com" end it "does not call task id extraction if task id provided" do allow(Fastlane::Actions::AsanaExtractTaskIdAction).to receive(:run) allow(@asana_client_stories).to receive(:create_story_for_task).and_return(double) - test_action(task_id: "123", comment: "comment", workflow_url: "http://www.example.com") + test_action(task_id: "123", comment: "comment") expect(Fastlane::Actions::AsanaExtractTaskIdAction).not_to have_received(:run) end it "extracts task id if task id not provided" do allow(@asana_client_stories).to receive(:create_story_for_task).and_return(double) allow(Fastlane::Actions::AsanaExtractTaskIdAction).to receive(:run) - test_action(task_url: "https://app.asana.com/0/753241/9999", comment: "comment", workflow_url: "http://www.example.com") + test_action(task_url: "https://app.asana.com/0/753241/9999", comment: "comment") expect(Fastlane::Actions::AsanaExtractTaskIdAction).to have_received(:run).with( task_url: "https://app.asana.com/0/753241/9999" ) @@ -36,12 +38,17 @@ end it "shows error if comment is provided but workflow_url is not" do - expect(Fastlane::UI).to receive(:user_error!).with("If comment is provided, workflow_url cannot be empty") - test_action(task_id: "123", comment: "comment") + ClimateControl.modify( + WORKFLOW_URL: '' + ) do + expect(Fastlane::UI).to receive(:user_error!).with("If comment is provided, workflow_url cannot be empty") + test_action(task_id: "123", comment: "comment") + end end it "shows error if provided template does not exist" do allow(File).to receive(:read).and_raise(Errno::ENOENT) + allow(Fastlane::Helper::DdgAppleAutomationHelper).to receive(:path_for_asset_file).and_return("non-existing.html") expect(Fastlane::UI).to receive(:user_error!).with("Error: The file 'non-existing.html' does not exist.") expect(@asana_client_stories).not_to receive(:create_story_for_task) test_action(task_id: "123", template_name: "non-existing") @@ -77,7 +84,11 @@ it "correctly builds text payload" do allow(@asana_client_stories).to receive(:create_story_for_task) - test_action(task_id: "123", comment: "This is a test comment.", workflow_url: "http://github.com/duckduckgo/iOS/actions/runs/123") + ClimateControl.modify( + WORKFLOW_URL: "http://github.com/duckduckgo/iOS/actions/runs/123" + ) do + test_action(task_id: "123", comment: "This is a test comment.") + end expect(@asana_client_stories).to have_received(:create_story_for_task).with( task_gid: "123", text: "This is a test comment.\n\nWorkflow URL: http://github.com/duckduckgo/iOS/actions/runs/123" @@ -87,7 +98,7 @@ it "fails when client raises error" do allow(@asana_client_stories).to receive(:create_story_for_task).and_raise(StandardError, "API error") expect(Fastlane::UI).to receive(:user_error!).with("Failed to post comment: API error") - test_action(task_id: "123", comment: "comment", workflow_url: "http://www.example.com") + test_action(task_id: "123", comment: "comment") end end @@ -95,7 +106,6 @@ def test_action(task_id: nil, task_url: nil, comment: nil, template_name: nil, w Fastlane::Actions::AsanaAddCommentAction.run(task_id: task_id, task_url: task_url, comment: comment, - template_name: template_name, - workflow_url: workflow_url) + template_name: template_name) end end diff --git a/spec/asana_get_user_id_for_github_handle_spec.rb b/spec/asana_get_user_id_for_github_handle_spec.rb index 7cba8a5..53a6c22 100644 --- a/spec/asana_get_user_id_for_github_handle_spec.rb +++ b/spec/asana_get_user_id_for_github_handle_spec.rb @@ -21,17 +21,17 @@ end it "shows warning when handle does not exist" do - expect(Fastlane::UI).to receive(:warning).with("Asana User ID not found for GitHub handle: chicken") + expect(Fastlane::UI).to receive(:message).with("Asana User ID not found for GitHub handle: chicken") test_action("chicken") end it "shows warning when handle is nil" do - expect(Fastlane::UI).to receive(:warning).with("Asana User ID not found for GitHub handle: pigeon") + expect(Fastlane::UI).to receive(:message).with("Asana User ID not found for GitHub handle: pigeon") test_action("pigeon") end it "shows warning when handle is empty" do - expect(Fastlane::UI).to receive(:warning).with("Asana User ID not found for GitHub handle: hawk") + expect(Fastlane::UI).to receive(:message).with("Asana User ID not found for GitHub handle: hawk") test_action("hawk") end end diff --git a/spec/asana_log_message_spec.rb b/spec/asana_log_message_spec.rb new file mode 100644 index 0000000..c17a900 --- /dev/null +++ b/spec/asana_log_message_spec.rb @@ -0,0 +1,76 @@ +describe Fastlane::Actions::AsanaLogMessageAction do + describe "#run" do + let(:task_url) { "https://example.com" } + let(:task_id) { "1" } + let(:automation_subtask_id) { "2" } + let(:assignee_id) { "11" } + let(:comment) { "comment" } + let(:github_handle) { "user" } + + 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(Fastlane::Actions::AsanaGetReleaseAutomationSubtaskIdAction).to receive(:run).and_return(automation_subtask_id) + allow(Fastlane::Actions::AsanaExtractTaskIdAction).to receive(:run).and_return(task_id) + allow(Fastlane::Actions::AsanaExtractTaskAssigneeAction).to receive(:run).and_return(assignee_id) + allow(Fastlane::Actions::AsanaGetUserIdForGithubHandleAction).to receive(:run).and_return(assignee_id) + allow(@asana_client_tasks).to receive(:add_followers_for_task) + allow(Fastlane::Actions::AsanaAddCommentAction).to receive(:run) + end + + it "extracts assignee id from release task when is scheduled release" do + expect(Fastlane::Actions::AsanaExtractTaskIdAction).to receive(:run).with(task_url: task_url) + expect(Fastlane::Actions::AsanaExtractTaskAssigneeAction).to receive(:run).with( + task_id: task_id, + asana_access_token: anything + ) + test_action(task_url: task_url, comment: comment, is_scheduled_release: true) + end + + it "takes assignee id from github handle when is manual release" do + expect(Fastlane::Actions::AsanaGetUserIdForGithubHandleAction).to receive(:run).with( + github_handle: github_handle, + asana_access_token: anything + ) + test_action(task_url: task_url, comment: comment, is_scheduled_release: false, github_handle: github_handle) + end + + it "raises an error when github handle is empty and is manual release" do + expect(Fastlane::UI).to receive(:user_error!).with("Github handle cannot be empty for manual release") + test_action(task_url: task_url, comment: comment, is_scheduled_release: false, github_handle: "") + end + + it "adds an assignee as follower to the automation task" do + expect(@asana_client_tasks).to receive(:add_followers_for_task).with(task_gid: automation_subtask_id, followers: [assignee_id]) + test_action(task_url: task_url, comment: comment, is_scheduled_release: false, github_handle: github_handle) + end + + it "raises an error if adding a collaborator fails" do + allow(Fastlane::UI).to receive(:user_error!) + allow(@asana_client_tasks).to receive(:add_followers_for_task).and_raise(StandardError, 'some error') + test_action(task_url: task_url, comment: comment, is_scheduled_release: false, github_handle: github_handle) + expect(Fastlane::UI).to have_received(:user_error!).with("Failed to add user 11 as collaborator on task 2: some error") + end + + it "adds a comment to the automation subtask" do + expect(Fastlane::Actions::AsanaAddCommentAction).to receive(:run).with( + task_id: automation_subtask_id, + comment: comment, + template_name: nil, + asana_access_token: anything + ) + test_action(task_url: task_url, comment: comment, is_scheduled_release: false, github_handle: github_handle) + end + end + + def test_action(task_url:, github_handle: nil, comment: nil, template_name: nil, is_scheduled_release: false) + Fastlane::Actions::AsanaLogMessageAction.run(task_url: task_url, + comment: comment, + template_name: template_name, + is_scheduled_release: is_scheduled_release, + github_handle: github_handle) + end +end