-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathindex.js
132 lines (121 loc) · 3.32 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
const bunyan = require('bunyan');
const got = require('got');
const {
BITBUCKET_USERNAME,
BITBUCKET_PASSWORD,
BITBUCKET_WORKSPACE,
RENOVATE_BOT_USER,
} = process.env;
const MANUAL_MERGE_MESSAGE = 'merge this manually';
const AUTO_MERGE_MESSAGE = '**Automerge**: Enabled.';
const DEFAULT_OPTIONS = {
prefixUrl: 'https://api.bitbucket.org',
// If we use username/password options, they will be URL encoded
// https://github.com/sindresorhus/got/issues/1169
// https://github.com/nodejs/node/issues/31439
headers: {
Authorization: `Basic ${Buffer.from(
`${BITBUCKET_USERNAME}:${BITBUCKET_PASSWORD}`
).toString('base64')}`,
},
responseType: 'json',
};
const log = bunyan.createLogger({
name: 'renovate-approve-bot',
serializers: {
res: bunyan.stdSerializers.res,
},
});
function isAutomerging(pr) {
try {
return (
pr.description.includes(AUTO_MERGE_MESSAGE) &&
!pr.description.includes(MANUAL_MERGE_MESSAGE)
);
} catch (error) {
log.error(error);
return false;
}
}
function getPullRequests() {
const prEndpoint = `/2.0/workspaces/${BITBUCKET_WORKSPACE}/pullrequests/${RENOVATE_BOT_USER}`;
log.info('Requesting %s%s...', DEFAULT_OPTIONS.prefixUrl, prEndpoint);
return got.paginate('', {
...DEFAULT_OPTIONS,
pathname: prEndpoint,
pagination: {
transform: (response) =>
response.body.values
.filter((pr) => isAutomerging(pr))
.map((pr) => pr.links.self.href),
paginate: (response) => {
if ('next' in response.body && response.body.next !== '') {
log.info('Requesting %s...', response.body.next);
return {
url: new URL(response.body.next),
};
}
log.info('All pull-requests gathered.');
return false;
},
},
});
}
function approvePullRequest(prHref) {
return got('', {
...DEFAULT_OPTIONS,
prefixUrl: `${prHref}/approve`,
method: 'POST',
throwHttpErrors: false,
});
}
async function main() {
if (
!BITBUCKET_USERNAME ||
!BITBUCKET_PASSWORD ||
!BITBUCKET_WORKSPACE ||
!RENOVATE_BOT_USER
) {
log.fatal(
'At least one of BITBUCKET_USERNAME, BITBUCKET_PASSWORD, BITBUCKET_WORKSPACE, RENOVATE_BOT_USER environement variables is not set.'
);
process.exit(1);
}
let prHrefs;
try {
prHrefs = await getPullRequests();
} catch (error) {
log.fatal(error);
process.exit(1);
}
for await (const prHref of prHrefs) {
log.info('Approving: %s', prHref);
approvePullRequest(prHref)
.then((response) => {
switch (response.statusCode) {
case 200:
log.info({ pr: prHref, res: response }, 'Approved');
break;
case 409:
// likely already approved
if ('error' in response.body && 'message' in response.body.error) {
log.info(
{ pr: prHref, res: response },
response.body.error.message
);
} else {
log.error({ pr: prHref, res: response }, response.body);
}
break;
default:
log.error({ pr: prHref, res: response }, response.body);
break;
}
return response;
})
.catch((error) => log.error(error, { pr: prHref }));
}
}
if (require.main === module) {
main();
}