<commit_before>import {bold, cyan, green, italic, red, yellow} from 'chalk';
import {existsSync, readFileSync, writeFileSync} from 'fs';
import {prompt} from 'inquirer';
import {join} from 'path';
import {GitClient} from './git/git-client';
import {promptForNewVersion} from './prompt/new-version-prompt';
import {parseVersionName, Version} from './version-name/parse-version';
import {getExpectedPublishBranch} from './version-name/publish-branch';

/**
 * Class that can be instantiated in order to stage a new release. The tasks requires user
 * interaction/input through command line prompts.
 *
 * Staging a release involves the following the steps:
 *
 *  1) Prompt for release type (with version suggestion)
 *  2) Prompt for version name if no suggestions has been selected
 *  3) Assert that the proper publish branch is checked out (e.g. 6.4.x for patches)
 *  4) Assert that there are no local changes which are uncommitted.
 *  5) Assert that the local branch is up to date with the remote branch.
 *  6) Creates a new branch for the release staging (release-stage/{VERSION})
 *  7) Switches to the staging branch and updates the package.json
 *  8) Waits for the user to continue (users can generate the changelog in the meanwhile)
 *  9) Create a commit that includes all changes in the staging branch.
 */
class StageReleaseTask {

  /** Path to the project package JSON. */
  packageJsonPath: string;

  /** Serialized package.json of the specified project. */
  packageJson: any;

  /** Parsed current version of the project. */
  currentVersion: Version;

  /** Instance of a wrapper that can execute Git commands. */
  git: GitClient;

  constructor(public projectDir: string) {
    this.packageJsonPath = join(projectDir, 'package.json');

    console.log(this.projectDir);

    if (!existsSync(this.packageJsonPath)) {
      console.error(red(`The specified directory is not referring to a project directory. ` +
        `There must be a ${italic('package.json')} file in the project directory.`));
      process.exit(1);
    }

    this.packageJson = JSON.parse(readFileSync(this.packageJsonPath, 'utf-8'));
    this.currentVersion = parseVersionName(this.packageJson.version);

    if (!this.currentVersion) {
      console.error(red(`Cannot parse current version in ${italic('package.json')}. Please ` +
        `make sure "${this.packageJson.version}" is a valid Semver version.`));
      process.exit(1);
    }

    this.git = new GitClient(projectDir, this.packageJson.repository.url);
  }

