Skip to content

Commit bd3002f

Browse files
authored
V2 Migration (game-ci#47)
* Fix issues discovered during deployment * Fix compile issues * Fix predeploy * Add test function deployment * Fix linting * Fix linting * Pin versions, add module to package type * Fix linting * Revert to commonjs * Revert module resolution * Fix missing token field * Remove token * Fix lint * Revert node fetch version * Cleanup test function * Use force delete * Finish migration to v2 functions. Converts to new secrets management. Update packages * Fix formatting * Remove require * Read file contents * Downgrade node-fetch * Downgrade octokit * Verbose secret paths * Improve service account credential read * Force service account credential * Revert secret names * Add fallback path to service account credentials * Fixes from code review. Docs on database backup/restore
1 parent 66b91e9 commit bd3002f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+7109
-2605
lines changed

.github/workflows/main.yml

+46-21
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,86 @@
11
name: 🚀
22

33
on:
4-
pull_request: { }
5-
push: { branches: [ main ] }
4+
pull_request: {}
5+
push: { branches: [main] }
66

77
jobs:
88
test:
99
name: 🧪 Test
1010
runs-on: ubuntu-latest
1111
steps:
12-
- uses: actions/checkout@v3
13-
- uses: actions/setup-node@v3
12+
- uses: actions/checkout@v4
13+
- uses: actions/setup-node@v4
1414
with:
15-
node-version: 16
15+
node-version: 20
1616
cache: 'yarn'
1717
- name: install dependencies
1818
run: yarn && yarn --cwd ./functions
1919
- name: run linter
2020
run: yarn lint && yarn --cwd ./functions lint
2121
- name: run tests
2222
run: yarn test && yarn --cwd ./functions test
23-
# - name: Upload test results
24-
# uses: actions/upload-artifact@v1
25-
# with:
26-
# name: Test results
27-
# path: "**/artifacs"
23+
# - name: Upload test results
24+
# uses: actions/upload-artifact@v1
25+
# with:
26+
# name: Test results
27+
# path: "**/artifacs"
2828

2929
build:
3030
name: 🛠 Build
3131
runs-on: ubuntu-latest
3232
steps:
33-
- uses: actions/checkout@v3
34-
- uses: actions/setup-node@v3
33+
- uses: actions/checkout@v4
34+
- uses: actions/setup-node@v4
3535
with:
36-
node-version: 16
36+
node-version: 20
3737
cache: 'yarn'
3838
- name: install dependencies
3939
run: yarn && yarn --cwd ./functions
4040
- name: build
4141
run: yarn --cwd ./functions build
4242

43+
testDeploy:
44+
name: Test Deploy
45+
needs: [test, build]
46+
runs-on: ubuntu-latest
47+
steps:
48+
- uses: actions/checkout@v4
49+
- uses: actions/setup-node@v4
50+
with:
51+
node-version: 20
52+
cache: 'yarn'
53+
- name: install dependencies
54+
run: yarn && yarn --cwd ./functions
55+
- name: Deploy test to Firebase
56+
uses: w9jds/[email protected]
57+
with:
58+
args: deploy --only functions:testFunction
59+
env:
60+
GCP_SA_KEY: '${{ secrets.FIREBASE_SERVICE_ACCOUNT_UNITY_CI_VERSIONS }}'
61+
- name: Cleanup Firebase Test
62+
uses: w9jds/[email protected]
63+
with:
64+
args: functions:delete testFunction --force
65+
env:
66+
GCP_SA_KEY: '${{ secrets.FIREBASE_SERVICE_ACCOUNT_UNITY_CI_VERSIONS }}'
67+
4368
deploy:
4469
name: ✨ Deploy
45-
needs: [ test, build ]
70+
needs: [test, build, testDeploy]
4671
runs-on: ubuntu-latest
4772
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
4873
steps:
49-
- uses: actions/checkout@v3
50-
- uses: actions/setup-node@v3
74+
- uses: actions/checkout@v4
75+
- uses: actions/setup-node@v4
5176
with:
52-
node-version: 16
53-
yarn: 'yarn'
77+
node-version: 20
78+
cache: 'yarn'
5479
- name: install dependencies
5580
run: yarn && yarn --cwd ./functions
5681
- name: Deploy to Firebase
57-
uses: w9jds/firebase-action@v11.24.1
82+
uses: w9jds/firebase-action@v13.10.2
5883
with:
59-
args: deploy
84+
args: deploy --except functions:testFunction
6085
env:
61-
FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}
86+
GCP_SA_KEY: '${{ secrets.FIREBASE_SERVICE_ACCOUNT_UNITY_CI_VERSIONS }}'

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -68,4 +68,5 @@ node_modules/
6868
# IDE
6969
.idea
7070
.vs
71-
.vscode
71+
.vscode
72+
functions/.yarn/

