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

Add AsanaCreateActionItemAction #8

Merged
merged 22 commits into from
Sep 12, 2024
Merged
Show file tree
Hide file tree
Changes from 19 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 @@ -33,7 +33,7 @@ def self.run(params)
template_content = Helper::DdgAppleAutomationHelper.load_file(template_file)
return unless template_content

html_text = process_template_content(template_content)
html_text = Helper::DdgAppleAutomationHelper.sanitize_html_and_replace_env_vars(template_content)
create_story(asana_access_token, task_id, html_text: html_text)
end
end
Expand Down Expand Up @@ -110,14 +110,6 @@ def self.create_story(asana_access_token, task_id, text: nil, html_text: nil)
UI.user_error!("Failed to post comment: #{e}")
end
end

def self.process_template_content(template_content)
template_content.gsub(/\$\{(\w+)\}/) { ENV.fetch($1, '') } # replace environment variables
.gsub(/\s+/, ' ') # replace multiple whitespaces with a single space
.gsub(/>\s+</, '><') # remove spaces between HTML tags
.strip # remove leading and trailing whitespaces
.gsub(%r{<br\s*/?>}, "\n") # replace <br> tags with newlines
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
require "fastlane/action"
require "fastlane_core/configuration/config_item"
require "asana"
require "yaml"
require_relative "../helper/ddg_apple_automation_helper"
require_relative "../helper/github_actions_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 AsanaCreateActionItemAction < Action
def self.run(params)
token = params[:asana_access_token]
task_url = params[:task_url]
task_name = params[:task_name]
notes = params[:notes]
html_notes = params[:html_notes]
template_name = params[:template_name]
is_scheduled_release = params[:is_scheduled_release]
github_handle = params[:github_handle]

task_id = AsanaExtractTaskIdAction.run(task_url: task_url)
automation_subtask_id = AsanaGetReleaseAutomationSubtaskIdAction.run(task_url: task_url, asana_access_token: token)
if is_scheduled_release
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

Helper::GitHubActionsHelper.set_output("asana_assignee_id", assignee_id)

if template_name
template_file = Helper::DdgAppleAutomationHelper.path_for_asset_file("asana_create_action_item/templates/#{template_name}.yml")
template_content = YAML.safe_load(Helper::DdgAppleAutomationHelper.load_file(template_file))
task_name = Helper::DdgAppleAutomationHelper.sanitize_html_and_replace_env_vars(template_content["name"])
html_notes = Helper::DdgAppleAutomationHelper.sanitize_html_and_replace_env_vars(template_content["html_notes"])
end

begin
subtask = create_subtask(
task_id: automation_subtask_id,
assignee_id: assignee_id,
task_name: task_name,
notes: notes,
html_notes: html_notes
)
rescue StandardError => e
UI.user_error!("Failed to create subtask for task: #{e}")
end

Helper::GitHubActionsHelper.set_output("asana_new_task_id", subtask.gid) if subtask&.gid
end

def self.description
"Add a subtask to Asana Release Automation Task"
end

def self.authors
["DuckDuckGo"]
end

def self.return_value
""
end

