Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
5 changes: 5 additions & 0 deletions .changeset/empty-snakes-return.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@openfn/cli': patch
---

When running legacy deploy with an openfn.yaml file (ie, github sync), do not generate credentials.yaml by default"
15 changes: 11 additions & 4 deletions packages/cli/src/projects/checkout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,16 @@ import { createProjectCredentials } from './create-credentials';

export type CheckoutOptions = Pick<
Opts,
'command' | 'project' | 'workspace' | 'log' | 'clean' | 'force'
| 'command'
| 'project'
| 'workspace'
| 'log'
| 'clean'
| 'force'
| 'createCredentials'
>;

const options = [o.log, po.workspace, po.clean, o.force];
const options = [o.log, po.workspace, po.clean, o.force, po.creds];

const command: yargs.CommandModule = {
command: 'checkout <project>',
Expand Down Expand Up @@ -125,8 +131,9 @@ export const handler = async (options: CheckoutOptions, logger?: Logger) => {
logger?.warn('WARNING! No content for file', f);
}
}

createProjectCredentials(workspacePath, switchProject, logger);
if (options.createCredentials) {
createProjectCredentials(workspacePath, switchProject, logger);
}

logger?.success(`Expanded project to ${workspacePath}`);
};
11 changes: 11 additions & 0 deletions packages/cli/src/projects/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export type Opts = BaseOpts & {
project?: string;
format?: 'yaml' | 'json' | 'state';
clean?: boolean;
createCredentials?: boolean;
};

// project specific options
Expand Down Expand Up @@ -39,6 +40,16 @@ export const clean: CLIOption = {
},
};

export const creds: CLIOption = {
name: 'create-credentials',
yargs: {
boolean: true,
default: true,
description:
'Create a credentials.yaml file and intialize with empty values',
},
};

export const dryRun: CLIOption = {
name: 'dryRun',
yargs: {
Expand Down
2 changes: 2 additions & 0 deletions packages/cli/src/projects/pull.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export type PullOptions = Pick<
| 'confirm'
| 'snapshots'
| 'force'
| 'createCredentials'
>;

const options = [
Expand All @@ -32,6 +33,7 @@ const options = [
o2.alias,
o2.env,
o2.workspace,
o2.creds,

// general options
o.apiKey,
Expand Down
4 changes: 3 additions & 1 deletion packages/cli/src/pull/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ async function pullHandler(options: PullOptions, logger: Logger) {
);
if (!process.env.PREFER_LEGACY_SYNC && (await fileExists(v2ConfigPath))) {
// override endpoint with one from openfn.yaml
const config = yamlToJson(await fs.readFile(v2ConfigPath, 'utf-8'));
const config = yamlToJson(await fs.readFile(v2ConfigPath, 'utf-8')) ?? {};
if (config?.project?.endpoint) {
config.endpoint = config.project.endpoint;
}
Expand All @@ -42,6 +42,8 @@ async function pullHandler(options: PullOptions, logger: Logger) {
project: options.projectId,
force: true,
endpoint: config.endpoint,
apiKey: config.apiKey,
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand why I had to add this (it hasn't worked anyway), but I'm also a bit surprised it wasn't there any way. I guess GH sync uses an env var so its not really needed.

But I think I want to leave it in

createCredentials: false,
},
logger
);
Expand Down
102 changes: 101 additions & 1 deletion packages/cli/test/projects/checkout.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -561,7 +561,7 @@ test.serial(
triggers: [],
edges: [],
},
],
],
}),
});

Expand All @@ -580,6 +580,106 @@ test.serial(
}
);

test.serial('checkout: creates credentials.yaml', async (t) => {
mock({
'/ws2/workflows': {},
'/ws2/openfn.yaml': jsonToYaml({
project: { id: 'main-project' },
}),
'/ws2/.projects/main-project@server.yaml': jsonToYaml({
id: '<uuid:main>',
name: 'Main Project',
project_credentials: [
{
id: 'cred-uuid',
name: 'my-credential',
owner: 'alice',
},
],
workflows: [
{
name: 'My Workflow',
jobs: [
{
name: 'Run Job',
body: 'fn(s => s)',
adaptor: '@openfn/language-http@latest',
project_credential_id: 'cred-uuid',
},
],
triggers: [],
edges: [],
},
],
}),
});

t.false(fs.existsSync('/ws2/credentials.yaml'));

await checkoutHandler(
{
command: 'project-checkout',
project: 'main-project',
workspace: '/ws2',
createCredentials: true,
},
logger
);

t.true(fs.existsSync('/ws2/credentials.yaml'));

const creds = yamlToJson(fs.readFileSync('/ws2/credentials.yaml', 'utf8'));
t.deepEqual(creds, { 'alice|my-credential': {} });
});

