Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions packages/cli/src/checkout/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ import { ensure, build } from '../util/command-builders';
import * as o from '../options';

export type CheckoutOptions = Required<
Pick<Opts, 'command' | 'projectName' | 'projectPath'>
Pick<Opts, 'command' | 'projectId' | 'projectPath'>
> &
Pick<Opts, 'log'>;

const options = [o.projectName, o.projectPath, o.log];
const options = [o.projectId, o.projectPath, o.log];

const checkoutCommand: yargs.CommandModule = {
command: 'checkout <project-name>',
command: 'checkout <project-id>',
describe: 'Switch to a different openfn project in the same workspace',
handler: ensure('checkout', options),
builder: (yargs) => build(options, yargs),
Expand Down
8 changes: 4 additions & 4 deletions packages/cli/src/checkout/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,20 @@ const checkoutHandler = async (options: CheckoutOptions, logger: Logger) => {

// get the project
let switchProject;
if (/\.(yaml|json)$/.test(options.projectName)) {
if (/\.(yaml|json)$/.test(options.projectId)) {
// TODO: should we allow checkout into an arbitrary folder?
const filePath = path.join(commandPath, options.projectName);
const filePath = path.join(commandPath, options.projectId);
logger.debug('Loading project from path ', filePath);
switchProject = await Project.from('path', filePath, {
config,
});
} else {
switchProject = workspace.get(options.projectName);
switchProject = workspace.get(options.projectId);
}

if (!switchProject) {
logger.error(
`Project with id/name ${options.projectName} not found in the workspace`
`Project with id/name ${options.projectId} not found in the workspace`
);
return;
}
Expand Down
11 changes: 5 additions & 6 deletions packages/cli/src/merge/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,16 @@ export type MergeOptions = Required<
Pick<
Opts,
| 'command'
| 'projectName'
| 'projectId'
| 'projectPath'
| 'removeUnmapped'
| 'workflowMappings'
| 'log'
| 'force'
>
>;
> &
Pick<Opts, 'log' | 'force'>;

const options = [
o.projectName,
o.projectId,
o.projectPath,
o.removeUnmapped,
o.workflowMappings,
Expand All @@ -28,7 +27,7 @@ const options = [
];

const mergeCommand: yargs.CommandModule = {
command: 'merge [project-name]',
command: 'merge <project-id>',
describe: 'Merges the specified project into the checked out project',
handler: ensure('merge', options),
builder: (yargs) => build(options, yargs),
Expand Down
20 changes: 10 additions & 10 deletions packages/cli/src/merge/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,29 +23,29 @@ const mergeHandler = async (options: MergeOptions, logger: Logger) => {

// Lookup the source project - the thing we are getting changes from
let sourceProject;
if (/\.(yaml|json)$/.test(options.projectName)) {
const filePath = path.join(commandPath, options.projectName);
if (/\.(yaml|json)$/.test(options.projectId)) {
const filePath = path.join(commandPath, options.projectId);
logger.debug('Loading source project from path ', filePath);
sourceProject = await Project.from('path', filePath);
} else {
sourceProject = workspace.get(options.projectName);
sourceProject = workspace.get(options.projectId);
}
if (!sourceProject) {
logger.error(`Project "${options.projectName}" not found in the workspace`);
logger.error(`Project "${options.projectId}" not found in the workspace`);
return;
}

if (targetProject.name === sourceProject.name) {
if (targetProject.id === sourceProject.id) {
logger.error('Merging into the same project not allowed');
return;
}

if (!targetProject.name) {
logger.error('The checked out project has no name/id');
if (!targetProject.id) {
logger.error('The checked out project has no id');
return;
}

const finalPath = workspace.getProjectPath(targetProject.name);
const finalPath = workspace.getProjectPath(targetProject.id);
if (!finalPath) {
logger.error('Path to checked out project not found.');
return;
Expand All @@ -64,13 +64,13 @@ const mergeHandler = async (options: MergeOptions, logger: Logger) => {
{
command: 'checkout',
projectPath: commandPath,
projectName: final.name || '',
projectId: final.id,
log: options.log,
},
logger
);
logger.success(
`Project ${sourceProject.name} has been merged into Project ${targetProject.name} successfully`
`Project ${sourceProject.id} has been merged into Project ${targetProject.id} successfully`
);
};

Expand Down
14 changes: 1 addition & 13 deletions packages/cli/src/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -336,19 +336,7 @@ const getBaseDir = (opts: { path?: string }) => {
export const projectId: CLIOption = {
name: 'project-id',
yargs: {
hidden: true,
},
ensure: (opts) => {
const projectId = opts.projectId;
//check that this is a uuid
return projectId;
},
};

export const projectName: CLIOption = {
name: 'project-name',
yargs: {
description: 'The name of an openfn project',
description: 'The id or UUID of an openfn project',
string: true,
},
ensure: (opts) => {
Expand Down
12 changes: 5 additions & 7 deletions packages/cli/src/projects/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,17 @@ const projectsHandler = async (options: ProjectsOptions, logger: Logger) => {

logger.success(`Available openfn projects\n\n${workspace
.list()
.map((p) => describeProject(p, p.name === workspace.activeProjectId))
.map((p) => describeProject(p, p.id === workspace.activeProjectId))
.join('\n\n')}
`);
};

function describeProject(project: Project, active = false) {
// @ts-ignore
const pId = project.openfn?.uuid;
return `${project.name} ${active ? '(active)' : ''}\n ${
pId || '<project-id>'
}\n workflows:\n${project.workflows
.map((w) => ' - ' + w.name)
.join('\n')}`;
const uuid = project.openfn?.uuid;
return `${project.id} ${active ? '(active)' : ''}\n ${
uuid || '<project-id>'
}\n workflows:\n${project.workflows.map((w) => ' - ' + w.id).join('\n')}`;
}

export default projectsHandler;
15 changes: 2 additions & 13 deletions packages/cli/src/version/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,11 @@ import * as o from '../options';
export type VersionOptions = Required<
Pick<
Opts,
| 'command'
| 'workflow'
| 'projectName'
| 'projectPath'
| 'workflowMappings'
| 'json'
'command' | 'workflow' | 'projectPath' | 'workflowMappings' | 'json'
>
>;

const options = [
o.workflow,
o.projectName,
o.projectPath,
o.workflowMappings,
o.json,
];
const options = [o.workflow, o.projectPath, o.workflowMappings, o.json];

const workflowVersionCommand: yargs.CommandModule = {
command: 'project version [workflow]',
Expand Down
81 changes: 39 additions & 42 deletions packages/cli/test/checkout/handler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,21 @@ test.beforeEach(() => {
mock({
'/ws/workflows': {},
'/ws/openfn.yaml': jsonToYaml({
name: 'some-project-name',
workflowRoot: 'workflows',
formats: {
openfn: 'yaml',
project: 'yaml',
workflow: 'yaml',
project: {
id: 'my-project',
},
workspace: {
workflowRoot: 'workflows',
formats: {
openfn: 'yaml',
project: 'yaml',
workflow: 'yaml',
},
},
}),
'/ws/.projects/staging@app.openfn.org.yaml': jsonToYaml({
id: 'some-id',
name: 'some-project-name',
id: '<uuid:staging>>',
name: 'My Staging',
workflows: [
{
name: 'simple-workflow',
Expand Down Expand Up @@ -80,8 +84,8 @@ test.beforeEach(() => {
],
}),
'/ws/.projects/project@app.openfn.org.yaml': jsonToYaml({
id: 'main-id',
name: 'main-project-id',
id: '<uuid:main>',
name: 'My Project',
workflows: [
{
name: 'simple-workflow-main',
Expand Down Expand Up @@ -149,35 +153,33 @@ const logger = createMockLogger('', { level: 'debug' });
test.serial('get active project', (t) => {
const workspace = new Workspace('/ws');
t.is(workspace.valid, true);
t.is(workspace.activeProjectId, 'some-project-name');
t.is(workspace.activeProjectId, 'my-project');
});

test.serial('checkout: invalid project id', (t) => {
checkoutHandler(
{ command: 'checkout', projectName: 'not-known', projectPath: '/ws' },
{ command: 'checkout', projectId: 'not-known', projectPath: '/ws' },
logger
);
const { message } = logger._parse(logger._last);
t.is(message, 'Project with id/name not-known not found in the workspace');
});

test.serial('checkout: to a different valid project', async (t) => {
// before checkout. some-project-name is active and expanded
// before checkout. my-project is active and expanded
const bcheckout = new Workspace('/ws');
t.is(bcheckout.projectMeta.name, 'some-project-name');
t.is(bcheckout.getActiveProject()?.name, 'some-project-name');
t.is(bcheckout.activeProject.id, 'my-project');

await checkoutHandler(
{ command: 'checkout', projectName: 'main-project-id', projectPath: '/ws' },
{ command: 'checkout', projectId: 'my-project', projectPath: '/ws' },
logger
);
const { message } = logger._parse(logger._last);
t.is(message, 'Expanded project to /ws');

// after checkout. main-project-id is active and expanded
// after checkout. my-project is active and expanded
const acheckout = new Workspace('/ws');
t.is(acheckout.projectMeta.name, 'main-project-id');
t.is(acheckout.getActiveProject()?.name, 'main-project-id');
t.is(acheckout.activeProject.id, 'my-project');

// check if files where well expanded
t.deepEqual(
Expand All @@ -187,79 +189,74 @@ test.serial('checkout: to a different valid project', async (t) => {
});

test.serial('checkout: same id as active', async (t) => {
// before checkout. some-project-name is active and expanded
// before checkout. my-project is active and expanded
const bcheckout = new Workspace('/ws');
t.is(bcheckout.projectMeta.name, 'some-project-name');
t.is(bcheckout.getActiveProject()?.name, 'some-project-name');
t.is(bcheckout.activeProject.id, 'my-project');

await checkoutHandler(
{
command: 'checkout',
projectName: 'some-project-name',
projectId: 'my-project',
projectPath: '/ws',
},
logger
);
const { message } = logger._parse(logger._last);
t.is(message, 'Expanded project to /ws');

// after checkout. main-project-id is active and expanded
// after checkout. my-project is active and expanded
const acheckout = new Workspace('/ws');
t.is(acheckout.projectMeta.name, 'some-project-name');
t.is(acheckout.getActiveProject()?.name, 'some-project-name');
t.is(acheckout.activeProject.id, 'my-project');

// check if files where well expanded
t.deepEqual(
fs.readdirSync('/ws/workflows').sort(),
['simple-workflow', 'another-workflow'].sort()
['simple-workflow-main', 'another-workflow-main'].sort()
);
});

test.serial('checkout: switching to and back between projects', async (t) => {
// before checkout. some-project-name is active and expanded
// before checkout. my-project is active and expanded
const bcheckout = new Workspace('/ws');
t.is(bcheckout.projectMeta.name, 'some-project-name');
t.is(bcheckout.getActiveProject()?.name, 'some-project-name');
t.is(bcheckout.activeProject.id, 'my-project');

// 1. switch from some-project-name to main-project-id
// 1. switch from my-project to my-staging
await checkoutHandler(
{ command: 'checkout', projectName: 'main-project-id', projectPath: '/ws' },
{ command: 'checkout', projectId: 'my-staging', projectPath: '/ws' },
logger
);
const { message } = logger._parse(logger._last);
t.is(message, 'Expanded project to /ws');

// after checkout. main-project-id is active and expanded
// after checkout. my-staging is active and expanded
const acheckout = new Workspace('/ws');
t.is(acheckout.projectMeta.name, 'main-project-id');
t.is(acheckout.getActiveProject()?.name, 'main-project-id');
t.is(acheckout.activeProject.id, 'my-staging');

// check if files where well expanded
t.deepEqual(
fs.readdirSync('/ws/workflows').sort(),
['simple-workflow-main', 'another-workflow-main'].sort()
['simple-workflow', 'another-workflow'].sort()
);

// 2. switch back from main-project-id to some-project-name
// 2. switch back from my-project to my-project
await checkoutHandler(
{
command: 'checkout',
projectName: 'some-project-name',
projectId: 'my-project',
projectPath: '/ws',
},
logger
);
const { message: lastMsg } = logger._parse(logger._last);
t.is(lastMsg, 'Expanded project to /ws');

// after checkout. main-project-id is active and expanded
// after checkout. my-project is active and expanded
const fcheckout = new Workspace('/ws');
t.is(fcheckout.projectMeta.name, 'some-project-name');
t.is(fcheckout.getActiveProject()?.name, 'some-project-name');
t.is(fcheckout.activeProject.id, 'my-project');

// check if files where well expanded
t.deepEqual(
fs.readdirSync('/ws/workflows').sort(),
['simple-workflow', 'another-workflow'].sort()
['simple-workflow-main', 'another-workflow-main'].sort()
);
});
Loading