README.md

+11
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,14 @@ Completed CiJobs are reported to Discord.
3434
## Ingeminator
3535

3636
TODO - Describe how it works
37+
38+
## Database Backup
39+
40+
The firestore database can be backed up with the following command:
41+
`yarn run backfire export ./export/versioningBackendBackup --project unity-ci-versions --keyFile <PATH_TO_GOOGLE_CLOUD_SERVICE_ACCOUNT_KEYFILE.json>`
42+
43+
Similarly, it can be used to restore a backup with:
44+
`yarn run backfire import ./export/versioningBackendBackup --project unity-ci-versions --keyFile <PATH_TO_GOOGLE_CLOUD_SERVICE_ACCOUNT_KEYFILE.json>`
45+
46+
You likely would want to empty the database before restoring but you can also use flags like overwrite, merge, etc to control the restoration
47+
rules.

firebase.json

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
},
66
"functions": {
77
"predeploy": [
8-
"npm --prefix \"$RESOURCE_DIR\" run lint",
9-
"npm --prefix \"$RESOURCE_DIR\" run test",
10-
"npm --prefix \"$RESOURCE_DIR\" run build"
8+
"yarn --cwd \"$RESOURCE_DIR\" lint",
9+
"yarn --cwd \"$RESOURCE_DIR\" test",
10+
"yarn --cwd \"$RESOURCE_DIR\" build"
1111
]
1212
},
1313
"hosting": {

functions/.yarnrc.yml

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
nodeLinker: node-modules

functions/package.json

+28-23
Original file line numberDiff line numberDiff line change
@@ -12,35 +12,40 @@
1212
"test": "echo \"No tests yet, feel free to add\" && exit 0"
1313
},
1414
"engines": {
15-
"node": "16"
15+
"node": "20"
1616
},
1717
"main": "lib/index.js",
1818
"dependencies": {
19-
"@octokit/auth-app": "^4.0.9",
20-
"@octokit/rest": "^19.0.7",
19+
"@octokit/auth-app": "^6.1.1",
20+
"@octokit/rest": "^20.1.1",
2121
"eris": "^0.17.2",
22-
"firebase-admin": "^11.7.0",
23-
"firebase-functions": "^4.3.0",
22+
"firebase-admin": "^12.1.1",
23+
"firebase-functions": "^5.0.1",
2424
"httpie": "^1.1.2",
25-
"jsdom": "^21.1.1",
26-
"lodash": "^4.17.20",
27-
"node-fetch": "^3.3.1",
28-
"semver": "^7.3.2"
25+
"jsdom": "^24.1.0",
26+
"lodash": "^4.17.21",
27+
"node-fetch": "^2.7.0",
28+
"semver": "^7.6.2"
2929
},
3030
"devDependencies": {
31-
"@types/jsdom": "^21.1.1",
32-
"@types/lodash": "^4.14.162",
33-
"@types/node": "^18.15.11",
34-
"@types/node-fetch": "^2.5.7",
35-
"@types/semver": "^7.3.4",
36-
"@types/ws": "^8.5.4",
37-
"@typescript-eslint/eslint-plugin": "^5.59.0",
38-
"@typescript-eslint/parser": "^5.59.0",
39-
"eslint": "^8.38.0",
40-
"eslint-plugin-import": "^2.22.0",
41-
"firebase-functions-test": "^3.1.0",
42-
"jest": "^29.5.0",
43-
"typescript": "^5.0.4"
31+
"@octokit/types": "^13.5.0",
32+
"@types/jsdom": "^21.1.7",
33+
"@types/lodash": "^4.17.4",
34+
"@types/node": "^20.14.0",
35+
"@types/node-fetch": "^2.6.11",
36+
"@types/semver": "^7.5.8",
37+
"@types/ws": "^8.5.10",
38+
"@typescript-eslint/eslint-plugin": "^7.12.0",
39+
"@typescript-eslint/parser": "^7.12.0",
40+
"eslint": "^8.57.0",
41+
"eslint-plugin-import": "^2.29.1",
42+
"firebase-functions-test": "^3.3.0",
43+
"jest": "^29.7.0",
44+
"typescript": "^5.4.5"
4445
},
45-
"private": true
46+
"private": true,
47+
"volta": {
48+
"node": "20.14.0",
49+
"yarn": "1.22.22"
50+
}
4651
}

functions/src/api/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ export { reportNewBuild } from './reportNewBuild';
44
export { reportPublication } from './reportPublication';
55
export { unityVersions } from './unityVersions';
66
export { retryBuild } from './retryBuild';
7+
export { testFunction } from './testFunction';

