async function handler()

in ng-dev/misc/update-yarn/cli.ts [36:122]


async function handler() {
  /**
   * Process command that refers to the global Yarn installation.
   *
   * Note that we intend to use the global Yarn command here as this allows us to let Yarn
   * respect the `.yarnrc` file, allowing us to check if the update has completed properly.
   * Just using `yarn` does not necessarily resolve to the global Yarn version as Yarn-initiated
   * sub-processes will have a modified `process.env.PATH` that directly points to the Yarn
   * version that spawned the sub-process.
   */
  const yarnGlobalBin = (await getYarnPathFromNpmGlobalBinaries()) ?? '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(yarnGlobalBin, ['policies', 'set-version', 'latest']);

    spinner.update('Confirming the version of yarn was updated.');
    const newYarnVersion = spawnSync(yarnGlobalBin, ['-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);
  }
}