@knocklabs/cli 1.1.1 → 1.2.2

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.
Files changed (42) hide show
  1. package/README.md +297 -170
  2. package/dist/commands/audience/new.js +2 -2
  3. package/dist/commands/branch/rebase.js +65 -0
  4. package/dist/commands/commit/index.js +15 -11
  5. package/dist/commands/commit/list.js +2 -8
  6. package/dist/commands/guide/get.js +6 -0
  7. package/dist/commands/guide/list.js +6 -0
  8. package/dist/commands/guide/push.js +1 -0
  9. package/dist/commands/layout/push.js +1 -0
  10. package/dist/commands/message-type/push.js +1 -0
  11. package/dist/commands/partial/push.js +1 -0
  12. package/dist/commands/push.js +4 -0
  13. package/dist/commands/schema/pull.js +197 -0
  14. package/dist/commands/schema/push.js +203 -0
  15. package/dist/commands/source/get.js +180 -0
  16. package/dist/commands/source/list.js +96 -0
  17. package/dist/commands/translation/push.js +1 -0
  18. package/dist/commands/whoami.js +8 -2
  19. package/dist/commands/workflow/get.js +6 -0
  20. package/dist/commands/workflow/list.js +6 -0
  21. package/dist/commands/workflow/push.js +1 -0
  22. package/dist/commands/workflow/run.js +6 -0
  23. package/dist/help.js +74 -0
  24. package/dist/lib/api-v1.js +78 -1
  25. package/dist/lib/auth.js +3 -2
  26. package/dist/lib/helpers/flag.js +15 -0
  27. package/dist/lib/marshal/guide/helpers.js +11 -0
  28. package/dist/lib/marshal/schema/helpers.js +142 -0
  29. package/dist/lib/marshal/schema/index.js +21 -0
  30. package/dist/lib/marshal/schema/reader.js +177 -0
  31. package/dist/lib/marshal/schema/types.js +15 -0
  32. package/dist/lib/marshal/schema/writer.js +154 -0
  33. package/dist/lib/marshal/shared/helpers.js +30 -14
  34. package/dist/lib/marshal/source/helpers.js +28 -0
  35. package/dist/lib/marshal/source/index.js +19 -0
  36. package/dist/lib/marshal/source/types.js +4 -0
  37. package/dist/lib/marshal/workflow/generator.js +11 -8
  38. package/dist/lib/marshal/workflow/helpers.js +10 -6
  39. package/dist/lib/resources.js +11 -0
  40. package/npm-shrinkwrap.json +10698 -0
  41. package/oclif.manifest.json +448 -11
  42. package/package.json +22 -15
