Skip to content
Merged
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
6 changes: 3 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ jobs:
TEAMWORK_URI: "localhost"
TEAMWORK_API_TOKEN: "test_api_token"
AUTOMATIC_TAGGING: true
BOARD_COLUMN_OPENED: "PR Open"
BOARD_COLUMN_MERGED: "Ready to Test"
BOARD_COLUMN_CLOSED: "Rejected"
WORKFLOW_STAGE_OPENED: "PR Open"
WORKFLOW_STAGE_MERGED: "Ready to Test"
WORKFLOW_STAGE_CLOSED: "Rejected"
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ jobs:
TEAMWORK_URI: ${{ secrets.TEAMWORK_URI }}
TEAMWORK_API_TOKEN: ${{ secrets.TEAMWORK_API_TOKEN }}
AUTOMATIC_TAGGING: false
BOARD_COLUMN_OPENED: 'PR Open'
BOARD_COLUMN_MERGED: 'Ready to Test'
BOARD_COLUMN_CLOSED: 'Rejected'
WORKFLOW_STAGE_OPENED: 'PR Open'
WORKFLOW_STAGE_MERGED: 'Ready to Test'
WORKFLOW_STAGE_CLOSED: 'Rejected'
env:
IGNORE_PROJECT_IDS: '1 2 3'

