Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: adds quality gate for rerunning e2e spec files that are new or have been modified #24556

Merged
merged 54 commits into from
Jul 1, 2024
Merged
Show file tree
Hide file tree
Changes from 52 commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
e66f2fa
quality gate mock alt
seaona May 16, 2024
d2298f6
fix export
seaona May 16, 2024
d89be42
fix PR number match
seaona May 16, 2024
57269c9
overwrite retries number for retry-until-failure cases
seaona May 16, 2024
3a8b0fa
change file to ts and add log for debugging
seaona May 16, 2024
90690cd
revert js
seaona May 16, 2024
65b3467
add ts spec files to the filter and make another test fail to verify …
seaona May 20, 2024
df8d21e
address dev review: move retries to variable remove try/catch
seaona May 21, 2024
5029d49
leave the specs as they were before (changed for ci testing purposes)
seaona May 21, 2024
71bbf50
Merge branch 'develop' into quality-gate-gh
seaona May 21, 2024
1c728ac
Quality gate gh ci job (#24787)
seaona May 27, 2024
c46b3b8
address comments
seaona Jun 4, 2024
b6d1f45
origin develop
seaona Jun 4, 2024
870f875
depth update
seaona Jun 4, 2024
81f954a
50 fetch
seaona Jun 4, 2024
8c0516c
rename funcs
seaona Jun 4, 2024
bc6b76c
Merge branch 'develop' into quality-gate-gh
seaona Jun 4, 2024
8179d2d
switch from sh to js file
seaona Jun 5, 2024
27a4be3
fix changedfilesUtils
seaona Jun 5, 2024
af6e4d6
move script to config file
seaona Jun 6, 2024
e781327
git diff incremental depth
seaona Jun 6, 2024
a26f7ea
fix git fetch incremental
seaona Jun 6, 2024
cd0027f
git fetch pr branch with depth too
seaona Jun 6, 2024
6ef0174
console log path
seaona Jun 6, 2024
48482c8
define output path
seaona Jun 6, 2024
b061ba5
format spec entries with path and new lines
seaona Jun 6, 2024
580eee5
fix back the spec files for testing ci
seaona Jun 6, 2024
c3dbacf
only do for loop if there are changed e2e files
seaona Jun 6, 2024
2da87eb
update git diff fallback and adjust
seaona Jun 18, 2024
918e1fb
testing git diff with full checkout
seaona Jun 18, 2024
6f429d3
fix fetch develop
seaona Jun 18, 2024
4ee548d
unshallow
seaona Jun 18, 2024
ab52848
separate job
seaona Jun 18, 2024
7726eb3
remove requried job
seaona Jun 18, 2024
475764a
Merge branch 'develop' into quality-gate-gh
seaona Jun 18, 2024
49ab885
Merge branch 'develop' into quality-gate-gh
seaona Jun 19, 2024
7cd00e4
Merge branch 'develop' into quality-gate-gh
seaona Jun 25, 2024
2d8a65a
addressing some of the review comments
seaona Jun 25, 2024
94bae47
change .js to .ts
seaona Jun 25, 2024
5ebf061
addressed comments and test failing test
seaona Jun 26, 2024
0a548d2
update function name
seaona Jun 26, 2024
0821ecb
add console logs and remove extra path
seaona Jun 26, 2024
e91024c
tweak path
seaona Jun 26, 2024
1eb2ea0
add missing /
seaona Jun 26, 2024
89b6fc5
remove changes used to test ci
seaona Jun 26, 2024
fa71fa9
cleanup
seaona Jun 26, 2024
3e952e7
add missing newline Mark's suggestion
seaona Jun 28, 2024
2ae6c6f
Omit type from tsdoc - Mark's suggestion
seaona Jun 28, 2024
ecea19c
simplifying variables - Mark's suggestion
seaona Jun 28, 2024
eb79c08
avoid using any in ts - Mark's suggestion
seaona Jun 28, 2024
5874bb0
add job comment for config
seaona Jun 28, 2024
9b1c7cc
changed changedOrnew var definition
seaona Jun 28, 2024
0974070
missing to remove the rest of the types in the descriptions - Mark's …
seaona Jun 28, 2024
07e81d8
Merge branch 'develop' into quality-gate-gh
HowardBraham Jun 28, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ workflows:
- prep-deps
- check-pr-tag
- prep-deps
- get-changed-files-with-git-diff:
requires:
- prep-deps
- test-deps-audit:
requires:
- prep-deps
Expand Down Expand Up @@ -187,41 +190,51 @@ workflows:
- test-e2e-chrome:
requires:
- prep-build-test
- get-changed-files-with-git-diff
- test-e2e-chrome-confirmation-redesign:
requires:
- prep-build-confirmation-redesign-test
- get-changed-files-with-git-diff
- test-e2e-firefox:
requires:
- prep-build-test-mv2
- get-changed-files-with-git-diff
- test-e2e-firefox-confirmation-redesign:
<<: *develop_master_rc_only
requires:
- prep-build-confirmation-redesign-test-mv2
- get-changed-files-with-git-diff
- test-e2e-chrome-rpc:
requires:
- prep-build-test
- get-changed-files-with-git-diff
- test-api-specs:
requires:
- prep-build-test
- test-e2e-chrome-multiple-providers:
requires:
- prep-build-test
- get-changed-files-with-git-diff
- test-e2e-chrome-flask:
requires:
- prep-build-test-flask
- get-changed-files-with-git-diff
- test-e2e-firefox-flask:
<<: *develop_master_rc_only
requires:
- prep-build-test-flask-mv2
- get-changed-files-with-git-diff
- test-e2e-chrome-mmi:
requires:
- prep-build-test-mmi
- get-changed-files-with-git-diff
- test-e2e-mmi-playwright - OPTIONAL:
requires:
- prep-build-test-mmi-playwright
- test-e2e-chrome-rpc-mmi:
requires:
- prep-build-test-mmi
- get-changed-files-with-git-diff
- test-e2e-chrome-vault-decryption:
filters:
branches:
Expand All @@ -230,6 +243,7 @@ workflows:
- /^Version-v(\d+)[.](\d+)[.](\d+)/
requires:
- prep-build
- get-changed-files-with-git-diff
- test-unit-jest-main:
requires:
- prep-deps
Expand Down Expand Up @@ -472,6 +486,23 @@ jobs:
- node_modules
- build-artifacts

# This job is used for the e2e quality gate.
# It must be run before any job which uses the run-all.js script.
get-changed-files-with-git-diff:
seaona marked this conversation as resolved.
Show resolved Hide resolved
executor: node-browsers-small
steps:
- run: *shallow-git-clone
- run: sudo corepack enable
- attach_workspace:
at: .
- run:
name: Get changed files with git diff
command: npx tsx .circleci/scripts/git-diff-develop.ts
- persist_to_workspace:
root: .
paths:
- changed-files

validate-lavamoat-allow-scripts:
executor: node-browsers-small
steps:
Expand Down
99 changes: 99 additions & 0 deletions .circleci/scripts/git-diff-develop.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { hasProperty } from '@metamask/utils';
import { exec as execCallback } from 'child_process';
import fs from 'fs';
import path from 'path';
import { promisify } from 'util';

const exec = promisify(execCallback);

/**
* Fetches the git repository with a specified depth.
*
* @param depth - The depth to use for the fetch command.
* @returns {Promise<boolean>} True if the fetch is successful, otherwise false.
*/
async function fetchWithDepth(depth: number): Promise<boolean> {
try {
await exec(`git fetch --depth ${depth} origin develop`);
await exec(`git fetch --depth ${depth} origin ${process.env.CIRCLE_BRANCH}`);
return true;
} catch (error: unknown) {
console.error(`Failed to fetch with depth ${depth}:`, error);
return false;
}
}

/**
* Attempts to fetch the necessary commits until the merge base is found.
* It tries different fetch depths and performs a full fetch if needed.
*
* @throws {Error} If an unexpected error occurs during the execution of git commands.
*/
async function fetchUntilMergeBaseFound() {
const depths = [1, 10, 100];
for (const depth of depths) {
console.log(`Attempting git diff with depth ${depth}...`);
await fetchWithDepth(depth);

try {
await exec(`git merge-base origin/HEAD HEAD`);
return;
} catch (error: unknown) {
if (
error instanceof Error &&
hasProperty(error, 'code') &&
error.code === 1
) {
console.error(`Error 'no merge base' encountered with depth ${depth}. Incrementing depth...`);
} else {
throw error;
}
}
}
await exec(`git fetch --unshallow origin develop`);
}

/**
* Performs a git diff command to get the list of files changed between the current branch and the origin.
* It first ensures that the necessary commits are fetched until the merge base is found.
*
* @returns {Promise<string>} The output of the git diff command, listing the changed files.
* @throws {Error} If unable to get the diff after fetching the merge base or if an unexpected error occurs.
*/
async function gitDiff(): Promise<string> {
await fetchUntilMergeBaseFound();
const { stdout: diffResult } = await exec(`git diff --name-only origin/HEAD...${process.env.CIRCLE_BRANCH}`);
if (!diffResult) {
throw new Error('Unable to get diff after full checkout.');
}
return diffResult;
}

/**
* Stores the output of git diff to a file.
*
* @returns {Promise<void>} Returns a promise that resolves when the git diff output is successfully stored.
seaona marked this conversation as resolved.
Show resolved Hide resolved
*/
async function storeGitDiffOutput() {
try {
console.log("Attempting to get git diff...");
const diffOutput = await gitDiff();
console.log(diffOutput);

// Create the directory
const outputDir = 'changed-files';
fs.mkdirSync(outputDir, { recursive: true });

// Store the output of git diff
const outputPath = path.resolve(outputDir, 'changed-files.txt');
fs.writeFileSync(outputPath, diffOutput);

console.log(`Git diff results saved to ${outputPath}`);
process.exit(0);
} catch (error: any) {
console.error('An error occurred:', error.message);
process.exit(1);
}
}

storeGitDiffOutput();
20 changes: 12 additions & 8 deletions development/lib/retry.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,20 @@
* @param {string} [args.rejectionMessage] - The message for the rejected promise
* this function will return in the event of failure. (Default: "Retry limit
* reached")
* @param {boolean} [args.retryUntilFailure] - Retries until the function fails.
* @param {boolean} [args.stopAfterOneFailure] - Retries until the function fails.
* @param {Function} functionToRetry - The function that is run and tested for
* failure.
* @returns {Promise<* | null | Error>} a promise that either resolves with one of the following:
* - If successful, resolves with the return value of functionToRetry.
* - If functionToRetry fails while retryUntilFailure is true, resolves with null.
* - If functionToRetry fails while stopAfterOneFailure is true, resolves with null.
* - Otherwise it is rejected with rejectionMessage.
*/
async function retry(
{
retries,
delay = 0,
rejectionMessage = 'Retry limit reached',
retryUntilFailure = false,
stopAfterOneFailure = false,
},
functionToRetry,
) {
Expand All @@ -36,7 +36,7 @@ async function retry(

try {
const result = await functionToRetry();
if (!retryUntilFailure) {
if (!stopAfterOneFailure) {
return result;
}
} catch (error) {
Expand All @@ -46,18 +46,22 @@ async function retry(
console.error('error caught in retry():', error);
}

if (attempts < retries) {
console.log('Ready to retry() again');
if (stopAfterOneFailure) {
throw new Error('Test failed. No more retries will be performed');
}

if (retryUntilFailure) {
return null;
if (attempts < retries) {
console.log('Ready to retry() again');
}
} finally {
attempts += 1;
}
}

if (stopAfterOneFailure) {
return null;
}

seaona marked this conversation as resolved.
Show resolved Hide resolved
throw new Error(rejectionMessage);
}

Expand Down
44 changes: 44 additions & 0 deletions test/e2e/changedFilesUtil.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
const fs = require('fs').promises;
const path = require('path');

const BASE_PATH = path.resolve(__dirname, '..', '..');
const CHANGED_FILES_PATH = path.join(
BASE_PATH,
'changed-files',
'changed-files.txt',
);

/**
* Reads the list of changed files from the git diff file.
*
* @returns {Promise<string[]>} An array of changed file paths.
*/
async function readChangedFiles() {
seaona marked this conversation as resolved.
Show resolved Hide resolved
try {
const data = await fs.readFile(CHANGED_FILES_PATH, 'utf8');
const changedFiles = data.split('\n');
return changedFiles;
} catch (error) {
console.error('Error reading from file:', error);
return '';
}
}

/**
* Filters the list of changed files to include only E2E test files within the 'test/e2e/' directory.
*
* @returns {Promise<string[]>} An array of filtered E2E test file paths.
*/
async function filterE2eChangedFiles() {
const changedFiles = await readChangedFiles();
const e2eChangedFiles = changedFiles
.filter(
(file) =>
file.startsWith('test/e2e/') &&
(file.endsWith('.spec.js') || file.endsWith('.spec.ts')),
)
.map((file) => `${BASE_PATH}/${file}`);
return e2eChangedFiles;
}

module.exports = { filterE2eChangedFiles };
Loading