Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
gkalpak committed Aug 28, 2024
1 parent db7ebf2 commit 1cb7301
Show file tree
Hide file tree
Showing 5 changed files with 589 additions and 650 deletions.
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,13 @@ Things I want to (but won't necessarily) do:
- Installing the latest Node.js version on a branch. E.g. `nvi 8` would:
- Install the latest 8.x version.
- Install packages (either via `naga` or by looking at the highest installed version).

- TODO:
- Investigate the failed nua update (probably do manually and skip `eslint`).
- Investigate whether the 10.x `inquirer` update is breaking.
- Check whether overriding `watch > exec-sh` to v0.4.0 works.
- Break up new changes into commits.
- Add tests where needed.
- Publish and test new version.

[build-status]: https://github.com/gkalpak/aliases/actions/workflows/ci.yml
[build-status-image]: https://github.com/gkalpak/aliases/actions/workflows/ci.yml/badge.svg?branch=master&event=push
Expand Down
96 changes: 52 additions & 44 deletions lib/alias-scripts/g-pick-branch.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ import {importWithEnv} from '../utils.js';


// Constants
const branchNameSuffices = {
'': '',
'*': ' (current)',
'+': ' (other worktree)',
};
const internal = {
_gPickBranch,
};
Expand All @@ -15,12 +20,16 @@ export {
* @function gPickBranch
*
* @description
* Prompt the user to pick one of the available git branches via an interactive list.
* Prompt the user to pick one of the available git branches via an interactive list. By default, local branches are
* shown, but this can be optionally switched to remote branches only. Supported runtime arguments:
* - `--remote` [flag]: Only show remote branches when present (otherwise only show local branches).
*
* @param {string[]} [runtimeArgs=[]] - The runtime arguments.
* @param {IRunConfig} [config={}] - A configuration object. See {@link commandUtils#IRunConfig} for more details.
*
* @return {Promise<void|string>} - A promise that resolves to either `undefined` or the selected branch (depending on
* the value of `config.returnOutput`).
* the value of `config.returnOutput`). When switched to remote branches only the selected branch consists of the
* remote name, followed by a space, followed by the actual branch name (for example, `origin some-branch`).
*/
gPickBranch,

Expand All @@ -31,16 +40,18 @@ export {
};

// Helpers
async function _gPickBranch(config) {
async function _gPickBranch(runtimeArgs = [], config = {}) {
const gbConfig = Object.assign({}, config, {returnOutput: true});
const branchType = runtimeArgs.includes('--remote') ? 'remote' : 'local';

if (config.dryrun) {
console.log('Pick one from a list of branches.');
console.log(`Pick one from a list of ${branchType} branches.`);
return;
}

const branchOutput = await commandUtils.run('git branch', [], gbConfig);
const branch = await pickBranch(branchOutput);
const branchOutput = await commandUtils.run('git branch --all', [], gbConfig);
const branches = processBranches(branchOutput).filter(({remote}) => remote === (branchType === 'remote'));
const branch = await pickBranch(branchType, branches);

if (config.returnOutput) {
return branch;
Expand All @@ -49,49 +60,19 @@ async function _gPickBranch(config) {
console.log(branch);
}

function gPickBranch(config) {
return internal._gPickBranch(config);
function gPickBranch(runtimeArgs, config) {
return internal._gPickBranch(runtimeArgs, config);
}

function main(_runtimeArgs, config) {
return gPickBranch(config);
function main(runtimeArgs, config) {
return gPickBranch(runtimeArgs, config);
}

async function pickBranch(branchesStr) {
async function pickBranch(branchType, branches) {
// Ensure colors are always used (even when running with `returnOutput: <number>`).
const {default: inquirer} = await importWithEnv(() => import('inquirer'), {FORCE_COLOR: '1'});

let currentBranchIdx = 0;
const branches = branchesStr.
split('\n').
map(line => line.trim()).
filter(Boolean).
map((branch, i) => {
const [, specialSymbol = '', branchName] = /^(?:([*+])\s*)?(\S.*)$/.exec(branch);
let displayName = branchName.replace(/^(gcoghpr)-(.*)$/, '[$1] $2');

switch (specialSymbol) {
case '':
break;
case '*':
currentBranchIdx = i;
displayName += ' (current)';
break;
case '+':
displayName += ' (other worktree)';
break;
default:
throw new Error(`Unexpected branch prefix symbol: ${specialSymbol}`);
}

return {
name: displayName,
value: branchName,
short: branchName,
};
}).
sort((a, b) => (a.name > b.name) ? 1 : -1).
concat(new inquirer.Separator());
const currentBranchIdx = branches.findIndex(({name}) => name.endsWith(branchNameSuffices['*']));

const unlisten = processUtils.doOnExit(process, code => {
if (code === 0) {
Expand All @@ -107,8 +88,8 @@ async function pickBranch(branchesStr) {
{
type: 'list',
name: 'branch',
message: 'Pick a branch:',
choices: branches,
message: `Pick a ${branchType} branch:`,
choices: branches.concat(new inquirer.Separator()),
default: currentBranchIdx,
},
]);
Expand All @@ -118,3 +99,30 @@ async function pickBranch(branchesStr) {
unlisten();
}
}

function processBranches(branchesStr) {
return branchesStr.
split('\n').
map(line => line.trim()).
// Filter out empty lines and `HEAD` "aliases".
filter(line => (line.length > 0) && !line.includes('/HEAD -> ')).
map(branch => {
const [, specialSymbol = '', remote = false, branchName] = /^(?:([*+])\s*)?(remotes\/)?(\S.*)$/.exec(branch);
const branchNameSuffix = branchNameSuffices[specialSymbol];

if (branchNameSuffix === undefined) {
throw new Error(`Unexpected branch prefix symbol: ${specialSymbol}`);
}

const displayName = branchName.replace(/^(gcoghpr)-(.*)$/, '[$1] $2') + branchNameSuffix;
const isRemote = remote !== false;

return {
name: displayName,
short: branchName,
value: isRemote ? branchName.replace('/', ' ') : branchName,
remote: isRemote,
};
}).
sort((a, b) => (a.name > b.name) ? 1 : -1);
}
8 changes: 7 additions & 1 deletion lib/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ const DESC_REPLACEMENTS = {
[AliasUnknown.DESCRIPTION]: '???',
'::gdefb': '<default-branch>',
'::__a-builds-dir': '(<.../angular/aio/aio-builds-setup>)',
'::__g-pick-branch --gkcu-returnOutput=1': '(interactively pick a branch)',
'::__g-pick-branch --gkcu-returnOutput=1': '(interactively pick a local branch)',
'::__g-pick-branch --remote --gkcu-returnOutput=1': '(interactively pick a remote branch)',
'::__g-pick-commit --gkcu-returnOutput=1': '(interactively pick a commit)',
'::__g-pick-commit --filter-commits="$1" --gkcu-returnOutput=1': '(interactively pick a filtered commit)',
};
Expand Down Expand Up @@ -314,10 +315,15 @@ const ALIASES = {

// BRANCH
gb: new AliasDefault('git branch $*'),
gba: new AliasDefault('git branch --all $*'),
gbc: new AliasDefault(GIT_CREATE_BRANCH_CMD('${2:HEAD}')),
gbcd: new AliasDefault(GIT_CREATE_BRANCH_CMD('${0:::gdefb}')),
gbco: new AliasDefault(`git fetch origin $1 && ${GIT_CREATE_BRANCH_CMD('origin/$1')}`),
gbd: new AliasDefault('git branch --delete --force ${*:::__g-pick-branch --gkcu-returnOutput=1}'),
gbdr: new AliasDefault('git push --delete ${*:::__g-pick-branch --remote --gkcu-returnOutput=1}'),
gbdio: new AliasDefault(
'git branch --delete --force ${1:::__g-pick-branch --gkcu-returnOutput=1} && ' +
'git push --delete origin ${1:::__g-pick-branch --gkcu-returnOutput=1}'),

// PULL(-REBASE)
gpr: new AliasDefault('git pull --rebase $*'),
Expand Down
Loading

0 comments on commit 1cb7301

Please sign in to comment.