test.serial('checkout: do not create credentials.yaml', async (t) => {
mock({
'/ws2/workflows': {},
'/ws2/openfn.yaml': jsonToYaml({
project: { id: 'main-project' },
}),
'/ws2/.projects/main-project@server.yaml': jsonToYaml({
id: '<uuid:main>',
name: 'Main Project',
project_credentials: [
{
id: 'cred-uuid',
name: 'my-credential',
owner: 'alice',
},
],
workflows: [
{
name: 'My Workflow',
jobs: [
{
name: 'Run Job',
body: 'fn(s => s)',
adaptor: '@openfn/language-http@latest',
project_credential_id: 'cred-uuid',
},
],
triggers: [],
edges: [],
},
],
}),
});

t.false(fs.existsSync('/ws2/credentials.yaml'));

await checkoutHandler(
{
command: 'project-checkout',
project: 'main-project',
workspace: '/ws2',
createCredentials: false,
},
logger
);

t.false(fs.existsSync('/ws2/credentials.yaml'));
});
test.serial(
'checkout: removes workflow directory when workflow is deleted on server',
async (t) => {
Expand Down
54 changes: 48 additions & 6 deletions packages/cli/test/pull/handler.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
import test from 'ava';
import mockfs from 'mock-fs';
import fs from 'node:fs';
import { MockAgent, setGlobalDispatcher } from 'undici';
import { createMockLogger } from '@openfn/logger';

import pullHandler from '../../src/pull/handler';
import { PullOptions } from '../../src/pull/command';
import { myProject_v1 } from '../projects/fixtures';

const ENDPOINT = 'https://app.openfn.org';
const PROJECT_UUID = 'e16c5f09-f0cb-4ba7-a4c2-73fcb2f29d00';

test.beforeEach(() => {
mockfs.restore();
Expand All @@ -12,27 +19,62 @@ test.afterEach(() => {
mockfs.restore();
});

let mockAgent = new MockAgent();
mockAgent.disableNetConnect();
setGlobalDispatcher(mockAgent);

test.before(() => {
const mockPool = mockAgent.get(ENDPOINT);
mockPool
.intercept({
path: `/api/provision/${PROJECT_UUID}?`,
method: 'GET',
})
.reply(200, {
data: myProject_v1,
})
.persist();
});

const options: PullOptions = {
beta: false,
command: 'pull',
projectPath: './project.yaml',
configPath: './config.json',
projectId: 'abc-123',
configPath: '/tmp/config.json',
projectId: PROJECT_UUID,
confirm: false,
snapshots: [],
workspace: '/tmp', // needed in tests to drive other paths
};

test.serial(
'redirects to beta handler when openfn.yaml exists in cwd',
async (t) => {
const logger = createMockLogger('', { level: 'debug' });
mockfs({
['./config.json']: `{"apiKey": "123"}`,
['./openfn.yaml']: '',
['/tmp/config.json']: `{"apiKey": "123", "endpoint": "${ENDPOINT}"}`,
['/tmp/openfn.yaml']: `
project:
endpoint: ${ENDPOINT}`,
});

await t.throwsAsync(() => pullHandler(options, logger));
await pullHandler(options, logger);

t.true(fs.existsSync('/tmp/.projects/main@app.openfn.org.yaml'));

t.truthy(logger._find('always', /Detected openfn.yaml file/i));
}
);

test.serial('does not create credentials.yaml when redirecting', async (t) => {
const logger = createMockLogger('', { level: 'debug' });
mockfs({
['/tmp/config.json']: `{"apiKey": "123", "endpoint": "${ENDPOINT}"}`,
['/tmp/openfn.yaml']: `
project:
endpoint: ${ENDPOINT}`,
});

await pullHandler(options, logger);

t.false(fs.existsSync('/tmp/credentials.yaml'));
});