wuffle 0.75.0 → 0.76.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app.yml +1 -0
- package/lib/apps/board-api-routes/board-api-routes.js +16 -18
- package/lib/apps/events-sync/EventsSync.js +20 -3
- package/lib/apps/github-app/GithubApp.js +30 -2
- package/lib/filters.js +4 -2
- package/lib/util/links.js +16 -0
- package/package.json +7 -7
- package/public/bundle.js +1 -1
- package/public/bundle.js.map +1 -1
package/app.yml
CHANGED
|
@@ -172,19 +172,19 @@ export default async function BoardApiRoutes(
|
|
|
172
172
|
const items = store.getBoard();
|
|
173
173
|
const cursor = store.getUpdateCursor();
|
|
174
174
|
|
|
175
|
-
filterBoardItems(req, items).then(filteredItems => {
|
|
175
|
+
return filterBoardItems(req, items).then(filteredItems => {
|
|
176
176
|
|
|
177
|
-
|
|
177
|
+
res.type('json').json({
|
|
178
178
|
items: filteredItems,
|
|
179
179
|
cursor
|
|
180
|
-
})
|
|
180
|
+
});
|
|
181
181
|
}).catch(err => {
|
|
182
182
|
log.error({
|
|
183
183
|
err,
|
|
184
184
|
cursor
|
|
185
185
|
}, 'failed to retrieve cards');
|
|
186
186
|
|
|
187
|
-
|
|
187
|
+
res.status(500).json({ error : true });
|
|
188
188
|
});
|
|
189
189
|
});
|
|
190
190
|
|
|
@@ -206,7 +206,7 @@ export default async function BoardApiRoutes(
|
|
|
206
206
|
};
|
|
207
207
|
}),
|
|
208
208
|
name: name || 'Wuffle Board'
|
|
209
|
-
})
|
|
209
|
+
});
|
|
210
210
|
|
|
211
211
|
});
|
|
212
212
|
|
|
@@ -216,18 +216,16 @@ export default async function BoardApiRoutes(
|
|
|
216
216
|
|
|
217
217
|
const updates = cursor ? store.getUpdates(cursor) : [];
|
|
218
218
|
|
|
219
|
-
return (
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
})
|
|
230
|
-
);
|
|
219
|
+
return filterUpdates(req, updates).then(filteredUpdates => {
|
|
220
|
+
res.type('json').json(filteredUpdates);
|
|
221
|
+
}).catch(err => {
|
|
222
|
+
log.error({
|
|
223
|
+
err,
|
|
224
|
+
cursor
|
|
225
|
+
}, 'failed to retrieve card updates');
|
|
226
|
+
|
|
227
|
+
res.status(500).json({ error : true });
|
|
228
|
+
});
|
|
231
229
|
});
|
|
232
230
|
|
|
233
231
|
|
|
@@ -288,7 +286,7 @@ export default async function BoardApiRoutes(
|
|
|
288
286
|
}
|
|
289
287
|
};
|
|
290
288
|
|
|
291
|
-
moveIssue(context, issue, column, { before, after }).then(() => {
|
|
289
|
+
return moveIssue(context, issue, column, { before, after }).then(() => {
|
|
292
290
|
res.type('json').json({});
|
|
293
291
|
}).catch(err => {
|
|
294
292
|
log.error(err, 'failed to move issue');
|
|
@@ -227,12 +227,29 @@ export default function EventsSync(webhookEvents, store, logger) {
|
|
|
227
227
|
});
|
|
228
228
|
|
|
229
229
|
|
|
230
|
-
// issues
|
|
230
|
+
// sub-issues /////////////////////
|
|
231
231
|
|
|
232
|
-
// https://docs.github.com/en/free-pro-team@latest/developers/webhooks-and-events/webhook-events-and-payloads#issues
|
|
233
232
|
|
|
234
|
-
//
|
|
233
|
+
// https://docs.github.com/en/webhooks/webhook-events-and-payloads#sub_issues
|
|
234
|
+
//
|
|
235
|
+
// update sub-issues on change - updating parent <> child relationship
|
|
236
|
+
webhookEvents.on(
|
|
237
|
+
/** @type {any} */ ([ 'sub_issues.sub_issue_added', 'sub_issues.sub_issue_removed' ]),
|
|
238
|
+
async ({ payload }) => {
|
|
239
|
+
|
|
240
|
+
const {
|
|
241
|
+
sub_issue,
|
|
242
|
+
repository
|
|
243
|
+
} = /** @type {any} */ (payload);
|
|
244
|
+
|
|
245
|
+
return store.updateIssue(filterIssue(sub_issue, repository));
|
|
246
|
+
}
|
|
247
|
+
);
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
// https://docs.github.com/en/free-pro-team@latest/developers/webhooks-and-events/webhook-events-and-payloads#issues
|
|
235
251
|
//
|
|
252
|
+
// issue transfer is mapped to the following GitHub events:
|
|
236
253
|
// -> issues.opened (new issue is being opened by GitHub)
|
|
237
254
|
// -> issues.transferred (old issue was deleted by GitHub)
|
|
238
255
|
//
|
|
@@ -19,11 +19,13 @@ const RequiredEvents = [
|
|
|
19
19
|
'issues',
|
|
20
20
|
'issue_comment',
|
|
21
21
|
'label',
|
|
22
|
+
'member',
|
|
22
23
|
'milestone',
|
|
23
24
|
'pull_request',
|
|
24
25
|
'pull_request_review',
|
|
25
26
|
'repository',
|
|
26
|
-
'status'
|
|
27
|
+
'status',
|
|
28
|
+
'sub_issues'
|
|
27
29
|
];
|
|
28
30
|
|
|
29
31
|
/**
|
|
@@ -41,8 +43,9 @@ const RequiredEvents = [
|
|
|
41
43
|
* @param {import('../../types.js').ProbotApp} app
|
|
42
44
|
* @param {import('../../types.js').Logger} logger
|
|
43
45
|
* @param {import('../../types.js').Injector} injector
|
|
46
|
+
* @param {import('../../events.js').default} events
|
|
44
47
|
*/
|
|
45
|
-
export default function GithubApp(config, app, logger, injector) {
|
|
48
|
+
export default function GithubApp(config, app, logger, injector, events) {
|
|
46
49
|
|
|
47
50
|
const log = logger.child({
|
|
48
51
|
name: 'wuffle:github-app'
|
|
@@ -266,6 +269,31 @@ export default function GithubApp(config, app, logger, injector) {
|
|
|
266
269
|
log.debug('validated installations');
|
|
267
270
|
}
|
|
268
271
|
|
|
272
|
+
async function validateApp() {
|
|
273
|
+
const octokit = await getAppScopedClient();
|
|
274
|
+
const { data: app } = await octokit.rest.apps.getAuthenticated();
|
|
275
|
+
|
|
276
|
+
// app may not be configured yet
|
|
277
|
+
if (!app) {
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const missingEvents = RequiredEvents.filter(
|
|
282
|
+
event => !app.events.includes(event)
|
|
283
|
+
);
|
|
284
|
+
|
|
285
|
+
if (missingEvents.length) {
|
|
286
|
+
log.error({
|
|
287
|
+
missingEvents,
|
|
288
|
+
events: app.events
|
|
289
|
+
}, 'app is missing required event subscriptions; update app settings on GitHub');
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
events.once('wuffle.start', async function() {
|
|
294
|
+
await validateApp().catch(err => log.warn({ err }, 'failed to validate app configuration'));
|
|
295
|
+
});
|
|
296
|
+
|
|
269
297
|
/**
|
|
270
298
|
* Fetch active installations.
|
|
271
299
|
*
|
package/lib/filters.js
CHANGED
|
@@ -214,7 +214,8 @@ export function filterIssue(githubIssue, githubRepository) {
|
|
|
214
214
|
milestone,
|
|
215
215
|
pull_request,
|
|
216
216
|
html_url,
|
|
217
|
-
author_association
|
|
217
|
+
author_association,
|
|
218
|
+
parent_issue_url
|
|
218
219
|
} = githubIssue;
|
|
219
220
|
|
|
220
221
|
// stable ID that is independent from GitHubs internal issue/pr distinction
|
|
@@ -245,7 +246,8 @@ export function filterIssue(githubIssue, githubRepository) {
|
|
|
245
246
|
repository: filterRepository(githubRepository),
|
|
246
247
|
pull_request: !!pull_request,
|
|
247
248
|
html_url,
|
|
248
|
-
author_association
|
|
249
|
+
author_association,
|
|
250
|
+
parent_issue_url: parent_issue_url || null
|
|
249
251
|
};
|
|
250
252
|
|
|
251
253
|
}
|
package/lib/util/links.js
CHANGED
|
@@ -145,6 +145,22 @@ export function findLinks(issue, types) {
|
|
|
145
145
|
links.push(link);
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
+
// add CHILD_OF link from parent_issue_url (GitHub sub-issues)
|
|
149
|
+
const { parent_issue_url } = issue;
|
|
150
|
+
|
|
151
|
+
if (parent_issue_url) {
|
|
152
|
+
const parentMatch = parent_issue_url.match(/\/repos\/([^/]+)\/([^/]+)\/issues\/(\d+)/);
|
|
153
|
+
|
|
154
|
+
if (parentMatch) {
|
|
155
|
+
links.push({
|
|
156
|
+
type: CHILD_OF,
|
|
157
|
+
owner: parentMatch[1],
|
|
158
|
+
repo: parentMatch[2],
|
|
159
|
+
number: parseInt(parentMatch[3], 10)
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
148
164
|
if (typeof types !== 'undefined') {
|
|
149
165
|
return filterLinks(links, types);
|
|
150
166
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wuffle",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.76.0",
|
|
4
4
|
"description": "A multi-repository task board for GitHub issues",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Nico Rehwaldt",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"@aws-sdk/client-s3": "^3.1037.0",
|
|
46
46
|
"async-didi": "^1.0.0",
|
|
47
|
-
"body-parser": "^2.
|
|
47
|
+
"body-parser": "^2.3.0",
|
|
48
48
|
"compression": "^1.8.1",
|
|
49
49
|
"express-session": "^1.19.0",
|
|
50
50
|
"fake-tag": "^5.0.0",
|
|
@@ -63,11 +63,11 @@
|
|
|
63
63
|
"@types/mocha": "^10.0.10",
|
|
64
64
|
"@types/sinon": "^21.0.1",
|
|
65
65
|
"chai": "^6.2.2",
|
|
66
|
-
"graphql": "^
|
|
67
|
-
"mocha": "^11.7.
|
|
68
|
-
"nock": "^14.0.
|
|
66
|
+
"graphql": "^17.0.0",
|
|
67
|
+
"mocha": "^11.7.6",
|
|
68
|
+
"nock": "^14.0.15",
|
|
69
69
|
"nodemon": "^3.1.14",
|
|
70
|
-
"npm-run-all2": "^
|
|
70
|
+
"npm-run-all2": "^9.0.2",
|
|
71
71
|
"sinon": "^22.0.0",
|
|
72
72
|
"sinon-chai": "^4.0.0",
|
|
73
73
|
"typescript": "^5.9.3"
|
|
@@ -83,5 +83,5 @@
|
|
|
83
83
|
"index.js",
|
|
84
84
|
"wuffle.config.example.js"
|
|
85
85
|
],
|
|
86
|
-
"gitHead": "
|
|
86
|
+
"gitHead": "3a21cf84280395b89d369422bbaf16f2b63c20dd"
|
|
87
87
|
}
|