wuffle 0.73.3 → 0.75.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/lib/apps/auth-routes/AuthRoutes.js +16 -14
- package/lib/apps/{automatic-dev-flow.js → automatic-dev-flow/AutomaticDevFlow.js} +12 -13
- package/lib/apps/automatic-dev-flow/index.js +6 -0
- package/lib/apps/background-sync/BackgroundSync.js +41 -83
- package/lib/apps/background-sync/BackgroundSyncBackend.js +140 -0
- package/lib/apps/background-sync/index.js +3 -1
- package/lib/apps/board-api-routes/board-api-routes.js +20 -14
- package/lib/apps/dump-store/s3/S3.js +12 -0
- package/lib/apps/{events-sync.js → events-sync/EventsSync.js} +7 -5
- package/lib/apps/events-sync/index.js +6 -0
- package/lib/apps/github-app/GithubApp.js +69 -6
- package/lib/apps/github-checks/GithubChecks.js +2 -0
- package/lib/apps/github-comments/GithubComments.js +9 -78
- package/lib/apps/github-comments/GithubCommentsBackend.js +132 -0
- package/lib/apps/github-comments/index.js +3 -1
- package/lib/apps/github-issues/GithubIssues.js +161 -9
- package/lib/apps/github-reviews/GithubReviews.js +2 -0
- package/lib/apps/github-statuses/GithubStatuses.js +2 -0
- package/lib/apps/issue-filter/IssueFilter.js +5 -3
- package/lib/apps/log-events.js +4 -4
- package/lib/apps/{reindex-store.js → reindex-store/ReindexStore.js} +6 -4
- package/lib/apps/reindex-store/index.js +6 -0
- package/lib/apps/search/Search.js +9 -5
- package/lib/apps/webhook-events/WebhookEvents.js +12 -5
- package/lib/events.js +2 -2
- package/lib/index.js +13 -5
- package/lib/probot/CustomProbot.js +2 -1
- package/lib/util/search.js +1 -1
- package/package.json +6 -5
|
@@ -60,7 +60,7 @@ export default function AuthRoutes(logger, router, securityContext) {
|
|
|
60
60
|
};
|
|
61
61
|
|
|
62
62
|
const params = new URLSearchParams();
|
|
63
|
-
params.append('client_id', process.env.GITHUB_CLIENT_ID);
|
|
63
|
+
params.append('client_id', /** @type {string} */ (process.env.GITHUB_CLIENT_ID));
|
|
64
64
|
params.append('state', state);
|
|
65
65
|
params.append('redirect_uri', appUrl('/wuffle/login/callback'));
|
|
66
66
|
|
|
@@ -81,10 +81,9 @@ export default function AuthRoutes(logger, router, securityContext) {
|
|
|
81
81
|
|
|
82
82
|
log.debug({ session_id }, 'logging out');
|
|
83
83
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
})
|
|
87
|
-
|
|
84
|
+
req.session.destroy(function(err) {
|
|
85
|
+
res.redirect(redirectTo);
|
|
86
|
+
});
|
|
88
87
|
});
|
|
89
88
|
|
|
90
89
|
|
|
@@ -128,8 +127,8 @@ export default function AuthRoutes(logger, router, securityContext) {
|
|
|
128
127
|
const params = new URLSearchParams();
|
|
129
128
|
params.append('code', /** @type {string} */ (code));
|
|
130
129
|
params.append('state', /** @type {string} */ (state));
|
|
131
|
-
params.append('client_id', process.env.GITHUB_CLIENT_ID);
|
|
132
|
-
params.append('client_secret', process.env.GITHUB_CLIENT_SECRET);
|
|
130
|
+
params.append('client_id', /** @type {string} */ (process.env.GITHUB_CLIENT_ID));
|
|
131
|
+
params.append('client_secret', /** @type {string} */ (process.env.GITHUB_CLIENT_SECRET));
|
|
133
132
|
params.append('redirect_uri', appUrl('/wuffle/login/callback'));
|
|
134
133
|
|
|
135
134
|
const {
|
|
@@ -185,7 +184,9 @@ export default function AuthRoutes(logger, router, securityContext) {
|
|
|
185
184
|
} = session;
|
|
186
185
|
|
|
187
186
|
if (!githubUser) {
|
|
188
|
-
|
|
187
|
+
res.type('json').json(null);
|
|
188
|
+
|
|
189
|
+
return;
|
|
189
190
|
}
|
|
190
191
|
|
|
191
192
|
const {
|
|
@@ -216,17 +217,18 @@ export default function AuthRoutes(logger, router, securityContext) {
|
|
|
216
217
|
}, 'failed to check GitHub authentication');
|
|
217
218
|
|
|
218
219
|
// access is not granted anymore, clear current session
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
})
|
|
220
|
+
req.session.destroy(function(err) {
|
|
221
|
+
res.type('json').json(null);
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
return;
|
|
222
225
|
}
|
|
223
226
|
}
|
|
224
227
|
|
|
225
|
-
|
|
228
|
+
res.type('json').json({
|
|
226
229
|
login,
|
|
227
230
|
avatar_url
|
|
228
|
-
})
|
|
229
|
-
|
|
231
|
+
});
|
|
230
232
|
});
|
|
231
233
|
|
|
232
234
|
|
|
@@ -12,11 +12,11 @@ const CHANGES_REQUESTED = 'changes_requested';
|
|
|
12
12
|
*
|
|
13
13
|
* @constructor
|
|
14
14
|
*
|
|
15
|
-
* @param {import('
|
|
16
|
-
* @param {import('
|
|
17
|
-
* @param {import('
|
|
18
|
-
* @param {import('
|
|
19
|
-
* @param {import('
|
|
15
|
+
* @param {import('../webhook-events/WebhookEvents.js').default} webhookEvents
|
|
16
|
+
* @param {import('../github-issues/GithubIssues.js').default} githubIssues
|
|
17
|
+
* @param {import('../../columns.js').default} columns
|
|
18
|
+
* @param {import('../issue-filter/IssueFilter.js').default} issueFilter
|
|
19
|
+
* @param {import('../../types.js').Logger } logger
|
|
20
20
|
*/
|
|
21
21
|
export default function(webhookEvents, githubIssues, columns, issueFilter, logger) {
|
|
22
22
|
|
|
@@ -31,14 +31,13 @@ export default function(webhookEvents, githubIssues, columns, issueFilter, logge
|
|
|
31
31
|
'pull_request.closed'
|
|
32
32
|
], ifEnabled(async (context) => {
|
|
33
33
|
|
|
34
|
-
const {
|
|
35
|
-
pull_request,
|
|
36
|
-
issue
|
|
37
|
-
} = context.payload;
|
|
38
|
-
|
|
39
34
|
const column = columns.getByState(DONE);
|
|
40
35
|
|
|
41
|
-
|
|
36
|
+
const issueOrPull = 'issue' in context.payload
|
|
37
|
+
? context.payload.issue
|
|
38
|
+
: context.payload.pull_request;
|
|
39
|
+
|
|
40
|
+
await githubIssues.moveIssue(context, issueOrPull, column);
|
|
42
41
|
}));
|
|
43
42
|
|
|
44
43
|
webhookEvents.on('pull_request.converted_to_draft', ifEnabled(async (context) => {
|
|
@@ -107,7 +106,7 @@ export default function(webhookEvents, githubIssues, columns, issueFilter, logge
|
|
|
107
106
|
const newAssignee = (
|
|
108
107
|
process.env.AUTO_ASSIGN_PULLS && !external &&
|
|
109
108
|
author && author.type === 'User' && author.login
|
|
110
|
-
);
|
|
109
|
+
) || null;
|
|
111
110
|
|
|
112
111
|
await Promise.all([
|
|
113
112
|
githubIssues.moveIssue(context, pull_request, column, newAssignee),
|
|
@@ -172,7 +171,7 @@ export default function(webhookEvents, githubIssues, columns, issueFilter, logge
|
|
|
172
171
|
return;
|
|
173
172
|
}
|
|
174
173
|
|
|
175
|
-
const issue_number = match[1];
|
|
174
|
+
const issue_number = parseInt(match[1], 10);
|
|
176
175
|
|
|
177
176
|
const column = columns.getByState(IN_PROGRESS);
|
|
178
177
|
|
|
@@ -9,38 +9,48 @@ function isInternalError(error) {
|
|
|
9
9
|
/**
|
|
10
10
|
* This component performs a periodic background sync of a project.
|
|
11
11
|
*
|
|
12
|
+
* Unless disabled via `process.env.DISABLE_BACKGROUND_SYNC` it will
|
|
13
|
+
* register a recurring check.
|
|
14
|
+
*
|
|
15
|
+
* Background check performs various optimizations to ensure only relevant
|
|
16
|
+
* data is stored on the board:
|
|
17
|
+
*
|
|
18
|
+
* * Closed issues/PRs on the board will be thrashed
|
|
19
|
+
* * Closed issues/PRs wiil not be synchronized from GitHub
|
|
20
|
+
* * Open but stale issues/PRs will not be synchronized to the board
|
|
21
|
+
* * Open issue/PR details will only be synchronized for recent issues
|
|
22
|
+
*
|
|
12
23
|
* @constructor
|
|
13
24
|
*
|
|
14
|
-
* @param {import('../../types.js').Logger} logger
|
|
15
25
|
* @param {Object} config
|
|
26
|
+
* @param {import('../../types.js').Logger} logger
|
|
16
27
|
* @param {import('../../store.js').default} store
|
|
17
|
-
* @param {import('../github-client/GithubClient.js').default} githubClient
|
|
18
|
-
* @param {import('../github-app/GithubApp.js').default} githubApp
|
|
19
28
|
* @param {import('../../events.js').default} events
|
|
29
|
+
* @param {import('./BackgroundSyncBackend.js').default} backgroundSyncBackend
|
|
20
30
|
*/
|
|
21
|
-
export default function BackgroundSync(
|
|
31
|
+
export default function BackgroundSync(config, logger, store, events, backgroundSyncBackend) {
|
|
22
32
|
|
|
23
33
|
// 30 days
|
|
24
34
|
const syncClosedLookback = (
|
|
25
|
-
parseInt(process.env.BACKGROUND_SYNC_SYNC_CLOSED_LOOKBACK, 10) ||
|
|
35
|
+
parseInt(process.env.BACKGROUND_SYNC_SYNC_CLOSED_LOOKBACK || '', 10) ||
|
|
26
36
|
1000 * 60 * 60 * 24 * 30
|
|
27
37
|
);
|
|
28
38
|
|
|
29
39
|
// 4 hours
|
|
30
40
|
const syncClosedDetailsLookback = (
|
|
31
|
-
parseInt(process.env.BACKGROUND_SYNC_SYNC_CLOSED_DETAILS_LOOKBACK, 10) ||
|
|
41
|
+
parseInt(process.env.BACKGROUND_SYNC_SYNC_CLOSED_DETAILS_LOOKBACK || '', 10) ||
|
|
32
42
|
1000 * 60 * 60 * 4
|
|
33
43
|
);
|
|
34
44
|
|
|
35
45
|
// 1 day
|
|
36
46
|
const syncOpenDetailsLookback = (
|
|
37
|
-
parseInt(process.env.BACKGROUND_SYNC_SYNC_OPEN_DETAILS_LOOKBACK, 10) ||
|
|
47
|
+
parseInt(process.env.BACKGROUND_SYNC_SYNC_OPEN_DETAILS_LOOKBACK || '', 10) ||
|
|
38
48
|
1000 * 60 * 60 * 24
|
|
39
49
|
);
|
|
40
50
|
|
|
41
51
|
// 60 days
|
|
42
52
|
const removeClosedLookback = (
|
|
43
|
-
parseInt(process.env.BACKGROUND_SYNC_REMOVE_CLOSED_LOOKBACK, 10) ||
|
|
53
|
+
parseInt(process.env.BACKGROUND_SYNC_REMOVE_CLOSED_LOOKBACK || '', 10) ||
|
|
44
54
|
1000 * 60 * 60 * 24 * 60
|
|
45
55
|
);
|
|
46
56
|
|
|
@@ -101,18 +111,14 @@ We automatically synchronize all repositories you granted us access to via the G
|
|
|
101
111
|
log.debug({ installation: owner }, 'processing');
|
|
102
112
|
|
|
103
113
|
try {
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
const repositories = await octokit.paginate(
|
|
107
|
-
octokit.rest.apps.listReposAccessibleToInstallation,
|
|
108
|
-
{
|
|
109
|
-
per_page: 100
|
|
110
|
-
}
|
|
111
|
-
);
|
|
114
|
+
const repositories = await backgroundSyncBackend.getInstallationRepositories(installation);
|
|
112
115
|
|
|
113
116
|
for (const repository of repositories) {
|
|
114
117
|
|
|
115
|
-
|
|
118
|
+
if (repository.owner.login !== owner) {
|
|
119
|
+
throw new Error('repository.owner !== installation.owner');
|
|
120
|
+
}
|
|
121
|
+
|
|
116
122
|
const repo = repository.name;
|
|
117
123
|
|
|
118
124
|
// log found repository
|
|
@@ -135,74 +141,12 @@ We automatically synchronize all repositories you granted us access to via the G
|
|
|
135
141
|
repo
|
|
136
142
|
}, 'processing');
|
|
137
143
|
|
|
138
|
-
const
|
|
139
|
-
sort: /** @type { 'updated' } */ ('updated'),
|
|
140
|
-
direction: /** @type { 'desc' } */ ('desc'),
|
|
141
|
-
per_page: 100,
|
|
142
|
-
owner,
|
|
143
|
-
repo
|
|
144
|
-
};
|
|
145
|
-
|
|
146
|
-
const [
|
|
144
|
+
const {
|
|
147
145
|
open_issues,
|
|
148
146
|
closed_issues,
|
|
149
147
|
open_pull_requests,
|
|
150
148
|
closed_pull_requests
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
// open issues
|
|
154
|
-
octokit.paginate(
|
|
155
|
-
octokit.rest.issues.listForRepo,
|
|
156
|
-
{
|
|
157
|
-
...params,
|
|
158
|
-
state: 'open'
|
|
159
|
-
},
|
|
160
|
-
response => response.data.filter(issue => !('pull_request' in issue))
|
|
161
|
-
),
|
|
162
|
-
|
|
163
|
-
// closed issues, updated last 30 days
|
|
164
|
-
octokit.paginate(
|
|
165
|
-
octokit.rest.issues.listForRepo,
|
|
166
|
-
{
|
|
167
|
-
...params,
|
|
168
|
-
state: 'closed',
|
|
169
|
-
since: new Date(syncClosedSince).toISOString()
|
|
170
|
-
},
|
|
171
|
-
response => response.data.filter(issue => !('pull_request' in issue))
|
|
172
|
-
),
|
|
173
|
-
|
|
174
|
-
// open pulls, all
|
|
175
|
-
octokit.paginate(
|
|
176
|
-
octokit.rest.pulls.list,
|
|
177
|
-
{
|
|
178
|
-
...params,
|
|
179
|
-
state: 'open'
|
|
180
|
-
}
|
|
181
|
-
),
|
|
182
|
-
|
|
183
|
-
// closed pulls, updated last 30 days
|
|
184
|
-
octokit.paginate(
|
|
185
|
-
octokit.rest.pulls.list,
|
|
186
|
-
{
|
|
187
|
-
...params,
|
|
188
|
-
state: 'closed'
|
|
189
|
-
},
|
|
190
|
-
(response, done) => {
|
|
191
|
-
|
|
192
|
-
const pulls = response.data;
|
|
193
|
-
|
|
194
|
-
const filtered = pulls.filter(
|
|
195
|
-
pull => new Date(pull.updated_at).getTime() > syncClosedSince
|
|
196
|
-
);
|
|
197
|
-
|
|
198
|
-
if (filtered.length !== pulls.length) {
|
|
199
|
-
done();
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
return filtered;
|
|
203
|
-
}
|
|
204
|
-
)
|
|
205
|
-
]);
|
|
149
|
+
} = await backgroundSyncBackend.getRepositoryIssuesAndPulls(repository, syncClosedSince);
|
|
206
150
|
|
|
207
151
|
for (const issueOrPull of [
|
|
208
152
|
...open_issues,
|
|
@@ -460,12 +404,19 @@ We automatically synchronize all repositories you granted us access to via the G
|
|
|
460
404
|
return Promise.all(jobs);
|
|
461
405
|
}
|
|
462
406
|
|
|
407
|
+
/**
|
|
408
|
+
* Trigger background synchronization for all connected repositories.
|
|
409
|
+
*
|
|
410
|
+
* This ensures that data out-of-sync with the board is fetched from remote.
|
|
411
|
+
*
|
|
412
|
+
* @return {Promise<void>}
|
|
413
|
+
*/
|
|
463
414
|
async function backgroundSync() {
|
|
464
415
|
|
|
465
416
|
log.info('start');
|
|
466
417
|
|
|
467
418
|
try {
|
|
468
|
-
const installations = await
|
|
419
|
+
const installations = await backgroundSyncBackend.getInstallations();
|
|
469
420
|
|
|
470
421
|
await doSync(installations);
|
|
471
422
|
|
|
@@ -477,7 +428,7 @@ We automatically synchronize all repositories you granted us access to via the G
|
|
|
477
428
|
}
|
|
478
429
|
|
|
479
430
|
const syncInterval = (
|
|
480
|
-
parseInt(process.env.BACKGROUND_SYNC_SYNC_INTERVAL, 10) || (
|
|
431
|
+
parseInt(process.env.BACKGROUND_SYNC_SYNC_INTERVAL || '', 10) || (
|
|
481
432
|
process.env.NODE_ENV !== 'production'
|
|
482
433
|
|
|
483
434
|
// five minutes
|
|
@@ -509,6 +460,13 @@ We automatically synchronize all repositories you granted us access to via the G
|
|
|
509
460
|
|
|
510
461
|
// api ///////////////////
|
|
511
462
|
|
|
463
|
+
/**
|
|
464
|
+
* Trigger background synchronization for all connected repositories.
|
|
465
|
+
*
|
|
466
|
+
* This ensures that data out-of-sync with the board is fetched from remote.
|
|
467
|
+
*
|
|
468
|
+
* @return {Promise<void>}
|
|
469
|
+
*/
|
|
512
470
|
this.backgroundSync = backgroundSync;
|
|
513
471
|
|
|
514
472
|
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef { import('../github-app/types.js').Installation } Installation
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* This component fetches GitHub data required for background synchronization.
|
|
7
|
+
*
|
|
8
|
+
* @constructor
|
|
9
|
+
*
|
|
10
|
+
* @param {import('../github-client/GithubClient.js').default} githubClient
|
|
11
|
+
* @param {import('../github-app/GithubApp.js').default} githubApp
|
|
12
|
+
*/
|
|
13
|
+
export default function BackgroundSyncBackend(githubClient, githubApp) {
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Return available installations.
|
|
17
|
+
*
|
|
18
|
+
* @return {Promise<Installation[]>}
|
|
19
|
+
*/
|
|
20
|
+
async function getInstallations(installation) {
|
|
21
|
+
return githubApp.getInstallations();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Return repositories accessible to a GitHub app installation.
|
|
26
|
+
*
|
|
27
|
+
* @param {Installation} installation
|
|
28
|
+
*
|
|
29
|
+
* @return {Promise<Array>}
|
|
30
|
+
*/
|
|
31
|
+
async function getInstallationRepositories(installation) {
|
|
32
|
+
const owner = installation.account.login;
|
|
33
|
+
const octokit = await githubClient.getOrgScoped(owner);
|
|
34
|
+
|
|
35
|
+
return octokit.paginate(
|
|
36
|
+
octokit.rest.apps.listReposAccessibleToInstallation,
|
|
37
|
+
{ per_page: 100 }
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Fetch issues and pull requests for a repository.
|
|
43
|
+
*
|
|
44
|
+
* @param {{ owner: { login: string }, name: string }} repository
|
|
45
|
+
* @param {number} syncClosedSince
|
|
46
|
+
*
|
|
47
|
+
* @return {Promise<{ open_issues: Array, closed_issues: Array, open_pull_requests: Array, closed_pull_requests: Array }>}
|
|
48
|
+
*/
|
|
49
|
+
async function getRepositoryIssuesAndPulls(repository, syncClosedSince) {
|
|
50
|
+
const owner = repository.owner.login;
|
|
51
|
+
const octokit = await githubClient.getOrgScoped(owner);
|
|
52
|
+
|
|
53
|
+
const repo = repository.name;
|
|
54
|
+
|
|
55
|
+
const params = {
|
|
56
|
+
sort: /** @type { 'updated' } */ ('updated'),
|
|
57
|
+
direction: /** @type { 'desc' } */ ('desc'),
|
|
58
|
+
per_page: 100,
|
|
59
|
+
owner,
|
|
60
|
+
repo
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const [
|
|
64
|
+
open_issues,
|
|
65
|
+
closed_issues,
|
|
66
|
+
open_pull_requests,
|
|
67
|
+
closed_pull_requests
|
|
68
|
+
] = await Promise.all([
|
|
69
|
+
|
|
70
|
+
// open issues
|
|
71
|
+
octokit.paginate(
|
|
72
|
+
octokit.rest.issues.listForRepo,
|
|
73
|
+
{
|
|
74
|
+
...params,
|
|
75
|
+
state: 'open'
|
|
76
|
+
},
|
|
77
|
+
response => response.data.filter(issue => !('pull_request' in issue))
|
|
78
|
+
),
|
|
79
|
+
|
|
80
|
+
// closed issues, updated since syncClosedSince
|
|
81
|
+
octokit.paginate(
|
|
82
|
+
octokit.rest.issues.listForRepo,
|
|
83
|
+
{
|
|
84
|
+
...params,
|
|
85
|
+
state: 'closed',
|
|
86
|
+
since: new Date(syncClosedSince).toISOString()
|
|
87
|
+
},
|
|
88
|
+
response => response.data.filter(issue => !('pull_request' in issue))
|
|
89
|
+
),
|
|
90
|
+
|
|
91
|
+
// open pulls, all
|
|
92
|
+
octokit.paginate(
|
|
93
|
+
octokit.rest.pulls.list,
|
|
94
|
+
{
|
|
95
|
+
...params,
|
|
96
|
+
state: 'open'
|
|
97
|
+
}
|
|
98
|
+
),
|
|
99
|
+
|
|
100
|
+
// closed pulls, updated since syncClosedSince
|
|
101
|
+
octokit.paginate(
|
|
102
|
+
octokit.rest.pulls.list,
|
|
103
|
+
{
|
|
104
|
+
...params,
|
|
105
|
+
state: 'closed'
|
|
106
|
+
},
|
|
107
|
+
(response, done) => {
|
|
108
|
+
|
|
109
|
+
const pulls = response.data;
|
|
110
|
+
|
|
111
|
+
const filtered = pulls.filter(
|
|
112
|
+
pull => new Date(pull.updated_at).getTime() > syncClosedSince
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
if (filtered.length !== pulls.length) {
|
|
116
|
+
done();
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return filtered;
|
|
120
|
+
}
|
|
121
|
+
)
|
|
122
|
+
]);
|
|
123
|
+
|
|
124
|
+
return {
|
|
125
|
+
open_issues,
|
|
126
|
+
closed_issues,
|
|
127
|
+
open_pull_requests,
|
|
128
|
+
closed_pull_requests
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
// api ///////////////////
|
|
134
|
+
|
|
135
|
+
this.getInstallations = getInstallations;
|
|
136
|
+
|
|
137
|
+
this.getInstallationRepositories = getInstallationRepositories;
|
|
138
|
+
|
|
139
|
+
this.getRepositoryIssuesAndPulls = getRepositoryIssuesAndPulls;
|
|
140
|
+
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import BackgroundSync from './BackgroundSync.js';
|
|
2
|
+
import BackgroundSyncBackend from './BackgroundSyncBackend.js';
|
|
2
3
|
|
|
3
4
|
export default {
|
|
4
5
|
__init__: [ 'backgroundSync' ],
|
|
5
|
-
backgroundSync: [ 'type', BackgroundSync ]
|
|
6
|
+
backgroundSync: [ 'type', BackgroundSync ],
|
|
7
|
+
backgroundSyncBackend: [ 'type', BackgroundSyncBackend ]
|
|
6
8
|
};
|
|
@@ -172,7 +172,7 @@ export default async function BoardApiRoutes(
|
|
|
172
172
|
const items = store.getBoard();
|
|
173
173
|
const cursor = store.getUpdateCursor();
|
|
174
174
|
|
|
175
|
-
|
|
175
|
+
filterBoardItems(req, items).then(filteredItems => {
|
|
176
176
|
|
|
177
177
|
return res.type('json').json({
|
|
178
178
|
items: filteredItems,
|
|
@@ -196,7 +196,7 @@ export default async function BoardApiRoutes(
|
|
|
196
196
|
name
|
|
197
197
|
} = config;
|
|
198
198
|
|
|
199
|
-
|
|
199
|
+
res.type('json').json({
|
|
200
200
|
columns: columns.map(c => {
|
|
201
201
|
const { name, collapsed } = c;
|
|
202
202
|
|
|
@@ -236,7 +236,9 @@ export default async function BoardApiRoutes(
|
|
|
236
236
|
const user = authRoutes.getGitHubUser(req);
|
|
237
237
|
|
|
238
238
|
if (!user) {
|
|
239
|
-
|
|
239
|
+
res.status(401).json({});
|
|
240
|
+
|
|
241
|
+
return;
|
|
240
242
|
}
|
|
241
243
|
|
|
242
244
|
const body = JSON.parse(req.body);
|
|
@@ -251,13 +253,17 @@ export default async function BoardApiRoutes(
|
|
|
251
253
|
const issue = await store.getIssueById(id);
|
|
252
254
|
|
|
253
255
|
if (!issue) {
|
|
254
|
-
|
|
256
|
+
res.status(404).json({});
|
|
257
|
+
|
|
258
|
+
return;
|
|
255
259
|
}
|
|
256
260
|
|
|
257
261
|
const column = columns.getByName(columnName);
|
|
258
262
|
|
|
259
263
|
if (!column) {
|
|
260
|
-
|
|
264
|
+
res.status(404).json({});
|
|
265
|
+
|
|
266
|
+
return;
|
|
261
267
|
}
|
|
262
268
|
|
|
263
269
|
const repo = repoAndOwner(issue);
|
|
@@ -265,7 +271,9 @@ export default async function BoardApiRoutes(
|
|
|
265
271
|
const canWrite = await userAccess.canWrite(user, repo);
|
|
266
272
|
|
|
267
273
|
if (!canWrite) {
|
|
268
|
-
|
|
274
|
+
res.status(403).json({});
|
|
275
|
+
|
|
276
|
+
return;
|
|
269
277
|
}
|
|
270
278
|
|
|
271
279
|
const octokit = await githubClient.getUserScoped(user);
|
|
@@ -280,15 +288,13 @@ export default async function BoardApiRoutes(
|
|
|
280
288
|
}
|
|
281
289
|
};
|
|
282
290
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
log.error(err, 'failed to move issue');
|
|
291
|
+
moveIssue(context, issue, column, { before, after }).then(() => {
|
|
292
|
+
res.type('json').json({});
|
|
293
|
+
}).catch(err => {
|
|
294
|
+
log.error(err, 'failed to move issue');
|
|
288
295
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
) && null;
|
|
296
|
+
res.status(500).json({ error : true });
|
|
297
|
+
});
|
|
292
298
|
|
|
293
299
|
});
|
|
294
300
|
|
|
@@ -16,6 +16,18 @@ export default function S3() {
|
|
|
16
16
|
S3_ENDPOINT: endpoint
|
|
17
17
|
} = process.env;
|
|
18
18
|
|
|
19
|
+
if (!accessKeyId) {
|
|
20
|
+
throw new Error('process.env.AWS_ACCESS_KEY_ID required');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (!secretAccessKey) {
|
|
24
|
+
throw new Error('process.env.AWS_SECRET_ACCESS_KEY required');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (!bucket) {
|
|
28
|
+
throw new Error('process.env.S3_BUCKET required');
|
|
29
|
+
}
|
|
30
|
+
|
|
19
31
|
const s3client = new S3Client({
|
|
20
32
|
region,
|
|
21
33
|
endpoint,
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
filterRepository,
|
|
6
6
|
getIdentifier,
|
|
7
7
|
getKey
|
|
8
|
-
} from '
|
|
8
|
+
} from '../../filters.js';
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
/**
|
|
@@ -13,14 +13,14 @@ import {
|
|
|
13
13
|
*
|
|
14
14
|
* @constructor
|
|
15
15
|
*
|
|
16
|
-
* @param {import('
|
|
17
|
-
* @param {import('
|
|
18
|
-
* @param {import('
|
|
16
|
+
* @param {import('../webhook-events/WebhookEvents.js').default} webhookEvents
|
|
17
|
+
* @param {import('../../store.js').default} store
|
|
18
|
+
* @param {import('../../types.js').Logger} logger
|
|
19
19
|
*/
|
|
20
20
|
export default function EventsSync(webhookEvents, store, logger) {
|
|
21
21
|
|
|
22
22
|
const log = logger.child({
|
|
23
|
-
name: 'wuffle:
|
|
23
|
+
name: 'wuffle:events-sync'
|
|
24
24
|
});
|
|
25
25
|
|
|
26
26
|
// issues /////////////////////
|
|
@@ -104,6 +104,8 @@ export default function EventsSync(webhookEvents, store, logger) {
|
|
|
104
104
|
'pull_request.converted_to_draft',
|
|
105
105
|
'pull_request.assigned',
|
|
106
106
|
'pull_request.unassigned',
|
|
107
|
+
'pull_request.milestoned',
|
|
108
|
+
'pull_request.demilestoned',
|
|
107
109
|
'pull_request.synchronize',
|
|
108
110
|
'pull_request.closed',
|
|
109
111
|
'pull_request.review_requested',
|