@@ -0,0 +1,180 @@
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 SourceGet;
9
+ }
10
+ });
11
+ const _core = require("@oclif/core");
12
+ const _basecommand = /*#__PURE__*/ _interop_require_default(require("../../lib/base-command"));
13
+ const _command = require("../../lib/helpers/command");
14
+ const _date = require("../../lib/helpers/date");
15
+ const _error = require("../../lib/helpers/error");
16
+ const _request = require("../../lib/helpers/request");
17
+ const _ux = require("../../lib/helpers/ux");
18
+ const _helpers = require("../../lib/marshal/source/helpers");
19
+ function _define_property(obj, key, value) {
20
+ if (key in obj) {
21
+ Object.defineProperty(obj, key, {
22
+ value: value,
23
+ enumerable: true,
24
+ configurable: true,
25
+ writable: true
26
+ });
27
+ } else {
28
+ obj[key] = value;
29
+ }
30
+ return obj;
31
+ }
32
+ function _interop_require_default(obj) {
33
+ return obj && obj.__esModule ? obj : {
34
+ default: obj
35
+ };
36
+ }
37
+ class SourceGet extends _basecommand.default {
38
+ async run() {
39
+ _ux.spinner.start("‣ Loading");
40
+ const { source } = await this.loadSource();
41
+ _ux.spinner.stop();
42
+ const { flags } = this.props;
43
+ if (flags.json) return source;
44
+ this.render(source);
45
+ }
46
+ async loadSource() {
47
+ const sourceResp = await this.apiV1.getSource(this.props);
48
+ if (!(0, _request.isSuccessResp)(sourceResp)) {
49
+ const message = (0, _request.formatErrorRespMessage)(sourceResp);
50
+ _core.ux.error(new _error.ApiError(message));
51
+ }
52
+ return {
53
+ source: sourceResp.data
54
+ };
55
+ }
56
+ render(source) {
57
+ var _source_environment_settings;
58
+ const { sourceKey } = this.props.args;
59
+ const { environment } = this.props.flags;
60
+ const scope = environment ? ` in ${(0, _command.formatCommandScope)({
61
+ environment
62
+ })}` : "";
63
+ this.log(`‣ Showing source \`${sourceKey}\`${scope}\n`);
64
+ /*
65
+ * Source table
66
+ */ const rows = [
67
+ {
68
+ key: "Name",
69
+ value: source.name
70
+ },
71
+ {
72
+ key: "Key",
73
+ value: source.key
74
+ },
75
+ {
76
+ key: "Description",
77
+ value: source.description || "-"
78
+ },
79
+ {
80
+ key: "Custom image URL",
81
+ value: source.custom_image_url || "-"
82
+ },
83
+ {
84
+ key: "Created at",
85
+ value: (0, _date.formatDateTime)(source.created_at)
86
+ },
87
+ {
88
+ key: "Updated at",
89
+ value: (0, _date.formatDateTime)(source.updated_at)
90
+ }
91
+ ];
92
+ _core.ux.table(rows, {
93
+ key: {
94
+ header: "Source",
95
+ minWidth: 24
96
+ },
97
+ value: {
98
+ header: "",
99
+ minWidth: 24
100
+ }
101
+ });
102
+ this.log("");
103
+ /*
104
+ * Per-environment settings
105
+ */ const envSettings = (_source_environment_settings = source.environment_settings) !== null && _source_environment_settings !== void 0 ? _source_environment_settings : {};
106
+ for (const slug of Object.keys(envSettings)){
107
+ this.renderEnvironmentSettings(slug, envSettings[slug]);
108
+ }
109
+ }
110
+ renderEnvironmentSettings(slug, envSettings) {
111
+ const { settings, mappings } = envSettings;
112
+ /*
113
+ * A curated subset of the open-ended `settings` object, in display order;
114
+ * the full object is always available via `--json`.
115
+ */ const settingsRows = [
116
+ {
117
+ key: "Endpoint",
118
+ value: (0, _helpers.formatSettingValue)(settings.endpoint)
119
+ },
120
+ {
121
+ key: "Event type path",
122
+ value: (0, _helpers.formatSettingValue)(settings.event_type_path)
123
+ },
124
+ {
125
+ key: "Timestamp path",
126
+ value: (0, _helpers.formatSettingValue)(settings.timestamp_path)
127
+ },
128
+ {
129
+ key: "Idempotency key path",
130
+ value: (0, _helpers.formatSettingValue)(settings.idempotency_key_path)
131
+ },
132
+ {
133
+ key: "Enforce verification",
134
+ value: (0, _helpers.formatSettingValue)(settings.enforce_verification)
135
+ },
136
+ {
137
+ key: "Preprocess script",
138
+ value: (0, _helpers.formatPreprocessScript)(settings)
139
+ }
140
+ ];
141
+ _core.ux.table(settingsRows, {
142
+ key: {
143
+ header: `Settings (${slug})`,
144
+ minWidth: 24
145
+ },
146
+ value: {
147
+ header: "",
148
+ minWidth: 24
149
+ }
150
+ });
151
+ this.log("");
152
+ if (mappings.length > 0) {
153
+ _core.ux.table(mappings, {
154
+ event_type: {
155
+ header: "Event type"
156
+ },
157
+ action_type: {
158
+ header: "Action type"
159
+ },
160
+ status: {
161
+ header: "Status",
162
+ get: (mapping)=>(0, _helpers.formatMappingStatus)(mapping)
163
+ }
164
+ });
165
+ this.log("");
166
+ }
167
+ }
168
+ }
169
+ _define_property(SourceGet, "summary", "Display a single source from an environment.");
170
+ _define_property(SourceGet, "flags", {
171
+ environment: _core.Flags.string({
172
+ summary: "The environment to use."
173
+ })
174
+ });
175
+ _define_property(SourceGet, "args", {
176
+ sourceKey: _core.Args.string({
177
+ required: true
178
+ })
179
+ });
180
+ _define_property(SourceGet, "enableJsonFlag", true);
@@ -0,0 +1,96 @@
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 SourceList;
9
+ }
10
+ });
11
+ const _core = require("@oclif/core");
12
+ const _basecommand = /*#__PURE__*/ _interop_require_default(require("../../lib/base-command"));
13
+ const _command = require("../../lib/helpers/command");
14
+ const _date = require("../../lib/helpers/date");
15
+ const _objectisomorphic = require("../../lib/helpers/object.isomorphic");
16
+ const _page = require("../../lib/helpers/page");
17
+ const _request = require("../../lib/helpers/request");
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
+ class SourceList extends _basecommand.default {
37
+ async run() {
38
+ const resp = await this.request();
39
+ const { flags } = this.props;
40
+ if (flags.json) return resp.data;
41
+ this.render(resp.data);
42
+ }
43
+ async request(pageParams = {}) {
44
+ const props = (0, _objectisomorphic.merge)(this.props, {
45
+ flags: {
46
+ ...pageParams
47
+ }
48
+ });
49
+ return (0, _request.withSpinner)(()=>this.apiV1.listSources(props));
50
+ }
51
+ async render(data) {
52
+ const { entries } = data;
53
+ const { environment } = this.props.flags;
54
+ const scope = environment ? ` in ${(0, _command.formatCommandScope)({
55
+ environment
56
+ })}` : "";
57
+ this.log(`‣ Showing ${entries.length} sources${scope}\n`);
58
+ /*
59
+ * Sources list table
60
+ */ _core.ux.table(entries, {
61
+ key: {
62
+ header: "Key"
63
+ },
64
+ name: {
65
+ header: "Name"
66
+ },
67
+ description: {
68
+ header: "Description",
69
+ get: (entry)=>entry.description || "-"
70
+ },
71
+ updated_at: {
72
+ header: "Updated at",
73
+ get: (entry)=>(0, _date.formatDate)(entry.updated_at)
74
+ }
75
+ });
76
+ return this.prompt(data);
77
+ }
78
+ async prompt(data) {
79
+ const { page_info } = data;
80
+ const pageAction = await (0, _page.maybePromptPageAction)(page_info);
81
+ const pageParams = pageAction && (0, _page.paramsForPageAction)(pageAction, page_info);
82
+ if (pageParams) {
83
+ this.log("\n");
84
+ const resp = await this.request(pageParams);
85
+ return this.render(resp.data);
86
+ }
87
+ }
88
+ }
89
+ _define_property(SourceList, "summary", "Display all sources for an environment.");
90
+ _define_property(SourceList, "flags", {
91
+ environment: _core.Flags.string({
92
+ summary: "The environment to use."
93
+ }),
94
+ ..._page.pageFlags
95
+ });
96
+ _define_property(SourceList, "enableJsonFlag", true);
@@ -154,6 +154,7 @@ _define_property(TranslationPush, "flags", {
154
154
  "commit"
155
155
  ]
156
156
  }),
