Skip to content

Commit

Permalink
feat(ng-dev): add tooling to update vendored yarn version
Browse files Browse the repository at this point in the history
  • Loading branch information
josephperrott authored and devversion committed Nov 25, 2021
1 parent c05814d commit 30c518d
Show file tree
Hide file tree
Showing 6 changed files with 213 additions and 42 deletions.
42 changes: 42 additions & 0 deletions github-actions/slash-commands/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -51666,12 +51666,40 @@ Ran at: ${now}
}
});

// ng-dev/utils/git/graphql-queries.js
var require_graphql_queries = __commonJS({
"ng-dev/utils/git/graphql-queries.js"(exports2) {
"use strict";
Object.defineProperty(exports2, "__esModule", { value: true });
exports2.findOwnedForksOfRepoQuery = void 0;
var typed_graphqlify_1 = require_dist();
exports2.findOwnedForksOfRepoQuery = (0, typed_graphqlify_1.params)({
$owner: "String!",
$name: "String!"
}, {
repository: (0, typed_graphqlify_1.params)({ owner: "$owner", name: "$name" }, {
forks: (0, typed_graphqlify_1.params)({ affiliations: "OWNER", first: 1 }, {
nodes: [
{
owner: {
login: typed_graphqlify_1.types.string
},
name: typed_graphqlify_1.types.string
}
]
})
})
});
}
});