def self.details
"Adds a task with an action item 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: :task_name,
description: "Task name",
optional: true,
type: String),
FastlaneCore::ConfigItem.new(key: :notes,
description: "Task notes",
optional: true,
type: String),
FastlaneCore::ConfigItem.new(key: :html_notes,
description: "Task HTML notes",
optional: true,
type: String),
FastlaneCore::ConfigItem.new(key: :template_name,
description: "Name of a template file (without extension) for the task content. Templates can be found in assets/asana_create_action_item/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

def self.create_subtask(task_id:, assignee_id:, task_name:, notes: nil, html_notes: nil)
subtask_options = {
task_gid: task_id,
assignee: assignee_id,
name: task_name
}
subtask_options[:notes] = notes unless notes.nil?
subtask_options[:html_notes] = html_notes unless html_notes.nil?

asana_client = Asana::Client.new do |c|
c.authentication(:access_token, token)
end
asana_client.tasks.create_subtask_for_task(**subtask_options)
end
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def self.available_options
optional: false,
type: String),
FastlaneCore::ConfigItem.new(key: :file_name,
description: "Path to the file that will be uploaded",
description: "Path to a file that will be uploaded",
optional: false,
type: String)
]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Generate appcast2.xml for ${TAG} hotfix release and upload assets to S3
html_notes: |
<body>
Publishing ${TAG} hotfix release failed in CI. Please follow the steps to generate the appcast file and upload files to S3 from your local machine.<br>
<ol>
<li>Create a new file called <code>release-notes.txt</code> on your disk.
<ul>
<li>Add each release note as a separate line and don't add bullet points (•) – the script will add them automatically.</li>
</ul></li>
<li>Run <code>appcastManager</code>:
<ul>
<li><code>./scripts/appcast_manager/appcastManager.swift --release-hotfix-to-public-channel --dmg ~/Downloads/${DMG_NAME} --release-notes release-notes.txt</code></li>
</ul></li>
<li>Verify that the new build is in the appcast file with the latest release notes and no internal channel tag. The phased rollout tag should <em>not</em> be present:
<ul>
<li><code>&lt;sparkle:phasedRolloutInterval&gt;43200&lt;/sparkle:phasedRolloutInterval&gt;</code></li>
</ul></li>
<li>Run <code>upload_to_s3.sh</code> script:
<ul>
<li><code>./scripts/upload_to_s3/upload_to_s3.sh --run --overwrite-duckduckgo-dmg ${VERSION}</code></li>
</ul></li>
</ol>
When done, please verify that "Check for Updates" works correctly:
<ol>
<li>Launch a debug version of the app with an old version number.</li>
<li>Make sure you're not identified as an internal user in the app.</li>
<li>Go to Main Menu → DuckDuckGo → Check for Updates...</li>
<li>Verify that you're being offered to update to ${TAG}.</li>
<li>Verify that the update works.</li>
</ol><br>
🔗 Workflow URL: <a href='${WORKFLOW_URL}'>${WORKFLOW_URL}</a>.
</body>

Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: Generate appcast2.xml for ${TAG} internal release and upload assets to S3
html_notes: |
<body>
Publishing ${TAG} internal release failed in CI. Please follow the steps to generate the appcast file and upload files to S3 from your local machine.<br>
<ol>
<li>Download <a href='${DMG_URL}'>the DMG for ${TAG} release</a>.</li>
<li>Create a new file called <code>release-notes.txt</code> on your disk.
<ul>
<li>Add each release note as a separate line and don't add bullet points (•) – the script will add them automatically.</li>
</ul></li>
<li>Run <code>appcastManager</code>:
<ul>
<li><code>./scripts/appcast_manager/appcastManager.swift --release-to-internal-channel --dmg ~/Downloads/${DMG_NAME} --release-notes release-notes.txt</code></li>
</ul></li>
<li>Verify that the new build is in the appcast file with the following internal channel tag:
<ul>
<li><code>&lt;sparkle:channel&gt;internal-channel&lt;/sparkle:channel&gt;</code></li>
</ul></li>
<li>Run <code>upload_to_s3.sh</code> script:
<ul>
<li><code>./scripts/upload_to_s3/upload_to_s3.sh --run</code></li>
</ul></li>
</ol>
When done, please verify that "Check for Updates" works correctly:
<ol>
<li>Launch a debug version of the app with an old version number.</li>
<li>Identify as an internal user in the app.</li>
<li>Go to Main Menu → DuckDuckGo → Check for Updates...</li>
<li>Verify that you're being offered to update to ${TAG}.</li>
<li>Verify that the update works.</li>
</ol><br>
🔗 Workflow URL: <a href='${WORKFLOW_URL}'>${WORKFLOW_URL}</a>.
</body>

Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Generate appcast2.xml for ${TAG} public release and upload assets to S3
html_notes: |
<body>
Publishing ${TAG} release failed in CI. Please follow the steps to generate the appcast file and upload files to S3 from your local machine.<br>
<ol>
<li>Create a new file called <code>release-notes.txt</code> on your disk.
<ul>
<li>Add each release note as a separate line and don't add bullet points (•) – the script will add them automatically.</li>
</ul></li>
<li>Run <code>appcastManager</code>:
<ul>
<li><code>./scripts/appcast_manager/appcastManager.swift --release-to-public-channel --version ${VERSION} --release-notes release-notes.txt</code></li>
</ul></li>
<li>Verify that the new build is in the appcast file with the latest release notes, the phased rollout tag (below) and no internal channel tag:
<ul>
<li><code>&lt;sparkle:phasedRolloutInterval&gt;43200&lt;/sparkle:phasedRolloutInterval&gt;</code></li>
</ul></li>
<li>Run <code>upload_to_s3.sh</code> script:
<ul>
<li><code>./scripts/upload_to_s3/upload_to_s3.sh --run --overwrite-duckduckgo-dmg ${VERSION}</code></li>
</ul></li>
</ol>
When done, please verify that "Check for Updates" works correctly:
<ol>
<li>Launch a debug version of the app with an old version number.</li>
<li>Make sure you're not identified as an internal user in the app.</li>
<li>Go to Main Menu → DuckDuckGo → Check for Updates...</li>
<li>Verify that you're being offered to update to ${TAG}.</li>
<li>Verify that the update works.</li>
</ol><br>
🔗 Workflow URL: <a href='${WORKFLOW_URL}'>${WORKFLOW_URL}</a>.
</body>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
name: Delete ${BRANCH} branch
html_notes: |
<body>
The <code>${TAG}</code> public release has been successfully tagged and published in GitHub releases,
but deleting <code>${BRANCH}</code> branch failed. Please delete it manually:
<ul>
<li><code>git push origin --delete ${BRANCH}</code></li>
</ul>
Complete this task when ready, or if the release branch has already been deleted.<br>
<br>
🔗 Workflow URL: <a href='${WORKFLOW_URL}'>${WORKFLOW_URL}</a>.
</body>
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: Tag ${BRANCH} branch and create GitHub release
html_notes: |
<body>
Failed to tag the release with <code>${TAG}</code> tag.<br>
Please follow instructions below to tag the branch, make GitHub release and merge release branch to <code>${BASE_BRANCH}</code> manually.<br>
<br>
Issue the following git commands to tag the release and merge the branch:
<ul>
<li><code>git fetch origin</code></li>
<li><code>git checkout ${BRANCH}</code> switch to the release branch</li>
<li><code>git pull origin ${BRANCH}</code> pull latest changes</li>
<li><code>git tag ${TAG}</code> tag the release</li>
<li><code>git push origin ${TAG}</code> push the tag</li>
<li><code>git checkout ${BASE_BRANCH}</code> switch to ${BASE_BRANCH}</li>
<li><code>git pull origin ${BASE_BRANCH}</code> pull the latest code</li>
<li><code>git merge ${BRANCH}</code>
<ul>
<li>Resolve conflicts as needed</li>
<li>When merging a hotfix branch into an internal release branch, you will get conflicts in version and build number xcconfig files:
<ul>
<li>In the version file: accept the internal version number (higher).</li>
<li>In the build number file: accept the hotfix build number (higher). This step is very important in order to calculate the build number of the next internal release correctly.</li>
</ul></li>
</ul></li>
<li><code>git push origin ${BASE_BRANCH}</code> push merged branch</li>
</ul><br>
To create GitHub release:
<ul>
<li>Set up GH CLI if you haven't yet: <a data-asana-gid='1203791243007683'/></li>
<li>Run the following command:
<ul>
<li><code>gh release create ${TAG} --generate-notes --prerelease --notes-start-tag ${LAST_RELEASE_TAG}</code></li>
</ul></li>
</ul><br>
Complete this task when ready and proceed with testing the build. If you're bumping an internal release, you should get another task asking you to publish the release in Sparkle.
Look for other tasks in <a data-asana-gid='${AUTOMATION_TASK_ID}'/> task and handle them as needed.<br>
<br>
🔗 Workflow URL: <a href='${WORKFLOW_URL}'>${WORKFLOW_URL}</a>.
</body>
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Merge ${BRANCH} to ${BASE_BRANCH}
html_notes: |
<body>
The <code>${TAG}</code> release has been successfully tagged and published in GitHub releases,
but merging to <code>${BASE_BRANCH}</code> failed. Please resolve conflicts and merge <code>${BRANCH}</code> to <code>${BASE_BRANCH}</code> manually.<br>
<br>
Issue the following git commands:
<ul>
<li><code>git fetch origin</code></li>
<li><code>git checkout ${BRANCH}</code> switch to the release branch</li>
<li><code>git pull origin ${BRANCH}</code> pull latest changes</li>
<li><code>git checkout ${BASE_BRANCH}</code> switch to ${BASE_BRANCH}</li>
<li><code>git pull origin ${BASE_BRANCH}</code> pull the latest code</li>
<li><code>git merge ${BRANCH}</code>
<ul>
<li>Resolve conflicts as needed</li>
<li>When merging a hotfix branch into an internal release branch, you will get conflicts in version and build number xcconfig files:
<ul>
<li>In the version file: accept the internal version number (higher).</li>
<li>In the build number file: accept the hotfix build number (higher). This step is very important in order to calculate the build number of the next internal release correctly.</li>
</ul></li>
</ul></li>
<li><code>git push origin ${BASE_BRANCH}</code> push merged branch</li>
</ul>
Complete this task when ready and proceed with testing the build.<br>
<br>
🔗 Workflow URL: <a href='${WORKFLOW_URL}'>${WORKFLOW_URL}</a>.
</body>
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Tag ${BRANCH} branch, delete it, and create GitHub release
html_notes: |
<body>
Failed to tag the release with <code>${TAG}</code> tag.<br>
Please follow instructions below to tag the branch, make GitHub release and delete the release branch manually.
<ul>
<li>If the tag has already been created, please proceed with creating GitHub release and deleting the branch.</li>
<li>If both tag and GitHub release have already been created, please close this task already.</li>
</ul><br>
Issue the following git commands to tag the release and delete the branch:
<ul>
<li><code>git fetch origin</code></li>
<li><code>git checkout ${BRANCH}</code> switch to the release branch</li>
<li><code>git pull origin ${BRANCH}</code> pull latest changes</li>
<li><code>git tag ${TAG}</code> tag the release</li>
<li><code>git push origin ${TAG}</code> push the tag</li>
<li><code>git checkout ${BASE_BRANCH}</code> switch to ${BASE_BRANCH}</li>
<li><code>git push origin --delete ${BRANCH}</code> delete the release branch</li>
</ul><br>
To create GitHub release:
<ul>
<li>Set up GH CLI if you haven't yet: <a data-asana-gid='1203791243007683'/></li>
<li>Run the following command:
<ul>
<li><code>gh release create ${TAG} --generate-notes --latest --notes-start-tag ${LAST_RELEASE_TAG}</code></li>
</ul></li>
</ul><br>
Complete this task when ready.<br>
<br>
🔗 Workflow URL: <a href='${WORKFLOW_URL}'>${WORKFLOW_URL}</a>.
</body>
Loading