Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Asana log message #6

Merged
merged 10 commits into from
Sep 6, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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)
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
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] || false
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 a collaborator to the release task: #{e}")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically it's not the release task that the user is added to, but the 'Automation' subtask of a release task. How about the following? To allow easier debugging, perhaps.

Suggested change
UI.user_error!("Failed to add a collaborator to the release task: #{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,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ConfigItem provides default_value parameter which you could leverage here instead of using || false in the action body 👍

description: "Indicates whether the release was scheduled or started manually",
optional: true,
type: Boolean)
]
end

def self.is_supported?(platform)
true
end
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -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
Comment on lines +26 to +30
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious if we's ever need to call path_for_asset_file standalone. If not, we could perhaps combine these two functions int one and have a function that computes the path and reads the file. And then write tests for it :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

makes perfect sense, but let me do it in another PR today!

end
end
end
Expand Down
26 changes: 18 additions & 8 deletions spec/asana_add_comment_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
Expand All @@ -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")
Expand Down Expand Up @@ -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"
Expand All @@ -87,15 +98,14 @@
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

def test_action(task_id: nil, task_url: nil, comment: nil, template_name: nil, workflow_url: nil)
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
6 changes: 3 additions & 3 deletions spec/asana_get_user_id_for_github_handle_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
76 changes: 76 additions & 0 deletions spec/asana_log_message_spec.rb
Original file line number Diff line number Diff line change
@@ -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 "does extract assignee id from release task when is scheduled release" do
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extracts in place of does extract, maybe?

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 "does takes assignee id from github handle when is manual release" do
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/does takes/takes/

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 a assignee as a follower to the automation task" do
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

adds an assignee as follower 😇

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 a collaborator to the release task: 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