Expand All @@ -71,12 +71,12 @@ Tags are added automatically on the task if you are have the option `AUTOMATIC_T
- A PR is merged: tags `PR Open` and `PR Approved` removed, tag `PR merged` added
- A PR is closed: tags `PR Open` and `PR Approved` removed

You may also specify columns you'd like the task to be moved to on every stage of the PR:
- `BOARD_COLUMN_OPENED`: The case-sensitive column name of the column you'd like the task to be moved to once the PR has been opened
- `BOARD_COLUMN_MERGED`: The case-sensitive column name of the column you'd like the task to be moved to once the PR has been merged
- `BOARD_COLUMN_CLOSED`: The case-sensitive column name of the column you'd like the task to be moved to if the PR was closed without being merged
You may also specify [workflow](https://support.teamwork.com/projects/workflows/workflows-introduction) stages you'd like the task to be moved to on every stage of the PR:
- `WORKFLOW_STAGE_OPENED`: The case-sensitive name of the workflow stage you'd like the task to be moved to once the PR has been opened
- `WORKFLOW_STAGE_MERGED`: The case-sensitive name of the workflow stage you'd like the task to be moved to once the PR has been merged
- `WORKFLOW_STAGE_CLOSED`: The case-sensitive name of the workflow stage you'd like the task to be moved to if the PR was closed without being merged

The column names will be checked against all board columns in the task's project, this will be using a `contains()` method so you may specify part of the name instead of the full name, however this `contains()` check is case-sensitive. The first matching column will be used.
The stage names will be checked against the stages of every workflow in the task's project, this will be using a `contains()` method so you may specify part of the name instead of the full name, however this `contains()` check is case-sensitive. The first matching stage will be used.

## Contributing
* Open a PR: https://github.com/Teamwork/github-sync/pulls
Expand Down
31 changes: 23 additions & 8 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,34 @@ inputs:
AUTOMATIC_TAGGING:
description: 'Do you want to enable automatic tagging: true/false'
required: false
BOARD_COLUMN_OPENED:
description: 'The case-sensitive column name of the column you would like the task to be moved to once the PR has been opened'
WORKFLOW_STAGE_OPENED:
description: 'The case-sensitive name of the workflow stage you would like the task to be moved to once the PR has been opened'
required: false
default: ''
BOARD_COLUMN_MERGED:
description: 'The case-sensitive column name of the column you would like the task to be moved to once the PR has been merged'
WORKFLOW_STAGE_MERGED:
description: 'The case-sensitive name of the workflow stage you would like the task to be moved to once the PR has been merged'
required: false
default: ''
BOARD_COLUMN_CLOSED:
description: 'The case-sensitive column name of the column you would like the task to be moved to if the PR was closed without being merged'
WORKFLOW_STAGE_CLOSED:
description: 'The case-sensitive name of the workflow stage you would like the task to be moved to if the PR was closed without being merged'
required: false
default: ''
LIGHTWEIGHT_COMMENT:
description: 'Generate tiny comments with minimal information'
required: false
default: 'false'
BOARD_COLUMN_OPENED:
description: 'Deprecated.'
required: false
default: ''
BOARD_COLUMN_MERGED:
description: 'Deprecated.'
required: false
default: ''
BOARD_COLUMN_CLOSED:
description: 'Deprecated.'
required: false
default: ''
runs:
using: 'docker'
image: 'Dockerfile'
Expand All @@ -40,7 +52,10 @@ runs:
- ${{ inputs.TEAMWORK_URI }}
- ${{ inputs.TEAMWORK_API_TOKEN }}
- ${{ inputs.AUTOMATIC_TAGGING }}
- ${{ inputs.WORKFLOW_STAGE_OPENED }}
- ${{ inputs.WORKFLOW_STAGE_MERGED }}
- ${{ inputs.WORKFLOW_STAGE_CLOSED }}
- ${{ inputs.LIGHTWEIGHT_COMMENT }}
- ${{ inputs.BOARD_COLUMN_OPENED }}
- ${{ inputs.BOARD_COLUMN_MERGED }}
- ${{ inputs.BOARD_COLUMN_CLOSED }}
- ${{ inputs.LIGHTWEIGHT_COMMENT }}
- ${{ inputs.BOARD_COLUMN_CLOSED }}
16 changes: 13 additions & 3 deletions src/main.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,20 @@ main() {
export TEAMWORK_URI="$2"
export TEAMWORK_API_TOKEN="$3"
export AUTOMATIC_TAGGING="$4"
export BOARD_COLUMN_OPENED="$5"
export BOARD_COLUMN_MERGED="$6"
export BOARD_COLUMN_CLOSED="$7"
export WORKFLOW_STAGE_OPENED="$5"
export WORKFLOW_STAGE_MERGED="$6"
export WORKFLOW_STAGE_CLOSED="$7"
export LIGHTWEIGHT_COMMENT="$8"
# BOARD_COLUMN_* are deprecated aliases kept for backwards compatibility.
export BOARD_COLUMN_OPENED="${9:-}"
export BOARD_COLUMN_MERGED="${10:-}"
export BOARD_COLUMN_CLOSED="${11:-}"

# Fall back to the deprecated BOARD_COLUMN_* inputs when their WORKFLOW_STAGE_*
# replacements are not set.
: "${WORKFLOW_STAGE_OPENED:=$BOARD_COLUMN_OPENED}"
: "${WORKFLOW_STAGE_MERGED:=$BOARD_COLUMN_MERGED}"
: "${WORKFLOW_STAGE_CLOSED:=$BOARD_COLUMN_CLOSED}"

env::set_environment

Expand Down
61 changes: 32 additions & 29 deletions src/teamwork.sh
Original file line number Diff line number Diff line change
Expand Up @@ -31,54 +31,57 @@ teamwork::get_project_id_from_task() {
echo "$response"
}

teamwork::get_matching_board_column_id() {
local -r column_name=$1

if [ -z "$column_name" ]; then
# Resolves a workflow stage name to its "<workflowId> <stageId>" pair within the
# task's project. Matching is a case-sensitive substring match against the stage
# name (mirroring the legacy board-column behaviour), and the first match wins.
# Echoes nothing when no stage name is provided or no stage matches.
teamwork::get_workflow_stage() {
local -r stage_name=$1

if [ -z "$stage_name" ]; then
return
fi

if [ "$ENV" == "test" ]; then
echo "$TEAMWORK_PROJECT_ID"
echo "$TEAMWORK_PROJECT_ID $TEAMWORK_PROJECT_ID"
return
fi

response=$(
curl "$TEAMWORK_URI/projects/$TEAMWORK_PROJECT_ID/boards/columns.json" -u "$TEAMWORK_API_TOKEN"':' |\
jq -r --arg column_name "$column_name" '[.columns[] | select(.name | contains($column_name))] | map(.id)[0]'
)

if [ "$response" = "null" ]; then
return
fi

echo "$response"
# A single call scoped to the project sideloads every stage across the
# project's workflow(s); each stage carries its parent workflow id, which the
# move endpoint also needs.
curl -s "$TEAMWORK_URI/projects/api/v3/workflows.json?projectIds=$TEAMWORK_PROJECT_ID&include=stages" \
-u "$TEAMWORK_API_TOKEN"':' |\
jq -r --arg stage_name "$stage_name" \
'[.included.stages[]? | select(.name | contains($stage_name)) | "\(.workflow.id) \(.id)"][0] // empty'
}

teamwork::move_task_to_column() {
local -r task_id=$TEAMWORK_TASK_ID
local -r column_name=$1
teamwork::move_task_to_stage() {
local -r stage_name=$1

if [ -z "$column_name" ]; then
log::message "No column name provided"
if [ -z "$stage_name" ]; then
log::message "No workflow stage name provided"
return
fi

local -r column_id=$(teamwork::get_matching_board_column_id "$column_name")
if [ -z "$column_id" ]; then
log::message "Failed to find a matching board column for '$column_name'"
local -r stage=$(teamwork::get_workflow_stage "$stage_name")
if [ -z "$stage" ]; then
log::message "Failed to find a matching workflow stage for '$stage_name'"
return
fi

local workflow_id stage_id
read -r workflow_id stage_id <<< "$stage"

if [ "$ENV" == "test" ]; then
log::message "Test - Simulate request. Task ID: $TEAMWORK_TASK_ID - Project ID: $TEAMWORK_PROJECT_ID - Column ID: $column_id"
log::message "Test - Simulate request. Task ID: $TEAMWORK_TASK_ID - Project ID: $TEAMWORK_PROJECT_ID - Workflow ID: $workflow_id - Stage ID: $stage_id"
return
fi

response=$(curl -X "PUT" "$TEAMWORK_URI/tasks/$TEAMWORK_TASK_ID.json" \
response=$(curl -X "PATCH" "$TEAMWORK_URI/projects/api/v3/tasks/$TEAMWORK_TASK_ID/workflows/$workflow_id.json" \
-u "$TEAMWORK_API_TOKEN"':' \
-H 'Content-Type: application/json; charset=utf-8' \
-d "{ \"todo-item\": { \"columnId\": $column_id } }" )
-d "{ \"stageId\": $stage_id, \"positionAfterTask\": -1 }" )

log::message "$response"
}
Expand Down Expand Up @@ -165,7 +168,7 @@ ${pr_body}
fi

teamwork::add_tag "PR Open"
teamwork::move_task_to_column "$BOARD_COLUMN_OPENED"
teamwork::move_task_to_stage "$WORKFLOW_STAGE_OPENED"
}

teamwork::pull_request_closed() {
Expand All @@ -186,7 +189,7 @@ teamwork::pull_request_closed() {
teamwork::add_tag "PR Merged"
teamwork::remove_tag "PR Open"
teamwork::remove_tag "PR Approved"
teamwork::move_task_to_column "$BOARD_COLUMN_MERGED"
teamwork::move_task_to_stage "$WORKFLOW_STAGE_MERGED"
else
if [ "$LIGHTWEIGHT_COMMENT" == "true" ]; then
teamwork::add_comment "PR [**\"$pr_title\"**]($pr_url) closed without merging by **$user**"
Expand All @@ -198,7 +201,7 @@ teamwork::pull_request_closed() {
fi
teamwork::remove_tag "PR Open"
teamwork::remove_tag "PR Approved"
teamwork::move_task_to_column "$BOARD_COLUMN_CLOSED"
teamwork::move_task_to_stage "$WORKFLOW_STAGE_CLOSED"
fi
}

Expand Down