Skip to content

Commit 7fb6630

Browse files
authored
chore(ci): backport actions updates (#10853)
1 parent 737b80b commit 7fb6630

File tree

8 files changed

+3229
-371
lines changed

8 files changed

+3229
-371
lines changed

.github/workflows/cleanup-cache.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#force-deleting-cache-entries
1+
# https://docs.github.com/actions/using-workflows/caching-dependencies-to-speed-up-workflows#force-deleting-cache-entries
22
name: Cleanup caches
33
on:
44
pull_request:

.github/workflows/documentation.yml

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,15 @@ jobs:
103103
if: ${{ env.REF_TYPE == 'tag' && (!inputs.ref || inputs.ref == 'main') }}
104104
env:
105105
DATABASE_URL: ${{ secrets.DATABASE_URL }}
106+
CF_D1_DOCS_API_KEY: ${{ secrets.CF_D1_DOCS_API_KEY }}
107+
CF_D1_DOCS_ID: ${{ secrets.CF_D1_DOCS_ID }}
108+
CF_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }}
106109
BLOB_READ_WRITE_TOKEN: ${{ secrets.BLOB_READ_WRITE_TOKEN }}
110+
CF_R2_DOCS_URL: ${{ secrets.CF_R2_DOCS_URL }}
111+
CF_R2_DOCS_ACCESS_KEY_ID: ${{ secrets.CF_R2_DOCS_ACCESS_KEY_ID }}
112+
CF_R2_DOCS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_DOCS_SECRET_ACCESS_KEY }}
113+
CF_R2_DOCS_BUCKET: ${{ secrets.CF_R2_DOCS_BUCKET }}
114+
CF_R2_DOCS_BUCKET_URL: ${{ secrets.CF_R2_DOCS_BUCKET_URL }}
107115
uses: ./packages/actions/src/uploadDocumentation
108116
with:
109117
package: ${{ steps.extract-tag.outputs.package }}
@@ -113,7 +121,15 @@ jobs:
113121
if: ${{ env.REF_TYPE == 'tag' && inputs.ref && inputs.ref != 'main' }}
114122
env:
115123
DATABASE_URL: ${{ secrets.DATABASE_URL }}
124+
CF_D1_DOCS_API_KEY: ${{ secrets.CF_D1_DOCS_API_KEY }}
125+
CF_D1_DOCS_ID: ${{ secrets.CF_D1_DOCS_ID }}
126+
CF_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }}
116127
BLOB_READ_WRITE_TOKEN: ${{ secrets.BLOB_READ_WRITE_TOKEN }}
128+
CF_R2_DOCS_URL: ${{ secrets.CF_R2_DOCS_URL }}
129+
CF_R2_DOCS_ACCESS_KEY_ID: ${{ secrets.CF_R2_DOCS_ACCESS_KEY_ID }}
130+
CF_R2_DOCS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_DOCS_SECRET_ACCESS_KEY }}
131+
CF_R2_DOCS_BUCKET: ${{ secrets.CF_R2_DOCS_BUCKET }}
132+
CF_R2_DOCS_BUCKET_URL: ${{ secrets.CF_R2_DOCS_BUCKET_URL }}
117133
uses: ./main/packages/actions/src/uploadDocumentation
118134
with:
119135
package: ${{ steps.extract-tag.outputs.package }}
@@ -123,6 +139,10 @@ jobs:
123139
if: ${{ env.REF_TYPE == 'tag' && (!inputs.ref || inputs.ref == 'main') }}
124140
env:
125141
BLOB_READ_WRITE_TOKEN: ${{ secrets.BLOB_READ_WRITE_TOKEN }}
142+
CF_R2_DOCS_URL: ${{ secrets.CF_R2_DOCS_URL }}
143+
CF_R2_DOCS_ACCESS_KEY_ID: ${{ secrets.CF_R2_DOCS_ACCESS_KEY_ID }}
144+
CF_R2_DOCS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_DOCS_SECRET_ACCESS_KEY }}
145+
CF_R2_DOCS_BUCKET: ${{ secrets.CF_R2_DOCS_BUCKET }}
126146
uses: ./packages/actions/src/uploadSplitDocumentation
127147
with:
128148
package: ${{ steps.extract-tag.outputs.package }}
@@ -132,6 +152,10 @@ jobs:
132152
if: ${{ env.REF_TYPE == 'tag' && inputs.ref && inputs.ref != 'main' }}
133153
env:
134154
BLOB_READ_WRITE_TOKEN: ${{ secrets.BLOB_READ_WRITE_TOKEN }}
155+
CF_R2_DOCS_URL: ${{ secrets.CF_R2_DOCS_URL }}
156+
CF_R2_DOCS_ACCESS_KEY_ID: ${{ secrets.CF_R2_DOCS_ACCESS_KEY_ID }}
157+
CF_R2_DOCS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_DOCS_SECRET_ACCESS_KEY }}
158+
CF_R2_DOCS_BUCKET: ${{ secrets.CF_R2_DOCS_BUCKET }}
135159
uses: ./main/packages/actions/src/uploadSplitDocumentation
136160
with:
137161
package: ${{ steps.extract-tag.outputs.package }}
@@ -155,26 +179,50 @@ jobs:
155179
if: ${{ env.REF_TYPE == 'branch' && (!inputs.ref || inputs.ref == 'main') }}
156180
env:
157181
DATABASE_URL: ${{ secrets.DATABASE_URL }}
182+
CF_D1_DOCS_API_KEY: ${{ secrets.CF_D1_DOCS_API_KEY }}
183+
CF_D1_DOCS_ID: ${{ secrets.CF_D1_DOCS_ID }}
184+
CF_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }}
158185
BLOB_READ_WRITE_TOKEN: ${{ secrets.BLOB_READ_WRITE_TOKEN }}
186+
CF_R2_DOCS_URL: ${{ secrets.CF_R2_DOCS_URL }}
187+
CF_R2_DOCS_ACCESS_KEY_ID: ${{ secrets.CF_R2_DOCS_ACCESS_KEY_ID }}
188+
CF_R2_DOCS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_DOCS_SECRET_ACCESS_KEY }}
189+
CF_R2_DOCS_BUCKET: ${{ secrets.CF_R2_DOCS_BUCKET }}
190+
CF_R2_DOCS_BUCKET_URL: ${{ secrets.CF_R2_DOCS_BUCKET_URL }}
159191
uses: ./packages/actions/src/uploadDocumentation
160192

