Skip to content

Commit 9316f52

Browse files
authored
chore: add renovate APIC-490 (#522)
1 parent 577293e commit 9316f52

15 files changed

+268
-34
lines changed

.github/workflows/check.yml

+3-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,9 @@ jobs:
4545
exit $diff
4646
4747
- name: Lint json files
48-
run: yarn eslint --ext=json .
48+
run: |
49+
yarn eslint --ext=json .
50+
echo 'Use yarn fix:json to fix issues'
4951
5052
outputs:
5153
RUN_SCRIPTS: ${{ steps.setup.outputs.RUN_SCRIPTS }}

.github/workflows/renovate.yml

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
name: Renovate
2+
3+
on:
4+
schedule:
5+
- cron: '0 14 * * 5'
6+
7+
jobs:
8+
renovate:
9+
name: Renovate
10+
runs-on: ubuntu-20.04
11+
steps:
12+
- uses: actions/checkout@v2
13+
14+
- name: Setup
15+
id: setup
16+
uses: ./.github/actions/setup
17+
with:
18+
type: minimal
19+
20+
- run: yarn workspace scripts renovateWeeklyPR
21+
env:
22+
GITHUB_TOKEN: ${{ secrets.TOKEN_RELEASE_BOT }}

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
"mustache": "4.2.0",
5757
"prettier": "2.6.2",
5858
"prettier-plugin-java": "1.6.1",
59+
"renovate-config-algolia": "2.1.10",
5960
"typescript": "4.6.3"
6061
},
6162
"engines": {

renovate.json

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"extends": [
3+
"config:js-app",
4+
"algolia"
5+
],
6+
"enabledManagers": [
7+
"npm",
8+
"nvm"
9+
],
10+
"baseBranches": [
11+
"chore/renovateBaseBranch"
12+
],
13+
"packageRules": [
14+
{
15+
"matchDepTypes": [
16+
"required_provider"
17+
],
18+
"rangeStrategy": "bump"
19+
}
20+
],
21+
"prHourlyLimit": 10,
22+
"prConcurrentLimit": 50
23+
}