157
+ "allow-empty": _flag.allowEmptyOnPush,
157
158
  force: _flag.force
158
159
  });
159
160
  _define_property(TranslationPush, "args", {
@@ -40,10 +40,16 @@ class Whoami extends _basecommand.default {
40
40
  `Service token name: ${resp.service_token_name}`
41
41
  ] : [
42
42
  `Account name: ${resp.account_name}`,
43
- `User ID: ${resp.user_id}`
43
+ `User ID: ${resp.user_id}`,
44
+ ...resp.user_name ? [
45
+ `User name: ${resp.user_name}`
46
+ ] : [],
47
+ ...resp.user_email ? [
48
+ `User email: ${resp.user_email}`
49
+ ] : []
44
50
  ];
45
51
  this.log((0, _string.indentString)(info.join("\n"), 4));
46
52
  }
47
53
  }
48
- _define_property(Whoami, "summary", "Verify the provided service token.");
54
+ _define_property(Whoami, "summary", "Verify authentication and show the current account and user.");
49
55
  _define_property(Whoami, "enableJsonFlag", true);
@@ -135,6 +135,12 @@ class WorkflowGet extends _basecommand.default {
135
135
  emptyDisplay: "-"
136
136
  })
137
137
  },
138
+ {
139
+ key: "Tags",
140
+ value: _workflow.formatTags(workflow, {
141
+ emptyDisplay: "-"
142
+ })
143
+ },
138
144
  {
139
145
  key: "Created at",
140
146
  value: (0, _date.formatDateTime)(workflow.created_at)
@@ -116,6 +116,12 @@ class WorkflowList extends _basecommand.default {
116
116
  truncateAfter: 3
117
117
  })
118
118
  },
