ci: reduce flakiness of docs-infra `deploy-to-firebase.js` tests (#40088)
The `deploy-to-firebase.js` tests rely on git info retrieved from the `angular/angular` repository (via `git ls-remote ...`). Previously, different calls to `git ls-remote ...` could return different values if a new commit was pushed or a new branch was created during test execution, resulting in errors ([example CI failure][1]). This commit makes the tests more stable by memoizing the result of `git ls-remote ...` and returning the same result for subsequent calls with the same arguments (even if meanwhile the remote has been updated). [1]: https://circleci.com/gh/angular/angular/877626 PR Close #40088
This commit is contained in:
parent
4f4f318d28
commit
c18a9d5c79
|
@ -12,6 +12,7 @@ set('-e');
|
||||||
// Constants
|
// Constants
|
||||||
const REPO_SLUG = 'angular/angular';
|
const REPO_SLUG = 'angular/angular';
|
||||||
const NG_REMOTE_URL = `https://github.com/${REPO_SLUG}.git`;
|
const NG_REMOTE_URL = `https://github.com/${REPO_SLUG}.git`;
|
||||||
|
const GIT_REMOTE_REFS_CACHE = new Map();
|
||||||
|
|
||||||
// Exports
|
// Exports
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
@ -55,7 +56,6 @@ if (require.main === module) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
|
@ -260,13 +260,29 @@ function deploy(data) {
|
||||||
postDeployActions.forEach(fn => fn(data));
|
postDeployActions.forEach(fn => fn(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRemoteRefs(refOrPattern, remote = NG_REMOTE_URL) {
|
function getRemoteRefs(refOrPattern, {remote = NG_REMOTE_URL, retrieveFromCache = true} = {}) {
|
||||||
return exec(`git ls-remote ${remote} ${refOrPattern}`, {silent: true}).trim().split('\n');
|
// If remote refs for the same `refOrPattern` and `remote` have been requested before, return the
|
||||||
|
// cached results. This improves the performance and ensures a more stable behavior.
|
||||||
|
//
|
||||||
|
// NOTE:
|
||||||
|
// This shouldn't make any difference during normal execution (since there are no duplicate
|
||||||
|
// requests atm), but makes the tests more stable (for example, avoiding errors caused by pushing
|
||||||
|
// a new commit on a branch while the tests execute, which would cause `getLatestCommit()` to
|
||||||
|
// return a different value).
|
||||||
|
const cmd = `git ls-remote ${remote} ${refOrPattern}`;
|
||||||
|
const result = (retrieveFromCache && GIT_REMOTE_REFS_CACHE.has(cmd))
|
||||||
|
? GIT_REMOTE_REFS_CACHE.get(cmd)
|
||||||
|
: exec(cmd, {silent: true}).trim().split('\n');
|
||||||
|
|
||||||
|
// Cache the result for future use (regardless of the value of `retrieveFromCache`).
|
||||||
|
GIT_REMOTE_REFS_CACHE.set(cmd, result);
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getMostRecentMinorBranch(major = '*') {
|
function getMostRecentMinorBranch(major = '*', options = undefined) {
|
||||||
// List the branches that start with the given major version (or any major if none given).
|
// List the branches that start with the given major version (or any major if none given).
|
||||||
return getRemoteRefs(`refs/heads/${major}.*.x`)
|
return getRemoteRefs(`refs/heads/${major}.*.x`, options)
|
||||||
// Extract the branch name.
|
// Extract the branch name.
|
||||||
.map(line => line.split('/')[2])
|
.map(line => line.split('/')[2])
|
||||||
// Filter out branches that are not of the format `<number>.<number>.x`.
|
// Filter out branches that are not of the format `<number>.<number>.x`.
|
||||||
|
@ -281,8 +297,8 @@ function getMostRecentMinorBranch(major = '*') {
|
||||||
.pop();
|
.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getLatestCommit(branchName, remote = undefined) {
|
function getLatestCommit(branchName, options = undefined) {
|
||||||
return getRemoteRefs(branchName, remote)[0].slice(0, 40);
|
return getRemoteRefs(branchName, options)[0].slice(0, 40);
|
||||||
}
|
}
|
||||||
|
|
||||||
function redirectToAngularIo() {
|
function redirectToAngularIo() {
|
||||||
|
|
|
@ -388,13 +388,18 @@ describe('deploy-to-firebase:', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('integration - should run the main script without error', () => {
|
it('integration - should run the main script without error', () => {
|
||||||
|
// NOTE:
|
||||||
|
// This test executes a new instance of the `deploy-to-firebase.js` script on a separate process
|
||||||
|
// and thus does not share the `getRemoteRefs()` cache. To improve stability, we retrieve the
|
||||||
|
// latest commit from master ignoring any cached entries.
|
||||||
|
const latestCommitOnMaster = getLatestCommit('master', {retrieveFromCache: false});
|
||||||
const cmd = `"${process.execPath}" "${__dirname}/deploy-to-firebase" --dry-run`;
|
const cmd = `"${process.execPath}" "${__dirname}/deploy-to-firebase" --dry-run`;
|
||||||
const env = {
|
const env = {
|
||||||
CI_REPO_OWNER: 'angular',
|
CI_REPO_OWNER: 'angular',
|
||||||
CI_REPO_NAME: 'angular',
|
CI_REPO_NAME: 'angular',
|
||||||
CI_PULL_REQUEST: 'false',
|
CI_PULL_REQUEST: 'false',
|
||||||
CI_BRANCH: 'master',
|
CI_BRANCH: 'master',
|
||||||
CI_COMMIT: latestCommits.master,
|
CI_COMMIT: latestCommitOnMaster,
|
||||||
};
|
};
|
||||||
const result = execSync(cmd, {encoding: 'utf8', env}).trim();
|
const result = execSync(cmd, {encoding: 'utf8', env}).trim();
|
||||||
expect(result).toBe(
|
expect(result).toBe(
|
||||||
|
@ -405,7 +410,7 @@ describe('deploy-to-firebase:', () => {
|
||||||
'Deployment 1 of 1\n' +
|
'Deployment 1 of 1\n' +
|
||||||
'-----------------\n' +
|
'-----------------\n' +
|
||||||
'Git branch : master\n' +
|
'Git branch : master\n' +
|
||||||
`Git commit : ${latestCommits.master}\n` +
|
`Git commit : ${latestCommitOnMaster}\n` +
|
||||||
'Build/deploy mode : next\n' +
|
'Build/deploy mode : next\n' +
|
||||||
'Firebase project : angular-io\n' +
|
'Firebase project : angular-io\n' +
|
||||||
'Firebase site : next-angular-io-site\n' +
|
'Firebase site : next-angular-io-site\n' +
|
||||||
|
|
Loading…
Reference in New Issue