Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
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
2 changes: 1 addition & 1 deletion integration-tests/worker/test/exit-reasons.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -242,5 +242,5 @@ test('crash: process.exit() triggered by postgres', async (t) => {

t.is(reason, 'crash');
t.is(error_type, 'ExitError');
t.regex(error_message, /Process exited with code: 1/i);
t.regex(error_message, /Worker thread exited with code: 1/i);
});
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