119
+ tags: {
120
+ header: "Tags",
121
+ get: (entry)=>_workflow.formatTags(entry, {
122
+ truncateAfter: 3
123
+ })
124
+ },
119
125
  steps: {
120
126
  header: "Steps",
121
127
  get: (entry)=>{
@@ -163,6 +163,7 @@ _define_property(WorkflowPush, "flags", {
163
163
  "commit"
164
164
  ]
165
165
  }),
166
+ "allow-empty": _flag.allowEmptyOnPush,
166
167
  force: _flag.force
167
168
  });
168
169
  _define_property(WorkflowPush, "args", {
@@ -106,6 +106,12 @@ _define_property(WorkflowRun, "flags", {
106
106
  }),
107
107
  data: (0, _flag.jsonStr)({
108
108
  summary: "A JSON string of the data for this workflow"
109
+ }),
110
+ "sandbox-mode": _core.Flags.boolean({
111
+ summary: "When enabled, channels in this workflow generate messages but don't send them to the downstream provider."
112
+ }),
113
+ "skip-delay": _core.Flags.boolean({
114
+ summary: "When enabled, delay steps in this workflow will be skipped"
109
115
  })
110
116
  });
111
117
  _define_property(WorkflowRun, "args", {
package/dist/help.js ADDED
@@ -0,0 +1,74 @@
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 KnockHelp;
9
+ }
10
+ });
11
+ const _core = require("@oclif/core");
12
+ const BRAND_COLOR = "#FF573A";
13
+ const WORDMARK = `
14
+ ██╗ ██╗███╗ ██╗ ██████╗ ██████╗██╗ ██╗
15
+ ██║ ██╔╝████╗ ██║██╔═══██╗██╔════╝██║ ██╔╝
16
+ █████╔╝ ██╔██╗ ██║██║ ██║██║ █████╔╝
17
+ ██╔═██╗ ██║╚██╗██║██║ ██║██║ ██╔═██╗
18
+ ██║ ██╗██║ ╚████║╚██████╔╝╚██████╗██║ ██╗
19
+ ╚═╝ ╚═╝╚═╝ ╚═══╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝
20
+ `.trim();
21
+ const GET_STARTED = [
22
+ [
23
+ "knock login",
24
+ "Log in with a Knock user account"
25
+ ],
26
+ [
27
+ "knock init",
28
+ "Initialize a new Knock project (knock.json)"
29
+ ]
30
+ ];
31
+ const COMMON = [
32
+ [
33
+ "knock workflow pull",
34
+ "Pull workflows into a local file system"
35
+ ],
36
+ [
37
+ "knock workflow push",
38
+ "Push workflows from a local file system to Knock"
39
+ ],
40
+ [
41
+ "knock push",
42
+ "Push all resources from a local file system to Knock"
43
+ ],
44
+ [
45
+ "knock commit promote",
46
+ "Promote commits to the subsequent environment"
47
+ ],
48
+ [
49
+ "knock <command> --help",
50
+ "Get help for a command"
51
+ ]
52
+ ];
53
+ function brand(text) {
54
+ return _core.ux.colorize(BRAND_COLOR, text);
55
+ }
56
+ class KnockHelp extends _core.Help {
57
+ async showRootHelp() {
58
+ this.log("");
59
+ this.log(brand(WORDMARK));
60
+ this.log("");
61
+ this.log(`» Knock CLI\n`);
62
+ this.logSection("Get started:", GET_STARTED);
63
+ this.logSection("Common commands:", COMMON);
64
+ }
65
+ logSection(title, entries) {
66
+ const pad = Math.max(...entries.map(([c])=>c.length));
67
+ this.log(title);
68
+ this.log("");
69
+ for (const [cmd, summary] of entries){
70
+ this.log(` ${brand(cmd.padEnd(pad))} ${summary}`);
71
+ }
72
+ this.log("");
73
+ }
74
+ }
@@ -74,6 +74,7 @@ class ApiV1 {
74
74
  annotate: flags.annotate,
75
75
  commit: flags.commit,
76
76
  commit_message: flags["commit-message"],
77
+ allow_empty: flags["allow-empty"],
77
78
  force: flags.force
78
79
  });
79
80
  const data = {
@@ -110,11 +111,18 @@ class ApiV1 {
110
111
  environment: flags.environment,
111
112
  branch: flags.branch
112
113
  });
114
+ const settings = (0, _objectisomorphic.prune)({
115
+ sandbox_mode: flags["sandbox-mode"],
116
+ skip_delay: flags["skip-delay"]
117
+ });
113
118
  const data = (0, _objectisomorphic.prune)({
114
119
  recipients: flags.recipients,
115
120
  tenant: flags.tenant,
116
121
  data: flags.data,
117
- actor: flags.actor
122
+ actor: flags.actor,
123
+ ...Object.keys(settings).length > 0 ? {
124
+ settings
125
+ } : {}
118
126
  });
