Skip to content

Commit 335ebcc

Browse files
Merge branch 'release/5.239.0'
2 parents f04bd61 + 46a4771 commit 335ebcc

File tree

224 files changed

+104806
-1956
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

224 files changed

+104806
-1956
lines changed

.github/actions/assign-release-task/action.yml

Lines changed: 67 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -19,53 +19,79 @@ outputs:
1919
runs:
2020
using: 'composite'
2121
steps:
22-
- name: Find task in Asana and assign it to owner
22+
- name: Find task, assign it, and write ID to file
2323
shell: bash
24+
env: # Make inputs available as environment variables for easier access in the script
25+
INPUT_TASK_NAME: ${{ inputs.task_name }}
26+
INPUT_ASANA_TOKEN: ${{ inputs.asana_token }}
27+
INPUT_PROJECT_GID: ${{ inputs.project_gid }}
28+
INPUT_USERNAME: ${{ inputs.username }}
29+
OUTPUT_FILE_PATH: "${{ github.workspace }}/asana_task_id.txt" # Define the output file path
2430
run: |
25-
task_name="${{ inputs.task_name }}"
26-
asana_token="${{ inputs.asana_token }}"
27-
project_gid="${{ inputs.project_gid }}"
28-
username="${{ inputs.username }}"
29-
30-
# Make the API request to get tasks from the specified project
31-
response=$(curl -s -X GET "https://app.asana.com/api/1.0/projects/${project_gid}/tasks" \
32-
-H "Authorization: Bearer ${asana_token}")
33-
34-
# Check if the response contains any tasks that match the specified task name exactly
35-
task_id=$(echo "$response" | jq -r '.data[] | select(.name == "'"$task_name"'") | .gid')
31+
set -e # Exit immediately if a command exits with a non-zero status.
32+
echo "Searching for task: '$INPUT_TASK_NAME' in project GID: '$INPUT_PROJECT_GID'"
33+
34+
asana_api_response=$(curl -s -X GET "https://app.asana.com/api/1.0/projects/${INPUT_PROJECT_GID}/tasks" \
35+
-H "Authorization: Bearer ${INPUT_ASANA_TOKEN}")
36+
37+
# Using jq to extract the task_id - ensure it's robust
38+
# This will get the first matching task ID if multiple tasks have the same name.
39+
# Add error handling if multiple tasks with the same name is an issue.
40+
found_task_id=$(echo "$asana_api_response" | jq -r --arg TASK_NAME "$INPUT_TASK_NAME" '.data[] | select(.name == $TASK_NAME) | .gid | select(.)' | head -n 1)
3641
37-
if [ -z "$task_id" ]; then
38-
echo "No tasks with the exact name '$task_name' found in project GID '$project_gid'."
42+
if [ -z "$found_task_id" ]; then
43+
echo "::error::No task with the exact name '$INPUT_TASK_NAME' found in project GID '$INPUT_PROJECT_GID'."
44+
# Write an empty string or a specific marker to the file if task not found
45+
echo "TASK_NOT_FOUND" > "$OUTPUT_FILE_PATH"
3946
exit 1
4047
else
41-
echo "Task ID for the task named '$task_name': $task_id"
42-
echo "task_id=$task_id" >> $GITHUB_OUTPUT
48+
echo "Found Task ID: '$found_task_id'"
49+
# Write the found task ID to the specified file
50+
echo "$found_task_id" > "$OUTPUT_FILE_PATH"
51+
echo "Task ID successfully written to $OUTPUT_FILE_PATH"
4352
fi
44-
45-
asana_user_id=$(grep -E "^$username: " .github/actions/assign-release-task/github_asana_mapping.yml | awk -F': ' '{print $2}' | tr -d '"')
4653
47-
if [ -z "asana_user_id" ]; then
48-
echo "User $username not found."
49-
exit 1
50-
else
51-
echo "User ID for $username: $asana_user_id"
52-
fi
54+
# --- Get Asana User ID ---
55+
# Assuming github_asana_mapping.yml is at .github/actions/assign-release-task/github_asana_mapping.yml
56+
# relative to the REPO ROOT, not the action directory itself during runtime.
57+
# For composite actions, paths in scripts are relative to github.workspace.
58+
# If the mapping file is part of the action's folder, the path might need to be:
59+
# ${{ github.action_path }}/github_asana_mapping.yml
60+
# However, it's often better if such mapping files are at a known repo location.
61+
# Let's assume it's checked into the root for simplicity here, or adjust as needed.
62+
MAPPING_FILE="${{ github.workspace }}/.github/actions/assign-release-task/github_asana_mapping.yml" # Or adjust path
5363
54-
echo "Assigning task ID $task_id to user ID $asana_user_id"
55-
56-
# Assign the task to the user
57-
response=$(curl -s -X PUT "https://app.asana.com/api/1.0/tasks/${task_id}" \
58-
-H "Authorization: Bearer ${asana_token}" \
59-
-H "Content-Type: application/json" \
60-
-d "{\"data\": {\"assignee\": \"${asana_user_id}\"}}")
61-
62-
# Check if the assignment was successful
63-
status=$(echo $response | jq -r '.errors')
64-
65-
if [ "$status" == "null" ]; then
66-
echo "Task $task_id successfully assigned to user $asana_user_id."
67-
else
68-
echo "Failed to assign task: $status"
69-
exit 1
64+
echo "Looking up Asana User ID for GitHub user: '$INPUT_USERNAME' in file: '$MAPPING_FILE'"
65+
if [ ! -f "$MAPPING_FILE" ]; then
66+
echo "::error::Mapping file not found at $MAPPING_FILE"
67+
echo "USER_MAPPING_FILE_NOT_FOUND" > "$OUTPUT_FILE_PATH" # Overwrite with error state
68+
exit 1
7069
fi
71-
70+
71+
# asana_user_id=$(grep -E "^$username: " .github/actions/assign-release-task/github_asana_mapping.yml | awk -F': ' '{print $2}' | tr -d '"')
72+
#
73+
# if [ -z "asana_user_id" ]; then
74+
# echo "User $username not found."
75+
# exit 1
76+
# else
77+
# echo "User ID for $username: $asana_user_id"
78+
# fi
79+
#
80+
# echo "Assigning task ID $task_id to user ID $asana_user_id"
81+
#
82+
# # Assign the task to the user
83+
# response=$(curl -s -X PUT "https://app.asana.com/api/1.0/tasks/${task_id}" \
84+
# -H "Authorization: Bearer ${asana_token}" \
85+
# -H "Content-Type: application/json" \
86+
# -d "{\"data\": {\"assignee\": \"${asana_user_id}\"}}")
87+
#
88+
# # Check if the assignment was successful
89+
# status=$(echo $response | jq -r '.errors')
90+
#
91+
# if [ "$status" == "null" ]; then
92+
# echo "Task $task_id successfully assigned to user $asana_user_id."
93+
# else
94+
# echo "Failed to assign task: $status"
95+
# exit 1
96+
# fi
97+
#
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
dist/
2+
lib/
3+
node_modules/
4+
jest.config.js
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"plugins": ["jest", "@typescript-eslint", "import"],
3+
"extends": [
4+
"plugin:github/recommended",
5+
"plugin:import/typescript",
6+
"plugin:@typescript-eslint/recommended"
7+
],
8+
"parser": "@typescript-eslint/parser",
9+
"parserOptions": {
10+
"ecmaVersion": 9,
11+
"sourceType": "module",
12+
"project": "./tsconfig.json"
13+
},
14+
"env": {
15+
"node": true,
16+
"es6": true,
17+
"jest/globals": true
18+
},
19+
"rules": {
20+
"i18n-text/no-en": "off"
21+
},
22+
"settings": {
23+
"import/parsers": {
24+
"@typescript-eslint/parser": [".ts", ".tsx"]
25+
},
26+
"import/resolver": {
27+
"typescript": {
28+
"alwaysTryTypes": true
29+
}
30+
}
31+
}
32+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
dist/** -diff linguist-generated=true
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
# Dependency directory
2+
node_modules
3+
4+
# Rest pulled from https://github.com/github/gitignore/blob/master/Node.gitignore
5+
# Logs
6+
logs
7+
*.log
8+
npm-debug.log*
9+
yarn-debug.log*
10+
yarn-error.log*
11+
lerna-debug.log*
12+
13+
# Diagnostic reports (https://nodejs.org/api/report.html)
14+
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
15+
16+
# Runtime data
17+
pids
18+
*.pid
19+
*.seed
20+
*.pid.lock
21+
22+
# Directory for instrumented libs generated by jscoverage/JSCover
23+
lib-cov
24+
25+
# Coverage directory used by tools like istanbul
26+
coverage
27+
*.lcov
28+
29+
# nyc test coverage
30+
.nyc_output
31+
32+
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
33+
.grunt
34+
35+
# Bower dependency directory (https://bower.io/)
36+
bower_components
37+
38+
# node-waf configuration
39+
.lock-wscript
40+
41+
# Compiled binary addons (https://nodejs.org/api/addons.html)
42+
build/Release
43+
44+
# Dependency directories
45+
jspm_packages/
46+
47+
# TypeScript v1 declaration files
48+
typings/
49+
50+
# TypeScript cache
51+
*.tsbuildinfo
52+
53+
# Optional npm cache directory
54+
.npm
55+
56+
# Optional eslint cache
57+
.eslintcache
58+
59+
# Optional REPL history
60+
.node_repl_history
61+
62+
# Output of 'npm pack'
63+
*.tgz
64+
65+
# Yarn Integrity file
66+
.yarn-integrity
67+
68+
# dotenv environment variables file
69+
.env
70+
.env.test
71+
72+
# parcel-bundler cache (https://parceljs.org/)
73+
.cache
74+
75+
# next.js build output
76+
.next
77+
78+
# nuxt.js build output
79+
.nuxt
80+
81+
# vuepress build output
82+
.vuepress/dist
83+
84+
# Serverless directories
85+
.serverless/
86+
87+
# FuseBox cache
88+
.fusebox/
89+
90+
# DynamoDB Local files
91+
.dynamodb/
92+
93+
# OS metadata
94+
.DS_Store
95+
Thumbs.db
96+
97+
# Ignore built ts files
98+
__tests__/runner/*
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
dist/
2+
lib/
3+
node_modules/

.github/actions/pr-asana-sync/LICENSE

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
2+
The MIT License (MIT)
3+
4+
Copyright (c) 2018 GitHub, Inc. and contributors
5+
6+
Permission is hereby granted, free of charge, to any person obtaining a copy
7+
of this software and associated documentation files (the "Software"), to deal
8+
in the Software without restriction, including without limitation the rights
9+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
copies of the Software, and to permit persons to whom the Software is
11+
furnished to do so, subject to the following conditions:
12+
13+
The above copyright notice and this permission notice shall be included in
14+
all copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
THE SOFTWARE.
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Asana sync action
2+
3+
This is a Github Action for tracking the status of Github Pull requests in Asana. It does the following:
4+
5+
1. Creates tasks for each new pull request in a project.
6+
2. Puts these tasks in a specified Asana project (and optionally section)
7+
3. Makes the PR task as a subtask of Asana task referenced in PR description
8+
4. Syncs any change to the PR name to Asana.
9+
5. Syncs the PR state (Open, Closed, Draft, Merged) to an Asana custom field.
10+
6. Creates a subtask for each requested review and automatically resolves these once approved or merged
11+
12+
## Usage
13+
14+
Create a [workflow file](./.github/workflows/asana.yml) that runs on
15+
`pull_request` and `pull_request_review` events:
16+
17+
```yml
18+
name: 'asana sync'
19+
on:
20+
pull_request_review:
21+
pull_request:
22+
types:
23+
- opened
24+
- edited
25+
- closed
26+
- reopened
27+
- synchronize
28+
- review_requested
29+
30+
jobs:
31+
sync:
32+
runs-on: ubuntu-latest
33+
steps:
34+
- uses: actions/checkout@v3
35+
- uses: duckduckgo/action-asana-sync@v1
36+
with:
37+
ASANA_ACCESS_TOKEN: ${{ secrets.ASANA_ACCESS_TOKEN }}
38+
ASANA_WORKSPACE_ID: ${{ secrets.ASANA_WORKSPACE_ID }}
39+
ASANA_PROJECT_ID: 'GID of project to create the tasks in'
40+
```
41+
42+
## Configuration
43+
44+
There are a few additional configuration options that can be used to tweak
45+
behaviour of this Github Action:
46+
47+
- `NO_AUTOCLOSE_PROJECTS`: By default this action will automatically close PR
48+
task it opens. It will not close merged tasks when they are added to projects
49+
listed in this variable (comma separated string of IDs). (default: REVIEW/RELEASE project)
50+
- `SKIPPED_USERS`: Some users don't like receiving reviews in Asana. This is a
51+
comma separated list of github usernames that will be ignored (replaced with
52+
dax).
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: "Asana Sync"
2+
description: "Sync Github PRs to Asana Tasks"
3+
author: "David Gonzalez based on Quang Nguyen and Sam Macbeth's work"
4+
inputs:
5+
GITHUB_TOKEN:
6+
required: true
7+
description: "Access token for GitHub API calls"
8+
ASANA_ACCESS_TOKEN:
9+
required: true
10+
description: "Access token for Asana API calls"
11+
ASANA_WORKSPACE_ID:
12+
required: true
13+
description: "ID of your Asana workspace"
14+
ASANA_PROJECT_ID:
15+
required: true
16+
description: "Project ID where issues should be created in Asana"
17+
ASANA_IN_PROGRESS_SECTION_ID:
18+
required: false
19+
description: "If set: move the task to this section once review is in progress"
20+
USER_MAP:
21+
required: false
22+
description: "JSON string mapping Github user IDs to Asana user IDs"
23+
RANDOMIZED_REVIEWERS:
24+
required: false
25+
description: "Comma separated list of GitHub users who can be assigned as randomized reviewers"
26+
outputs:
27+
task_url:
28+
description: URL of created/updated PR review task
29+
result:
30+
description: "Will be one of: created, updated"
31+
runs:
32+
using: "node20"
33+
main: "dist/index.js"

0 commit comments

Comments
 (0)