161193
- name: Upload documentation to database
162194
if: ${{ env.REF_TYPE == 'branch' && inputs.ref && inputs.ref != 'main' }}
163195
env:
164196
DATABASE_URL: ${{ secrets.DATABASE_URL }}
197+
CF_D1_DOCS_API_KEY: ${{ secrets.CF_D1_DOCS_API_KEY }}
198+
CF_D1_DOCS_ID: ${{ secrets.CF_D1_DOCS_ID }}
199+
CF_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }}
165200
BLOB_READ_WRITE_TOKEN: ${{ secrets.BLOB_READ_WRITE_TOKEN }}
201+
CF_R2_DOCS_URL: ${{ secrets.CF_R2_DOCS_URL }}
202+
CF_R2_DOCS_ACCESS_KEY_ID: ${{ secrets.CF_R2_DOCS_ACCESS_KEY_ID }}
203+
CF_R2_DOCS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_DOCS_SECRET_ACCESS_KEY }}
204+
CF_R2_DOCS_BUCKET: ${{ secrets.CF_R2_DOCS_BUCKET }}
205+
CF_R2_DOCS_BUCKET_URL: ${{ secrets.CF_R2_DOCS_BUCKET_URL }}
166206
uses: ./main/packages/actions/src/uploadDocumentation
167207

168208
- name: Upload split documentation to blob storage
169209
if: ${{ env.REF_TYPE == 'branch' && (!inputs.ref || inputs.ref == 'main') }}
170210
env:
171211
BLOB_READ_WRITE_TOKEN: ${{ secrets.BLOB_READ_WRITE_TOKEN }}
212+
CF_R2_DOCS_URL: ${{ secrets.CF_R2_DOCS_URL }}
213+
CF_R2_DOCS_ACCESS_KEY_ID: ${{ secrets.CF_R2_DOCS_ACCESS_KEY_ID }}
214+
CF_R2_DOCS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_DOCS_SECRET_ACCESS_KEY }}
215+
CF_R2_DOCS_BUCKET: ${{ secrets.CF_R2_DOCS_BUCKET }}
172216
uses: ./packages/actions/src/uploadSplitDocumentation
173217

