Skip to content

Commit 1741a87

Browse files
committed
add “mark-complete” functionality
1 parent 5264940 commit 1741a87

File tree

5 files changed

+108
-17
lines changed

5 files changed

+108
-17
lines changed

README.md

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ This action integrates asana with github.
1616

1717
### `action`
1818

19-
**Required** The action to be performed assert-link|add-comment|remove-comment|move-section
19+
**Required** The action to be performed assert-link|add-comment|remove-comment|move-section|complete-task
2020

2121
### `github-token`
2222

@@ -50,6 +50,10 @@ if you don't want to move task omit `targets`.
5050

5151
**Required for `assert-link`** When set to true will fail pull requests without an asana link
5252

53+
### `is-complete`
54+
55+
**Required for `complete-task`** If the task is complete or not
56+
5357
## Example usage
5458

5559
```yaml
@@ -133,4 +137,23 @@ jobs:
133137
# if the branch is labeled a hotfix, skip this check
134138
link-required: ${{ !contains(github.event.pull_request.labels.*.name, 'hotfix') }}
135139
github-token: ${{ github.token }}
140+
```
141+
142+
```yaml
143+
name: Mark a task complete
144+
145+
on:
146+
pull_request:
147+
types: [closed]
148+
149+
jobs:
150+
sync:
151+
runs-on: ubuntu-latest
152+
steps:
153+
- uses: everphone-gmbh/github-asana-action
154+
if: github.event.pull_request.merged
155+
with:
156+
asana-pat: ${{ secrets.ASANA_PAT }}
157+
action: 'complete-task'
158+
is-complete: true
136159
```

action.js

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,14 @@ async function addComment(client, taskId, commentId, text, isPinned) {
4949
}
5050
}
5151

