Skip to content
Open
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
2 changes: 2 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,5 @@ jobs:
WORKFLOW_STAGE_OPENED: "PR Open"
WORKFLOW_STAGE_MERGED: "Ready to Test"
WORKFLOW_STAGE_CLOSED: "Rejected"
- name: Run the tests against a mock Teamwork API
run: ./tests/run.sh
18 changes: 18 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,24 @@
* [Install Docker](https://docs.docker.com/get-docker/)
* [Install act tool](https://github.com/nektos/act)

## Running the tests

The tests run the action's Docker image against a mock Teamwork API (`tests/mock-teamwork.py`) and check what it sends:

```
./tests/run.sh
```

Each directory in `tests/cases` is a test case:

* `event.json`: the GitHub event the action receives
* `inputs`: the action's inputs as the `INPUT_*` environment variables GitHub creates for them, plus `GITHUB_EVENT_NAME` and any other environment variables such as `IGNORE_PROJECT_IDS`
* `expected`: the exit code, errors and requests the mock Teamwork API should end up with

`./tests/run.sh <filter>` only runs the cases whose name contains the filter.

To add a case, create its `event.json` and `inputs`, run `./tests/run.sh --update <case name>` to record its `expected` file, and check that file is right before committing it. The mock's data (which tasks exist, their projects and the workflow stages) is at the top of `tests/mock-teamwork.py`.

## Usage

Simulate a new pull request
Expand Down
43 changes: 24 additions & 19 deletions src/teamwork.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,20 @@ teamwork::get_task_id_from_body() {
echo "$task_ids_str"
}

# Calls the Teamwork API and prints the response body.
teamwork::request() {
local -r method=$1
local -r path=$2
local -r payload=${3:-}

local args=(-sS -X "$method" -u "$TEAMWORK_API_TOKEN"':')
if [ -n "$payload" ]; then
args+=(-H 'Content-Type: application/json; charset=utf-8' -d "$payload")
fi

curl "${args[@]}" "$TEAMWORK_URI$path"
}

teamwork::get_project_id_from_task() {
local -r task_id=$1

Expand All @@ -25,7 +39,7 @@ teamwork::get_project_id_from_task() {
fi

response=$(
curl "$TEAMWORK_URI/projects/api/v1/tasks/$task_id.json" -u "$TEAMWORK_API_TOKEN"':' |\
teamwork::request GET "/projects/api/v1/tasks/$task_id.json" |\
jq -r '.["todo-item"]["project-id"]'
)
echo "$response"
Expand All @@ -50,8 +64,7 @@ teamwork::get_workflow_stage() {
# 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"':' |\
teamwork::request GET "/projects/api/v3/workflows.json?projectIds=$TEAMWORK_PROJECT_ID&include=stages" |\
jq -r --arg stage_name "$stage_name" \
'[.included.stages[]? | select(.name | contains($stage_name)) | "\(.workflow.id) \(.id)"][0] // empty'
}
Expand All @@ -78,10 +91,8 @@ teamwork::move_task_to_stage() {
return
fi

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 "{ \"stageId\": $stage_id, \"positionAfterTask\": -1 }" )
response=$(teamwork::request PATCH "/projects/api/v3/tasks/$TEAMWORK_TASK_ID/workflows/$workflow_id.json" \
"{ \"stageId\": $stage_id, \"positionAfterTask\": -1 }")

log::message "$response"
}
Expand All @@ -94,10 +105,8 @@ teamwork::add_comment() {
return
fi

response=$(curl -X "POST" "$TEAMWORK_URI/tasks/$TEAMWORK_TASK_ID/comments.json" \
-u "$TEAMWORK_API_TOKEN"':' \
-H 'Content-Type: application/json; charset=utf-8' \
-d "{ \"comment\": { \"body\": \"${body//\"/}\", \"notify\": true, \"content-type\": \"text\", \"isprivate\": false } }" )
response=$(teamwork::request POST "/tasks/$TEAMWORK_TASK_ID/comments.json" \
"{ \"comment\": { \"body\": \"${body//\"/}\", \"notify\": true, \"content-type\": \"text\", \"isprivate\": false } }")

log::message "$response"
}
Expand All @@ -111,10 +120,8 @@ teamwork::add_tag() {
fi

if [ "$AUTOMATIC_TAGGING" == true ]; then
response=$(curl -X "PUT" "$TEAMWORK_URI/tasks/$TEAMWORK_TASK_ID/tags.json" \
-u "$TEAMWORK_API_TOKEN"':' \
-H 'Content-Type: application/json; charset=utf-8' \
-d "{ \"tags\": { \"content\": \"${tag_name//\"/}\" } }" )
response=$(teamwork::request PUT "/tasks/$TEAMWORK_TASK_ID/tags.json" \
"{ \"tags\": { \"content\": \"${tag_name//\"/}\" } }")

log::message "$response"
fi
Expand All @@ -129,10 +136,8 @@ teamwork::remove_tag() {
fi

if [ "$AUTOMATIC_TAGGING" == true ]; then
response=$(curl -X "PUT" "$TEAMWORK_URI/tasks/$TEAMWORK_TASK_ID/tags.json" \
-u "$TEAMWORK_API_TOKEN"':' \
-H 'Content-Type: application/json; charset=utf-8' \
-d "{ \"tags\": { \"content\": \"${tag_name//\"/}\" },\"removeProvidedTags\":\"true\" }" )
response=$(teamwork::request PUT "/tasks/$TEAMWORK_TASK_ID/tags.json" \
"{ \"tags\": { \"content\": \"${tag_name//\"/}\" },\"removeProvidedTags\":\"true\" }")

log::message "$response"
fi
Expand Down
27 changes: 27 additions & 0 deletions tests/cases/closed-merged-lightweight/event.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"action": "closed",
"number": 42,
"pull_request": {
"number": 42,
"title": "Add OAuth login",
"body": "Task: http://teamwork:8080/app/tasks/1001",
"html_url": "https://github.com/acme/webapp/pull/42",
"head": {
"ref": "feature/oauth",
"repo": {
"full_name": "acme/webapp"
}
},
"base": {
"ref": "main"
},
"commits": 3,
"changed_files": 5,
"additions": 120,
"deletions": 8,
"merged": true
},
"sender": {
"login": "octocat"
}
}
10 changes: 10 additions & 0 deletions tests/cases/closed-merged-lightweight/expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
exit code: 0

GET /projects/api/v1/tasks/1001.json -> 200

POST /tasks/1001/comments.json -> 201
comment:
body: "PR [**Add OAuth login**](https://github.com/acme/webapp/pull/42) merged by **octocat**"
content-type: "text"
isprivate: false
notify: true
2 changes: 2 additions & 0 deletions tests/cases/closed-merged-lightweight/inputs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
GITHUB_EVENT_NAME=pull_request
INPUT_LIGHTWEIGHT_COMMENT=true
27 changes: 27 additions & 0 deletions tests/cases/closed-merged/event.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"action": "closed",
"number": 42,
"pull_request": {
"number": 42,
"title": "Add OAuth login",
"body": "Task: http://teamwork:8080/app/tasks/1001",
"html_url": "https://github.com/acme/webapp/pull/42",
"head": {
"ref": "feature/oauth",
"repo": {
"full_name": "acme/webapp"
}
},
"base": {
"ref": "main"
},
"commits": 3,
"changed_files": 5,
"additions": 120,
"deletions": 8,
"merged": true
},
"sender": {
"login": "octocat"
}
}
27 changes: 27 additions & 0 deletions tests/cases/closed-merged/expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
exit code: 0

GET /projects/api/v1/tasks/1001.json -> 200

POST /tasks/1001/comments.json -> 400
invalid JSON: Invalid control character at: line 1 column 25 (char 24)
"{ \"comment\": { \"body\": \"\n**octocat** merged a PR: **Add OAuth login**\n[https://github.com/acme/webapp/pull/42](https://github.com/acme/webapp/pull/42)\n\", \"notify\": true, \"content-type\": \"text\", \"isprivate\": false } }"

PUT /tasks/1001/tags.json -> 200
tags:
content: "PR Merged"

PUT /tasks/1001/tags.json -> 200
removeProvidedTags: "true"
tags:
content: "PR Open"

PUT /tasks/1001/tags.json -> 200
removeProvidedTags: "true"
tags:
content: "PR Approved"

GET /projects/api/v3/workflows.json?projectIds=100&include=stages -> 200

PATCH /projects/api/v3/tasks/1001/workflows/7.json -> 204
positionAfterTask: -1
stageId: 73
5 changes: 5 additions & 0 deletions tests/cases/closed-merged/inputs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
GITHUB_EVENT_NAME=pull_request
INPUT_AUTOMATIC_TAGGING=true
INPUT_WORKFLOW_STAGE_OPENED=PR Open
INPUT_WORKFLOW_STAGE_MERGED=Ready to Test
INPUT_WORKFLOW_STAGE_CLOSED=Rejected
27 changes: 27 additions & 0 deletions tests/cases/closed-unmerged-lightweight/event.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"action": "closed",
"number": 42,
"pull_request": {
"number": 42,
"title": "Add OAuth login",
"body": "Task: http://teamwork:8080/app/tasks/1001",
"html_url": "https://github.com/acme/webapp/pull/42",
"head": {
"ref": "feature/oauth",
"repo": {
"full_name": "acme/webapp"
}
},
"base": {
"ref": "main"
},
"commits": 3,
"changed_files": 5,
"additions": 120,
"deletions": 8,
"merged": false
},
"sender": {
"login": "octocat"
}
}
10 changes: 10 additions & 0 deletions tests/cases/closed-unmerged-lightweight/expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
exit code: 0

GET /projects/api/v1/tasks/1001.json -> 200

POST /tasks/1001/comments.json -> 201
comment:
body: "PR [**Add OAuth login**](https://github.com/acme/webapp/pull/42) closed without merging by **octocat**"
content-type: "text"
isprivate: false
notify: true
2 changes: 2 additions & 0 deletions tests/cases/closed-unmerged-lightweight/inputs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
GITHUB_EVENT_NAME=pull_request
INPUT_LIGHTWEIGHT_COMMENT=true
27 changes: 27 additions & 0 deletions tests/cases/closed-unmerged/event.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"action": "closed",
"number": 42,
"pull_request": {
"number": 42,
"title": "Add OAuth login",
"body": "Task: http://teamwork:8080/app/tasks/1001",
"html_url": "https://github.com/acme/webapp/pull/42",
"head": {
"ref": "feature/oauth",
"repo": {
"full_name": "acme/webapp"
}
},
"base": {
"ref": "main"
},
"commits": 3,
"changed_files": 5,
"additions": 120,
"deletions": 8,
"merged": false
},
"sender": {
"login": "octocat"
}
}
23 changes: 23 additions & 0 deletions tests/cases/closed-unmerged/expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
exit code: 0

GET /projects/api/v1/tasks/1001.json -> 200

POST /tasks/1001/comments.json -> 400
invalid JSON: Invalid control character at: line 1 column 25 (char 24)
"{ \"comment\": { \"body\": \"\n**octocat** closed a PR without merging: **Add OAuth login**\n[https://github.com/acme/webapp/pull/42](https://github.com/acme/webapp/pull/42)\n\", \"notify\": true, \"content-type\": \"text\", \"isprivate\": false } }"

PUT /tasks/1001/tags.json -> 200
removeProvidedTags: "true"
tags:
content: "PR Open"

PUT /tasks/1001/tags.json -> 200
removeProvidedTags: "true"
tags:
content: "PR Approved"

GET /projects/api/v3/workflows.json?projectIds=100&include=stages -> 200

PATCH /projects/api/v3/tasks/1001/workflows/7.json -> 204
positionAfterTask: -1
stageId: 74
5 changes: 5 additions & 0 deletions tests/cases/closed-unmerged/inputs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
GITHUB_EVENT_NAME=pull_request
INPUT_AUTOMATIC_TAGGING=true
INPUT_WORKFLOW_STAGE_OPENED=PR Open
INPUT_WORKFLOW_STAGE_MERGED=Ready to Test
INPUT_WORKFLOW_STAGE_CLOSED=Rejected
27 changes: 27 additions & 0 deletions tests/cases/comment-fails/event.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"action": "opened",
"number": 42,
"pull_request": {
"number": 42,
"title": "Add OAuth login",
"body": "Task: http://teamwork:8080/app/tasks/1003",
"html_url": "https://github.com/acme/webapp/pull/42",
"head": {
"ref": "feature/oauth",
"repo": {
"full_name": "acme/webapp"
}
},
"base": {
"ref": "main"
},
"commits": 3,
"changed_files": 5,
"additions": 120,
"deletions": 8,
"merged": false
},
"sender": {
"login": "octocat"
}
}
20 changes: 20 additions & 0 deletions tests/cases/comment-fails/expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
exit code: 0

GET /projects/api/v1/tasks/1003.json -> 200

POST /tasks/1003/comments.json -> 500
comment:
body: "PR [**Add OAuth login**](https://github.com/acme/webapp/pull/42) opened by **octocat**"
content-type: "text"
isprivate: false
notify: true

PUT /tasks/1003/tags.json -> 200
tags:
content: "PR Open"

GET /projects/api/v3/workflows.json?projectIds=300&include=stages -> 200

PATCH /projects/api/v3/tasks/1003/workflows/7.json -> 204
positionAfterTask: -1
stageId: 72
6 changes: 6 additions & 0 deletions tests/cases/comment-fails/inputs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
GITHUB_EVENT_NAME=pull_request
INPUT_AUTOMATIC_TAGGING=true
INPUT_WORKFLOW_STAGE_OPENED=PR Open
INPUT_WORKFLOW_STAGE_MERGED=Ready to Test
INPUT_WORKFLOW_STAGE_CLOSED=Rejected
INPUT_LIGHTWEIGHT_COMMENT=true
Loading
Loading