copykitku/src/cli/replicate.ts
2021-02-26 00:58:36 +01:00

152 lines
4.8 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
}),
patchHook: flags.string({
description: 'node.js file to patch the patches',
}),
excludePath: flags.string({
description:
'files to exclude when applying a patch (as in git apply --exclude, but always after includes)',
multiple: true,
}),
includePath: flags.string({
description:
'files to include when applying a patch (as in git apply --include, but always before excludes)',
multiple: true,
}),
};
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,
patchHook,
includePath: includePaths,
excludePath: excludePaths,
} = { ...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,
patchHook,
remote,
targetBranch,
includePaths,
excludePaths,
});
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: {
const sourceCommit = await sourceRepo.getCommit(sourcePath.entityID);
const repl = await kitku.replicateCommits(sourceCommit, destRepo, {
destBranch:
destBranch ||
`${sourceRepo.repo.owner.username}/${sourceRepo.repo.name}/commit-${sourceCommit.id}`,
doNotCommit,
patchHook,
includePaths,
excludePaths,
});
if (repl) {
console.log('Replicated commit successfully');
}
break;
}
default: {
throw new Error('Unknown entity type');
}
}
}
}