  async run() {
    console.log();
    console.log(cyan('-----------------------------------------'));
    console.log(cyan('  Angular Material stage release script'));
    console.log(cyan('-----------------------------------------'));
    console.log();

    const newVersion = await promptForNewVersion(this.currentVersion);
    const expectedPublishBranch = getExpectedPublishBranch(newVersion);

    // After the prompt for the new version, we print a new line because we want the
    // new log messages to be more in the foreground.
    console.log();

    this.verifyPublishBranch(expectedPublishBranch);
    this.verifyLocalCommitsMatchUpstream(expectedPublishBranch);
    this.verifyNoUncommittedChanges();

    // TODO(devversion): Assert that GitHub statuses succeed for this branch.

    const newVersionName = newVersion.format();
    const stagingBranch = `release-stage/${newVersionName}`;

    if (!this.git.checkoutNewBranch(stagingBranch)) {
      console.error(red(`Could not create release staging branch: ${stagingBranch}. Aborting...`));
      process.exit(1);
    }

    this.updatePackageJsonVersion(newVersionName);

    console.log(green(`  ✓   Updated the version to "${bold(newVersionName)}" inside of the ` +
      `${italic('package.json')}`));

    // TODO(devversion): run changelog script w/prompts in the future.
    // For now, we just let users make modifications and stage the changes.

    console.log(yellow(`  ⚠   Please generate the ${bold('CHANGELOG')} for the new version. ` +
      `You can also make other unrelated modifications. After the changes have been made, ` +
      `just continue here.`));
    console.log();

    const {shouldContinue} = await prompt<{shouldContinue: boolean}>({
      type: 'confirm',
      name: 'shouldContinue',
      message: 'Do you want to proceed and commit the changes?'
    });

    if (!shouldContinue) {
      console.log();
      console.log(yellow('Aborting release staging...'));
      process.exit(1);
    }

    this.git.stageAllChanges();
    // this.git.createNewCommit(`chore: bump version to ${newVersionName} w/ changelog`);
<commit_msg>chore: stage release script should create commit (#13748)<commit_after>import {bold, cyan, green, italic, red, yellow} from 'chalk';
import {existsSync, readFileSync, writeFileSync} from 'fs';
import {prompt} from 'inquirer';
import {join} from 'path';
import {GitClient} from './git/git-client';
import {promptForNewVersion} from './prompt/new-version-prompt';
import {parseVersionName, Version} from './version-name/parse-version';
import {getExpectedPublishBranch} from './version-name/publish-branch';

/**
 * Class that can be instantiated in order to stage a new release. The tasks requires user
 * interaction/input through command line prompts.
 *
 * Staging a release involves the following the steps:
 *
 *  1) Prompt for release type (with version suggestion)
 *  2) Prompt for version name if no suggestions has been selected
 *  3) Assert that the proper publish branch is checked out (e.g. 6.4.x for patches)
 *  4) Assert that there are no local changes which are uncommitted.
 *  5) Assert that the local branch is up to date with the remote branch.
 *  6) Creates a new branch for the release staging (release-stage/{VERSION})
 *  7) Switches to the staging branch and updates the package.json
 *  8) Waits for the user to continue (users can generate the changelog in the meanwhile)
 *  9) Create a commit that includes all changes in the staging branch.
 */
class StageReleaseTask {

  /** Path to the project package JSON. */
  packageJsonPath: string;

  /** Serialized package.json of the specified project. */
  packageJson: any;

  /** Parsed current version of the project. */
  currentVersion: Version;

  /** Instance of a wrapper that can execute Git commands. */
  git: GitClient;

  constructor(public projectDir: string) {
    this.packageJsonPath = join(projectDir, 'package.json');

    console.log(this.projectDir);

    if (!existsSync(this.packageJsonPath)) {
      console.error(red(`The specified directory is not referring to a project directory. ` +
        `There must be a ${italic('package.json')} file in the project directory.`));
      process.exit(1);
    }

    this.packageJson = JSON.parse(readFileSync(this.packageJsonPath, 'utf-8'));
    this.currentVersion = parseVersionName(this.packageJson.version);

    if (!this.currentVersion) {
      console.error(red(`Cannot parse current version in ${italic('package.json')}. Please ` +
        `make sure "${this.packageJson.version}" is a valid Semver version.`));
      process.exit(1);
    }

    this.git = new GitClient(projectDir, this.packageJson.repository.url);
  }

  async run() {
    console.log();
    console.log(cyan('-----------------------------------------'));
    console.log(cyan('  Angular Material stage release script'));
    console.log(cyan('-----------------------------------------'));
    console.log();

    const newVersion = await promptForNewVersion(this.currentVersion);
    const expectedPublishBranch = getExpectedPublishBranch(newVersion);

    // After the prompt for the new version, we print a new line because we want the
    // new log messages to be more in the foreground.
    console.log();

    this.verifyPublishBranch(expectedPublishBranch);
    this.verifyLocalCommitsMatchUpstream(expectedPublishBranch);
    this.verifyNoUncommittedChanges();

    // TODO(devversion): Assert that GitHub statuses succeed for this branch.

    const newVersionName = newVersion.format();
    const stagingBranch = `release-stage/${newVersionName}`;

    if (!this.git.checkoutNewBranch(stagingBranch)) {
      console.error(red(`Could not create release staging branch: ${stagingBranch}. Aborting...`));
      process.exit(1);
    }

    this.updatePackageJsonVersion(newVersionName);

    console.log(green(`  ✓   Updated the version to "${bold(newVersionName)}" inside of the ` +
      `${italic('package.json')}`));

    // TODO(devversion): run changelog script w/prompts in the future.
    // For now, we just let users make modifications and stage the changes.

    console.log(yellow(`  ⚠   Please generate the ${bold('CHANGELOG')} for the new version. ` +
      `You can also make other unrelated modifications. After the changes have been made, ` +
      `just continue here.`));
    console.log();

    const {shouldContinue} = await prompt<{shouldContinue: boolean}>({
      type: 'confirm',
      name: 'shouldContinue',
      message: 'Do you want to proceed and commit the changes?'
    });

    if (!shouldContinue) {
      console.log();
      console.log(yellow('Aborting release staging...'));
      process.exit(1);
    }

    this.git.stageAllChanges();
    this.git.createNewCommit(`chore: bump version to ${newVersionName} w/ changelog`);

{'fraction_non_alphanumeric': 0.13122123514930964, 'fraction_numerical': 0.003960184095044418, 'mean_word_length': 3.4305357989568517, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5876071', 'n_tokens_mistral': 2614, 'n_tokens_neox': 2552, 'n_words': 877}