119
127
  return this.put(`/workflows/${args.workflowKey}/run`, data, {
120
128
  params
@@ -139,6 +147,7 @@ class ApiV1 {
139
147
  environment: flags.environment,
140
148
  branch: flags.branch,
141
149
  commit_message: flags["commit-message"],
150
+ allow_empty: flags["allow-empty"],
142
151
  resource_type: flags["resource-type"],
143
152
  resource_id: flags["resource-id"]
144
153
  });
@@ -190,6 +199,7 @@ class ApiV1 {
190
199
  branch: flags.branch,
191
200
  commit: flags.commit,
192
201
  commit_message: flags["commit-message"],
202
+ allow_empty: flags["allow-empty"],
193
203
  namespace: translation.namespace,
194
204
  force: flags.force
195
205
  });
@@ -243,6 +253,7 @@ class ApiV1 {
243
253
  annotate: flags.annotate,
244
254
  commit: flags.commit,
245
255
  commit_message: flags["commit-message"],
256
+ allow_empty: flags["allow-empty"],
246
257
  force: flags.force
247
258
  });
248
259
  const data = {
@@ -295,6 +306,7 @@ class ApiV1 {
295
306
  annotate: flags.annotate,
296
307
  commit: flags.commit,
297
308
  commit_message: flags["commit-message"],
309
+ allow_empty: flags["allow-empty"],
298
310
  force: flags.force
299
311
  });
300
312
  const data = {
@@ -354,6 +366,7 @@ class ApiV1 {
354
366
  annotate: flags.annotate,
355
367
  commit: flags.commit,
356
368
  commit_message: flags["commit-message"],
369
+ allow_empty: flags["allow-empty"],
357
370
  force: flags.force
358
371
  });
359
372
  const data = {
@@ -400,6 +413,25 @@ class ApiV1 {
400
413
  params
401
414
  });
402
415
  }
416
+ async listSources({ flags }) {
417
+ const params = (0, _objectisomorphic.prune)({
418
+ environment: flags.environment,
419
+ annotate: flags.annotate,
420
+ ...(0, _page.toPageParams)(flags)
421
+ });
422
+ return this.get("/sources", {
423
+ params
424
+ });
425
+ }
426
+ async getSource({ args, flags }) {
427
+ const params = (0, _objectisomorphic.prune)({
428
+ environment: flags.environment,
429
+ annotate: flags.annotate
430
+ });
431
+ return this.get(`/sources/${args.sourceKey}`, {
432
+ params
433
+ });
434
+ }
403
435
  async validateGuide({ flags }, guide) {
404
436
  const params = (0, _objectisomorphic.prune)({
405
437
  environment: flags.environment,
@@ -419,6 +451,7 @@ class ApiV1 {
419
451
  annotate: flags.annotate,
420
452
  commit: flags.commit,
421
453
  commit_message: flags["commit-message"],
454
+ allow_empty: flags["allow-empty"],
422
455
  force: flags.force
423
456
  });
424
457
  const data = {
@@ -440,6 +473,41 @@ class ApiV1 {
440
473
  params
441
474
  });
442
475
  }
476
+ // By resources: Schemas
477
+ async listSchemas({ flags }, filters = {}) {
478
+ const params = (0, _objectisomorphic.prune)({
479
+ environment: flags.environment,
480
+ branch: flags.branch,
481
+ item_type: filters.itemType,
482
+ after: filters.after
483
+ });
484
+ return this.get("/schemas", {
485
+ params
486
+ });
487
+ }
488
+ async getSchema({ flags }, itemType, collection) {
489
+ const params = (0, _objectisomorphic.prune)({
490
+ environment: flags.environment,
491
+ branch: flags.branch,
492
+ item_id: collection
493
+ });
494
+ return this.get(`/schemas/${itemType}`, {
495
+ params
496
+ });
497
+ }
498
+ async upsertSchema({ flags }, itemType, schema, collection) {
499
+ const params = (0, _objectisomorphic.prune)({
500
+ environment: flags.environment,
501
+ branch: flags.branch,
502
+ item_id: collection
503
+ });
504
+ const data = {
505
+ schema
506
+ };
507
+ return this.put(`/schemas/${itemType}`, data, {
508
+ params
509
+ });
510
+ }
443
511
  async listAllChannels() {
444
512
  const channels = [];
445
513
  for await (const channel of this.mgmtClient.channels.list()){
@@ -454,6 +522,15 @@ class ApiV1 {
454
522
  }
455
523
  return environments;
456
524
  }
525
+ // By resources: Branches
526
+ async rebaseBranch(branchSlug, environment) {
527
+ const params = {
528
+ environment
529
+ };
530
+ return this.put(`/branches/${branchSlug}/rebase`, {}, {
531
+ params
532
+ });
533
+ }
457
534
  // By methods:
458
535
  async get(subpath, config) {
459
536
  return this.client.get(`/${API_VERSION}` + subpath, config);
package/dist/lib/auth.js CHANGED
@@ -38,6 +38,7 @@ function _interop_require_default(obj) {
38
38
  };
39
39
  }
40
40
  const DEFAULT_TIMEOUT = 5000;
41
+ const LOGIN_TIMEOUT = 5 * 60 * 1000;
41
42
  function createChallenge() {
42
43
  // PKCE code verifier and challenge
43
44
  const codeVerifier = _nodecrypto.default.randomBytes(32).toString("base64url");
@@ -167,8 +168,8 @@ async function waitForAccessToken(dashboardUrl, authUrl) {
167
168
  });
168
169
  const { codeVerifier, codeChallenge, state } = createChallenge();
169
170
  const timeout = setTimeout(()=>{
170
- cleanupAndReject(`authentication timed out after ${DEFAULT_TIMEOUT / 1000} seconds`);
171
- }, 60000);
171
+ cleanupAndReject(`authentication timed out after ${LOGIN_TIMEOUT / 1000} seconds`);
172
+ }, LOGIN_TIMEOUT);
172
173
  function cleanupAndReject(message) {
173
174
  cleanup();
174
175
  reject(new Error(`Could not authenticate: ${message}`));
@@ -9,6 +9,12 @@ function _export(target, all) {
9
9
  });
