ForestAdmin/toolbelt

View on GitHub
src/commands/switch.js

Summary

Maintainability
C
1 day
Test Coverage
A
94%
const { Flags, Args } = require('@oclif/core');
const AbstractAuthenticatedCommand = require('../abstract-authenticated-command').default;
const BranchManager = require('../services/branch-manager');
const ProjectManager = require('../services/project-manager');
const withCurrentProject = require('../services/with-current-project');

class SwitchCommand extends AbstractAuthenticatedCommand {
  constructor(argv, config, plan) {
    super(argv, config, plan);
    const { assertPresent, env, inquirer } = this.context;
    assertPresent({ env, inquirer });
    this.env = env;
    this.inquirer = inquirer;
  }

  async selectBranch(branches) {
    try {
      const { branch } = await this.inquirer.prompt([
        {
          name: 'branch',
          message: 'Select the branch you want to set current',
          type: 'list',
          choices: [
            // NOTICE: Current branch should be last displayed branch.
            ...branches.filter(currentBranch => !currentBranch.isCurrent),
            ...branches.filter(currentBranch => currentBranch.isCurrent),
          ].map(currentBranch => currentBranch.name),
        },
      ]);

      return branch;
    } catch (error) {
      const customError = await BranchManager.handleBranchError(error);

      this.logger.error(customError);
      return null;
    }
  }

  async switchTo(selectedBranch, environmentSecret) {
    try {
      await BranchManager.switchBranch(selectedBranch, environmentSecret);

      this.logger.success(`Switched to branch: ${selectedBranch.name}.`);
    } catch (error) {
      const customError = await BranchManager.handleBranchError(error);

      this.logger.error(customError);
      this.exit(2);
    }
  }

  async getConfig() {
    const envSecret = this.env.FOREST_ENV_SECRET;
    const parsed = await this.parse(SwitchCommand);
    const commandOptions = { ...parsed.flags, ...parsed.args, envSecret };

    const config = await withCurrentProject({ ...this.env, ...commandOptions });

    if (!config.envSecret) {
      const environment = await new ProjectManager(config).getDevelopmentEnvironmentForUser(
        config.projectId,
      );
      config.envSecret = environment.secretKey;
    }

    return config;
  }

  async runAuthenticated() {
    try {
      const config = await this.getConfig();
      const branches = (await BranchManager.getBranches(config.envSecret)) || [];

      if (branches.length === 0) {
        this.logger.warn(
          "You don't have any branch to set as current. Use `forest branch <branch_name>` to create one.",
        );
        return;
      }

      const selectedBranchName = config.BRANCH_NAME || (await this.selectBranch(branches));
      if (!selectedBranchName) {
        this.exit(2);
      }

      const selectedBranch = branches.find(branch => branch.name === selectedBranchName);
      const currentBranch = branches.find(branch => branch.isCurrent);

      if (selectedBranch === undefined) {
        throw new Error('Branch does not exist.');
      }

      if (currentBranch && currentBranch.name === selectedBranchName) {
        this.logger.info(`${selectedBranchName} is already your current branch.`);
      } else {
        await this.switchTo(selectedBranch, config.envSecret);
      }
    } catch (error) {
      const customError = await BranchManager.handleBranchError(error);
      this.logger.error(customError);
      this.exit(2);
    }
  }
}

SwitchCommand.aliases = ['branches:switch'];

SwitchCommand.description = 'Switch to another branch in your local development environment.';

SwitchCommand.flags = {
  help: Flags.boolean({
    description: 'Display usage information.',
  }),
};

SwitchCommand.args = {
  BRANCH_NAME: Args.string({
    name: 'BRANCH_NAME',
    required: false,
    description: 'The name of the local branch to set as current.',
  }),
};

SwitchCommand.aliases = ['branch:switch'];

module.exports = SwitchCommand;