reviewable-enterprise-tools 2.1.2 → 2.2.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/cleanup_refs.js +102 -0
- package/package.json +3 -2
- package/rules_firecrypt.json +123 -0
package/cleanup_refs.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import readline from 'readline';
|
|
5
|
+
import yargs from 'yargs';
|
|
6
|
+
import {hideBin} from 'yargs/helpers';
|
|
7
|
+
import {eachLimit} from 'async';
|
|
8
|
+
import ms from 'ms';
|
|
9
|
+
import Pace from 'pace';
|
|
10
|
+
import _ from 'lodash';
|
|
11
|
+
|
|
12
|
+
const UPDATE_SIZE = 20;
|
|
13
|
+
const MAX_PARALLEL_UPDATES = 3;
|
|
14
|
+
const REF_REGEXP = /^refs\/reviewable\/(pr\d+\/r\d+)$/;
|
|
15
|
+
|
|
16
|
+
function parseArgs() {
|
|
17
|
+
return yargs(hideBin(process.argv))
|
|
18
|
+
.usage('Usage: $0 <filename> --repo=owner/repo [options]')
|
|
19
|
+
.positional('filename', {
|
|
20
|
+
describe: 'The file to read Git refs from, one per line',
|
|
21
|
+
type: 'string'
|
|
22
|
+
})
|
|
23
|
+
.option('repo', {
|
|
24
|
+
describe: 'The repository (e.g. Reviewable/enterprise-tools) the refs are stored in',
|
|
25
|
+
})
|
|
26
|
+
.option('max-delay', {
|
|
27
|
+
type: 'string',
|
|
28
|
+
describe: 'The amount of time over which to distribute tasks in the cleanup work queue, ' +
|
|
29
|
+
'to avoid overloading the GitHub server',
|
|
30
|
+
default: '1d',
|
|
31
|
+
})
|
|
32
|
+
.option('validate-only', {
|
|
33
|
+
type: 'boolean',
|
|
34
|
+
describe: 'Do not schedule refs for cleanup, only validate input file'
|
|
35
|
+
})
|
|
36
|
+
.option('ignore-invalid', {
|
|
37
|
+
type: 'boolean',
|
|
38
|
+
describe: 'Do not fail when encountering invalid refs but continue to ' +
|
|
39
|
+
'schedule cleanup of remaining valid refs'
|
|
40
|
+
})
|
|
41
|
+
.demandCommand(1, 'You must provide a filename')
|
|
42
|
+
.check(argv => {
|
|
43
|
+
if (!argv.repo && !argv.validateOnly) {
|
|
44
|
+
throw new Error('Option --repo is required');
|
|
45
|
+
}
|
|
46
|
+
if (argv.validateOnly && argv.ignoreInvalid) {
|
|
47
|
+
throw new Error('--validate-only and --ignore-invalid are mutually exclusive');
|
|
48
|
+
}
|
|
49
|
+
return true;
|
|
50
|
+
})
|
|
51
|
+
.version(false)
|
|
52
|
+
.help()
|
|
53
|
+
.parse();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async function validate(filename, ignoreInvalid) {
|
|
57
|
+
const refs = new Set();
|
|
58
|
+
let lineno = 0;
|
|
59
|
+
let valid = true;
|
|
60
|
+
for await (const line of readline.createInterface(fs.createReadStream(filename))) {
|
|
61
|
+
lineno++;
|
|
62
|
+
const ref = _.trim(line);
|
|
63
|
+
if (!ref) continue; // Silently ignore blank lines
|
|
64
|
+
if (ref.match(REF_REGEXP)) {refs.add(ref); continue;}
|
|
65
|
+
console.warn(`Line ${lineno}, invalid ref: ${ref}`);
|
|
66
|
+
valid = false;
|
|
67
|
+
}
|
|
68
|
+
if (!valid && !ignoreInvalid) process.exit(1);
|
|
69
|
+
return Array.from(refs);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async function main() {
|
|
73
|
+
const args = parseArgs();
|
|
74
|
+
const refs = await validate(args._[0], args.ignoreInvalid);
|
|
75
|
+
if (!args.repo) return;
|
|
76
|
+
await import('./lib/loadFirebase.js');
|
|
77
|
+
const [, owner, repo] = _.toLower(args.repo).match(/([^/]*)\/?(.*)/);
|
|
78
|
+
const ldb = db.scope({owner, repo});
|
|
79
|
+
if (!await ldb.child('repositories/:owner/:repo/core').get()) {
|
|
80
|
+
console.error('Repository does not exist.');
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
if (args.validateOnly) return;
|
|
84
|
+
const pace = Pace(refs.length);
|
|
85
|
+
const maxDelay = ms(args.maxDelay);
|
|
86
|
+
let saved = 0;
|
|
87
|
+
await eachLimit(_.chunk(refs, UPDATE_SIZE), MAX_PARALLEL_UPDATES, async refsBatch => {
|
|
88
|
+
const updates = {};
|
|
89
|
+
_.forEach(refsBatch, ref => {
|
|
90
|
+
const delay = Math.round(Math.random() * maxDelay);
|
|
91
|
+
const task = {owner, repo, ref, _lease: {expiry: db.now + delay}};
|
|
92
|
+
const shortRef = ref.match(REF_REGEXP)[1].replaceAll('/', '-');
|
|
93
|
+
ldb.scope({shortRef}).assign(updates, {'queues/refCleanup/:owner|:repo|:shortRef': task});
|
|
94
|
+
});
|
|
95
|
+
await ldb.update(updates);
|
|
96
|
+
saved += refsBatch.length;
|
|
97
|
+
pace.op(saved);
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
await main();
|
|
102
|
+
process.exit(0);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "reviewable-enterprise-tools",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Admin tools for Reviewable Enterprise",
|
|
6
6
|
"bin": {
|
|
@@ -52,7 +52,8 @@
|
|
|
52
52
|
"promise-writable": "^6.0.0",
|
|
53
53
|
"request": "^2.88.2",
|
|
54
54
|
"serialized-lru-cache": "^3.1.0",
|
|
55
|
-
"stream-throttle": "^0.1.3"
|
|
55
|
+
"stream-throttle": "^0.1.3",
|
|
56
|
+
"yargs": "^17.7.2"
|
|
56
57
|
},
|
|
57
58
|
"devDependencies": {
|
|
58
59
|
"eslint": "^8.10.0",
|
package/rules_firecrypt.json
CHANGED
|
@@ -406,6 +406,50 @@
|
|
|
406
406
|
}
|
|
407
407
|
}
|
|
408
408
|
},
|
|
409
|
+
"refCleanup": {
|
|
410
|
+
"ping": {
|
|
411
|
+
".encrypt": {
|
|
412
|
+
"key": ""
|
|
413
|
+
}
|
|
414
|
+
},
|
|
415
|
+
"$refKey": {
|
|
416
|
+
"owner": {
|
|
417
|
+
".encrypt": {
|
|
418
|
+
"value": "#"
|
|
419
|
+
}
|
|
420
|
+
},
|
|
421
|
+
"repo": {
|
|
422
|
+
".encrypt": {
|
|
423
|
+
"value": "#"
|
|
424
|
+
}
|
|
425
|
+
},
|
|
426
|
+
"ref": {
|
|
427
|
+
".encrypt": {
|
|
428
|
+
"value": "#"
|
|
429
|
+
}
|
|
430
|
+
},
|
|
431
|
+
".encrypt": {
|
|
432
|
+
"key": "#|#|."
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
},
|
|
436
|
+
"masterRepoUpdate": {
|
|
437
|
+
"ping": {
|
|
438
|
+
".encrypt": {
|
|
439
|
+
"key": ""
|
|
440
|
+
}
|
|
441
|
+
},
|
|
442
|
+
"$ownerName": {
|
|
443
|
+
"owner": {
|
|
444
|
+
".encrypt": {
|
|
445
|
+
"value": "#"
|
|
446
|
+
}
|
|
447
|
+
},
|
|
448
|
+
".encrypt": {
|
|
449
|
+
"key": "#"
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
},
|
|
409
453
|
"permissions": {
|
|
410
454
|
"ping": {
|
|
411
455
|
".encrypt": {
|
|
@@ -477,6 +521,13 @@
|
|
|
477
521
|
}
|
|
478
522
|
}
|
|
479
523
|
},
|
|
524
|
+
"masterRepository": {
|
|
525
|
+
"name": {
|
|
526
|
+
".encrypt": {
|
|
527
|
+
"value": "#"
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
},
|
|
480
531
|
"owners": {
|
|
481
532
|
"$userKey": {
|
|
482
533
|
".encrypt": {
|
|
@@ -484,6 +535,36 @@
|
|
|
484
535
|
}
|
|
485
536
|
}
|
|
486
537
|
},
|
|
538
|
+
"connections": {
|
|
539
|
+
"index": {
|
|
540
|
+
"active": {
|
|
541
|
+
".encrypt": {
|
|
542
|
+
"value": "#"
|
|
543
|
+
}
|
|
544
|
+
},
|
|
545
|
+
"broken": {
|
|
546
|
+
".encrypt": {
|
|
547
|
+
"value": "#"
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
},
|
|
552
|
+
"cache": {
|
|
553
|
+
"members": {
|
|
554
|
+
"value": {
|
|
555
|
+
".encrypt": {
|
|
556
|
+
"value": "#"
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
},
|
|
560
|
+
"teams": {
|
|
561
|
+
"value": {
|
|
562
|
+
".encrypt": {
|
|
563
|
+
"value": "#"
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
},
|
|
487
568
|
".encrypt": {
|
|
488
569
|
"key": "#"
|
|
489
570
|
}
|
|
@@ -571,6 +652,38 @@
|
|
|
571
652
|
}
|
|
572
653
|
}
|
|
573
654
|
},
|
|
655
|
+
"cache": {
|
|
656
|
+
"assignees": {
|
|
657
|
+
"value": {
|
|
658
|
+
".encrypt": {
|
|
659
|
+
"value": "#"
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
},
|
|
663
|
+
"labels": {
|
|
664
|
+
"value": {
|
|
665
|
+
".encrypt": {
|
|
666
|
+
"value": "#"
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
},
|
|
670
|
+
"milestones": {
|
|
671
|
+
"value": {
|
|
672
|
+
".encrypt": {
|
|
673
|
+
"value": "#"
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
},
|
|
678
|
+
"pushOnlyCache": {
|
|
679
|
+
"collaborators": {
|
|
680
|
+
"value": {
|
|
681
|
+
".encrypt": {
|
|
682
|
+
"value": "#"
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
},
|
|
574
687
|
"branches": {
|
|
575
688
|
"$branch": {
|
|
576
689
|
".encrypt": {
|
|
@@ -716,6 +829,11 @@
|
|
|
716
829
|
"value": "#"
|
|
717
830
|
}
|
|
718
831
|
},
|
|
832
|
+
"stage": {
|
|
833
|
+
".encrypt": {
|
|
834
|
+
"value": "#"
|
|
835
|
+
}
|
|
836
|
+
},
|
|
719
837
|
"error": {
|
|
720
838
|
".encrypt": {
|
|
721
839
|
"value": "#"
|
|
@@ -1115,6 +1233,11 @@
|
|
|
1115
1233
|
"value": "#"
|
|
1116
1234
|
}
|
|
1117
1235
|
},
|
|
1236
|
+
"emuSuffix": {
|
|
1237
|
+
".encrypt": {
|
|
1238
|
+
"value": "#"
|
|
1239
|
+
}
|
|
1240
|
+
},
|
|
1118
1241
|
"periods": {
|
|
1119
1242
|
"$periodStart": {
|
|
1120
1243
|
"activeUsers": {
|