Skip to content

GHA: Improve Assign Release Task #6148

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

Closed
Closed
Show file tree
Hide file tree
Changes from all 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
84 changes: 84 additions & 0 deletions .github/actions/assign-release-task/Main.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import com.asana.Client
import kotlinx.coroutines.runBlocking
import java.io.File
import org.yaml.snakeyaml.Yaml

object AsanaSync {
private val asanaToken = System.getenv("ASANA_ACCESS_TOKEN")
private val taskName = System.getenv("ASANA_TASK_NAME")
private val githubUsername = System.getenv("GITHUB_USERNAME")
private val projectId = System.getenv("ASANA_PROJECT_ID")

private val asanaClient = Client.accessToken(asanaToken)

private fun parseUserMap(): Map<String, String> {
val actionPath = System.getenv("GITHUB_ACTION_PATH") ?: "."
val userMapFile = File("$actionPath/github_asana_mapping.yml")

return try {
if (!userMapFile.exists()) {
System.err.println("User map file not found at: ${userMapFile.absolutePath}")
return emptyMap()
}

Yaml().load<Map<String, String>>(userMapFile.readText()).also {
println("Loaded user map from file: $it")
}
} catch (e: Exception) {
System.err.println("Error parsing user map file: ${e.message}")
e.printStackTrace()
emptyMap()
}
}

private fun getAsanaUserId(githubUsername: String): String? {
return userMap[githubUsername]?.also {
println("Found Asana user ID $it for GitHub user $githubUsername")
} ?: run {
System.err.println("No Asana user ID found for GitHub user $githubUsername")
null
}
}

fun findAndAssignTask() = runBlocking {
try {
println("Searching for task with name: $taskName")

// Search for tasks in the project
val tasks = asanaClient.tasks.findByProject(projectId)
.option("fields", listOf("name", "permalink_url"))
.execute()

// Find task by name
val task = tasks.data.find { it.name == taskName }

if (task != null) {
println("Found task: ${task.name}")

// Assign the task to the user
val asanaUserId = getAsanaUserId(githubUsername)
if (asanaUserId != null) {
asanaClient.tasks.update(task.gid)
.data("assignee", asanaUserId)
.execute()
println("Assigned task to Asana user ID: $asanaUserId")
}

// Set output for GitHub Actions
File(System.getenv("GITHUB_OUTPUT")).appendText("ASANA_TASK_URL=${task.permalinkUrl}\n")
println("Task URL: ${task.permalinkUrl}")
} else {
System.err.println("No task found with name: $taskName")
System.exit(1)
}
} catch (e: Exception) {
System.err.println("Error finding/assigning task: ${e.message}")
e.printStackTrace()
System.exit(1)
}
}
}

fun main() {
AsanaSync.findAndAssignTask()
}
88 changes: 35 additions & 53 deletions .github/actions/assign-release-task/action.yml
Original file line number Diff line number Diff line change
@@ -1,67 +1,49 @@
name: 'Assign Android Release Task in Asana'
description: 'Assigns the latest Asana Release task to the user who runs the workflow'
inputs:
task_name:
description: 'The name of the task to search for'
ASANA_TASK_NAME:
description: 'The name of the Asana task to search for'
required: true
asana_token:
ASANA_ACCESS_TOKEN:
description: 'Asana Personal Access Token'
required: true
project_gid:
description: 'Asana Project GID to search within'
ASANA_PROJECT_ID:
description: 'Asana Project ID to search the task in'
required: true
username:
GITHUB_USERNAME:
description: 'The Github username to search for'
required: true

outputs:
ASANA_TASK_URL :
description: 'URL of the found Asana task'
value: ${{ steps.check_for_changes.outputs.has_changes }}

runs:
using: 'composite'
steps:
- name: Find task in Asana and assign it to owner
shell: bash
run: |
task_name="${{ inputs.task_name }}"
asana_token="${{ inputs.asana_token }}"
project_gid="${{ inputs.project_gid }}"
username="${{ inputs.username }}"

# Make the API request to get tasks from the specified project
response=$(curl -s -X GET "https://app.asana.com/api/1.0/projects/${project_gid}/tasks" \
-H "Authorization: Bearer ${asana_token}")

# Check if the response contains any tasks that match the specified task name exactly
task_id=$(echo "$response" | jq -r '.data[] | select(.name == "'"$task_name"'") | .gid')
- name: Setup Java SDK
uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: '17'
cache: 'gradle'

if [ -z "$task_id" ]; then
echo "No tasks with the exact name '$task_name' found in project GID '$project_gid'."
exit 1
else
echo "Task ID for the task named '$task_name': $task_id"
fi

