@knocklabs/cli 0.3.1 → 1.0.0
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 +343 -55
- package/dist/commands/branch/delete.js +4 -1
- package/dist/commands/branch/merge.js +82 -0
- package/dist/commands/channel/list.js +73 -0
- package/dist/commands/environment/list.js +73 -0
- package/dist/commands/guide/new.js +276 -0
- package/dist/commands/guide/open.js +106 -0
- package/dist/commands/guide/pull.js +5 -6
- package/dist/commands/guide/push.js +1 -1
- package/dist/commands/guide/validate.js +1 -1
- package/dist/commands/init.js +108 -0
- package/dist/commands/layout/new.js +228 -0
- package/dist/commands/layout/open.js +106 -0
- package/dist/commands/layout/pull.js +5 -6
- package/dist/commands/layout/push.js +1 -1
- package/dist/commands/layout/validate.js +1 -1
- package/dist/commands/message-type/new.js +228 -0
- package/dist/commands/message-type/open.js +106 -0
- package/dist/commands/message-type/pull.js +5 -6
- package/dist/commands/message-type/push.js +1 -1
- package/dist/commands/message-type/validate.js +1 -1
- package/dist/commands/partial/new.js +274 -0
- package/dist/commands/partial/open.js +106 -0
- package/dist/commands/partial/pull.js +5 -6
- package/dist/commands/partial/push.js +1 -1
- package/dist/commands/partial/validate.js +1 -1
- package/dist/commands/pull.js +7 -2
- package/dist/commands/push.js +6 -4
- package/dist/commands/translation/pull.js +1 -1
- package/dist/commands/translation/push.js +1 -1
- package/dist/commands/translation/validate.js +1 -1
- package/dist/commands/workflow/new.js +179 -54
- package/dist/commands/workflow/open.js +106 -0
- package/dist/commands/workflow/pull.js +6 -8
- package/dist/commands/workflow/push.js +1 -1
- package/dist/commands/workflow/validate.js +1 -1
- package/dist/lib/api-v1.js +23 -2
- package/dist/lib/auth.js +1 -1
- package/dist/lib/base-command.js +18 -15
- package/dist/lib/helpers/project-config.js +158 -0
- package/dist/lib/helpers/request.js +1 -2
- package/dist/lib/helpers/string.js +4 -4
- package/dist/lib/helpers/typegen.js +1 -1
- package/dist/lib/marshal/email-layout/generator.js +152 -0
- package/dist/lib/marshal/email-layout/helpers.js +6 -9
- package/dist/lib/marshal/email-layout/index.js +1 -0
- package/dist/lib/marshal/email-layout/writer.js +15 -3
- package/dist/lib/marshal/guide/generator.js +163 -0
- package/dist/lib/marshal/guide/helpers.js +6 -10
- package/dist/lib/marshal/guide/index.js +1 -0
- package/dist/lib/marshal/guide/writer.js +5 -9
- package/dist/lib/marshal/message-type/generator.js +139 -0
- package/dist/lib/marshal/message-type/helpers.js +6 -10
- package/dist/lib/marshal/message-type/index.js +1 -0
- package/dist/lib/marshal/message-type/writer.js +5 -1
- package/dist/lib/marshal/partial/generator.js +159 -0
- package/dist/lib/marshal/partial/helpers.js +6 -10
- package/dist/lib/marshal/partial/index.js +1 -0
- package/dist/lib/marshal/partial/writer.js +3 -0
- package/dist/lib/marshal/translation/helpers.js +6 -10
- package/dist/lib/marshal/translation/processor.isomorphic.js +4 -4
- package/dist/lib/marshal/translation/writer.js +2 -2
- package/dist/lib/marshal/workflow/generator.js +175 -19
- package/dist/lib/marshal/workflow/helpers.js +7 -10
- package/dist/lib/run-context/loader.js +5 -0
- package/dist/lib/templates.js +131 -0
- package/dist/lib/urls.js +16 -0
- package/oclif.manifest.json +1446 -547
- package/package.json +11 -9
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "default", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return PartialOpen;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _core = require("@oclif/core");
|
|
12
|
+
const _basecommand = /*#__PURE__*/ _interop_require_default(require("../../lib/base-command"));
|
|
13
|
+
const _browser = require("../../lib/helpers/browser");
|
|
14
|
+
const _error = require("../../lib/helpers/error");
|
|
15
|
+
const _flag = /*#__PURE__*/ _interop_require_wildcard(require("../../lib/helpers/flag"));
|
|
16
|
+
const _request = require("../../lib/helpers/request");
|
|
17
|
+
const _urls = require("../../lib/urls");
|
|
18
|
+
function _define_property(obj, key, value) {
|
|
19
|
+
if (key in obj) {
|
|
20
|
+
Object.defineProperty(obj, key, {
|
|
21
|
+
value: value,
|
|
22
|
+
enumerable: true,
|
|
23
|
+
configurable: true,
|
|
24
|
+
writable: true
|
|
25
|
+
});
|
|
26
|
+
} else {
|
|
27
|
+
obj[key] = value;
|
|
28
|
+
}
|
|
29
|
+
return obj;
|
|
30
|
+
}
|
|
31
|
+
function _interop_require_default(obj) {
|
|
32
|
+
return obj && obj.__esModule ? obj : {
|
|
33
|
+
default: obj
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function _getRequireWildcardCache(nodeInterop) {
|
|
37
|
+
if (typeof WeakMap !== "function") return null;
|
|
38
|
+
var cacheBabelInterop = new WeakMap();
|
|
39
|
+
var cacheNodeInterop = new WeakMap();
|
|
40
|
+
return (_getRequireWildcardCache = function(nodeInterop) {
|
|
41
|
+
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
|
|
42
|
+
})(nodeInterop);
|
|
43
|
+
}
|
|
44
|
+
function _interop_require_wildcard(obj, nodeInterop) {
|
|
45
|
+
if (!nodeInterop && obj && obj.__esModule) {
|
|
46
|
+
return obj;
|
|
47
|
+
}
|
|
48
|
+
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
|
|
49
|
+
return {
|
|
50
|
+
default: obj
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
var cache = _getRequireWildcardCache(nodeInterop);
|
|
54
|
+
if (cache && cache.has(obj)) {
|
|
55
|
+
return cache.get(obj);
|
|
56
|
+
}
|
|
57
|
+
var newObj = {
|
|
58
|
+
__proto__: null
|
|
59
|
+
};
|
|
60
|
+
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
|
|
61
|
+
for(var key in obj){
|
|
62
|
+
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
63
|
+
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
|
|
64
|
+
if (desc && (desc.get || desc.set)) {
|
|
65
|
+
Object.defineProperty(newObj, key, desc);
|
|
66
|
+
} else {
|
|
67
|
+
newObj[key] = obj[key];
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
newObj.default = obj;
|
|
72
|
+
if (cache) {
|
|
73
|
+
cache.set(obj, newObj);
|
|
74
|
+
}
|
|
75
|
+
return newObj;
|
|
76
|
+
}
|
|
77
|
+
class PartialOpen extends _basecommand.default {
|
|
78
|
+
async run() {
|
|
79
|
+
const whoamiResp = await this.apiV1.whoami();
|
|
80
|
+
if (!(0, _request.isSuccessResp)(whoamiResp)) {
|
|
81
|
+
const message = (0, _request.formatErrorRespMessage)(whoamiResp);
|
|
82
|
+
_core.ux.error(new _error.ApiError(message));
|
|
83
|
+
}
|
|
84
|
+
const { account_slug } = whoamiResp.data;
|
|
85
|
+
const { partialKey } = this.props.args;
|
|
86
|
+
const { environment, branch } = this.props.flags;
|
|
87
|
+
const envOrBranch = branch !== null && branch !== void 0 ? branch : environment;
|
|
88
|
+
const url = (0, _urls.viewPartialUrl)(this.sessionContext.dashboardOrigin, account_slug, envOrBranch, partialKey);
|
|
89
|
+
this.log(`‣ Opening partial \`${partialKey}\` in the Knock dashboard...`);
|
|
90
|
+
this.log(` ${url}`);
|
|
91
|
+
await _browser.browser.openUrl(url);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
_define_property(PartialOpen, "summary", "Open a partial in the Knock dashboard.");
|
|
95
|
+
_define_property(PartialOpen, "flags", {
|
|
96
|
+
environment: _core.Flags.string({
|
|
97
|
+
default: "development",
|
|
98
|
+
summary: "The environment to use."
|
|
99
|
+
}),
|
|
100
|
+
branch: _flag.branch
|
|
101
|
+
});
|
|
102
|
+
_define_property(PartialOpen, "args", {
|
|
103
|
+
partialKey: _core.Args.string({
|
|
104
|
+
required: true
|
|
105
|
+
})
|
|
106
|
+
});
|
|
@@ -16,6 +16,7 @@ const _error = require("../../lib/helpers/error");
|
|
|
16
16
|
const _flag = /*#__PURE__*/ _interop_require_wildcard(require("../../lib/helpers/flag"));
|
|
17
17
|
const _objectisomorphic = require("../../lib/helpers/object.isomorphic");
|
|
18
18
|
const _page = require("../../lib/helpers/page");
|
|
19
|
+
const _projectconfig = require("../../lib/helpers/project-config");
|
|
19
20
|
const _request = require("../../lib/helpers/request");
|
|
20
21
|
const _ux = require("../../lib/helpers/ux");
|
|
21
22
|
const _partial = /*#__PURE__*/ _interop_require_wildcard(require("../../lib/marshal/partial"));
|
|
@@ -119,11 +120,8 @@ class PartialPull extends _basecommand.default {
|
|
|
119
120
|
// Pull all partials
|
|
120
121
|
async pullAllPartials() {
|
|
121
122
|
const { flags } = this.props;
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
exists: true
|
|
125
|
-
};
|
|
126
|
-
const targetDirCtx = flags["partials-dir"] || defaultToCwd;
|
|
123
|
+
const partialsIndexDirCtx = await (0, _projectconfig.resolveResourceDir)(this.projectConfig, "partial", this.runContext.cwd);
|
|
124
|
+
const targetDirCtx = flags["partials-dir"] || partialsIndexDirCtx;
|
|
127
125
|
const prompt = targetDirCtx.exists ? `Pull latest partials into ${targetDirCtx.abspath}?\n This will overwrite the contents of this directory.` : `Create a new partials directory at ${targetDirCtx.abspath}?`;
|
|
128
126
|
const input = flags.force || await (0, _ux.promptToConfirm)(prompt);
|
|
129
127
|
if (!input) return;
|
|
@@ -171,10 +169,11 @@ class PartialPull extends _basecommand.default {
|
|
|
171
169
|
};
|
|
172
170
|
return (0, _runcontext.ensureResourceDirForTarget)(resourceDir, target);
|
|
173
171
|
}
|
|
172
|
+
const partialsIndexDirCtx = await (0, _projectconfig.resolveResourceDir)(this.projectConfig, "partial", runCwd);
|
|
174
173
|
// Not inside any existing partial directory, which means either create a
|
|
175
174
|
// new partial directory in the cwd, or update it if there is one already.
|
|
176
175
|
if (partialKey) {
|
|
177
|
-
const dirPath = _nodepath.resolve(
|
|
176
|
+
const dirPath = _nodepath.resolve(partialsIndexDirCtx.abspath, partialKey);
|
|
178
177
|
const exists = await _partial.isPartialDir(dirPath);
|
|
179
178
|
return {
|
|
180
179
|
type: "partial",
|
|
@@ -83,7 +83,7 @@ class PartialPush extends _basecommand.default {
|
|
|
83
83
|
async run() {
|
|
84
84
|
const { flags } = this.props;
|
|
85
85
|
// 1. First read all partial directories found for the given command.
|
|
86
|
-
const target = await _partial.ensureValidCommandTarget(this.props, this.runContext);
|
|
86
|
+
const target = await _partial.ensureValidCommandTarget(this.props, this.runContext, this.projectConfig);
|
|
87
87
|
const [partials, readErrors] = await _partial.readAllForCommandTarget(target, {
|
|
88
88
|
withExtractedFiles: true
|
|
89
89
|
});
|
|
@@ -80,7 +80,7 @@ function _interop_require_wildcard(obj, nodeInterop) {
|
|
|
80
80
|
class PartialValidate extends _basecommand.default {
|
|
81
81
|
async run() {
|
|
82
82
|
// 1. Read all partial directories found for the given command.
|
|
83
|
-
const target = await _partial.ensureValidCommandTarget(this.props, this.runContext);
|
|
83
|
+
const target = await _partial.ensureValidCommandTarget(this.props, this.runContext, this.projectConfig);
|
|
84
84
|
const [partials, readErrors] = await _partial.readAllForCommandTarget(target, {
|
|
85
85
|
withExtractedFiles: true
|
|
86
86
|
});
|
package/dist/commands/pull.js
CHANGED
|
@@ -12,6 +12,7 @@ const _nodepath = /*#__PURE__*/ _interop_require_wildcard(require("node:path"));
|
|
|
12
12
|
const _core = require("@oclif/core");
|
|
13
13
|
const _basecommand = /*#__PURE__*/ _interop_require_default(require("../lib/base-command"));
|
|
14
14
|
const _flag = /*#__PURE__*/ _interop_require_wildcard(require("../lib/helpers/flag"));
|
|
15
|
+
const _projectconfig = require("../lib/helpers/project-config");
|
|
15
16
|
const _ux = require("../lib/helpers/ux");
|
|
16
17
|
const _resources = require("../lib/resources");
|
|
17
18
|
const _pull = /*#__PURE__*/ _interop_require_default(require("./guide/pull"));
|
|
@@ -82,7 +83,11 @@ function _interop_require_wildcard(obj, nodeInterop) {
|
|
|
82
83
|
class Pull extends _basecommand.default {
|
|
83
84
|
async run() {
|
|
84
85
|
const { flags } = this.props;
|
|
85
|
-
|
|
86
|
+
// Resolve knock directory: flag takes precedence, otherwise use knock.json
|
|
87
|
+
const targetDirCtx = await (0, _projectconfig.resolveKnockDir)(flags["knock-dir"], this.projectConfig);
|
|
88
|
+
if (!targetDirCtx) {
|
|
89
|
+
this.error("No knock directory specified. Either provide --knock-dir flag or run `knock init` to create a knock.json configuration file.");
|
|
90
|
+
}
|
|
86
91
|
const prompt = targetDirCtx.exists ? `Pull latest resources into ${targetDirCtx.abspath}?\n This will overwrite the contents of this directory.` : `Create a new resources directory at ${targetDirCtx.abspath}?`;
|
|
87
92
|
const input = flags.force || await (0, _ux.promptToConfirm)(prompt);
|
|
88
93
|
if (!input) return;
|
|
@@ -123,7 +128,7 @@ _define_property(Pull, "flags", {
|
|
|
123
128
|
branch: _flag.branch,
|
|
124
129
|
"knock-dir": _flag.dirPath({
|
|
125
130
|
summary: "The target directory path to pull all resources into.",
|
|
126
|
-
required:
|
|
131
|
+
required: false
|
|
127
132
|
}),
|
|
128
133
|
"hide-uncommitted-changes": _core.Flags.boolean({
|
|
129
134
|
summary: "Hide any uncommitted changes."
|
package/dist/commands/push.js
CHANGED
|
@@ -14,6 +14,7 @@ const _fsextra = /*#__PURE__*/ _interop_require_wildcard(require("fs-extra"));
|
|
|
14
14
|
const _basecommand = /*#__PURE__*/ _interop_require_default(require("../lib/base-command"));
|
|
15
15
|
const _const = require("../lib/helpers/const");
|
|
16
16
|
const _flag = /*#__PURE__*/ _interop_require_wildcard(require("../lib/helpers/flag"));
|
|
17
|
+
const _projectconfig = require("../lib/helpers/project-config");
|
|
17
18
|
const _resources = require("../lib/resources");
|
|
18
19
|
const _push = /*#__PURE__*/ _interop_require_default(require("./guide/push"));
|
|
19
20
|
const _push1 = /*#__PURE__*/ _interop_require_default(require("./layout/push"));
|
|
@@ -83,9 +84,10 @@ function _interop_require_wildcard(obj, nodeInterop) {
|
|
|
83
84
|
class Push extends _basecommand.default {
|
|
84
85
|
async run() {
|
|
85
86
|
const { flags } = this.props;
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
87
|
+
// Resolve knock directory: flag takes precedence, otherwise use knock.json
|
|
88
|
+
const targetDirCtx = await (0, _projectconfig.resolveKnockDir)(flags["knock-dir"], this.projectConfig);
|
|
89
|
+
if (!targetDirCtx) {
|
|
90
|
+
this.error("No knock directory specified. Either provide --knock-dir flag or run `knock init` to create a knock.json configuration file.");
|
|
89
91
|
}
|
|
90
92
|
const args = [
|
|
91
93
|
"--all",
|
|
@@ -133,7 +135,7 @@ _define_property(Push, "flags", {
|
|
|
133
135
|
branch: _flag.branch,
|
|
134
136
|
"knock-dir": _flag.dirPath({
|
|
135
137
|
summary: "The target directory path to find all resources to push.",
|
|
136
|
-
required:
|
|
138
|
+
required: false
|
|
137
139
|
}),
|
|
138
140
|
commit: _core.Flags.boolean({
|
|
139
141
|
summary: "Push and commit the resource(s) at the same time"
|
|
@@ -79,7 +79,7 @@ function _interop_require_wildcard(obj, nodeInterop) {
|
|
|
79
79
|
}
|
|
80
80
|
class TranslationPull extends _basecommand.default {
|
|
81
81
|
async run() {
|
|
82
|
-
const target = await _translation.ensureValidCommandTarget(this.props, this.runContext);
|
|
82
|
+
const target = await _translation.ensureValidCommandTarget(this.props, this.runContext, this.projectConfig);
|
|
83
83
|
switch(target.type){
|
|
84
84
|
case "translationFile":
|
|
85
85
|
return this.pullOneTranslation(target.context);
|
|
@@ -82,7 +82,7 @@ class TranslationPush extends _basecommand.default {
|
|
|
82
82
|
async run() {
|
|
83
83
|
const { flags } = this.props;
|
|
84
84
|
// 1. First read all translation files found for the given command.
|
|
85
|
-
const target = await _translation.ensureValidCommandTarget(this.props, this.runContext);
|
|
85
|
+
const target = await _translation.ensureValidCommandTarget(this.props, this.runContext, this.projectConfig);
|
|
86
86
|
const [translations, readErrors] = await _translation.readAllForCommandTarget(target);
|
|
87
87
|
if (readErrors.length > 0) {
|
|
88
88
|
this.error((0, _error.formatErrors)(readErrors, {
|
|
@@ -79,7 +79,7 @@ function _interop_require_wildcard(obj, nodeInterop) {
|
|
|
79
79
|
}
|
|
80
80
|
class TranslationValidate extends _basecommand.default {
|
|
81
81
|
async run() {
|
|
82
|
-
const target = await _translation.ensureValidCommandTarget(this.props, this.runContext);
|
|
82
|
+
const target = await _translation.ensureValidCommandTarget(this.props, this.runContext, this.projectConfig);
|
|
83
83
|
const [translations, readErrors] = await _translation.readAllForCommandTarget(target);
|
|
84
84
|
if (readErrors.length > 0) {
|
|
85
85
|
this.error((0, _error.formatErrors)(readErrors, {
|
|
@@ -10,11 +10,17 @@ Object.defineProperty(exports, "default", {
|
|
|
10
10
|
});
|
|
11
11
|
const _nodepath = /*#__PURE__*/ _interop_require_wildcard(require("node:path"));
|
|
12
12
|
const _core = require("@oclif/core");
|
|
13
|
-
const
|
|
13
|
+
const _enquirer = require("enquirer");
|
|
14
14
|
const _basecommand = /*#__PURE__*/ _interop_require_default(require("../../lib/base-command"));
|
|
15
15
|
const _const = require("../../lib/helpers/const");
|
|
16
|
+
const _flag = /*#__PURE__*/ _interop_require_wildcard(require("../../lib/helpers/flag"));
|
|
17
|
+
const _projectconfig = require("../../lib/helpers/project-config");
|
|
18
|
+
const _string = require("../../lib/helpers/string");
|
|
16
19
|
const _ux = require("../../lib/helpers/ux");
|
|
17
20
|
const _workflow = /*#__PURE__*/ _interop_require_wildcard(require("../../lib/marshal/workflow"));
|
|
21
|
+
const _generator = require("../../lib/marshal/workflow/generator");
|
|
22
|
+
const _runcontext = require("../../lib/run-context");
|
|
23
|
+
const _push = /*#__PURE__*/ _interop_require_default(require("./push"));
|
|
18
24
|
function _define_property(obj, key, value) {
|
|
19
25
|
if (key in obj) {
|
|
20
26
|
Object.defineProperty(obj, key, {
|
|
@@ -76,75 +82,194 @@ function _interop_require_wildcard(obj, nodeInterop) {
|
|
|
76
82
|
}
|
|
77
83
|
class WorkflowNew extends _basecommand.default {
|
|
78
84
|
async run() {
|
|
79
|
-
const {
|
|
80
|
-
const {
|
|
81
|
-
_ux.spinner.start("‣ Validating");
|
|
85
|
+
const { flags } = this.props;
|
|
86
|
+
const { resourceDir } = this.runContext;
|
|
82
87
|
// 1. Ensure we aren't in any existing resource directory already.
|
|
83
|
-
// TODO: In the future, maybe check for the project context and if we are in
|
|
84
|
-
// /workflows directory.
|
|
85
88
|
if (resourceDir) {
|
|
86
|
-
return this.error(`Cannot
|
|
89
|
+
return this.error(`Cannot create a new workflow inside an existing ${resourceDir.type} directory`);
|
|
87
90
|
}
|
|
88
|
-
// 2.
|
|
89
|
-
|
|
91
|
+
// 2. Prompt for name and key if not provided
|
|
92
|
+
let name = flags.name;
|
|
93
|
+
let key = flags.key;
|
|
94
|
+
if (!name) {
|
|
95
|
+
const nameResponse = await (0, _enquirer.prompt)({
|
|
96
|
+
type: "input",
|
|
97
|
+
name: "name",
|
|
98
|
+
message: "Workflow name",
|
|
99
|
+
validate: (value)=>{
|
|
100
|
+
if (!value || value.trim().length === 0) {
|
|
101
|
+
return "Workflow name is required";
|
|
102
|
+
}
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
name = nameResponse.name;
|
|
107
|
+
}
|
|
108
|
+
if (!key) {
|
|
109
|
+
const keyResponse = await (0, _enquirer.prompt)({
|
|
110
|
+
type: "input",
|
|
111
|
+
name: "key",
|
|
112
|
+
message: "Workflow key (immutable slug)",
|
|
113
|
+
initial: (0, _string.slugify)(name),
|
|
114
|
+
validate: (value)=>{
|
|
115
|
+
if (!value || value.trim().length === 0) {
|
|
116
|
+
return "Workflow key is required";
|
|
117
|
+
}
|
|
118
|
+
const keyError = _workflow.validateWorkflowKey(value);
|
|
119
|
+
if (keyError) {
|
|
120
|
+
return `Invalid workflow key: ${keyError}`;
|
|
121
|
+
}
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
key = keyResponse.key;
|
|
126
|
+
}
|
|
127
|
+
// Validate the workflow key
|
|
128
|
+
const workflowKeyError = _workflow.validateWorkflowKey(key);
|
|
90
129
|
if (workflowKeyError) {
|
|
91
|
-
return this.error(`Invalid workflow key \`${
|
|
130
|
+
return this.error(`Invalid workflow key \`${key}\` (${workflowKeyError})`);
|
|
92
131
|
}
|
|
93
|
-
|
|
94
|
-
const
|
|
95
|
-
if
|
|
96
|
-
|
|
132
|
+
const workflowDirCtx = await this.getWorkflowDirContext(key);
|
|
133
|
+
const promptMessage = workflowDirCtx.exists ? `Found \`${workflowDirCtx.key}\` at ${workflowDirCtx.abspath}, overwrite?` : `Create a new workflow directory \`${workflowDirCtx.key}\` at ${workflowDirCtx.abspath}?`;
|
|
134
|
+
// Check if the workflow directory already exists, and prompt to confirm if not.
|
|
135
|
+
const input = flags.force || await (0, _ux.promptToConfirm)(promptMessage);
|
|
136
|
+
if (!input) return;
|
|
137
|
+
// Generate the workflow either from a template or from scratch
|
|
138
|
+
await (flags.template ? this.fromTemplate(workflowDirCtx, name, flags.template) : this.fromSteps(workflowDirCtx, name, flags.steps));
|
|
139
|
+
if (flags.push) {
|
|
140
|
+
_ux.spinner.start("‣ Pushing workflow to Knock");
|
|
141
|
+
try {
|
|
142
|
+
await _push.default.run([
|
|
143
|
+
key
|
|
144
|
+
]);
|
|
145
|
+
} catch (error) {
|
|
146
|
+
this.error(`Failed to push workflow to Knock: ${error}`);
|
|
147
|
+
} finally{
|
|
148
|
+
_ux.spinner.stop();
|
|
149
|
+
}
|
|
97
150
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
151
|
+
this.log(`‣ Successfully created workflow \`${key}\``);
|
|
152
|
+
}
|
|
153
|
+
async fromTemplate(workflowDirCtx, name, templateString) {
|
|
154
|
+
// When being called from the template string, we want to try and generate
|
|
155
|
+
// the workflow from the provided template.
|
|
156
|
+
const channelsByType = await this.listAllChannelsByType();
|
|
157
|
+
_ux.spinner.start(`‣ Generating workflow from template \`${templateString}\``);
|
|
158
|
+
try {
|
|
159
|
+
await _workflow.generateWorkflowFromTemplate(workflowDirCtx, templateString, {
|
|
160
|
+
name
|
|
161
|
+
}, channelsByType);
|
|
162
|
+
} catch (error) {
|
|
163
|
+
this.error(`Failed to generate workflow from template: ${error}`);
|
|
164
|
+
} finally{
|
|
165
|
+
_ux.spinner.stop();
|
|
103
166
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
167
|
+
}
|
|
168
|
+
async fromSteps(workflowDirCtx, name, stepStr) {
|
|
169
|
+
const channelsByType = await this.listAllChannelsByType();
|
|
170
|
+
const channelTypes = Object.keys(channelsByType);
|
|
171
|
+
const availableStepTypes = _workflow.getAvailableStepTypes(channelTypes);
|
|
172
|
+
let steps = [];
|
|
173
|
+
// Stuff with steps
|
|
174
|
+
if (stepStr) {
|
|
175
|
+
// Parse steps from flag
|
|
176
|
+
const [parsedSteps, stepsError] = (0, _generator.parseStepsInput)(stepStr, availableStepTypes);
|
|
177
|
+
if (stepsError) {
|
|
178
|
+
return this.error(`Invalid --steps \`${stepStr}\` (${stepsError})`);
|
|
179
|
+
}
|
|
180
|
+
steps = parsedSteps || [];
|
|
181
|
+
} else {
|
|
182
|
+
// Prompt for steps with multiselect
|
|
183
|
+
const stepChoices = availableStepTypes.map((stepType)=>({
|
|
184
|
+
name: stepType,
|
|
185
|
+
message: _generator.StepTagChoices[stepType]
|
|
186
|
+
}));
|
|
187
|
+
const stepsResponse = await (0, _enquirer.prompt)({
|
|
188
|
+
type: "multiselect",
|
|
189
|
+
name: "steps",
|
|
190
|
+
message: "(optional) Select step types to bootstrap the workflow with",
|
|
191
|
+
choices: stepChoices
|
|
192
|
+
});
|
|
193
|
+
steps = (stepsResponse === null || stepsResponse === void 0 ? void 0 : stepsResponse.steps) || [];
|
|
194
|
+
}
|
|
195
|
+
// 6. Generate the workflow directory with scaffolded steps
|
|
196
|
+
await _workflow.generateWorkflowDir(workflowDirCtx, {
|
|
197
|
+
name,
|
|
114
198
|
steps
|
|
115
|
-
};
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
if (
|
|
121
|
-
|
|
122
|
-
|
|
199
|
+
}, channelsByType);
|
|
200
|
+
}
|
|
201
|
+
async getWorkflowDirContext(workflowKey) {
|
|
202
|
+
const { resourceDir, cwd: runCwd } = this.runContext;
|
|
203
|
+
// Inside an existing resource dir, use it if valid for the target workflow.
|
|
204
|
+
if (resourceDir) {
|
|
205
|
+
const target = {
|
|
206
|
+
commandId: _basecommand.default.id,
|
|
207
|
+
type: "workflow",
|
|
208
|
+
key: workflowKey
|
|
209
|
+
};
|
|
210
|
+
return (0, _runcontext.ensureResourceDirForTarget)(resourceDir, target);
|
|
211
|
+
}
|
|
212
|
+
// Default to knock project config first if present, otherwise cwd.
|
|
213
|
+
const dirCtx = await (0, _projectconfig.resolveResourceDir)(this.projectConfig, "workflow", runCwd);
|
|
214
|
+
// Not inside any existing workflow directory, which means either create a
|
|
215
|
+
// new worfklow directory in the cwd, or update it if there is one already.
|
|
216
|
+
if (workflowKey) {
|
|
217
|
+
const dirPath = _nodepath.resolve(dirCtx.abspath, workflowKey);
|
|
218
|
+
const exists = await _workflow.isWorkflowDir(dirPath);
|
|
219
|
+
return {
|
|
220
|
+
type: "workflow",
|
|
221
|
+
key: workflowKey,
|
|
222
|
+
abspath: dirPath,
|
|
223
|
+
exists
|
|
224
|
+
};
|
|
123
225
|
}
|
|
226
|
+
// Not in any workflow directory, nor a workflow key arg was given so error.
|
|
227
|
+
return this.error("Missing 1 required arg:\nworkflowKey");
|
|
124
228
|
}
|
|
125
|
-
async
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
229
|
+
async listAllChannelsByType() {
|
|
230
|
+
const channels = await this.apiV1.listAllChannels();
|
|
231
|
+
// Group channels by type
|
|
232
|
+
// eslint-disable-next-line unicorn/no-array-reduce
|
|
233
|
+
const channelsByType = channels.reduce((acc, channel)=>({
|
|
234
|
+
...acc,
|
|
235
|
+
[channel.type]: [
|
|
236
|
+
...acc[channel.type] || [],
|
|
237
|
+
channel
|
|
238
|
+
]
|
|
239
|
+
}), {});
|
|
240
|
+
return channelsByType;
|
|
130
241
|
}
|
|
131
242
|
}
|
|
243
|
+
_define_property(WorkflowNew, "summary", "Create a new workflow with a minimal configuration.");
|
|
132
244
|
_define_property(WorkflowNew, "flags", {
|
|
245
|
+
name: _core.Flags.string({
|
|
246
|
+
summary: "The name of the workflow",
|
|
247
|
+
char: "n"
|
|
248
|
+
}),
|
|
249
|
+
key: _core.Flags.string({
|
|
250
|
+
summary: "The key of the workflow",
|
|
251
|
+
char: "k"
|
|
252
|
+
}),
|
|
133
253
|
steps: _core.Flags.string({
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
]
|
|
254
|
+
summary: "Comma-separated list of step types to include in the workflow",
|
|
255
|
+
char: "s"
|
|
137
256
|
}),
|
|
138
|
-
force: _core.Flags.boolean(),
|
|
139
257
|
environment: _core.Flags.string({
|
|
140
|
-
|
|
258
|
+
summary: "The environment to create the workflow in. Defaults to development.",
|
|
141
259
|
default: _const.KnockEnv.Development
|
|
260
|
+
}),
|
|
261
|
+
branch: _flag.branch,
|
|
262
|
+
force: _core.Flags.boolean({
|
|
263
|
+
summary: "Force the creation of the workflow directory without confirmation."
|
|
264
|
+
}),
|
|
265
|
+
push: _core.Flags.boolean({
|
|
266
|
+
summary: "Whether or not to push the workflow to Knock after creation.",
|
|
267
|
+
default: false,
|
|
268
|
+
char: "p"
|
|
269
|
+
}),
|
|
270
|
+
template: _core.Flags.string({
|
|
271
|
+
summary: "The template repository to use for the workflow. Should be `workflows/{type}`. You cannot use this flag with --steps.",
|
|
272
|
+
char: "t"
|
|
142
273
|
})
|
|
143
274
|
});
|
|
144
|
-
_define_property(WorkflowNew, "args", {
|
|
145
|
-
workflowKey: _core.Args.string({
|
|
146
|
-
required: true
|
|
147
|
-
})
|
|
148
|
-
});
|
|
149
|
-
// TODO(KNO-3072): Unhide after we move the generator logic to the backend.
|
|
150
|
-
_define_property(WorkflowNew, "hidden", true);
|
|
275
|
+
_define_property(WorkflowNew, "args", {});
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "default", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return WorkflowOpen;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _core = require("@oclif/core");
|
|
12
|
+
const _basecommand = /*#__PURE__*/ _interop_require_default(require("../../lib/base-command"));
|
|
13
|
+
const _browser = require("../../lib/helpers/browser");
|
|
14
|
+
const _error = require("../../lib/helpers/error");
|
|
15
|
+
const _flag = /*#__PURE__*/ _interop_require_wildcard(require("../../lib/helpers/flag"));
|
|
16
|
+
const _request = require("../../lib/helpers/request");
|
|
17
|
+
const _urls = require("../../lib/urls");
|
|
18
|
+
function _define_property(obj, key, value) {
|
|
19
|
+
if (key in obj) {
|
|
20
|
+
Object.defineProperty(obj, key, {
|
|
21
|
+
value: value,
|
|
22
|
+
enumerable: true,
|
|
23
|
+
configurable: true,
|
|
24
|
+
writable: true
|
|
25
|
+
});
|
|
26
|
+
} else {
|
|
27
|
+
obj[key] = value;
|
|
28
|
+
}
|
|
29
|
+
return obj;
|
|
30
|
+
}
|
|
31
|
+
function _interop_require_default(obj) {
|
|
32
|
+
return obj && obj.__esModule ? obj : {
|
|
33
|
+
default: obj
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function _getRequireWildcardCache(nodeInterop) {
|
|
37
|
+
if (typeof WeakMap !== "function") return null;
|
|
38
|
+
var cacheBabelInterop = new WeakMap();
|
|
39
|
+
var cacheNodeInterop = new WeakMap();
|
|
40
|
+
return (_getRequireWildcardCache = function(nodeInterop) {
|
|
41
|
+
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
|
|
42
|
+
})(nodeInterop);
|
|
43
|
+
}
|
|
44
|
+
function _interop_require_wildcard(obj, nodeInterop) {
|
|
45
|
+
if (!nodeInterop && obj && obj.__esModule) {
|
|
46
|
+
return obj;
|
|
47
|
+
}
|
|
48
|
+
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
|
|
49
|
+
return {
|
|
50
|
+
default: obj
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
var cache = _getRequireWildcardCache(nodeInterop);
|
|
54
|
+
if (cache && cache.has(obj)) {
|
|
55
|
+
return cache.get(obj);
|
|
56
|
+
}
|
|
57
|
+
var newObj = {
|
|
58
|
+
__proto__: null
|
|
59
|
+
};
|
|
60
|
+
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
|
|
61
|
+
for(var key in obj){
|
|
62
|
+
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
63
|
+
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
|
|
64
|
+
if (desc && (desc.get || desc.set)) {
|
|
65
|
+
Object.defineProperty(newObj, key, desc);
|
|
66
|
+
} else {
|
|
67
|
+
newObj[key] = obj[key];
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
newObj.default = obj;
|
|
72
|
+
if (cache) {
|
|
73
|
+
cache.set(obj, newObj);
|
|
74
|
+
}
|
|
75
|
+
return newObj;
|
|
76
|
+
}
|
|
77
|
+
class WorkflowOpen extends _basecommand.default {
|
|
78
|
+
async run() {
|
|
79
|
+
const whoamiResp = await this.apiV1.whoami();
|
|
80
|
+
if (!(0, _request.isSuccessResp)(whoamiResp)) {
|
|
81
|
+
const message = (0, _request.formatErrorRespMessage)(whoamiResp);
|
|
82
|
+
_core.ux.error(new _error.ApiError(message));
|
|
83
|
+
}
|
|
84
|
+
const { account_slug } = whoamiResp.data;
|
|
85
|
+
const { workflowKey } = this.props.args;
|
|
86
|
+
const { environment, branch } = this.props.flags;
|
|
87
|
+
const envOrBranch = branch !== null && branch !== void 0 ? branch : environment;
|
|
88
|
+
const url = (0, _urls.viewWorkflowUrl)(this.sessionContext.dashboardOrigin, account_slug, envOrBranch, workflowKey);
|
|
89
|
+
this.log(`‣ Opening workflow \`${workflowKey}\` in the Knock dashboard...`);
|
|
90
|
+
this.log(` ${url}`);
|
|
91
|
+
await _browser.browser.openUrl(url);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
_define_property(WorkflowOpen, "summary", "Open a workflow in the Knock dashboard.");
|
|
95
|
+
_define_property(WorkflowOpen, "flags", {
|
|
96
|
+
environment: _core.Flags.string({
|
|
97
|
+
default: "development",
|
|
98
|
+
summary: "The environment to use."
|
|
99
|
+
}),
|
|
100
|
+
branch: _flag.branch
|
|
101
|
+
});
|
|
102
|
+
_define_property(WorkflowOpen, "args", {
|
|
103
|
+
workflowKey: _core.Args.string({
|
|
104
|
+
required: true
|
|
105
|
+
})
|
|
106
|
+
});
|