174218
- name: Upload split documentation to blob storage
175219
if: ${{ env.REF_TYPE == 'branch' && inputs.ref && inputs.ref != 'main' }}
176220
env:
177221
BLOB_READ_WRITE_TOKEN: ${{ secrets.BLOB_READ_WRITE_TOKEN }}
222+
CF_R2_DOCS_URL: ${{ secrets.CF_R2_DOCS_URL }}
223+
CF_R2_DOCS_ACCESS_KEY_ID: ${{ secrets.CF_R2_DOCS_ACCESS_KEY_ID }}
224+
CF_R2_DOCS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_DOCS_SECRET_ACCESS_KEY }}
225+
CF_R2_DOCS_BUCKET: ${{ secrets.CF_R2_DOCS_BUCKET }}
178226
uses: ./main/packages/actions/src/uploadSplitDocumentation
179227

180228
- name: Move docs to correct directory

packages/actions/package.json

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -41,28 +41,32 @@
4141
"homepage": "https://discord.js.org",
4242
"funding": "https://github.com/discordjs/discord.js?sponsor",
4343
"dependencies": {
44-
"@actions/core": "^1.10.1",
44+
"@actions/core": "^1.11.1",
4545
"@actions/glob": "^0.5.0",
46+
"@aws-sdk/client-s3": "^3.787.0",
4647
"@discordjs/scripts": "workspace:^",
47-
"@vercel/blob": "^0.23.4",
48+
"@vercel/blob": "^0.27.3",
4849
"@vercel/postgres": "^0.9.0",
50+
"cloudflare": "^4.2.0",
4951
"meilisearch": "^0.38.0",
50-
"p-limit": "^6.1.0",
51-
"tslib": "^2.6.3",
52-
"undici": "6.21.1"
52+
"p-limit": "^6.2.0",
53+
"p-queue": "^8.1.0",
54+
"tslib": "^2.8.1",
55+
"undici": "7.8.0"
5356
},
5457
"devDependencies": {
55-
"@types/node": "^18.19.45",
56-
"@vitest/coverage-v8": "^2.0.5",
58+
"@types/node": "^22.14.0",
59+
"@vitest/coverage-v8": "^3.1.1",
5760
"cross-env": "^7.0.3",
5861
"eslint": "^8.57.0",
5962
"eslint-config-neon": "^0.1.62",
6063
"eslint-formatter-pretty": "^6.0.1",
61-
"prettier": "^3.3.3",
62-
"tsup": "^8.2.4",
63-
"turbo": "^2.0.14",
64-
"typescript": "~5.5.4",
65-
"vitest": "^2.0.5"
64+
"prettier": "^3.5.3",
65+
"terser": "^5.37.0",
66+
"tsup": "^8.4.0",
67+
"turbo": "^2.5.0",
68+
"typescript": "~5.8.3",
69+
"vitest": "^3.1.1"
6670
},
6771
"engines": {
6872
"node": ">=18"

packages/actions/src/pnpmCache/action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ runs:
99
with:
1010
swap-size-gb: 10
1111

12-
- uses: pnpm/action-setup@v4.0.0
12+
- uses: pnpm/action-setup@v4.1.0
1313
name: Install pnpm
1414
with:
1515
run_install: false

packages/actions/src/uploadDocumentation/index.ts

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,26 @@
1+
/* eslint-disable @typescript-eslint/no-loop-func */
12
import { readFile } from 'node:fs/promises';
23
import process from 'node:process';
34
import { getInput, setFailed } from '@actions/core';
45
import { create } from '@actions/glob';
6+
import { PutObjectCommand, S3Client } from '@aws-sdk/client-s3';
57
import { put } from '@vercel/blob';
68
import { createPool } from '@vercel/postgres';
9+
import Cloudflare from 'cloudflare';
710
import pLimit from 'p-limit';
811

9-
if (!process.env.DATABASE_URL) {
10-
setFailed('DATABASE_URL is not set');
12+
if (
13+
!process.env.DATABASE_URL ||
14+
!process.env.CF_R2_DOCS_URL ||
15+
!process.env.CF_R2_DOCS_ACCESS_KEY_ID ||
16+
!process.env.CF_R2_DOCS_SECRET_ACCESS_KEY ||
17+
!process.env.CF_R2_DOCS_BUCKET ||
18+
!process.env.CF_R2_DOCS_BUCKET_URL ||
19+
!process.env.CF_D1_DOCS_API_KEY ||
20+
!process.env.CF_D1_DOCS_ID ||
21+
!process.env.CF_ACCOUNT_ID
22+
) {
23+
setFailed('Missing environment variables');
1124
}
1225

1326
const pkg = getInput('package') || '*';
@@ -17,6 +30,21 @@ const pool = createPool({
1730
connectionString: process.env.DATABASE_URL,
1831
});
1932

33+
const S3 = new S3Client({
34+
region: 'auto',
35+
endpoint: process.env.CF_R2_DOCS_URL!,
36+
credentials: {
37+
accessKeyId: process.env.CF_R2_DOCS_ACCESS_KEY_ID!,
38+
secretAccessKey: process.env.CF_R2_DOCS_SECRET_ACCESS_KEY!,
39+
},
40+
requestChecksumCalculation: 'WHEN_REQUIRED',
41+
responseChecksumValidation: 'WHEN_REQUIRED',
42+
});
43+
44+
const client = new Cloudflare({
45+
apiToken: process.env.CF_D1_DOCS_API_KEY,
46+
});
47+
2048
const limit = pLimit(10);
2149
const promises = [];
2250

@@ -26,19 +54,34 @@ for await (const file of globber.globGenerator()) {
2654
const data = await readFile(file, 'utf8');
2755
try {
2856
promises.push(
29-
// eslint-disable-next-line @typescript-eslint/no-loop-func
3057
limit(async () => {
3158
console.log(`Uploading ${file} with ${version}...`);
3259
const json = JSON.parse(data);
3360
const name = json.name ?? json.n;
34-
const { url } = await put(`${name.replace('@discordjs/', '')}/${version}.json`, data, {
61+
62+
const key = `${name.replace('@discordjs/', '')}/${version}.json`;
63+
64+
const { url } = await put(key, data, {
3565
access: 'public',
3666
addRandomSuffix: false,
3767
});
3868
await pool.sql`insert into documentation (name, version, url) values (${name.replace(
3969
'@discordjs/',
4070
'',
4171
)}, ${version}, ${url}) on conflict (name, version) do update set url = EXCLUDED.url`;
72+
73+
await S3.send(
74+
new PutObjectCommand({
75+
Bucket: process.env.CF_R2_DOCS_BUCKET,
76+
Key: key,
77+
Body: data,
78+
}),
79+
);
80+
await client.d1.database.raw(process.env.CF_D1_DOCS_ID!, {
81+
account_id: process.env.CF_ACCOUNT_ID!,
82+
sql: `insert into documentation (name, version, url) values (?, ?, ?) on conflict (name, version) do update set url = excluded.url;`,
83+
params: [name.replace('@discordjs/', ''), version, process.env.CF_R2_DOCS_BUCKET_URL + '/' + key],
84+
});
4285
}),
4386
);
4487
} catch (error) {
Lines changed: 64 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,82 @@
1+
/* eslint-disable @typescript-eslint/no-loop-func */
12
import { readFile } from 'node:fs/promises';
23
import { basename, dirname, relative, sep } from 'node:path';
3-
import { cwd } from 'node:process';
4-
import { getInput } from '@actions/core';
4+
import process from 'node:process';
5+
import { setTimeout as sleep } from 'node:timers/promises';
6+
import { setFailed, getInput } from '@actions/core';
57
import { create } from '@actions/glob';
8+
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
69
import { put } from '@vercel/blob';
7-
import pLimit from 'p-limit';
10+
import PQueue from 'p-queue';
11+
12+
if (
13+
!process.env.CF_R2_DOCS_URL ||
14+
!process.env.CF_R2_DOCS_ACCESS_KEY_ID ||
15+
!process.env.CF_R2_DOCS_SECRET_ACCESS_KEY ||
16+
!process.env.CF_R2_DOCS_BUCKET
17+
) {
18+
setFailed('Missing environment variables');
19+
}
820

921
const pkg = getInput('package') || '*';
1022
const version = getInput('version') || 'main';
1123

12-
const limit = pLimit(10);
24+
const queue = new PQueue({ concurrency: 10, interval: 60_000, intervalCap: 1_000 });
1325
const promises = [];
26+
const failedUploads: string[] = [];
27+
28+
const S3 = new S3Client({
29+
region: 'auto',
30+
endpoint: process.env.CF_R2_DOCS_URL!,
31+
credentials: {
32+
accessKeyId: process.env.CF_R2_DOCS_ACCESS_KEY_ID!,
33+
secretAccessKey: process.env.CF_R2_DOCS_SECRET_ACCESS_KEY!,
34+
},
35+
requestChecksumCalculation: 'WHEN_REQUIRED',
36+
responseChecksumValidation: 'WHEN_REQUIRED',
37+
});
1438

1539
const globber = await create(`packages/${pkg}/docs/${pkg}/split/*.api.json`);
1640
console.log('Glob: ', await globber.glob());
1741
for await (const file of globber.globGenerator()) {
1842
const data = await readFile(file, 'utf8');
19-
const pkgName = dirname(relative(cwd(), file)).split(sep)[1];
43+
const pkgName = dirname(relative(process.cwd(), file)).split(sep)[1];
2044
try {
2145
promises.push(
22-
// eslint-disable-next-line @typescript-eslint/no-loop-func
23-
limit(async () => {
46+
queue.add(async () => {
2447
console.log(`Uploading ${file} with ${version} from ${pkgName}...`);
2548
const name = basename(file).replace('main.', '');
26-
await put(`rewrite/${pkgName}/${version}.${name}`, data, {
27-
access: 'public',
28-
addRandomSuffix: false,
29-
});
49+
async function upload(retries = 0) {
50+
try {
51+
await put(`rewrite/${pkgName}/${version}.${name}`, data, {
52+
access: 'public',
53+
addRandomSuffix: false,
54+
});
55+
await S3.send(
56+
new PutObjectCommand({
57+
Bucket: process.env.CF_R2_DOCS_BUCKET,
58+
Key: `${pkgName}/${version}.${name}`,
59+
Body: data,
60+
}),
61+
);
62+
} catch (error) {
63+
if (retries > 3) {
64+
console.error(`Could not upload ${file} after 3 retries`, error);
65+
failedUploads.push(name);
66+
return;
67+
}
68+
69+
if (typeof error === 'object' && error && 'retryAfter' in error && typeof error.retryAfter === 'number') {
70+
await sleep(error.retryAfter * 1_000);
71+
return upload(retries + 1);
72+
} else {
73+
console.error(`Could not upload ${file}`, error);
74+
failedUploads.push(name);
75+
}
76+
}
77+
}
78+
79+
await upload();
3080
}),
3181
);
3282
} catch (error) {
@@ -36,6 +86,9 @@ for await (const file of globber.globGenerator()) {
3686

3787
try {
3888
await Promise.all(promises);
89+
if (failedUploads.length) {
90+
setFailed(`Failed to upload ${failedUploads.length} files: ${failedUploads.join(', ')}`);
91+
}
3992
} catch (error) {
4093
console.log(error);
4194
}

packages/actions/tsconfig.test.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"$schema": "https://json.schemastore.org/tsconfig.json",
3+
"extends": "./tsconfig.json",
4+
"compilerOptions": {
5+
"noEmit": true,
6+
"skipLibCheck": true
7+
},
8+
"include": ["__tests__/**/*.ts"],
9+
"exclude": ["node_modules"]
10+
}

0 commit comments

Comments
 (0)