functions/src/api/queueStatus.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
import { functions } from '../service/firebase';
2-
import { Request } from 'firebase-functions/v2/https';
1+
import { onRequest, Request } from 'firebase-functions/v2/https';
32
import { Response } from 'express-serve-static-core';
43
import { CiJobs } from '../model/ciJobs';
54
import { CiBuilds } from '../model/ciBuilds';
65

7-
export const queueStatus = functions.https.onRequest(async (req: Request, res: Response) => {
6+
export const queueStatus = onRequest(async (req: Request, res: Response) => {
87
const jobs = await CiJobs.getAll();
98
const builds = await CiBuilds.getAll();
109

functions/src/api/repoVerions.ts

-17
This file was deleted.

functions/src/api/repoVersions.ts

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { onRequest, Request } from 'firebase-functions/v2/https';
2+
import { logger } from 'firebase-functions/v2';
3+
import { Response } from 'express-serve-static-core';
4+
import { RepoVersionInfo } from '../model/repoVersionInfo';
5+
6+
export const repoVersions = onRequest(async (request: Request, response: Response) => {
7+
try {
8+
const versions = await RepoVersionInfo.getAllIds();
9+
10+
response.send(versions);
11+
} catch (err) {
12+
logger.error(err);
13+
response.send('Oops.');
14+
}
15+
});
+40-27
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,56 @@
1-
import { firebase, functions } from '../service/firebase';
2-
import { Request } from 'firebase-functions/v2/https';
1+
import { onRequest, Request } from 'firebase-functions/v2/https';
2+
import { logger } from 'firebase-functions/v2';
33
import { Response } from 'express-serve-static-core';
44
import { Token } from '../config/token';
55
import { BuildFailure, CiBuilds } from '../model/ciBuilds';
66
import { CiJobs } from '../model/ciJobs';
77
import { Discord } from '../service/discord';
8+
import { defineSecret } from 'firebase-functions/params';
89

9-
export const reportBuildFailure = functions.https.onRequest(async (req: Request, res: Response) => {
10-
try {
11-
if (!Token.isValid(req.header('authorization'))) {
12-
firebase.logger.warn('unauthorised request', req.headers);
13-
res.status(403).send('Unauthorized');
14-
return;
15-
}
10+
const discordToken = defineSecret('DISCORD_TOKEN');
11+
const internalToken = defineSecret('INTERNAL_TOKEN');
12+
13+
export const reportBuildFailure = onRequest(
14+
{ secrets: [discordToken, internalToken] },
15+
async (req: Request, res: Response) => {
16+
const discordClient = new Discord();
17+
await discordClient.init(discordToken.value());
18+
19+
try {
20+
if (!Token.isValid(req.header('authorization'), internalToken.value())) {
21+
logger.warn('unauthorised request', req.headers);
22+
res.status(403).send('Unauthorized');
23+
return;
24+
}
1625

17-
const { body } = req;
18-
firebase.logger.debug('Build failure report incoming.', body);
26+
const { body } = req;
27+
logger.debug('Build failure report incoming.', body);
1928

20-
const { jobId, buildId, reason } = body;
21-
const failure: BuildFailure = { reason };
29+
const { jobId, buildId, reason } = body;
30+
const failure: BuildFailure = { reason };
2231

23-
await CiJobs.markFailureForJob(jobId);
24-
await CiBuilds.markBuildAsFailed(buildId, failure);
32+
await CiJobs.markFailureForJob(jobId);
33+
await CiBuilds.markBuildAsFailed(buildId, failure);
2534

26-
firebase.logger.info('Build failure reported.', body);
27-
res.status(200).send('OK');
28-
} catch (err: any) {
29-
const message = `
35+
logger.info('Build failure reported.', body);
36+
res.status(200).send('OK');
37+
} catch (err: any) {
38+
const message = `
3039
Something went wrong while reporting a build failure
3140
${err.message}
3241
`;
33-
firebase.logger.error(message, err);
34-
await Discord.sendAlert(message);
42+
logger.error(message, err);
43+
44+
await discordClient.sendAlert(message);
45+
46+
if (req.body?.jobId?.toString().startsWith('dryRun')) {
47+
await CiBuilds.removeDryRunBuild(req.body.buildId);
48+
await CiJobs.removeDryRunJob(req.body.jobId);
49+
}
3550

36-
if (req.body?.jobId?.toString().startsWith('dryRun')) {
37-
await CiBuilds.removeDryRunBuild(req.body.buildId);
38-
await CiJobs.removeDryRunJob(req.body.jobId);
51+
res.status(500).send('Something went wrong');
3952
}
4053

41-
res.status(500).send('Something went wrong');
42-
}
43-
});
54+
await discordClient.disconnect();
55+
},
56+
);

0 commit comments

Comments
 (0)