1
1
// @ts -check
2
- import fs from 'fs/promises'
3
2
import execa from 'execa'
4
- import path from 'path'
5
3
import yargs from 'yargs'
6
-
4
+ import getChangedTests from './get-changed-tests.mjs'
5
+
6
+ /**
7
+ * Run tests for added/changed tests in the current branch
8
+ * CLI Options:
9
+ * --mode: test mode (dev, deploy, start)
10
+ * --group: current group number / total groups
11
+ * --flake-detection: run tests multiple times to detect flaky
12
+ */
7
13
async function main ( ) {
8
14
let argv = await yargs ( process . argv . slice ( 2 ) )
9
- . boolean ( 'dev-mode' )
10
- . string ( 'group' ) . argv
15
+ . string ( 'mode' )
16
+ . string ( 'group' )
17
+ . boolean ( 'flake-detection' ) . argv
18
+
19
+ let testMode = argv . mode
20
+ const attempts = argv [ 'flake-detection' ] ? 3 : 1
21
+
22
+ if ( testMode && ! [ 'dev' , 'deploy' , 'start' ] . includes ( testMode ) ) {
23
+ throw new Error (
24
+ `Invalid test mode: ${ testMode } . Must be one of: dev, deploy, start`
25
+ )
26
+ }
11
27
12
- let testMode = argv . devMode ? 'dev' : 'start'
13
28
const rawGroup = argv [ 'group' ]
14
29
let currentGroup = 1
15
30
let groupTotal = 1
@@ -20,101 +35,12 @@ async function main() {
20
35
. map ( ( item ) => Number ( item ) )
21
36
}
22
37
23
- let eventData = { }
24
-
25
38
/** @type import('execa').Options */
26
39
const EXECA_OPTS = { shell : true }
27
40
/** @type import('execa').Options */
28
41
const EXECA_OPTS_STDIO = { ...EXECA_OPTS , stdio : 'inherit' }
29
42
30
- try {
31
- eventData =
32
- JSON . parse (
33
- await fs . readFile ( process . env . GITHUB_EVENT_PATH || '' , 'utf8' )
34
- ) [ 'pull_request' ] || { }
35
- } catch ( _ ) { }
36
-
37
- // detect changed test files
38
- const branchName =
39
- eventData ?. head ?. ref ||
40
- process . env . GITHUB_REF_NAME ||
41
- ( await execa ( 'git rev-parse --abbrev-ref HEAD' , EXECA_OPTS ) ) . stdout
42
-
43
- const remoteUrl =
44
- eventData ?. head ?. repo ?. full_name ||
45
- process . env . GITHUB_REPOSITORY ||
46
- ( await execa ( 'git remote get-url origin' , EXECA_OPTS ) ) . stdout
47
-
48
- const isCanary =
49
- branchName . trim ( ) === 'canary' && remoteUrl . includes ( 'vercel/next.js' )
50
-
51
- if ( isCanary ) {
52
- console . error ( `Skipping flake detection for canary` )
53
- return
54
- }
55
-
56
- try {
57
- await execa ( 'git remote set-branches --add origin canary' , EXECA_OPTS_STDIO )
58
- await execa ( 'git fetch origin canary --depth=20' , EXECA_OPTS_STDIO )
59
- } catch ( err ) {
60
- console . error ( await execa ( 'git remote -v' , EXECA_OPTS_STDIO ) )
61
- console . error ( `Failed to fetch origin/canary` , err )
62
- }
63
-
64
- const changesResult = await execa (
65
- `git diff origin/canary --name-only` ,
66
- EXECA_OPTS
67
- ) . catch ( ( err ) => {
68
- console . error ( err )
69
- return { stdout : '' , stderr : '' }
70
- } )
71
- console . error (
72
- {
73
- branchName,
74
- remoteUrl,
75
- isCanary,
76
- testMode,
77
- } ,
78
- `\ngit diff:\n${ changesResult . stderr } \n${ changesResult . stdout } `
79
- )
80
- const changedFiles = changesResult . stdout . split ( '\n' )
81
-
82
- // run each test 3 times in each test mode (if E2E) with no-retrying
83
- // and if any fail it's flakey
84
- const devTests = [ ]
85
- const prodTests = [ ]
86
-
87
- for ( let file of changedFiles ) {
88
- // normalize slashes
89
- file = file . replace ( / \\ / g, '/' )
90
- const fileExists = await fs
91
- . access ( path . join ( process . cwd ( ) , file ) , fs . constants . F_OK )
92
- . then ( ( ) => true )
93
- . catch ( ( ) => false )
94
-
95
- if ( fileExists && file . match ( / ^ t e s t \/ .* ?\. t e s t \. ( j s | t s | t s x ) $ / ) ) {
96
- if ( file . startsWith ( 'test/e2e/' ) ) {
97
- devTests . push ( file )
98
- prodTests . push ( file )
99
- } else if ( file . startsWith ( 'test/prod' ) ) {
100
- prodTests . push ( file )
101
- } else if ( file . startsWith ( 'test/development' ) ) {
102
- devTests . push ( file )
103
- }
104
- }
105
- }
106
-
107
- console . log (
108
- 'Detected tests:' ,
109
- JSON . stringify (
110
- {
111
- devTests,
112
- prodTests,
113
- } ,
114
- null ,
115
- 2
116
- )
117
- )
43
+ const { devTests, prodTests } = await getChangedTests ( )
118
44
119
45
let currentTests = testMode === 'dev' ? devTests : prodTests
120
46
@@ -153,8 +79,8 @@ async function main() {
153
79
154
80
const RUN_TESTS_ARGS = [ 'run-tests.js' , '-c' , '1' , '--retries' , '0' ]
155
81
156
- for ( let i = 0 ; i < 3 ; i ++ ) {
157
- console . log ( `\n\nRun ${ i + 1 } for ${ testMode } tests` )
82
+ for ( let i = 0 ; i < attempts ; i ++ ) {
83
+ console . log ( `\n\nRun ${ i + 1 } / ${ attempts } for ${ testMode } tests` )
158
84
await execa ( 'node' , [ ...RUN_TESTS_ARGS , ...currentTests ] , {
159
85
...EXECA_OPTS_STDIO ,
160
86
env : {
0 commit comments