10
10
  }
11
11
  _export(exports, {
12
+ get allowEmpty () {
13
+ return allowEmpty;
14
+ },
15
+ get allowEmptyOnPush () {
16
+ return allowEmptyOnPush;
17
+ },
12
18
  get booleanStr () {
13
19
  return booleanStr;
14
20
  },
@@ -158,3 +164,12 @@ const branch = slug({
158
164
  const force = _core.Flags.boolean({
159
165
  summary: "Force pushes the resource or resources to Knock, overwriting whatever is currently stored. " + "If you're using this on a non-development environment, you should also ensure you `commit` the changes."
160
166
  });
167
+ const allowEmpty = _core.Flags.boolean({
168
+ summary: "Create an empty commit for an already-published resource (analogous to git commit --allow-empty). " + "Requires --resource-type and --resource-id."
169
+ });
170
+ const allowEmptyOnPush = _core.Flags.boolean({
171
+ summary: "Create an empty commit for an already-published resource (analogous to git commit --allow-empty).",
172
+ dependsOn: [
173
+ "commit"
174
+ ]
175
+ });
@@ -21,6 +21,9 @@ _export(exports, {
21
21
  get formatStep () {
22
22
  return formatStep;
23
23
  },
24
+ get formatTags () {
25
+ return formatTags;
26
+ },
24
27
  get generateIndexTypeTS () {
25
28
  return generateIndexTypeTS;
26
29
  },
@@ -101,6 +104,14 @@ const formatActivationRules = (rules)=>{
101
104
  if (!rules || !Array.isArray(rules)) return "-";
102
105
  return rules.map(({ directive, pathname })=>`${directive} ${pathname}`).join(", ");
103
106
  };
107
+ const formatTags = (guide, opts = {})=>{
108
+ const { tags } = guide;
109
+ const { truncateAfter: limit, emptyDisplay = "" } = opts;
110
+ if (!tags) return emptyDisplay;
111
+ const count = tags.length;
112
+ if (!limit || limit >= count) return tags.join(", ");
113
+ return (0, _lodash.take)(tags, limit).join(", ") + ` (+ ${count - limit} more)`;
114
+ };
104
115
  const guideJsonPath = (guideDirCtx)=>_nodepath.resolve(guideDirCtx.abspath, _processorisomorphic.GUIDE_JSON);
105
116
  const lsGuideJson = async (dirPath)=>{
106
117
  const guideJsonPath = _nodepath.resolve(dirPath, _processorisomorphic.GUIDE_JSON);