asana_user_id=$(grep -E "^$username: " .github/actions/assign-release-task/github_asana_mapping.yml | awk -F': ' '{print $2}' | tr -d '"')
- name: Setup Gradle
uses: gradle/gradle-build-action@v2
with:
gradle-version: 8.5
cache-read-only: false
cache-overwrite-existing: true
gradle-home-cache-cleanup: true

if [ -z "asana_user_id" ]; then
echo "User $username not found."
exit 1
else
echo "User ID for $username: $asana_user_id"
fi

echo "Assigning task ID $task_id to user ID $asana_user_id"

# Assign the task to the user
response=$(curl -s -X PUT "https://app.asana.com/api/1.0/tasks/${task_id}" \
-H "Authorization: Bearer ${asana_token}" \
-H "Content-Type: application/json" \
-d "{\"data\": {\"assignee\": \"${asana_user_id}\"}}")

# Check if the assignment was successful
status=$(echo $response | jq -r '.errors')

if [ "$status" == "null" ]; then
echo "Task $task_id successfully assigned to user $asana_user_id."
else
echo "Failed to assign task: $status"
exit 1
fi

- name: Find task in Asana and assign it to the correct user
shell: bash
run: |
cd ${{ github.action_path }}
./gradlew run --build-cache
env:
ASANA_ACCESS_TOKEN: ${{ inputs.ASANA_ACCESS_TOKEN }}
ASANA_PROJECT_ID: ${{ inputs.ASANA_PROJECT_ID }}
ASANA_TASK_NAME: ${{ inputs.ASANA_TASK_NAME }}
GITHUB_USERNAME: ${{ inputs.GITHUB_USERNAME }}
29 changes: 29 additions & 0 deletions .github/actions/assign-release-task/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
plugins {
kotlin("jvm") version "1.9.22"
application
}

repositories {
mavenCentral()
}

dependencies {
implementation("com.asana:asana:1.0.0")
implementation("org.kohsuke:github-api:1.315")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
implementation("org.yaml:snakeyaml:2.2")

testImplementation(kotlin("test"))
}

application {
mainClass.set("MainKt")
}

tasks.test {
useJUnitPlatform()
}

kotlin {
jvmToolchain(17)
}
1 change: 1 addition & 0 deletions .github/actions/assign-release-task/settings.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
rootProject.name = "assign-release-task"
23 changes: 23 additions & 0 deletions .github/workflows/pr-sync.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: Pull Request Reviewed -> Sync With Asana
on:
pull_request_review:
pull_request_target:
types:
- opened
- edited
- closed
- reopened
- synchronize
- review_requested

jobs:
sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: duckduckgo/action-asana-sync@v11
with:
ASANA_ACCESS_TOKEN: ${{ secrets.ASANA_ACCESS_TOKEN }}
ASANA_WORKSPACE_ID: ${{ secrets.ASANA_WORKSPACE_ID }}
ASANA_PROJECT_ID: ${{ vars.GH_ASANA_CODE_REVIEWS_PROJECT_ID }}
GITHUB_PAT: ${{ secrets.GT_DAXMOBILE }}
53 changes: 24 additions & 29 deletions .github/workflows/release_production.yml
Original file line number Diff line number Diff line change
@@ -1,38 +1,33 @@
name: Release - Android App Production Release
name: Test Asana Task Assignment

on:
workflow_dispatch:
inputs:
app-version:
description: 'App Version for Release'
task_name:
description: 'Name of the Asana task to find'
required: true
default: 'PLACEHOLDER'

env:
ASANA_PAT: ${{ secrets.ASANA_ACCESS_TOKEN }}

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
type: string
github_username:
description: 'GitHub username to assign the task to'
required: true
type: string
default: 'malmstein'

jobs:
create_release_task:
uses: ./.github/workflows/release_create_task.yml
with:
app-version: ${{ github.event.inputs.app-version }}

create_release_tag:
needs: create_release_task
uses: ./.github/workflows/release_create_tag.yml
with:
app-version: ${{ github.event.inputs.app-version }}
test-action:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

launch_release_tests:
needs: create_release_tag
uses: ./.github/workflows/release_tests.yml
with:
app-version: ${{ github.event.inputs.app-version }}
- name: Test Asana Task Assignment
id: assign-task
uses: ./.github/actions/assign-release-task
with:
ASANA_ACCESS_TOKEN: ${{ secrets.ASANA_ACCESS_TOKEN }}
ASANA_TASK_NAME: ${{ inputs.task_name }}
ASANA_PROJECT_ID: ${{ vars.GH_ANDROID_RELEASE_BOARD_PROJECT_ID }}
GITHUB_USERNAME: ${{ inputs.github_username }}

report_workflow_failed:
if: ${{ failure() }}
uses: ./.github/workflows/release_report_error.yml
- name: Print Results
run: |
echo "Task URL: ${{ steps.assign-task.outputs.asana_task_url }}"
Loading