@elliemae/ds-monorepo-devops 3.50.1-next.8 → 3.51.0-beta.1
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/bin/cli.mjs +20 -0
- package/bin/ds-monorepo-devops.mjs +4 -0
- package/bin/execGitReverseMerge/index.mjs +210 -0
- package/bin/execSyncNxTags/index.mjs +104 -0
- package/bin/execute-commands-map.mjs +38 -0
- package/configs/jest.config.mjs +67 -11
- package/configs/noConsoleMode.mjs +1 -0
- package/package.json +13 -3
package/bin/cli.mjs
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import arg from 'arg';
|
|
2
|
+
import { checkCommandOrInquire, executeCommandsMap } from './execute-commands-map.mjs';
|
|
3
|
+
|
|
4
|
+
function parseArgumentsIntoOptions(rawArgs) {
|
|
5
|
+
const args = arg(
|
|
6
|
+
{},
|
|
7
|
+
{
|
|
8
|
+
argv: rawArgs.slice(2),
|
|
9
|
+
},
|
|
10
|
+
);
|
|
11
|
+
return {
|
|
12
|
+
command: args._[0],
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export async function cli(args) {
|
|
17
|
+
let options = parseArgumentsIntoOptions(args);
|
|
18
|
+
options = await checkCommandOrInquire(options);
|
|
19
|
+
executeCommandsMap(args, options);
|
|
20
|
+
}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
/* eslint-disable max-lines */
|
|
2
|
+
/* eslint-disable max-len */
|
|
3
|
+
/* eslint-disable complexity, no-console, max-statements */
|
|
4
|
+
import defGlob from 'glob';
|
|
5
|
+
import inquirer from 'inquirer';
|
|
6
|
+
import { exec } from 'node:child_process';
|
|
7
|
+
import fs from 'node:fs';
|
|
8
|
+
const { glob } = defGlob;
|
|
9
|
+
|
|
10
|
+
const execSyntaxSugar = async ({ command, dryRun = false, silentFail = false }) => {
|
|
11
|
+
const noLFNorCRLFCmd = command.replace(/\r?\n|\r/g, '');
|
|
12
|
+
if (dryRun) {
|
|
13
|
+
console.log(noLFNorCRLFCmd);
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
return new Promise((resolve, reject) => {
|
|
17
|
+
exec(noLFNorCRLFCmd, (error, stdout) => {
|
|
18
|
+
if (error && !silentFail) {
|
|
19
|
+
console.error(error);
|
|
20
|
+
reject(error);
|
|
21
|
+
}
|
|
22
|
+
resolve(stdout);
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export async function promptForCommandOptions() {
|
|
28
|
+
const preAnswears = await inquirer.prompt([
|
|
29
|
+
{
|
|
30
|
+
type: 'list',
|
|
31
|
+
name: 'readyForProcedure',
|
|
32
|
+
message: 'are you currently on the branch you want to reverse merge into?',
|
|
33
|
+
default: 'n',
|
|
34
|
+
choices: ['y', 'n'],
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
type: 'list',
|
|
38
|
+
name: 'pendingChanges',
|
|
39
|
+
message: 'you have pending changes in your working directory?',
|
|
40
|
+
default: 'y',
|
|
41
|
+
choices: ['y', 'n'],
|
|
42
|
+
},
|
|
43
|
+
]);
|
|
44
|
+
if (preAnswears.readyForProcedure === 'n') {
|
|
45
|
+
console.log('Please checkout the branch you want to reverse merge into and run the command again');
|
|
46
|
+
process.exit(0);
|
|
47
|
+
}
|
|
48
|
+
if (preAnswears.pendingChanges === 'y') {
|
|
49
|
+
console.log('Please commit or stash your changes and run the command again');
|
|
50
|
+
process.exit(0);
|
|
51
|
+
}
|
|
52
|
+
// we use git remote to get the list of remotes to choose from
|
|
53
|
+
const gitRemotes = await execSyntaxSugar({ command: 'git remote' });
|
|
54
|
+
const gitRemotesArray = gitRemotes.split('\n').filter((remote) => remote !== '');
|
|
55
|
+
|
|
56
|
+
const questions = [
|
|
57
|
+
{
|
|
58
|
+
type: 'list',
|
|
59
|
+
name: 'gitRemote',
|
|
60
|
+
message: 'which remote do you want to take the file from?',
|
|
61
|
+
choices: gitRemotesArray,
|
|
62
|
+
default: gitRemotesArray[0],
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
type: 'text',
|
|
66
|
+
name: 'gitBranch',
|
|
67
|
+
message: 'which branch do you want to take the files from?',
|
|
68
|
+
default: 'develop',
|
|
69
|
+
},
|
|
70
|
+
];
|
|
71
|
+
|
|
72
|
+
const answers = await inquirer.prompt(questions);
|
|
73
|
+
|
|
74
|
+
return {
|
|
75
|
+
...answers,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/*
|
|
80
|
+
* given a file name, gitRemote and gitBranch, return the command to restore the file in all subfolders, taking the file from the remote branch
|
|
81
|
+
* @param options
|
|
82
|
+
* @param {string} [options.gitRemote] - the remote to take the file from
|
|
83
|
+
* @param {string} [options.gitBranch] - the branch to take the file from
|
|
84
|
+
* @param {string} [options.fileName] - the file to restore
|
|
85
|
+
* @param {boolean} [options.wantSubfolder] - whether to restore the file in all subfolders or current folder only
|
|
86
|
+
* @returns {string} - the command to restore the file in all subfolders
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* // => git ls-files origin/develop '** /CHANGELOG.md' | xargs git restore --source=origin/develop'
|
|
90
|
+
* getRestoreFileFromBranchUnixCmd({gitRemote: 'origin', gitBranch: 'develop', fileName: 'CHANGELOG.md'})
|
|
91
|
+
*/
|
|
92
|
+
const getRestoreFileFromBranchUnixCmd = ({ gitRemote, gitBranch, fileName, wantSubfolder = true }) =>
|
|
93
|
+
wantSubfolder
|
|
94
|
+
? `git ls-files ${gitRemote}/${gitBranch} '**/${fileName}' | xargs git restore --source=${gitRemote}/${gitBranch} `
|
|
95
|
+
: `git ls-files ${gitRemote}/${gitBranch} '${fileName}' | xargs git restore --source=${gitRemote}/${gitBranch} `;
|
|
96
|
+
|
|
97
|
+
// 0 nothing to do, 1 can't auto-solve, -1 can auto-solve
|
|
98
|
+
const canAutosolvePackageJsonConflict = async (packageJsonFilePath) => {
|
|
99
|
+
const conflictRegexp = /<<<<<<<[\s\S]*=======[\s\S]*?>>>>>>>[\s\S]*?\n/g;
|
|
100
|
+
const packageJsonString = fs.readFileSync(packageJsonFilePath, 'utf8');
|
|
101
|
+
|
|
102
|
+
// check if only one conflict marker exists, if multiple, this requires manual resolution
|
|
103
|
+
const foundConflictMarkers = [...packageJsonString.matchAll(conflictRegexp)];
|
|
104
|
+
//check if no conflict markers exist
|
|
105
|
+
if (foundConflictMarkers.length === 0) return 0;
|
|
106
|
+
if (foundConflictMarkers.length === 1) {
|
|
107
|
+
// check if the conflict is only in the version field by matching "version" and see if it's found twice
|
|
108
|
+
const foundVersionKeys = [...packageJsonString.matchAll(/"version"/g)];
|
|
109
|
+
return foundVersionKeys.length === 2 ? -1 : 1;
|
|
110
|
+
}
|
|
111
|
+
return 1;
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
/*
|
|
115
|
+
* reverse merge a file from a remote branch using the following strategy:
|
|
116
|
+
* 1 - keep current branch ./lerna.json
|
|
117
|
+
* 2 - keep current branch ./ci_cd folder content
|
|
118
|
+
* 3 - keep current branch CHANGELOG.md (they will be auto-generated, but keeping "current" makes the diff easier to read)
|
|
119
|
+
* 4 - keep current branch ** /CHANGELOG.md (they will be auto-generated, but keeping "current" makes the diff easier to read
|
|
120
|
+
* 5 - check `** /* /package.json` that the conflict is ONLY in `version` field, any other conflict is marked for manual resolution
|
|
121
|
+
* 6 - run 'pnpm run use-registry-version && pnpm run use-workspace-version' to update the package.json files with the correct version
|
|
122
|
+
* also automatically switch to the $gitBranch-$gitCurrent-mmddyyyy new branch
|
|
123
|
+
* @param options
|
|
124
|
+
* @param {string} [options.gitRemote] - the remote to take the file from
|
|
125
|
+
* @param {string} [options.gitBranch] - the branch to take the file from
|
|
126
|
+
* @returns {Promise<void>}
|
|
127
|
+
*/
|
|
128
|
+
const gitReverseMerge = async (options) => {
|
|
129
|
+
const { gitRemote, gitBranch } = options;
|
|
130
|
+
|
|
131
|
+
const gitCurrent = await execSyntaxSugar({ command: 'git branch --show-current', dryRun: false });
|
|
132
|
+
const todayMMDDYYYY = new Intl.DateTimeFormat('en-US', {
|
|
133
|
+
month: '2-digit',
|
|
134
|
+
day: '2-digit',
|
|
135
|
+
year: 'numeric',
|
|
136
|
+
})
|
|
137
|
+
.format(new Date())
|
|
138
|
+
.replace(/\//g, '');
|
|
139
|
+
const newBranchName = `${gitBranch}-${gitCurrent}-${todayMMDDYYYY}`;
|
|
140
|
+
|
|
141
|
+
// create a new branch
|
|
142
|
+
await execSyntaxSugar({ command: `git checkout -b ${newBranchName}` });
|
|
143
|
+
// run the git merge command
|
|
144
|
+
await execSyntaxSugar({
|
|
145
|
+
command: `git merge --no-edit --no-commit --no-ff ${gitRemote}/${gitBranch}`,
|
|
146
|
+
silentFail: true,
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
// apply the strategy
|
|
150
|
+
// 1 - keep current branch ./lerna.json
|
|
151
|
+
const restoreLernaJsonCmd = `git restore --source=HEAD lerna.json`;
|
|
152
|
+
await execSyntaxSugar({ command: restoreLernaJsonCmd });
|
|
153
|
+
// 2 - keep current branch ./ci_cd folder content
|
|
154
|
+
const restoreCiCdCmd = `git restore --source=HEAD ci_cd`;
|
|
155
|
+
await execSyntaxSugar({ command: restoreCiCdCmd });
|
|
156
|
+
// 3 - keep any branch CHANGELOG.md (they will be auto-generated anyway)
|
|
157
|
+
const restoreChangelogCmd = getRestoreFileFromBranchUnixCmd({
|
|
158
|
+
gitRemote,
|
|
159
|
+
gitBranch: gitCurrent,
|
|
160
|
+
fileName: 'CHANGELOG.md',
|
|
161
|
+
wantSubfolder: false,
|
|
162
|
+
});
|
|
163
|
+
await execSyntaxSugar({ command: restoreChangelogCmd });
|
|
164
|
+
// 4 - keep any branch ** /CHANGELOG.md (they will be auto-generated anyway)
|
|
165
|
+
const restoreChangelogsCmd = getRestoreFileFromBranchUnixCmd({
|
|
166
|
+
gitRemote,
|
|
167
|
+
gitBranch: gitCurrent,
|
|
168
|
+
fileName: 'CHANGELOG.md',
|
|
169
|
+
wantSubfolder: true,
|
|
170
|
+
});
|
|
171
|
+
await execSyntaxSugar({ command: restoreChangelogsCmd });
|
|
172
|
+
|
|
173
|
+
// we check all package.json files for conflicts and resolve those that can be auto-resolved, listin the ones that can't
|
|
174
|
+
const cantAutoSolve = [];
|
|
175
|
+
const globPatternPackage = '**/*/package.json';
|
|
176
|
+
const packageJsonFilesPaths = glob(globPatternPackage, { sync: true, ignore: ['**/node_modules/**', '**/dist/**'] });
|
|
177
|
+
|
|
178
|
+
for (let i = 0; i < packageJsonFilesPaths.length; i += 1) {
|
|
179
|
+
const packageJsonFilePath = packageJsonFilesPaths[i];
|
|
180
|
+
const canAutoSolve = await canAutosolvePackageJsonConflict(packageJsonFilePath);
|
|
181
|
+
if (canAutoSolve === 0) continue;
|
|
182
|
+
|
|
183
|
+
if (canAutoSolve === 1) {
|
|
184
|
+
cantAutoSolve.push(packageJsonFilePath);
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const restorePackageJsonCmd = getRestoreFileFromBranchUnixCmd({
|
|
189
|
+
gitRemote,
|
|
190
|
+
gitBranch,
|
|
191
|
+
fileName: packageJsonFilePath,
|
|
192
|
+
wantSubfolder: false,
|
|
193
|
+
});
|
|
194
|
+
await execSyntaxSugar({ command: restorePackageJsonCmd });
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// 6 - run 'pnpm run use-registry-version && pnpm run use-workspace-version' to update the package.json files with the correct version
|
|
198
|
+
await execSyntaxSugar({ command: 'pnpm run use-registry-version && pnpm run use-workspace-version' });
|
|
199
|
+
|
|
200
|
+
// if there are conflicts that can't be auto-solved, list them
|
|
201
|
+
if (cantAutoSolve.length > 0) {
|
|
202
|
+
console.log("The following package.json files have conflicts that can't be auto-solved:");
|
|
203
|
+
console.log(cantAutoSolve.join('\n'));
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
export const execGitReverseMerge = async (options) => {
|
|
208
|
+
const commandOptions = await promptForCommandOptions(options);
|
|
209
|
+
await gitReverseMerge(commandOptions);
|
|
210
|
+
};
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/* eslint-disable complexity, no-console, max-statements */
|
|
2
|
+
import inquirer from 'inquirer';
|
|
3
|
+
import defGlob from 'glob';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import fs from 'node:fs';
|
|
6
|
+
const { glob } = defGlob;
|
|
7
|
+
|
|
8
|
+
export async function promptForCommandOptions(options) {
|
|
9
|
+
const questions = [];
|
|
10
|
+
if (!options.hello) {
|
|
11
|
+
questions.push({
|
|
12
|
+
type: 'list',
|
|
13
|
+
name: 'dryRun',
|
|
14
|
+
message: 'dry-run?',
|
|
15
|
+
default: 'n',
|
|
16
|
+
choices: ['y', 'n'],
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
const answers = await inquirer.prompt(questions);
|
|
20
|
+
|
|
21
|
+
return {
|
|
22
|
+
...answers,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* check all subfolders under cwd + packages/ for a package.json file
|
|
28
|
+
* - if it exists, check for project.json file in the same folder
|
|
29
|
+
* - if it doesn't exist, continue to the next folder
|
|
30
|
+
* - if both exist, check the "tags" array in the project.json file to
|
|
31
|
+
* - package.json `typesafety`
|
|
32
|
+
* - true
|
|
33
|
+
* - tag ensure "strict-eslint" exists in the tags array
|
|
34
|
+
* - false
|
|
35
|
+
* - tag remove "strict-eslint" from the tags array if it exists
|
|
36
|
+
* - `"status:eol"`
|
|
37
|
+
* - yes
|
|
38
|
+
* - remove the taxonomy tag from the tags array
|
|
39
|
+
* - no
|
|
40
|
+
* - add the taxonomy tag to the tags array if it doesn't exist or prompt the user to add it(in dry-run mode)
|
|
41
|
+
* (E.G. packages/layout/... -> "layout", packages/atom/... -> "atom")
|
|
42
|
+
* - if it doesn't exist, continue to the next folder
|
|
43
|
+
* @param options
|
|
44
|
+
* @param {string} [options.dryRun='n'] - Indicates whether to perform a dry run ('y' or 'n').
|
|
45
|
+
* @returns {Promise<void>}
|
|
46
|
+
*/
|
|
47
|
+
const fixMissingTags = async (options) => {
|
|
48
|
+
const { dryRun } = options;
|
|
49
|
+
const globPatternPackage = 'packages/**/*/package.json';
|
|
50
|
+
const packageJsonFilesPaths = glob(globPatternPackage, { sync: true, ignore: ['**/node_modules/**', '**/dist/**'] });
|
|
51
|
+
for (let i = 0; i < packageJsonFilesPaths.length; i += 1) {
|
|
52
|
+
const packageJsonFilePath = packageJsonFilesPaths[i];
|
|
53
|
+
const finalPath = path.resolve(process.cwd(), packageJsonFilePath);
|
|
54
|
+
const packageJson = JSON.parse(fs.readFileSync(finalPath, 'utf8'));
|
|
55
|
+
const { publishConfig: { typeSafety = false } = {} } = packageJson;
|
|
56
|
+
const taxonomy = finalPath.split('/').reverse()[2];
|
|
57
|
+
|
|
58
|
+
const projectJsonFilePath = path.resolve(finalPath, '../project.json');
|
|
59
|
+
if (!fs.existsSync(projectJsonFilePath)) continue;
|
|
60
|
+
const projectJson = JSON.parse(fs.readFileSync(projectJsonFilePath, 'utf8'));
|
|
61
|
+
const missingTags = [];
|
|
62
|
+
const extraTags = [];
|
|
63
|
+
|
|
64
|
+
const isMarkedAsStrict = projectJson.tags.includes('strict-eslint');
|
|
65
|
+
if (typeSafety && !isMarkedAsStrict) missingTags.push('strict-eslint');
|
|
66
|
+
if (!typeSafety && isMarkedAsStrict) extraTags.push('strict-eslint');
|
|
67
|
+
|
|
68
|
+
const isEol = projectJson.tags.includes('status:eol');
|
|
69
|
+
const hasTaxonomy = projectJson.tags.includes(taxonomy);
|
|
70
|
+
if (!isEol && !hasTaxonomy) missingTags.push(taxonomy);
|
|
71
|
+
if (isEol && hasTaxonomy) extraTags.push(taxonomy);
|
|
72
|
+
|
|
73
|
+
const shouldRemoveTags = extraTags.length !== 0;
|
|
74
|
+
const shouldAddTags = missingTags.length !== 0;
|
|
75
|
+
const shouldDoNothing = !shouldAddTags && !shouldRemoveTags;
|
|
76
|
+
if (shouldDoNothing) continue;
|
|
77
|
+
|
|
78
|
+
// mutate projectJson.tags
|
|
79
|
+
if (shouldAddTags) {
|
|
80
|
+
projectJson.tags.push(...missingTags);
|
|
81
|
+
}
|
|
82
|
+
// mutate projectJson.tags
|
|
83
|
+
if (shouldRemoveTags) {
|
|
84
|
+
projectJson.tags = projectJson.tags.filter((tag) => !extraTags.includes(tag));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (dryRun === 'n') {
|
|
88
|
+
projectJson.tags.sort();
|
|
89
|
+
fs.writeFileSync(projectJsonFilePath, JSON.stringify(projectJson, null, 2));
|
|
90
|
+
if (shouldAddTags) console.log(`Added ${missingTags.join(', ')} tag to ${projectJsonFilePath}`);
|
|
91
|
+
if (shouldRemoveTags) console.log(`Removed ${taxonomy} tag from ${projectJsonFilePath}`);
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
if (dryRun === 'y') {
|
|
95
|
+
if (shouldAddTags) console.log(`Would have added ${missingTags.join(', ')} to ${projectJsonFilePath}`);
|
|
96
|
+
if (shouldRemoveTags) console.log(`Would have removed ${taxonomy} from ${projectJsonFilePath}`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
export const execSyncNxTags = async (options) => {
|
|
102
|
+
const commandOptions = await promptForCommandOptions(options);
|
|
103
|
+
await fixMissingTags(commandOptions);
|
|
104
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import inquirer from 'inquirer';
|
|
2
|
+
import { execSyncNxTags } from './execSyncNxTags/index.mjs';
|
|
3
|
+
import {execGitReverseMerge} from './execGitReverseMerge/index.mjs';
|
|
4
|
+
|
|
5
|
+
const COMMANDS = {
|
|
6
|
+
SYNC_NX_TAGS: 'sync-nx-tags',
|
|
7
|
+
REVERSE_MERGE_BRANCH: 'reverse-merge-branch',
|
|
8
|
+
EXIT: 'exit',
|
|
9
|
+
};
|
|
10
|
+
export const checkCommandOrInquire = async (options) => {
|
|
11
|
+
const questions = [];
|
|
12
|
+
if (!options.command) {
|
|
13
|
+
questions.push({
|
|
14
|
+
type: 'list',
|
|
15
|
+
name: 'command',
|
|
16
|
+
message: 'Please choose which command to run',
|
|
17
|
+
choices: Object.values(COMMANDS),
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
const answers = await inquirer.prompt(questions);
|
|
21
|
+
return {
|
|
22
|
+
...options,
|
|
23
|
+
...answers,
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export async function executeCommandsMap(args, options) {
|
|
28
|
+
switch (options.command) {
|
|
29
|
+
case COMMANDS.SYNC_NX_TAGS:
|
|
30
|
+
execSyncNxTags(options);
|
|
31
|
+
break;
|
|
32
|
+
case COMMANDS.REVERSE_MERGE_BRANCH:
|
|
33
|
+
execGitReverseMerge(options);
|
|
34
|
+
break;
|
|
35
|
+
default:
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
}
|
package/configs/jest.config.mjs
CHANGED
|
@@ -1,14 +1,70 @@
|
|
|
1
1
|
import { jestConfig } from '@elliemae/pui-cli';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
const __filename = fileURLToPath(import.meta.url); // get the resolved path to the file
|
|
5
|
+
const __dirname = path.dirname(__filename); // get the name of the directory
|
|
6
|
+
const getFileFromCurrentFolder = (fileName) => path.normalize(path.resolve(__dirname, fileName));
|
|
7
|
+
/**
|
|
8
|
+
* Generates an array of setup files for Jest based on provided flags.
|
|
9
|
+
*
|
|
10
|
+
* @param {Object} options - The options object.
|
|
11
|
+
* @param {boolean} [options.silenceConsole=false] - Flag to determine if console output should be silenced.
|
|
12
|
+
* @returns {string[]} An array of setup files for Jest.
|
|
13
|
+
*/
|
|
14
|
+
const getSetupFilesAfterEnvBasedOnFlags = ({ silenceConsole = false }) => {
|
|
15
|
+
const setupFilesAfterEnv = [];
|
|
2
16
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
17
|
+
if (silenceConsole) {
|
|
18
|
+
setupFilesAfterEnv.push(getFileFromCurrentFolder('noConsoleMode.mjs'));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return setupFilesAfterEnv;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Generates a Jest configuration object.
|
|
26
|
+
*
|
|
27
|
+
* @param {Object} options - Configuration options.
|
|
28
|
+
* @param {string} [options.relativePathAfterTestsFolder] - Relative path after the tests folder to match test files.
|
|
29
|
+
* @param {Object} [options.firstLevelSpread] - Configuration options to override defaults.
|
|
30
|
+
* @param {Object} options.flags - Flags for configuration.
|
|
31
|
+
* @param {boolean} [options.flags.silenceConsole=false] - Flag to silence the console during tests.
|
|
32
|
+
* @returns {import('jest').Config} Jest configuration object.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* config({
|
|
36
|
+
* // matches tests/GlobalHeader.keyboard.test.js
|
|
37
|
+
* relativePathAfterTestsFolder: 'GlobalHeader.keyboard.test.js',
|
|
38
|
+
* // overrides the default configuration for jest config 'verbose' to true
|
|
39
|
+
* firstLevelSpread: { verbose: true },
|
|
40
|
+
* // silences the console during tests via custom setup file
|
|
41
|
+
* flags: { silenceConsole: true }
|
|
42
|
+
* });
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* // matches tests/GlobalHeader/a11y/test.keys.js
|
|
46
|
+
* config({
|
|
47
|
+
* relativePathAfterTestsFolder: 'GlobalHeader/a11y/test.keys.js',
|
|
48
|
+
* flags: { silenceConsole: true }
|
|
49
|
+
* });
|
|
50
|
+
*/
|
|
51
|
+
export const config = ({ relativePathAfterTestsFolder = undefined, firstLevelSpread = {}, flags = {} } = {}) => {
|
|
52
|
+
const silenceConsole = flags.silenceConsole ?? process.env.JEST_FORCE_SILENT_CONSOLE ?? false;
|
|
53
|
+
|
|
54
|
+
/** @type {import('jest').Config} */
|
|
55
|
+
return {
|
|
56
|
+
...jestConfig,
|
|
57
|
+
collectCoverage: false,
|
|
58
|
+
collectCoverageFrom: [],
|
|
59
|
+
coverageDirectory: undefined,
|
|
60
|
+
coverageReporters: undefined,
|
|
61
|
+
// testRegex: 'tests/.*\\.test\\.[jt]sx?$',
|
|
62
|
+
testRegex: relativePathAfterTestsFolder
|
|
63
|
+
? `.*/tests/${relativePathAfterTestsFolder}$`
|
|
64
|
+
: 'tests/.*\\.test\\.[jt]sx?$',
|
|
65
|
+
testTimeout: 120000,
|
|
66
|
+
setupFilesAfterEnv: [...jestConfig.setupFilesAfterEnv, ...getSetupFilesAfterEnvBasedOnFlags({ silenceConsole })],
|
|
67
|
+
...firstLevelSpread,
|
|
68
|
+
};
|
|
69
|
+
};
|
|
14
70
|
export default config;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
global.console = { jestLog: console.log, error: jest.fn(), warn: jest.fn(), log: jest.fn() };
|
package/package.json
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elliemae/ds-monorepo-devops",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.51.0-beta.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "ICE MT - Dimsum - Monorepo Devops",
|
|
6
|
+
"type": "module",
|
|
6
7
|
"files": [
|
|
8
|
+
"bin",
|
|
7
9
|
"configs"
|
|
8
10
|
],
|
|
11
|
+
"bin": {
|
|
12
|
+
"@elliemae/ds-monorepo-devops": "./bin/ds-monorepo-devops.mjs",
|
|
13
|
+
"ds-monorepo-devops": "./bin/ds-monorepo-devops.mjs"
|
|
14
|
+
},
|
|
9
15
|
"exports": {
|
|
10
16
|
"./configs/jest.config": {
|
|
11
17
|
"import": "./configs/jest.config.mjs",
|
|
@@ -19,7 +25,7 @@
|
|
|
19
25
|
},
|
|
20
26
|
"engines": {
|
|
21
27
|
"pnpm": ">=8",
|
|
22
|
-
"node": ">=
|
|
28
|
+
"node": ">=22"
|
|
23
29
|
},
|
|
24
30
|
"author": "ICE MT",
|
|
25
31
|
"jestSonar": {
|
|
@@ -29,7 +35,11 @@
|
|
|
29
35
|
"indent": 4
|
|
30
36
|
},
|
|
31
37
|
"peerDependencies": {
|
|
32
|
-
"@elliemae/pui-cli": "9.0.0-next.
|
|
38
|
+
"@elliemae/pui-cli": "9.0.0-next.55",
|
|
39
|
+
"arg": "~5.0.2",
|
|
40
|
+
"glob": "~10.2.5",
|
|
41
|
+
"ignore": "^5.3.0",
|
|
42
|
+
"inquirer": "~12.0.0",
|
|
33
43
|
"jest": "~29.7.0"
|
|
34
44
|
},
|
|
35
45
|
"publishConfig": {
|