52-
module.exports = async function action() {
52+
async function buildClient(asanaPAT) {
53+
return asana.Client.create({
54+
defaultHeaders: { 'asana-enable': 'new-sections,string_ids' },
55+
logAsanaChangeWarnings: false
56+
}).useAccessToken(asanaPAT).authorize();
57+
}
58+
59+
async function action() {
5360
const
5461
ASANA_PAT = core.getInput('asana-pat', {required: true}),
5562
ACTION = core.getInput('action', {required: true}),
@@ -61,11 +68,7 @@ module.exports = async function action() {
6168

6269
console.log('pull_request', PULL_REQUEST);
6370

64-
const client = await asana.Client.create({
65-
defaultHeaders: { 'asana-enable': 'new-sections,string_ids' },
66-
logAsanaChangeWarnings: false
67-
}).useAccessToken(ASANA_PAT).authorize();
68-
71+
const client = await buildClient(ASANA_PAT);
6972
if(client === null){
7073
throw new Error('client authorization failed');
7174
}
@@ -134,6 +137,22 @@ module.exports = async function action() {
134137
}
135138
return removedCommentIds;
136139
}
140+
case 'complete-task': {
141+
const isComplete = core.getInput('is-complete') === 'true';
142+
const taskIds = [];
143+
for(const taskId of foundAsanaTasks) {
144+
console.info("marking task", taskId, isComplete ? 'complete' : 'incomplete');
145+
try {
146+
await client.tasks.update(taskId, {
147+
completed: isComplete
148+
});
149+
} catch (error) {
150+
console.error('rejecting promise', error);
151+
}
152+
taskIds.push(taskId);
153+
};
154+
return taskIds;
155+
}
137156
case 'move-section': {
138157
const targetJSON = core.getInput('targets', {required: true});
139158
const targets = JSON.parse(targetJSON);
@@ -148,3 +167,9 @@ module.exports = async function action() {
148167
core.setFailed("unexpected action ${ACTION}");
149168
}
150169
}
170+
171+
module.exports = {
172+
action,
173+
default: action,
174+
buildClient: buildClient
175+
};

action.test.js

Lines changed: 49 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,22 @@ const github = require('@actions/github');
44

55
describe('asana github actions', () => {
66
let inputs = {};
7-
const defaultBody = 'Implement https://app.asana.com/0/1178251625498057/1178251625498064 in record time';
7+
let defaultBody;
8+
let client;
9+
let task;
10+
811
const asanaPAT = process.env['ASANA_PAT'];
912
if(!asanaPAT) {
1013
throw new Error('need ASANA_PAT in the test env');
1114
}
15+
const projectId = process.env['ASANA_PROJECT_ID'];
16+
if(!projectId) {
17+
throw new Error('need ASANA_PROJECT_ID in the test env');
18+
}
1219

1320
const commentId = Date.now().toString();
1421

15-
beforeAll(() => {
22+
beforeAll(async () => {
1623
// Mock getInput
1724
jest.spyOn(core, 'getInput').mockImplementation((name, options) => {
1825
if(inputs[name] === undefined && options && options.required){
@@ -31,6 +38,23 @@ describe('asana github actions', () => {
3138
github.context.sha = '1234567890123456789012345678901234567890'
3239

3340
process.env['GITHUB_REPOSITORY'] = 'a-cool-owner/a-cool-repo'
41+
42+
client = await action.buildClient(asanaPAT);
43+
if(client === null){
44+
throw new Error('client authorization failed');
45+
}
46+
47+
task = await client.tasks.create({
48+
'name': 'my fantastic task',
49+
'notes': 'generated automatically by the test suite',
50+
'projects': [projectId]
51+
});
52+
53+
defaultBody = `Implement https://app.asana.com/0/${projectId}/${task.gid} in record time`;
54+
})
55+
56+
afterAll(async () => {
57+
await client.tasks.delete(task);
3458
})
3559

3660
beforeEach(() => {
@@ -64,7 +88,7 @@ describe('asana github actions', () => {
6488
}
6589
});
6690

67-
await action();
91+
await action.action();
6892

6993
expect(mockCreateStatus).toHaveBeenCalledWith({
7094
owner: 'a-cool-owner',
@@ -91,10 +115,10 @@ describe('asana github actions', () => {
91115
}
92116
};
93117

94-
await expect(action()).resolves.toHaveLength(1);
118+
await expect(action.action()).resolves.toHaveLength(1);
95119

96120
// rerunning with the same comment-Id should not create a new comment
97-
await expect(action()).resolves.toHaveLength(0);
121+
await expect(action.action()).resolves.toHaveLength(0);
98122
});
99123

100124
test('removing a comment', async () => {
@@ -110,7 +134,7 @@ describe('asana github actions', () => {
110134
}
111135
};
112136

113-
await expect(action()).resolves.toHaveLength(1);
137+
await expect(action.action()).resolves.toHaveLength(1);
114138
});
115139

116140
test('moving sections', async () => {
@@ -125,14 +149,31 @@ describe('asana github actions', () => {
125149
}
126150
};
127151

128-
await expect(action()).resolves.toHaveLength(1);
152+
await expect(action.action()).resolves.toHaveLength(1);
129153

130154
inputs = {
131155
'asana-pat': asanaPAT,
132156
'action': 'move-section',
133157
'targets': '[{"project": "Asana bot test environment", "section": "New"}]'
134158
}
135159

136-
await expect(action()).resolves.toHaveLength(1);
160+
await expect(action.action()).resolves.toHaveLength(1);
161+
});
162+
163+
test('completing task', async () => {
164+
inputs = {
165+
'asana-pat': asanaPAT,
166+
'action': 'complete-task',
167+
'is-complete': 'true'
168+
}
169+
github.context.payload = {
170+
pull_request: {
171+
'body': defaultBody
172+
}
173+
};
174+
175+
await expect(action.action()).resolves.toHaveLength(1);
176+
const actualTask = await client.tasks.findById(task.gid);
177+
expect(actualTask.completed).toBe(true);
137178
});
138179
});

action.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ inputs:
55
description: 'Asana Public Access Token.'
66
required: true
77
action:
8-
description: 'The action to be performed assert-link|add-comment|remove-comment|move-section'
8+
description: 'The action to be performed assert-link|add-comment|remove-comment|move-section|complete-task'
99
required: false
1010
trigger-phrase:
1111
description: 'Prefix before the task i.e ASANA TASK: https://app.asana.com/1/2/3'
@@ -26,6 +26,8 @@ inputs:
2626
targets:
2727
description: 'JSON array of objects having project and section where to move current task. Move task only if it exists in target project.'
2828
required: false
29+
is-complete:
30+
description: 'Is the task complete'
2931
branding:
3032
icon: 'chevron-right'
3133
color: 'gray-dark'

index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ const action = require('./action');
33

44
async function run() {
55
try {
6-
await action();
6+
await action.action();
77
} catch (error) {
88
core.setFailed(error.message);
99
}

0 commit comments

Comments
 (0)