Skip to content
Closed
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
2 changes: 2 additions & 0 deletions packages/cli/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import projectsCommand from './projects/command';
import checkoutCommand from './checkout/command';
import mergeCommand from './merge/command';
import workflowVersionCommand from './version/command';
import fetchCommand from './fetch/command';

const y = yargs(hideBin(process.argv));

Expand All @@ -37,6 +38,7 @@ export const cmd = y
.command(projectsCommand)
.command(checkoutCommand)
.command(mergeCommand)
.command(fetchCommand as any)
.command(workflowVersionCommand)
.command({
command: 'version',
Expand Down
3 changes: 3 additions & 0 deletions packages/cli/src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import projects from './projects/handler';
import workflowVersion from './version/handler';
import checkout from './checkout/handler';
import merge from './merge/handler';
import fetchHandler from './fetch/handler';
import { clean, install, pwd, list } from './repo/handler';

import createLogger, { CLI, Logger } from './util/logger';
Expand All @@ -34,6 +35,7 @@ export type CommandList =
| 'execute'
| 'metadata'
| 'pull'
| 'fetch'
| 'projects'
| 'checkout'
| 'merge'
Expand All @@ -55,6 +57,7 @@ const handlers = {
docs,
metadata,
pull,
fetch: fetchHandler,
projects,
checkout,
merge,
Expand Down
57 changes: 57 additions & 0 deletions packages/cli/src/fetch/command.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import yargs from 'yargs';
import { build, ensure, override } from '../util/command-builders';
import { Opts } from '../options';
import * as o from '../options';

export type FetchOptions = Required<
Pick<
Opts,
| 'beta'
| 'command'
| 'log'
| 'logJson'
| 'statePath'
| 'projectPath'
| 'configPath'
| 'projectId'
| 'confirm'
| 'snapshots'
>
>;

const options = [
o.apikey,
o.beta,
o.beta,
o.configPath,
o.endpoint,
o.env,
o.log,
override(o.path, {
description: 'path to output the project to',
}),
o.logJson,
o.projectPath,
o.snapshots,
o.statePath,
o.path,
];

const fetchCommand: yargs.CommandModule<FetchOptions> = {
command: 'fetch [projectId]',
describe: `Fetch a project's state and spec from a Lightning Instance to the local state file without expanding to the filesystem.`,
builder: (yargs: yargs.Argv<FetchOptions>) =>
build(options, yargs)
.positional('projectId', {
describe:
'The id of the project that should be fetched, should be a UUID',
demandOption: true,
})
.example(
'fetch 57862287-23e6-4650-8d79-e1dd88b24b1c',
'Fetch an updated copy of a the above spec and state from a Lightning Instance'
),
handler: ensure('fetch', options),
};

export default fetchCommand;
80 changes: 80 additions & 0 deletions packages/cli/src/fetch/handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { DeployConfig, getProject } from '@openfn/deploy';
import Project from '@openfn/project';
import fs from 'node:fs/promises';
import path from 'path';
import { Opts } from '../options';
import type { Logger } from '../util/logger';

type Config = {
endpoint: string;
apiKey: string | null;

requireConfirmation?: boolean;
dryRun?: boolean;
};

export type FetchOptions = Required<
Pick<
Opts,
| 'apiKey'
| 'beta'
| 'command'
| 'confirm'
| 'endpoint'
| 'env'
| 'log'
| 'logJson'
| 'path'
| 'projectId'
>
>;

export default async function fetchHandler(
options: FetchOptions,
logger: Logger
) {
const { OPENFN_API_KEY, OPENFN_ENDPOINT } = process.env;

const config: Partial<Config> = {
apiKey: options.apiKey,
endpoint: options.endpoint,
};

if (!options.apiKey && OPENFN_API_KEY) {
logger.info('Using OPENFN_API_KEY environment variable');
config.apiKey = OPENFN_API_KEY;
}

if (!options.endpoint && OPENFN_ENDPOINT) {
logger.info('Using OPENFN_ENDPOINT environment variable');
config.endpoint = OPENFN_ENDPOINT;
}

// download the state.json from lightning
const { data } = await getProject(config as DeployConfig, options.projectId);
const name = options.env || 'project';

const project = Project.from('state', data, {
endpoint: config.endpoint,
env: name,
fetched_at: new Date().toISOString(),
});

const outputRoot = path.resolve(options.path || '.');

const projectFileName = project.getIdentifier();

await fs.mkdir(`${outputRoot}/.projects`, { recursive: true });
let stateOutputPath = `${outputRoot}/.projects/${projectFileName}`;

const state = project?.serialize('state');
if (project.repo?.formats.project === 'yaml') {
await fs.writeFile(`${stateOutputPath}.yaml`, state);
} else {
await fs.writeFile(
`${stateOutputPath}.json`,
JSON.stringify(state, null, 2)
);
}
logger.success(`Fetched project file to ${stateOutputPath}`);
}