// ng-dev/utils/git/authenticated-git-client.js
var require_authenticated_git_client = __commonJS({
"ng-dev/utils/git/authenticated-git-client.js"(exports2) {
"use strict";
Object.defineProperty(exports2, "__esModule", { value: true });
exports2.AuthenticatedGitClient = void 0;
var graphql_queries_1 = require_graphql_queries();
var console_1 = require_console();
var git_client_1 = require_git_client();
var github_12 = require_github2();
Expand All @@ -51682,6 +51710,7 @@ var require_authenticated_git_client = __commonJS({
this.githubToken = githubToken;
this._githubTokenRegex = new RegExp(this.githubToken, "g");
this._cachedOauthScopes = null;
this._cachedForkRepo = null;
this.github = new github_12.AuthenticatedGithubClient(this.githubToken);
}
sanitizeConsoleOutput(value) {
Expand All @@ -51706,6 +51735,19 @@ Alternatively, a new token can be created at: ${github_urls_1.GITHUB_TOKEN_GENER
`;
return { error };
}
async getForkOfAuthenticatedUser() {
if (this._cachedForkRepo !== null) {
return this._cachedForkRepo;
}
const { owner, name } = this.remoteConfig;
const result = await this.github.graphql(graphql_queries_1.findOwnedForksOfRepoQuery, { owner, name });
const forks = result.repository.forks.nodes;
if (forks.length === 0) {
throw Error(`Unable to find fork for currently authenticated user. Please ensure you created a fork of: ${owner}/${name}.`);
}
const fork = forks[0];
return this._cachedForkRepo = { owner: fork.owner.login, name: fork.name };
}
_fetchAuthScopesForToken() {
if (this._cachedOauthScopes !== null) {
return this._cachedOauthScopes;
Expand Down
7 changes: 6 additions & 1 deletion ng-dev/misc/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,13 @@
import * as yargs from 'yargs';

import {BuildAndLinkCommandModule} from './build-and-link/cli';
import {UpdateYarnCommandModule} from './update-yarn/cli';

/** Build the parser for the misc commands. */
export function buildMiscParser(localYargs: yargs.Argv) {
return localYargs.help().strict().command(BuildAndLinkCommandModule);
return localYargs
.help()
.strict()
.command(BuildAndLinkCommandModule)
.command(UpdateYarnCommandModule);
}
123 changes: 123 additions & 0 deletions ng-dev/misc/update-yarn/cli.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

import {readdirSync, unlinkSync} from 'fs';
import {join} from 'path';
import {Argv, CommandModule} from 'yargs';
import {spawnSync} from '../../utils/child-process';

import {error, info, red} from '../../utils/console';
import {Spinner} from '../../utils/spinner';
import {AuthenticatedGitClient} from '../../utils/git/authenticated-git-client';
import {addGithubTokenOption} from '../../utils/git/github-yargs';

async function builder(yargs: Argv) {
return addGithubTokenOption(yargs);
}

/** Environment object enabling the usage of yarn-path to determine the new version. */
const useYarnPathEnv = {
...process.env,
YARN_IGNORE_PATH: '0',
};

/** Environment object to prevent running husky workflow. */
const skipHuskyEnv = {
...process.env,
HUSKY: '0',
};

async function handler() {
/** Directory where node binary are globally installed. */
const npmBinDir = spawnSync('npm', ['bin', '--global', 'yarn']).stdout.trim();
/** The full path to the globally installed yarn binary. */
const yarnBin = `${npmBinDir}/yarn`;
/** Instance of the local git client. */
const git = AuthenticatedGitClient.get();
/** The main branch name of the repository. */
const mainBranchName = git.mainBranchName;
/** The original branch or ref before the command was invoked. */
const originalBranchOrRef = git.getCurrentBranchOrRevision();

if (git.hasUncommittedChanges()) {
error(red('Found changes in the local repository. Make sure there are no uncommitted files.'));
process.exitCode = 1;
return;
}

/** A spinner instance. */
const spinner = new Spinner('');
try {
spinner.update(`Fetching the latest primary branch from upstream: "${mainBranchName}"`);
git.run(['fetch', '-q', git.getRepoGitUrl(), mainBranchName]);
git.checkout('FETCH_HEAD', false);

spinner.update('Removing previous yarn version.');
const yarnReleasesDir = join(git.baseDir, '.yarn/releases');
readdirSync(yarnReleasesDir).forEach((file) => unlinkSync(join(yarnReleasesDir, file)));

spinner.update('Updating yarn version.');
spawnSync(yarnBin, ['policies', 'set-version', 'latest']);

spinner.update('Confirming the version of yarn was updated.');
const newYarnVersion = spawnSync(yarnBin, ['-v'], {env: useYarnPathEnv}).stdout.trim();
if (git.run(['status', '--porcelain']).stdout.length === 0) {
spinner.complete();
error(red('Yarn already up to date'));
process.exitCode = 0;
return;
}
/** The title for the PR. */
const title = `build: update to yarn v${newYarnVersion}`;
/** The body for the PR. */
const body = `Update to the latest version of yarn, ${newYarnVersion}.`;
/** The commit message for the change. */
const commitMessage = `${title}\n\n${body}`;
/** The name of the branch to use on remote. */
const branchName = `yarn-update-v${newYarnVersion}`;
/** The name of the owner for remote branch on Github. */
const {owner: localOwner} = await git.getForkOfAuthenticatedUser();

spinner.update('Staging yarn vendoring files and creating commit');
git.run(['add', '.yarn/releases/**', '.yarnrc']);
git.run(['commit', '-q', '--no-verify', '-m', commitMessage], {env: skipHuskyEnv});

spinner.update('Pushing commit changes to github.');
git.run(['push', '-q', 'origin', '--force-with-lease', `HEAD:refs/heads/${branchName}`]);

spinner.update('Creating a PR for the changes.');
const {number} = (
await git.github.pulls.create({
...git.remoteParams,
title,
body,
base: mainBranchName,
head: `${localOwner}:${branchName}`,
})
).data;

spinner.complete();
info(`Created PR #${number} to update to yarn v${newYarnVersion}`);
} catch (e) {
spinner.complete();
error(red('Aborted yarn update do to errors:'));
error(e);
process.exitCode = 1;
git.checkout(originalBranchOrRef, true);
} finally {
git.checkout(originalBranchOrRef, true);
}
}

/** CLI command module. */
export const UpdateYarnCommandModule: CommandModule = {
builder,
handler,
command: 'update-yarn',
describe: 'Automatically update the vendored yarn version in the repository and create a PR',
};
1 change: 0 additions & 1 deletion ng-dev/release/publish/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import {FatalReleaseActionError, UserAbortedReleaseActionError} from './actions-
import {getCommitMessageForRelease, getReleaseNoteCherryPickCommitMessage} from './commit-message';
import {githubReleaseBodyLimit, waitForPullRequestInterval} from './constants';
import {invokeReleaseBuildCommand, invokeYarnInstallCommand} from './external-commands';
import {findOwnedForksOfRepoQuery} from './graphql-queries';
import {getPullRequestState} from './pull-request-state';
import {getReleaseTagForVersion} from '../versioning/version-tags';
import {GithubApiRequestError} from '../../utils/git/github';
Expand Down
40 changes: 0 additions & 40 deletions ng-dev/release/publish/graphql-queries.ts

This file was deleted.

42 changes: 42 additions & 0 deletions tools/local-actions/changelog/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -52454,12 +52454,40 @@ var require_release_notes = __commonJS({
}
});

// ng-dev/utils/git/graphql-queries.js
var require_graphql_queries = __commonJS({
"ng-dev/utils/git/graphql-queries.js"(exports2) {
"use strict";
Object.defineProperty(exports2, "__esModule", { value: true });
exports2.findOwnedForksOfRepoQuery = void 0;
var typed_graphqlify_1 = require_dist();
exports2.findOwnedForksOfRepoQuery = (0, typed_graphqlify_1.params)({
$owner: "String!",
$name: "String!"
}, {
repository: (0, typed_graphqlify_1.params)({ owner: "$owner", name: "$name" }, {
forks: (0, typed_graphqlify_1.params)({ affiliations: "OWNER", first: 1 }, {
nodes: [
{
owner: {
login: typed_graphqlify_1.types.string
},
name: typed_graphqlify_1.types.string
}
]
})
})
});
}
});

// ng-dev/utils/git/authenticated-git-client.js
var require_authenticated_git_client = __commonJS({
"ng-dev/utils/git/authenticated-git-client.js"(exports2) {
"use strict";
Object.defineProperty(exports2, "__esModule", { value: true });
exports2.AuthenticatedGitClient = void 0;
var graphql_queries_1 = require_graphql_queries();
var console_1 = require_console();
var git_client_1 = require_git_client();
var github_12 = require_github2();
Expand All @@ -52470,6 +52498,7 @@ var require_authenticated_git_client = __commonJS({
this.githubToken = githubToken;
this._githubTokenRegex = new RegExp(this.githubToken, "g");
this._cachedOauthScopes = null;
this._cachedForkRepo = null;
this.github = new github_12.AuthenticatedGithubClient(this.githubToken);
}
sanitizeConsoleOutput(value) {
Expand All @@ -52494,6 +52523,19 @@ Alternatively, a new token can be created at: ${github_urls_1.GITHUB_TOKEN_GENER
`;
return { error };
}
async getForkOfAuthenticatedUser() {
if (this._cachedForkRepo !== null) {
return this._cachedForkRepo;
}
const { owner, name } = this.remoteConfig;
const result = await this.github.graphql(graphql_queries_1.findOwnedForksOfRepoQuery, { owner, name });
const forks = result.repository.forks.nodes;
if (forks.length === 0) {
throw Error(`Unable to find fork for currently authenticated user. Please ensure you created a fork of: ${owner}/${name}.`);
}
const fork = forks[0];
return this._cachedForkRepo = { owner: fork.owner.login, name: fork.name };
}
_fetchAuthScopesForToken() {
if (this._cachedOauthScopes !== null) {
return this._cachedOauthScopes;
Expand Down

0 comments on commit 30c518d

Please sign in to comment.