From 1d54a72a8cf8615d7d57ee461f9c794ec526005d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Gonz=C3=A1lez?= Date: Tue, 27 May 2025 17:05:46 +0200 Subject: [PATCH 1/3] GHA: Improve Assign Release Task --- .github/actions/assign-release-task/Main.kt | 84 ++++++++++++++++++ .../actions/assign-release-task/action.yml | 86 ++++++++----------- .github/workflows/pr-sync.yaml | 23 +++++ 3 files changed, 141 insertions(+), 52 deletions(-) create mode 100644 .github/actions/assign-release-task/Main.kt create mode 100644 .github/workflows/pr-sync.yaml diff --git a/.github/actions/assign-release-task/Main.kt b/.github/actions/assign-release-task/Main.kt new file mode 100644 index 000000000000..122ef92182c2 --- /dev/null +++ b/.github/actions/assign-release-task/Main.kt @@ -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 { + 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>(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() +} diff --git a/.github/actions/assign-release-task/action.yml b/.github/actions/assign-release-task/action.yml index 334921a02b94..78a29952c86d 100644 --- a/.github/actions/assign-release-task/action.yml +++ b/.github/actions/assign-release-task/action.yml @@ -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: description: 'The Github username to search for' required: true + +outputs: + 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 }} \ No newline at end of file diff --git a/.github/workflows/pr-sync.yaml b/.github/workflows/pr-sync.yaml new file mode 100644 index 000000000000..e0759f21b42e --- /dev/null +++ b/.github/workflows/pr-sync.yaml @@ -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 }} \ No newline at end of file From 1367adfd779c3fb134c35621adb72b80fefb8aa5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Gonz=C3=A1lez?= Date: Tue, 27 May 2025 17:32:54 +0200 Subject: [PATCH 2/3] make this action in kotlin build --- .../assign-release-task/build.gradle.kts | 29 +++++++++++ .../assign-release-task/settings.gradle.kts | 1 + .github/workflows/release_production.yml | 52 ++++++++----------- 3 files changed, 53 insertions(+), 29 deletions(-) create mode 100644 .github/actions/assign-release-task/build.gradle.kts create mode 100644 .github/actions/assign-release-task/settings.gradle.kts diff --git a/.github/actions/assign-release-task/build.gradle.kts b/.github/actions/assign-release-task/build.gradle.kts new file mode 100644 index 000000000000..8fae44148620 --- /dev/null +++ b/.github/actions/assign-release-task/build.gradle.kts @@ -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) +} diff --git a/.github/actions/assign-release-task/settings.gradle.kts b/.github/actions/assign-release-task/settings.gradle.kts new file mode 100644 index 000000000000..c29dc9b40200 --- /dev/null +++ b/.github/actions/assign-release-task/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "assign-release-task" \ No newline at end of file diff --git a/.github/workflows/release_production.yml b/.github/workflows/release_production.yml index a4ad14a56833..44bc0f2c37fe 100644 --- a/.github/workflows/release_production.yml +++ b/.github/workflows/release_production.yml @@ -1,38 +1,32 @@ -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_PAT_TEST }} + ASANA_TASK_NAME: ${{ inputs.task_name }} + GITHUB_USERNAME: ${{ inputs.github_username }} - report_workflow_failed: - if: ${{ failure() }} - uses: ./.github/workflows/release_report_error.yml \ No newline at end of file + - name: Print Results + run: | + echo "Task URL: ${{ steps.assign-task.outputs.asana_task_url }}" \ No newline at end of file From ab1c955d81b94bbc7626c3ca9c0ab5148830eec0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Gonz=C3=A1lez?= Date: Tue, 27 May 2025 17:49:23 +0200 Subject: [PATCH 3/3] clean up values --- .github/actions/assign-release-task/Main.kt | 2 +- .github/actions/assign-release-task/action.yml | 10 +++++----- .github/workflows/release_production.yml | 3 ++- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/.github/actions/assign-release-task/Main.kt b/.github/actions/assign-release-task/Main.kt index 122ef92182c2..035fc4e5c4ec 100644 --- a/.github/actions/assign-release-task/Main.kt +++ b/.github/actions/assign-release-task/Main.kt @@ -65,7 +65,7 @@ object AsanaSync { } // Set output for GitHub Actions - File(System.getenv("GITHUB_OUTPUT")).appendText("asana_task_url=${task.permalinkUrl}\n") + 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") diff --git a/.github/actions/assign-release-task/action.yml b/.github/actions/assign-release-task/action.yml index 78a29952c86d..4b0475071464 100644 --- a/.github/actions/assign-release-task/action.yml +++ b/.github/actions/assign-release-task/action.yml @@ -1,21 +1,21 @@ name: 'Assign Android Release Task in Asana' description: 'Assigns the latest Asana Release task to the user who runs the workflow' inputs: - asana_task_name: + ASANA_TASK_NAME: description: 'The name of the Asana task to search for' required: true - asana_access_token: + ASANA_ACCESS_TOKEN: description: 'Asana Personal Access Token' required: true - asana_project_id: + 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: - task_url : + ASANA_TASK_URL : description: 'URL of the found Asana task' value: ${{ steps.check_for_changes.outputs.has_changes }} diff --git a/.github/workflows/release_production.yml b/.github/workflows/release_production.yml index 44bc0f2c37fe..d451e6e43e61 100644 --- a/.github/workflows/release_production.yml +++ b/.github/workflows/release_production.yml @@ -23,8 +23,9 @@ jobs: id: assign-task uses: ./.github/actions/assign-release-task with: - ASANA_ACCESS_TOKEN: ${{ secrets.ASANA_PAT_TEST }} + 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 }} - name: Print Results