@knocklabs/cli 0.1.0-rc.4 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +172 -77
- package/dist/commands/commit/index.js +6 -3
- package/dist/commands/commit/promote.js +5 -2
- package/dist/commands/knock.js +102 -0
- package/dist/commands/ping.js +2 -4
- package/dist/commands/translation/get.js +128 -0
- package/dist/commands/translation/list.js +57 -9
- package/dist/commands/translation/pull.js +72 -21
- package/dist/commands/translation/push.js +23 -12
- package/dist/commands/translation/validate.js +12 -8
- package/dist/commands/whoami.js +31 -0
- package/dist/commands/workflow/activate.js +19 -8
- package/dist/commands/workflow/get.js +14 -10
- package/dist/commands/workflow/list.js +7 -3
- package/dist/commands/workflow/new.js +4 -5
- package/dist/commands/workflow/pull.js +18 -10
- package/dist/commands/workflow/push.js +60 -47
- package/dist/commands/workflow/run.js +58 -0
- package/dist/commands/workflow/validate.js +52 -48
- package/dist/lib/api-v1.js +32 -5
- package/dist/lib/base-command.js +8 -4
- package/dist/lib/helpers/flag.js +12 -1
- package/dist/lib/helpers/page.js +7 -2
- package/dist/lib/helpers/request.js +1 -1
- package/dist/lib/helpers/ux.js +2 -2
- package/dist/lib/marshal/translation/helpers.js +21 -7
- package/dist/lib/marshal/translation/reader.js +17 -14
- package/dist/lib/marshal/translation/types.js +1 -0
- package/dist/lib/marshal/translation/writer.js +26 -16
- package/dist/lib/marshal/workflow/helpers.js +64 -2
- package/dist/lib/marshal/workflow/reader.js +62 -0
- package/dist/lib/run-context/helpers.js +2 -2
- package/oclif.manifest.json +281 -24
- package/package.json +25 -19
|
@@ -78,7 +78,7 @@ class WorkflowPull extends _baseCommand.default {
|
|
|
78
78
|
if (dirContext.exists) {
|
|
79
79
|
this.log(`‣ Found \`${dirContext.key}\` at ${dirContext.abspath}`);
|
|
80
80
|
} else {
|
|
81
|
-
const prompt = `Create a new workflow directory \`${dirContext.key}
|
|
81
|
+
const prompt = `Create a new workflow directory \`${dirContext.key}\` at ${dirContext.abspath}?`;
|
|
82
82
|
const input = flags.force || await (0, _ux.promptToConfirm)(prompt);
|
|
83
83
|
if (!input) return;
|
|
84
84
|
}
|
|
@@ -171,22 +171,30 @@ class WorkflowPull extends _baseCommand.default {
|
|
|
171
171
|
}, workflows) : workflows;
|
|
172
172
|
}
|
|
173
173
|
}
|
|
174
|
+
WorkflowPull.summary = "Pull one or more workflows from an environment into a local file system.";
|
|
174
175
|
WorkflowPull.flags = {
|
|
175
176
|
environment: _core.Flags.string({
|
|
176
|
-
default: "development"
|
|
177
|
+
default: "development",
|
|
178
|
+
summary: "The environment to use."
|
|
179
|
+
}),
|
|
180
|
+
all: _core.Flags.boolean({
|
|
181
|
+
summary: "Whether to pull all workflows from the specified environment."
|
|
177
182
|
}),
|
|
178
|
-
all: _core.Flags.boolean(),
|
|
179
183
|
"workflows-dir": _flag.dirPath({
|
|
184
|
+
summary: "The target directory path to pull all workflows into.",
|
|
180
185
|
dependsOn: [
|
|
181
186
|
"all"
|
|
182
187
|
]
|
|
183
188
|
}),
|
|
184
|
-
"hide-uncommitted-changes": _core.Flags.boolean(
|
|
185
|
-
|
|
189
|
+
"hide-uncommitted-changes": _core.Flags.boolean({
|
|
190
|
+
summary: "Hide any uncommitted changes."
|
|
191
|
+
}),
|
|
192
|
+
force: _core.Flags.boolean({
|
|
193
|
+
summary: "Remove the confirmation prompt."
|
|
194
|
+
})
|
|
186
195
|
};
|
|
187
|
-
WorkflowPull.args =
|
|
188
|
-
{
|
|
189
|
-
name: "workflowKey",
|
|
196
|
+
WorkflowPull.args = {
|
|
197
|
+
workflowKey: _core.Args.string({
|
|
190
198
|
required: false
|
|
191
|
-
}
|
|
192
|
-
|
|
199
|
+
})
|
|
200
|
+
};
|
|
@@ -6,15 +6,17 @@ Object.defineProperty(exports, "default", {
|
|
|
6
6
|
enumerable: true,
|
|
7
7
|
get: ()=>WorkflowPush
|
|
8
8
|
});
|
|
9
|
-
const _nodePath = /*#__PURE__*/ _interopRequireWildcard(require("node:path"));
|
|
10
9
|
const _core = require("@oclif/core");
|
|
11
10
|
const _baseCommand = /*#__PURE__*/ _interopRequireDefault(require("../../lib/base-command"));
|
|
12
11
|
const _const = require("../../lib/helpers/const");
|
|
13
12
|
const _error = require("../../lib/helpers/error");
|
|
13
|
+
const _flag = /*#__PURE__*/ _interopRequireWildcard(require("../../lib/helpers/flag"));
|
|
14
14
|
const _object = require("../../lib/helpers/object");
|
|
15
15
|
const _request = require("../../lib/helpers/request");
|
|
16
|
+
const _string = require("../../lib/helpers/string");
|
|
17
|
+
const _ux = require("../../lib/helpers/ux");
|
|
16
18
|
const _workflow = /*#__PURE__*/ _interopRequireWildcard(require("../../lib/marshal/workflow"));
|
|
17
|
-
const
|
|
19
|
+
const _validate = /*#__PURE__*/ _interopRequireDefault(require("./validate"));
|
|
18
20
|
function _interopRequireDefault(obj) {
|
|
19
21
|
return obj && obj.__esModule ? obj : {
|
|
20
22
|
default: obj
|
|
@@ -61,57 +63,60 @@ function _interopRequireWildcard(obj, nodeInterop) {
|
|
|
61
63
|
}
|
|
62
64
|
class WorkflowPush extends _baseCommand.default {
|
|
63
65
|
async run() {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
const [workflow, errors] = await _workflow.readWorkflowDir(dirContext, {
|
|
66
|
+
const { flags } = this.props;
|
|
67
|
+
// 1. First read all workflow directories found for the given command.
|
|
68
|
+
const target = await _workflow.ensureValidCommandTarget(this.props, this.runContext);
|
|
69
|
+
const [workflows, readErrors] = await _workflow.readAllForCommandTarget(target, {
|
|
69
70
|
withExtractedFiles: true
|
|
70
71
|
});
|
|
71
|
-
if (
|
|
72
|
-
this.error(
|
|
72
|
+
if (readErrors.length > 0) {
|
|
73
|
+
this.error((0, _error.formatErrors)(readErrors, {
|
|
74
|
+
prependBy: "\n\n"
|
|
75
|
+
}));
|
|
73
76
|
}
|
|
74
|
-
|
|
75
|
-
|
|
77
|
+
if (workflows.length === 0) {
|
|
78
|
+
this.error(`No workflow directories found in ${target.context.abspath}`);
|
|
79
|
+
}
|
|
80
|
+
// 2. Then validate them all ahead of pushing them.
|
|
81
|
+
_ux.spinner.start(`‣ Validating`);
|
|
82
|
+
const apiErrors = await _validate.default.validateAll(this.apiV1, this.props, workflows);
|
|
83
|
+
if (apiErrors.length > 0) {
|
|
84
|
+
this.error((0, _error.formatErrors)(apiErrors, {
|
|
85
|
+
prependBy: "\n\n"
|
|
86
|
+
}));
|
|
87
|
+
}
|
|
88
|
+
_ux.spinner.stop();
|
|
89
|
+
// 3. Finally push up each workflow, abort on the first error.
|
|
90
|
+
_ux.spinner.start(`‣ Pushing`);
|
|
91
|
+
for (const workflow of workflows){
|
|
76
92
|
const props = (0, _object.merge)(this.props, {
|
|
77
|
-
args: {
|
|
78
|
-
workflowKey: dirContext.key
|
|
79
|
-
},
|
|
80
93
|
flags: {
|
|
81
94
|
annotate: true
|
|
82
95
|
}
|
|
83
96
|
});
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
key: workflowKey
|
|
99
|
-
};
|
|
100
|
-
return (0, _runContext.ensureResourceDirForTarget)(resourceDir, target);
|
|
101
|
-
}
|
|
102
|
-
if (workflowKey) {
|
|
103
|
-
const dirPath = _nodePath.resolve(runCwd, workflowKey);
|
|
104
|
-
const exists = await _workflow.isWorkflowDir(dirPath);
|
|
105
|
-
return exists ? {
|
|
106
|
-
type: "workflow",
|
|
107
|
-
key: workflowKey,
|
|
108
|
-
abspath: dirPath,
|
|
109
|
-
exists
|
|
110
|
-
} : this.error(`Cannot locate a workflow directory for \`${workflowKey}\``);
|
|
97
|
+
// eslint-disable-next-line no-await-in-loop
|
|
98
|
+
const resp = await this.apiV1.upsertWorkflow(props, {
|
|
99
|
+
...workflow.content,
|
|
100
|
+
key: workflow.key
|
|
101
|
+
});
|
|
102
|
+
if ((0, _request.isSuccessResp)(resp)) {
|
|
103
|
+
// Update the workflow directory with the successfully pushed workflow
|
|
104
|
+
// payload from the server.
|
|
105
|
+
// eslint-disable-next-line no-await-in-loop
|
|
106
|
+
await _workflow.writeWorkflowDirFromData(workflow, resp.data.workflow);
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
const error = new _error.SourceError((0, _request.formatErrorRespMessage)(resp), _workflow.workflowJsonPath(workflow), "ApiError");
|
|
110
|
+
this.error((0, _error.formatError)(error));
|
|
111
111
|
}
|
|
112
|
-
|
|
112
|
+
_ux.spinner.stop();
|
|
113
|
+
// 4. Display a success message.
|
|
114
|
+
const workflowKeys = workflows.map((w)=>w.key);
|
|
115
|
+
const actioned = flags.commit ? "pushed and committed" : "pushed";
|
|
116
|
+
this.log(`‣ Successfully ${actioned} ${workflows.length} workflow(s):\n` + (0, _string.indentString)(workflowKeys.join("\n"), 4));
|
|
113
117
|
}
|
|
114
118
|
}
|
|
119
|
+
WorkflowPush.summary = "Push one or more workflows from a local file system to Knock.";
|
|
115
120
|
WorkflowPush.flags = {
|
|
116
121
|
environment: _core.Flags.string({
|
|
117
122
|
summary: "Pushing a workflow is only allowed in the development environment",
|
|
@@ -120,6 +125,15 @@ WorkflowPush.flags = {
|
|
|
120
125
|
_const.KnockEnv.Development
|
|
121
126
|
]
|
|
122
127
|
}),
|
|
128
|
+
all: _core.Flags.boolean({
|
|
129
|
+
summary: "Whether to push all workflows from the target directory."
|
|
130
|
+
}),
|
|
131
|
+
"workflows-dir": _flag.dirPath({
|
|
132
|
+
summary: "The target directory path to find all workflows to push.",
|
|
133
|
+
dependsOn: [
|
|
134
|
+
"all"
|
|
135
|
+
]
|
|
136
|
+
}),
|
|
123
137
|
commit: _core.Flags.boolean({
|
|
124
138
|
summary: "Push and commit the workflow(s) at the same time"
|
|
125
139
|
}),
|
|
@@ -131,9 +145,8 @@ WorkflowPush.flags = {
|
|
|
131
145
|
]
|
|
132
146
|
})
|
|
133
147
|
};
|
|
134
|
-
WorkflowPush.args =
|
|
135
|
-
{
|
|
136
|
-
name: "workflowKey",
|
|
148
|
+
WorkflowPush.args = {
|
|
149
|
+
workflowKey: _core.Args.string({
|
|
137
150
|
required: false
|
|
138
|
-
}
|
|
139
|
-
|
|
151
|
+
})
|
|
152
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "default", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: ()=>WorkflowRun
|
|
8
|
+
});
|
|
9
|
+
const _core = require("@oclif/core");
|
|
10
|
+
const _baseCommand = /*#__PURE__*/ _interopRequireDefault(require("../../lib/base-command"));
|
|
11
|
+
const _flag = require("../../lib/helpers/flag");
|
|
12
|
+
const _request = require("../../lib/helpers/request");
|
|
13
|
+
const _string = require("../../lib/helpers/string");
|
|
14
|
+
function _interopRequireDefault(obj) {
|
|
15
|
+
return obj && obj.__esModule ? obj : {
|
|
16
|
+
default: obj
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
class WorkflowRun extends _baseCommand.default {
|
|
20
|
+
async run() {
|
|
21
|
+
const { args , flags } = this.props;
|
|
22
|
+
const resp = await (0, _request.withSpinner)(()=>this.apiV1.runWorkflow(this.props), {
|
|
23
|
+
action: "‣ Running"
|
|
24
|
+
});
|
|
25
|
+
this.log(`‣ Successfully ran \`${args.workflowKey}\` workflow in \`${flags.environment}\` environment`);
|
|
26
|
+
this.log((0, _string.indentString)(`Workflow run id: ${resp.data.workflow_run_id}`), 4);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
WorkflowRun.summary = "Test run a workflow using the latest version from Knock, or a local workflow directory.";
|
|
30
|
+
WorkflowRun.flags = {
|
|
31
|
+
environment: _core.Flags.string({
|
|
32
|
+
default: "development",
|
|
33
|
+
summary: "The environment in which to run the workflow"
|
|
34
|
+
}),
|
|
35
|
+
recipients: _core.Flags.string({
|
|
36
|
+
required: true,
|
|
37
|
+
aliases: [
|
|
38
|
+
"recipient"
|
|
39
|
+
],
|
|
40
|
+
summary: "One or more recipient ids for this workflow run, separated by comma.",
|
|
41
|
+
multiple: true,
|
|
42
|
+
delimiter: ","
|
|
43
|
+
}),
|
|
44
|
+
actor: _core.Flags.string({
|
|
45
|
+
summary: "An actor id for the workflow run."
|
|
46
|
+
}),
|
|
47
|
+
tenant: _core.Flags.string({
|
|
48
|
+
summary: "A tenant id for the workflow run."
|
|
49
|
+
}),
|
|
50
|
+
data: (0, _flag.jsonStr)({
|
|
51
|
+
summary: "A JSON string of the data for this workflow"
|
|
52
|
+
})
|
|
53
|
+
};
|
|
54
|
+
WorkflowRun.args = {
|
|
55
|
+
workflowKey: _core.Args.string({
|
|
56
|
+
required: true
|
|
57
|
+
})
|
|
58
|
+
};
|
|
@@ -6,15 +6,15 @@ Object.defineProperty(exports, "default", {
|
|
|
6
6
|
enumerable: true,
|
|
7
7
|
get: ()=>WorkflowValidate
|
|
8
8
|
});
|
|
9
|
-
const _nodePath = /*#__PURE__*/ _interopRequireWildcard(require("node:path"));
|
|
10
9
|
const _core = require("@oclif/core");
|
|
11
10
|
const _baseCommand = /*#__PURE__*/ _interopRequireDefault(require("../../lib/base-command"));
|
|
12
11
|
const _const = require("../../lib/helpers/const");
|
|
13
12
|
const _error = require("../../lib/helpers/error");
|
|
14
|
-
const
|
|
13
|
+
const _flag = /*#__PURE__*/ _interopRequireWildcard(require("../../lib/helpers/flag"));
|
|
15
14
|
const _request = require("../../lib/helpers/request");
|
|
15
|
+
const _string = require("../../lib/helpers/string");
|
|
16
|
+
const _ux = require("../../lib/helpers/ux");
|
|
16
17
|
const _workflow = /*#__PURE__*/ _interopRequireWildcard(require("../../lib/marshal/workflow"));
|
|
17
|
-
const _runContext = require("../../lib/run-context");
|
|
18
18
|
function _interopRequireDefault(obj) {
|
|
19
19
|
return obj && obj.__esModule ? obj : {
|
|
20
20
|
default: obj
|
|
@@ -61,53 +61,49 @@ function _interopRequireWildcard(obj, nodeInterop) {
|
|
|
61
61
|
}
|
|
62
62
|
class WorkflowValidate extends _baseCommand.default {
|
|
63
63
|
async run() {
|
|
64
|
-
// 1.
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
// 2. Read the workflow.json with its template files.
|
|
68
|
-
const [workflow, errors] = await _workflow.readWorkflowDir(dirContext, {
|
|
64
|
+
// 1. Read all workflow directories found for the given command.
|
|
65
|
+
const target = await _workflow.ensureValidCommandTarget(this.props, this.runContext);
|
|
66
|
+
const [workflows, readErrors] = await _workflow.readAllForCommandTarget(target, {
|
|
69
67
|
withExtractedFiles: true
|
|
70
68
|
});
|
|
71
|
-
if (
|
|
72
|
-
this.error(
|
|
69
|
+
if (readErrors.length > 0) {
|
|
70
|
+
this.error((0, _error.formatErrors)(readErrors, {
|
|
71
|
+
prependBy: "\n\n"
|
|
72
|
+
}));
|
|
73
73
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
const props = (0, _object.merge)(this.props, {
|
|
77
|
-
args: {
|
|
78
|
-
workflowKey: dirContext.key
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
return this.apiV1.validateWorkflow(props, workflow);
|
|
82
|
-
}, {
|
|
83
|
-
action: "‣ Validating"
|
|
84
|
-
});
|
|
85
|
-
this.log(`‣ Successfully validated \`${dirContext.key}\``);
|
|
86
|
-
}
|
|
87
|
-
async getWorkflowDirContext() {
|
|
88
|
-
const { workflowKey } = this.props.args;
|
|
89
|
-
const { resourceDir , cwd: runCwd } = this.runContext;
|
|
90
|
-
if (resourceDir) {
|
|
91
|
-
const target = {
|
|
92
|
-
commandId: _baseCommand.default.id,
|
|
93
|
-
type: "workflow",
|
|
94
|
-
key: workflowKey
|
|
95
|
-
};
|
|
96
|
-
return (0, _runContext.ensureResourceDirForTarget)(resourceDir, target);
|
|
74
|
+
if (workflows.length === 0) {
|
|
75
|
+
this.error(`No workflow directories found in ${target.context.abspath}`);
|
|
97
76
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
exists
|
|
106
|
-
} : this.error(`Cannot locate a workflow directory for \`${workflowKey}\``);
|
|
77
|
+
// 2. Validate each workflow data.
|
|
78
|
+
_ux.spinner.start(`‣ Validating`);
|
|
79
|
+
const apiErrors = await WorkflowValidate.validateAll(this.apiV1, this.props, workflows);
|
|
80
|
+
if (apiErrors.length > 0) {
|
|
81
|
+
this.error((0, _error.formatErrors)(apiErrors, {
|
|
82
|
+
prependBy: "\n\n"
|
|
83
|
+
}));
|
|
107
84
|
}
|
|
108
|
-
|
|
85
|
+
_ux.spinner.stop();
|
|
86
|
+
// 3. Display a success message.
|
|
87
|
+
const workflowKeys = workflows.map((w)=>w.key);
|
|
88
|
+
this.log(`‣ Successfully validated ${workflows.length} workflow(s):\n` + (0, _string.indentString)(workflowKeys.join("\n"), 4));
|
|
89
|
+
}
|
|
90
|
+
static async validateAll(api, props, workflows) {
|
|
91
|
+
// TODO: Throw an error if a non validation error (e.g. authentication error)
|
|
92
|
+
// instead of printing out same error messages repeatedly.
|
|
93
|
+
const errorPromises = workflows.map(async (workflow)=>{
|
|
94
|
+
const resp = await api.validateWorkflow(props, {
|
|
95
|
+
...workflow.content,
|
|
96
|
+
key: workflow.key
|
|
97
|
+
});
|
|
98
|
+
if ((0, _request.isSuccessResp)(resp)) return;
|
|
99
|
+
const error = new _error.SourceError((0, _request.formatErrorRespMessage)(resp), _workflow.workflowJsonPath(workflow), "ApiError");
|
|
100
|
+
return error;
|
|
101
|
+
});
|
|
102
|
+
const errors = (await Promise.all(errorPromises)).filter((e)=>Boolean(e));
|
|
103
|
+
return errors;
|
|
109
104
|
}
|
|
110
105
|
}
|
|
106
|
+
WorkflowValidate.summary = "Validate one or more workflows from a local file system.";
|
|
111
107
|
WorkflowValidate.flags = {
|
|
112
108
|
environment: _core.Flags.string({
|
|
113
109
|
summary: "Validating a workflow is only done in the development environment",
|
|
@@ -115,11 +111,19 @@ WorkflowValidate.flags = {
|
|
|
115
111
|
options: [
|
|
116
112
|
_const.KnockEnv.Development
|
|
117
113
|
]
|
|
114
|
+
}),
|
|
115
|
+
all: _core.Flags.boolean({
|
|
116
|
+
summary: "Whether to validate all workflows from the target directory."
|
|
117
|
+
}),
|
|
118
|
+
"workflows-dir": _flag.dirPath({
|
|
119
|
+
summary: "The target directory path to find all workflows to validate.",
|
|
120
|
+
dependsOn: [
|
|
121
|
+
"all"
|
|
122
|
+
]
|
|
118
123
|
})
|
|
119
124
|
};
|
|
120
|
-
WorkflowValidate.args =
|
|
121
|
-
{
|
|
122
|
-
name: "workflowKey",
|
|
125
|
+
WorkflowValidate.args = {
|
|
126
|
+
workflowKey: _core.Args.string({
|
|
123
127
|
required: false
|
|
124
|
-
}
|
|
125
|
-
|
|
128
|
+
})
|
|
129
|
+
};
|
package/dist/lib/api-v1.js
CHANGED
|
@@ -20,6 +20,9 @@ class ApiV1 {
|
|
|
20
20
|
async ping() {
|
|
21
21
|
return this.get("/ping");
|
|
22
22
|
}
|
|
23
|
+
async whoami() {
|
|
24
|
+
return this.get("/whoami");
|
|
25
|
+
}
|
|
23
26
|
// By resources: Workflows
|
|
24
27
|
async listWorkflows({ flags }) {
|
|
25
28
|
const params = (0, _object.prune)({
|
|
@@ -42,7 +45,7 @@ class ApiV1 {
|
|
|
42
45
|
params
|
|
43
46
|
});
|
|
44
47
|
}
|
|
45
|
-
async upsertWorkflow({
|
|
48
|
+
async upsertWorkflow({ flags }, workflow) {
|
|
46
49
|
const params = (0, _object.prune)({
|
|
47
50
|
environment: flags.environment,
|
|
48
51
|
annotate: flags.annotate,
|
|
@@ -52,18 +55,18 @@ class ApiV1 {
|
|
|
52
55
|
const data = {
|
|
53
56
|
workflow
|
|
54
57
|
};
|
|
55
|
-
return this.put(`/workflows/${
|
|
58
|
+
return this.put(`/workflows/${workflow.key}`, data, {
|
|
56
59
|
params
|
|
57
60
|
});
|
|
58
61
|
}
|
|
59
|
-
async validateWorkflow({
|
|
62
|
+
async validateWorkflow({ flags }, workflow) {
|
|
60
63
|
const params = (0, _object.prune)({
|
|
61
64
|
environment: flags.environment
|
|
62
65
|
});
|
|
63
66
|
const data = {
|
|
64
67
|
workflow
|
|
65
68
|
};
|
|
66
|
-
return this.put(`/workflows/${
|
|
69
|
+
return this.put(`/workflows/${workflow.key}/validate`, data, {
|
|
67
70
|
params
|
|
68
71
|
});
|
|
69
72
|
}
|
|
@@ -76,6 +79,18 @@ class ApiV1 {
|
|
|
76
79
|
params
|
|
77
80
|
});
|
|
78
81
|
}
|
|
82
|
+
async runWorkflow({ args , flags }) {
|
|
83
|
+
const params = (0, _object.prune)({
|
|
84
|
+
environment: flags.environment,
|
|
85
|
+
recipients: flags.recipients,
|
|
86
|
+
tenant: flags.tenant,
|
|
87
|
+
data: flags.data,
|
|
88
|
+
actor: flags.actor
|
|
89
|
+
});
|
|
90
|
+
return this.put(`/workflows/${args.workflowKey}/run`, {}, {
|
|
91
|
+
params
|
|
92
|
+
});
|
|
93
|
+
}
|
|
79
94
|
// By resources: Commits
|
|
80
95
|
async commitAllChanges({ flags }) {
|
|
81
96
|
const params = (0, _object.prune)({
|
|
@@ -95,16 +110,28 @@ class ApiV1 {
|
|
|
95
110
|
});
|
|
96
111
|
}
|
|
97
112
|
// By resources: Translations
|
|
98
|
-
async listTranslations({ flags }) {
|
|
113
|
+
async listTranslations({ flags }, filters = {}) {
|
|
99
114
|
const params = (0, _object.prune)({
|
|
100
115
|
environment: flags.environment,
|
|
101
116
|
hide_uncommitted_changes: flags["hide-uncommitted-changes"],
|
|
117
|
+
locale_code: filters.localeCode,
|
|
118
|
+
namespace: filters.namespace,
|
|
102
119
|
...(0, _page.toPageParams)(flags)
|
|
103
120
|
});
|
|
104
121
|
return this.get("/translations", {
|
|
105
122
|
params
|
|
106
123
|
});
|
|
107
124
|
}
|
|
125
|
+
async getTranslation({ flags }, translation) {
|
|
126
|
+
const params = (0, _object.prune)({
|
|
127
|
+
environment: flags.environment,
|
|
128
|
+
hide_uncommitted_changes: flags["hide-uncommitted-changes"],
|
|
129
|
+
namespace: translation.namespace
|
|
130
|
+
});
|
|
131
|
+
return this.get(`/translations/${translation.localeCode}`, {
|
|
132
|
+
params
|
|
133
|
+
});
|
|
134
|
+
}
|
|
108
135
|
async upsertTranslation({ flags }, translation) {
|
|
109
136
|
const params = (0, _object.prune)({
|
|
110
137
|
environment: flags.environment,
|
package/dist/lib/base-command.js
CHANGED
|
@@ -60,21 +60,25 @@ class BaseCommand extends _core.Command {
|
|
|
60
60
|
// 1. Load user's config from the config dir, as available.
|
|
61
61
|
await _userConfig.default.load(this.config.configDir);
|
|
62
62
|
// 2. Parse flags and args, must come after the user config load.
|
|
63
|
-
|
|
63
|
+
const { args , flags } = await this.parse(this.ctor);
|
|
64
|
+
this.props = {
|
|
65
|
+
args: args,
|
|
66
|
+
flags: flags
|
|
67
|
+
};
|
|
64
68
|
// 3. Instantiate a knock api client.
|
|
65
69
|
this.apiV1 = new _apiV1.default(this.props.flags, this.config);
|
|
66
70
|
// 4. Load the run context of the invoked command.
|
|
67
71
|
this.runContext = await _runContext.load(this.id);
|
|
68
72
|
}
|
|
69
73
|
}
|
|
70
|
-
//
|
|
71
|
-
BaseCommand.
|
|
74
|
+
// Base flags are inherited by any command that extends BaseCommand.
|
|
75
|
+
BaseCommand.baseFlags = {
|
|
72
76
|
// Evaluated in the following precedence:
|
|
73
77
|
// - service token flag passed into the command
|
|
74
78
|
// - if not provided, fall back to env variable
|
|
75
79
|
// - if not available, fall back to user config
|
|
76
80
|
"service-token": _core.Flags.string({
|
|
77
|
-
summary: "The service token to authenticate with",
|
|
81
|
+
summary: "The service token to authenticate with.",
|
|
78
82
|
required: true,
|
|
79
83
|
multiple: false,
|
|
80
84
|
env: "KNOCK_SERVICE_TOKEN",
|
package/dist/lib/helpers/flag.js
CHANGED
|
@@ -10,7 +10,8 @@ function _export(target, all) {
|
|
|
10
10
|
}
|
|
11
11
|
_export(exports, {
|
|
12
12
|
booleanStr: ()=>booleanStr,
|
|
13
|
-
dirPath: ()=>dirPath
|
|
13
|
+
dirPath: ()=>dirPath,
|
|
14
|
+
jsonStr: ()=>jsonStr
|
|
14
15
|
});
|
|
15
16
|
const _nodePath = /*#__PURE__*/ _interopRequireWildcard(require("node:path"));
|
|
16
17
|
const _core = require("@oclif/core");
|
|
@@ -74,3 +75,13 @@ const dirPath = _core.Flags.custom({
|
|
|
74
75
|
};
|
|
75
76
|
}
|
|
76
77
|
});
|
|
78
|
+
const jsonStr = _core.Flags.custom({
|
|
79
|
+
parse: async (input)=>{
|
|
80
|
+
try {
|
|
81
|
+
const data = JSON.parse(input);
|
|
82
|
+
return data;
|
|
83
|
+
} catch {
|
|
84
|
+
throw new Error(`${input} is not a valid JSON string.`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
});
|
package/dist/lib/helpers/page.js
CHANGED
|
@@ -28,9 +28,14 @@ function _interopRequireDefault(obj) {
|
|
|
28
28
|
}
|
|
29
29
|
const MAX_PAGINATION_LIMIT = 100;
|
|
30
30
|
const pageFlags = {
|
|
31
|
-
after: _core.Flags.string(
|
|
32
|
-
|
|
31
|
+
after: _core.Flags.string({
|
|
32
|
+
summary: "The cursor after which to fetch the next page."
|
|
33
|
+
}),
|
|
34
|
+
before: _core.Flags.string({
|
|
35
|
+
summary: "The cursor before which to fetch the previous page."
|
|
36
|
+
}),
|
|
33
37
|
limit: _core.Flags.integer({
|
|
38
|
+
summary: "The total number of entries to fetch per page.",
|
|
34
39
|
max: MAX_PAGINATION_LIMIT
|
|
35
40
|
})
|
|
36
41
|
};
|
|
@@ -38,7 +38,7 @@ const withSpinner = async (requestFn, opts = {})=>{
|
|
|
38
38
|
// Error out before the action stop so the spinner can update accordingly.
|
|
39
39
|
if (ensureSuccess && !isSuccessResp(resp)) {
|
|
40
40
|
const message = formatErrorRespMessage(resp);
|
|
41
|
-
_core.
|
|
41
|
+
_core.ux.error(new _error.ApiError(message));
|
|
42
42
|
}
|
|
43
43
|
_ux.spinner.stop();
|
|
44
44
|
return resp;
|
package/dist/lib/helpers/ux.js
CHANGED
|
@@ -34,9 +34,9 @@ const promptToConfirm = async (message)=>{
|
|
|
34
34
|
};
|
|
35
35
|
const spinner = {
|
|
36
36
|
start (action) {
|
|
37
|
-
if (!_const.isTestEnv) _core.
|
|
37
|
+
if (!_const.isTestEnv) _core.ux.action.start(action);
|
|
38
38
|
},
|
|
39
39
|
stop () {
|
|
40
|
-
_core.
|
|
40
|
+
_core.ux.action.stop();
|
|
41
41
|
}
|
|
42
42
|
};
|
|
@@ -9,6 +9,9 @@ function _export(target, all) {
|
|
|
9
9
|
});
|
|
10
10
|
}
|
|
11
11
|
_export(exports, {
|
|
12
|
+
translationRefDescription: ()=>translationRefDescription,
|
|
13
|
+
formatLanguage: ()=>formatLanguage,
|
|
14
|
+
formatRef: ()=>formatRef,
|
|
12
15
|
isValidLocale: ()=>isValidLocale,
|
|
13
16
|
isTranslationDir: ()=>isTranslationDir,
|
|
14
17
|
buildTranslationFileCtx: ()=>buildTranslationFileCtx,
|
|
@@ -65,6 +68,16 @@ function _interopRequireWildcard(obj, nodeInterop) {
|
|
|
65
68
|
}
|
|
66
69
|
return newObj;
|
|
67
70
|
}
|
|
71
|
+
const translationRefDescription = `
|
|
72
|
+
Translation ref is a identifier string that refers to a unique translation.
|
|
73
|
+
If a translation has no namespace, it is the same as the locale, e.g. \`en\`.
|
|
74
|
+
If namespaced, it is formatted as namespace.locale, e.g. \`admin.en\`.
|
|
75
|
+
`.trim();
|
|
76
|
+
const formatLanguage = (translation)=>{
|
|
77
|
+
const lang = _localeCodes.default.getByTag(translation.locale_code);
|
|
78
|
+
return lang.location ? `${lang.name}, ${lang.location}` : lang.name;
|
|
79
|
+
};
|
|
80
|
+
const formatRef = ({ locale_code , namespace })=>namespace ? `${namespace}.${locale_code}` : locale_code;
|
|
68
81
|
const isValidLocale = (localeCode)=>Boolean(_localeCodes.default.getByTag(localeCode));
|
|
69
82
|
const isTranslationDir = (dirPath)=>{
|
|
70
83
|
const locale = _nodePath.basename(dirPath);
|
|
@@ -87,7 +100,8 @@ const parseTranslationRef = (reference)=>{
|
|
|
87
100
|
// Locale code only (e.g. `en`)
|
|
88
101
|
if (strings.length === 1) {
|
|
89
102
|
return {
|
|
90
|
-
localeCode: strings[0]
|
|
103
|
+
localeCode: strings[0],
|
|
104
|
+
namespace: undefined
|
|
91
105
|
};
|
|
92
106
|
}
|
|
93
107
|
// Locale code prefixed with a namespace (e.g. `admin.en`)
|
|
@@ -105,16 +119,16 @@ const ensureValidCommandTarget = async (props, runContext)=>{
|
|
|
105
119
|
const { commandId , resourceDir: resourceDirCtx , cwd: runCwd } = runContext;
|
|
106
120
|
// Error, trying to run the command not in a translation directory.
|
|
107
121
|
if (resourceDirCtx && resourceDirCtx.type !== "translation") {
|
|
108
|
-
return _core.
|
|
122
|
+
return _core.ux.error(`Cannot run ${commandId} inside a ${resourceDirCtx.type} directory`);
|
|
109
123
|
}
|
|
110
124
|
// Error, got neither the translationRef arg nor the --all flag.
|
|
111
125
|
if (!args.translationRef && !flags.all) {
|
|
112
|
-
_core.
|
|
126
|
+
_core.ux.error("At least one of translation ref arg or --all flag must be given");
|
|
113
127
|
}
|
|
114
128
|
// No translationRef arg, which means --all flag is used.
|
|
115
129
|
if (!args.translationRef) {
|
|
116
130
|
// Targeting all translation files in the current locale directory.
|
|
117
|
-
if (resourceDirCtx) {
|
|
131
|
+
if (resourceDirCtx && !flags["translations-dir"]) {
|
|
118
132
|
return {
|
|
119
133
|
type: "translationDir",
|
|
120
134
|
context: resourceDirCtx
|
|
@@ -135,12 +149,12 @@ const ensureValidCommandTarget = async (props, runContext)=>{
|
|
|
135
149
|
// From this point on, we have translationRef so parse and validate the format.
|
|
136
150
|
const parsedRef = parseTranslationRef(args.translationRef);
|
|
137
151
|
if (!parsedRef) {
|
|
138
|
-
return _core.
|
|
152
|
+
return _core.ux.error(`Invalid translation ref \`${args.translationRef}\`, use valid <locale> or <namespace>.<locale> for namespaced translations`);
|
|
139
153
|
}
|
|
140
154
|
const { localeCode , namespace } = parsedRef;
|
|
141
155
|
// If we are in the translation dir, make sure the locale matches.
|
|
142
156
|
if (resourceDirCtx && resourceDirCtx.key !== localeCode) {
|
|
143
|
-
return _core.
|
|
157
|
+
return _core.ux.error(`Cannot run ${commandId} with \`${args.translationRef}\` inside a ${resourceDirCtx.key} directory`);
|
|
144
158
|
}
|
|
145
159
|
const targetDirPath = resourceDirCtx ? resourceDirCtx.abspath : _nodePath.resolve(runCwd, localeCode);
|
|
146
160
|
// Got translationRef arg but no --all flag, which means target only a single
|
|
@@ -155,7 +169,7 @@ const ensureValidCommandTarget = async (props, runContext)=>{
|
|
|
155
169
|
// From this point on, we have both translationRef and --all flag used
|
|
156
170
|
// together, so make sure we are targeting a non-namespaced top-level locale.
|
|
157
171
|
if (namespace) {
|
|
158
|
-
return _core.
|
|
172
|
+
return _core.ux.error(`Cannot use --all with a namespaced translation \`${args.translationRef}\``);
|
|
159
173
|
}
|
|
160
174
|
const translationDirCtx = {
|
|
161
175
|
type: "translation",
|