copykitku/src/cli/replicate.ts
2021-02-24 01:27:03 +01:00

124 lines
4.1 KiB
TypeScript

import { Command, flags } from '@oclif/command';
import assert from 'assert';
import Copykitku from '../copykitku';
import { ENTITY_TYPE } from '../types';
import { getProjectConfig, parsePath } from '../utils';
export default class Replicate extends Command {
static description = 'Replicate issues/MRs between repositories';
static flags = {
help: flags.help({ char: 'h' }),
destBranch: flags.string({
description: 'name of the new branch (optional for MRs, required for commits)',
}),
doNotCommit: flags.boolean({
description: 'do not commit the applied changes (for MRs)',
allowNo: false,
}),
remote: flags.string({
description: 'git remote where the commits are pushed (for MRs)',
default: 'origin',
}),
targetBranch: flags.string({
description: 'branch to which the MR should target',
default: 'master', // TODO: check in the repository instead of taking a wild guess
}),
};
static args = [
{
name: 'source',
required: true,
description: 'the thing you want to replicate',
},
{
name: 'dest',
required: false,
description:
'where you want the thing to be replicated [required in either cli arg or .copykitkurc.toml file]',
},
];
async run() {
const { flags, args } = this.parse(Replicate);
const proj = getProjectConfig();
const { destBranch, doNotCommit, remote, targetBranch } = { ...proj, ...flags };
const { source, dest } = {
...proj,
// oclif does set undefined values for non-existant args
// so we have to filter out these values, or they will replace project config values
...(Object.keys(args)
.filter((ak) => args[ak])
.reduce((acc, curk) => {
acc[curk] = args[curk];
return acc;
}, {} as { [k: string]: string }) as {
source: string;
dest?: string;
}),
};
assert(typeof dest === 'string', 'Destination repository must be defined');
const sourcePath = parsePath(source);
const destPath = parsePath(dest);
assert(sourcePath.entityID, 'Source must be a repo element, not a repo itself');
const kitku = new Copykitku();
await kitku.initialize();
const sourceVendor = kitku.vendorManagers.find((v) => v.vendor.domain === sourcePath.domain);
assert(sourceVendor, 'Source vendor not found in config');
const destVendor = kitku.vendorManagers.find((v) => v.vendor.domain === destPath.domain);
assert(destVendor, 'Destination vendor not found in config');
const sourceRepo = await sourceVendor.getRepo(sourcePath.path);
const destRepo = await destVendor.getRepo(destPath.path);
switch (sourcePath.entity) {
case ENTITY_TYPE.ISSUE: {
const sourceIssue = await sourceRepo.getIssue(sourcePath.entityID);
const repl = await kitku.replicateIssue(sourceIssue, destRepo);
console.log(`Replicated successfully: ${repl.url}`);
break;
}
case ENTITY_TYPE.MERGE_REQUEST: {
const sourceMR = await sourceRepo.getMergeRequest(sourcePath.entityID);
const repl = await kitku.replicateMergeRequest(sourceMR, destRepo, {
destBranch,
doNotCommit,
remote,
targetBranch,
});
if (repl === true) {
// patches got applied to the branch, without pushing and creating a MR (due to --doNotCommit)
console.log('Replicated commits successfully');
} else {
// commits got pushed and a MR was created
console.log(`Replicated successfully: ${repl.url}`);
}
break;
}
case ENTITY_TYPE.COMMIT: {
// there's no way to get a single commit from repository yet
/*
const sourceCommit = await sourceRepo.getCommit(sourcePath.entityID);
const repl = await kitku.replicateCommits(sourceCommit, destRepo, {
destBranch,
doNotCommit,
});
*/
console.log('No commit replication yet, sorry');
break;
}
default: {
throw new Error('Unknown entity type');
}
}
}
}