scripts/ci/codegen/__tests__/codegen.test.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,18 @@ describe('codegen', () => {
2121

2222
describe('pushGeneratedCode', () => {
2323
it('throws without GITHUB_TOKEN environment variable', async () => {
24+
process.env.GITHUB_TOKEN = '';
2425
await expect(pushGeneratedCode()).rejects.toThrow(
2526
'Environment variable `GITHUB_TOKEN` does not exist.'
2627
);
2728
});
2829
});
2930

3031
describe('upsertGenerationComment', () => {
32+
beforeAll(() => {
33+
process.env.GITHUB_TOKEN = 'mocked';
34+
});
35+
3136
it('throws without parameter', async () => {
3237
await expect(
3338
// @ts-expect-error a parameter is required
@@ -38,8 +43,6 @@ describe('codegen', () => {
3843
});
3944

4045
it('throws without PR_NUMBER environment variable', async () => {
41-
process.env.GITHUB_TOKEN = 'foo';
42-
4346
await expect(upsertGenerationComment('codegen')).rejects.toThrow(
4447
'`upsertGenerationComment` requires a `PR_NUMBER` environment variable.'
4548
);

scripts/ci/codegen/pushGeneratedCode.ts

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* eslint-disable no-console */
2-
import { MAIN_BRANCH, run } from '../../common';
2+
import { ensureGitHubToken, MAIN_BRANCH, run } from '../../common';
33
import { configureGitHubAuthor } from '../../release/common';
44
import { getNbGitDiff } from '../utils';
55

@@ -18,9 +18,7 @@ async function isUpToDate(baseBranch: string): Promise<boolean> {
1818
* Push generated code for the current `JOB` and `CLIENT` on a `generated/` branch.
1919
*/
2020
export async function pushGeneratedCode(): Promise<void> {
21-
if (!process.env.GITHUB_TOKEN) {
22-
throw new Error('Environment variable `GITHUB_TOKEN` does not exist.');
23-
}
21+
ensureGitHubToken();
2422

2523
await configureGitHubAuthor();
2624

scripts/ci/codegen/spreadGeneration.ts

+3-4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
run,
99
toAbsolutePath,
1010
REPO_URL,
11+
ensureGitHubToken,
1112
} from '../../common';
1213
import { getLanguageFolder } from '../../config';
1314
import { cloneRepository, configureGitHubAuthor } from '../../release/common';
@@ -60,9 +61,7 @@ export function cleanUpCommitMessage(commitMessage: string): string {
6061
}
6162

6263
async function spreadGeneration(): Promise<void> {
63-
if (!process.env.GITHUB_TOKEN) {
64-
throw new Error('Environment variable `GITHUB_TOKEN` does not exist.');
65-
}
64+
const githubToken = ensureGitHubToken();
6665

6766
const lastCommitMessage = await run('git log -1 --format="%s"');
6867
const author = (
@@ -81,7 +80,7 @@ async function spreadGeneration(): Promise<void> {
8180
for (const lang of langs) {
8281
const { tempGitDir } = await cloneRepository({
8382
lang,
84-
githubToken: process.env.GITHUB_TOKEN,
83+
githubToken,
8584
tempDir: process.env.RUNNER_TEMP!,
8685
});
8786

scripts/ci/codegen/upsertGenerationComment.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
/* eslint-disable no-console */
2-
import { run, OWNER, REPO } from '../../common';
3-
import { getOctokit } from '../../release/common';
2+
import { run, OWNER, REPO, getOctokit } from '../../common';
43

54
import commentText from './text';
65

76
const BOT_NAME = 'algolia-bot';
87
const PR_NUMBER = parseInt(process.env.PR_NUMBER || '0', 10);
9-
const octokit = getOctokit(process.env.GITHUB_TOKEN!);
108

119
const args = process.argv.slice(2);
1210
const allowedTriggers = [
@@ -47,6 +45,7 @@ ${commentText[trigger].body(
4745
* Adds or updates a comment on a pull request.
4846
*/
4947
export async function upsertGenerationComment(trigger: Trigger): Promise<void> {
48+
const octokit = getOctokit();
5049
if (!trigger || allowedTriggers.includes(trigger) === false) {
5150
throw new Error(
5251
`'upsertGenerationComment' requires a 'trigger' parameter (${allowedTriggers.join(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
/* eslint-disable no-console */
2+
// script coming from crawler <3
3+
import type { Octokit } from '@octokit/rest';
4+
5+
import { getOctokit, OWNER, REPO, wait } from '../../common';
6+
7+
const BRANCH = 'chore/renovateBaseBranch';
8+
const BRANCH_BASE = 'main';
9+
const EMPTY_COMMIT_MSG = 'Automatic empty commit';
10+
11+
async function getRef(
12+
octokit: Octokit,
13+
branch: string
14+
): Promise<string | false> {
15+
try {
16+
const ref = await octokit.git.getRef({
17+
owner: OWNER,
18+
repo: REPO,
19+
ref: `heads/${branch}`,
20+
});
21+
return ref.data.object.sha;
22+
} catch (err) {
23+
if (!(err instanceof Error) || (err as any).status !== 404) {
24+
throw err;
25+
}
26+
}
27+
return false;
28+
}
29+
30+
async function createBranch(octokit: Octokit, sha: string): Promise<any> {
31+
const create = await octokit.git.createRef({
32+
owner: OWNER,
33+
repo: REPO,
34+
ref: `refs/heads/${BRANCH}`,
35+
sha,
36+
});
37+
return create;
38+
}
39+
40+
async function deleteRef(octokit: Octokit): Promise<any> {
41+
console.log(`Deleting ref for ${BRANCH}`);
42+
const ref = await octokit.git.deleteRef({
43+
owner: OWNER,
44+
repo: REPO,
45+
ref: `heads/${BRANCH}`,
46+
});
47+
return ref;
48+
}
49+
50+
async function updateRef(octokit: Octokit, sha: string): Promise<any> {
51+
console.log(`Changing ref for ${BRANCH} to`, sha);
52+
const ref = await octokit.git.updateRef({
53+
owner: OWNER,
54+
repo: REPO,
55+
ref: `heads/${BRANCH}`,
56+
sha,
57+
});
58+
return ref;
59+
}
60+
61+
async function getCommit(octokit: Octokit, sha: string): Promise<any> {
62+
const commit = await octokit.git.getCommit({
63+
owner: OWNER,
64+
repo: REPO,
65+
commit_sha: sha,
66+
});
67+
return commit.data;
68+
}
69+
70+
function isCommitAnEmptyCommit(commit: any): boolean {
71+
return commit.message.search(EMPTY_COMMIT_MSG) >= 0;
72+
}
73+
74+
async function createEmptyCommit(
75+
octokit: Octokit,
76+
refCommit: any
77+
): Promise<any> {
78+
console.log('Creating empty commit');
79+
const commit = await octokit.git.createCommit({
80+
owner: OWNER,
81+
repo: REPO,
82+
message: EMPTY_COMMIT_MSG,
83+
tree: refCommit.tree.sha,
84+
parents: [refCommit.sha],
85+
});
86+
return commit.data;
87+
}
88+
89+
async function createPR(octokit: Octokit): Promise<any> {
90+
// Next monday
91+
const date = new Date();
92+
date.setDate(date.getDate() + 3);
93+
94+
const title = `chore(scripts): dependencies ${
95+
date.toISOString().split('T')[0]
96+
}`;
97+
const { data } = await octokit.pulls.create({
98+
repo: REPO,
99+
owner: OWNER,
100+
title,
101+
body: `Weekly dependencies update.
102+
Contributes to #528
103+
`,
104+
head: BRANCH,
105+
base: BRANCH_BASE,
106+
});
107+
return data;
108+
}
109+
110+
async function resetBranch(
111+
octokit: Octokit,
112+
refBase: string,
113+
exists: boolean
114+
): Promise<void> {
115+
if (exists) {
116+
console.log('Deleting branch');
117+
await deleteRef(octokit);
118+
await wait(5000);
119+
}
120+
121+
console.log('Creating branch');
122+
123+
await createBranch(octokit, refBase);
124+
125+
const commit = await getCommit(octokit, refBase);
126+
127+
const empty = await createEmptyCommit(octokit, commit);
128+
await updateRef(octokit, empty.sha);
129+
}
130+
131+
(async (): Promise<void> => {
132+
try {
133+
const octokit = getOctokit();
134+
135+
const refBase = await getRef(octokit, BRANCH_BASE);
136+
const refTarget = await getRef(octokit, BRANCH);
137+
console.log(BRANCH_BASE, 'is at', refBase);
138+
console.log(BRANCH, 'is at', refTarget);
139+
140+
if (!refBase) {
141+
console.error('no sha for base branch');
142+
return;
143+
}
144+
145+
if (refTarget) {
146+
console.log('Branch exists');
147+
const commit = await getCommit(octokit, refTarget);
148+
149+
if (isCommitAnEmptyCommit(commit)) {
150+
console.log('Empty commit exists');
151+
return;
152+
}
153+
}
154+
155+
await resetBranch(octokit, refBase, Boolean(refTarget));
156+
157+
console.log('Creating pull request');
158+
await createPR(octokit);
159+
} catch (err) {
160+
console.error(err);
161+
}
162+
})();

scripts/common.ts

+25
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import fsp from 'fs/promises';
22
import path from 'path';
33

4+
import { Octokit } from '@octokit/rest';
45
import execa from 'execa'; // https://github.com/sindresorhus/execa/tree/v5.1.1
56
import { hashElement } from 'folder-hash';
67
import { remove } from 'fs-extra';
@@ -258,3 +259,27 @@ export async function runComposerUpdate(verbose: boolean): Promise<void> {
258259
);
259260
}
260261
}
262+
263+
export function ensureGitHubToken(): string {
264+
// use process.env here to mock with jest
265+
if (!process.env.GITHUB_TOKEN) {
266+
throw new Error('Environment variable `GITHUB_TOKEN` does not exist.');
267+
}
268+
return process.env.GITHUB_TOKEN;
269+
}
270+
271+
export function getOctokit(): Octokit {
272+
const token = ensureGitHubToken();
273+
return new Octokit({
274+
auth: `token ${token}`,
275+
});
276+
}
277+
278+
export function wait(waitTime: number): Promise<void> {
279+
if (waitTime <= 0) {
280+
return Promise.resolve();
281+
}
282+
return new Promise((resolve) => {
283+
setTimeout(resolve, waitTime);
284+
});
285+
}

scripts/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"pre-commit": "./ci/husky/pre-commit.js",
99
"processRelease": "ts-node release/process-release.ts",
1010
"pushGeneratedCode": "ts-node ci/codegen/pushGeneratedCode.ts",
11+
"renovateWeeklyPR": "ts-node ci/githubActions/renovateWeeklyPR.ts",
1112
"setRunVariables": "ts-node ci/githubActions/setRunVariables.ts",
1213
"spreadGeneration": "ts-node ci/codegen/spreadGeneration.ts",
1314
"test": "jest",

scripts/release/common.ts

-8
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import path from 'path';
22

3-
import { Octokit } from '@octokit/rest';
4-
53
import config from '../../config/release.config.json';
64
import { run } from '../common';
75
import { getGitHubUrl } from '../config';
@@ -10,12 +8,6 @@ import type { Language } from '../types';
108
export const RELEASED_TAG = config.releasedTag;
119
export const TEAM_SLUG = config.teamSlug;
1210

13-
export function getOctokit(githubToken: string): Octokit {
14-
return new Octokit({
15-
auth: `token ${githubToken}`,
16-
});
17-
}
18-
1911
export function getTargetBranch(language: string): string {
2012
return config.targetBranch[language] || config.defaultTargetBranch;
2113
}

0 commit comments

Comments
 (0)