heroku 9.3.3-beta.0 → 10.0.0-alpha.1

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 (49) hide show
  1. package/README.md +1 -0
  2. package/lib/commands/access/index.js +1 -1
  3. package/lib/commands/apps/errors.js +1 -1
  4. package/lib/commands/apps/favorites/add.js +1 -1
  5. package/lib/commands/buildpacks/add.js +1 -1
  6. package/lib/commands/buildpacks/info.js +1 -1
  7. package/lib/commands/buildpacks/set.js +1 -1
  8. package/lib/commands/buildpacks/versions.js +1 -1
  9. package/lib/commands/logs.d.ts +5 -3
  10. package/lib/commands/logs.js +64 -23
  11. package/lib/commands/members/index.js +1 -1
  12. package/lib/commands/orgs/open.js +1 -1
  13. package/lib/commands/pg/copy.js +1 -1
  14. package/lib/commands/pipelines/promote.js +3 -3
  15. package/lib/commands/ps/restart.d.ts +2 -1
  16. package/lib/commands/ps/restart.js +43 -11
  17. package/lib/commands/ps/stop.d.ts +3 -2
  18. package/lib/commands/ps/stop.js +40 -9
  19. package/lib/commands/ps/type.js +4 -4
  20. package/lib/commands/spaces/create.d.ts +6 -5
  21. package/lib/commands/spaces/create.js +24 -10
  22. package/lib/commands/spaces/index.d.ts +2 -2
  23. package/lib/commands/spaces/index.js +6 -1
  24. package/lib/commands/spaces/info.js +5 -3
  25. package/lib/commands/spaces/wait.js +5 -3
  26. package/lib/commands/telemetry/add.d.ts +17 -0
  27. package/lib/commands/telemetry/add.js +60 -0
  28. package/lib/commands/telemetry/index.d.ts +13 -0
  29. package/lib/commands/telemetry/index.js +49 -0
  30. package/lib/commands/telemetry/info.d.ts +10 -0
  31. package/lib/commands/telemetry/info.js +24 -0
  32. package/lib/commands/telemetry/remove.d.ts +15 -0
  33. package/lib/commands/telemetry/remove.js +63 -0
  34. package/lib/commands/telemetry/update.d.ts +16 -0
  35. package/lib/commands/telemetry/update.js +60 -0
  36. package/lib/file.js +0 -2
  37. package/lib/lib/apps/generation.d.ts +4 -0
  38. package/lib/lib/apps/generation.js +24 -0
  39. package/lib/lib/run/colorize.js +1 -1
  40. package/lib/lib/run/log-displayer.d.ts +3 -2
  41. package/lib/lib/run/log-displayer.js +45 -33
  42. package/lib/lib/spaces/spaces.d.ts +4 -2
  43. package/lib/lib/spaces/spaces.js +2 -1
  44. package/lib/lib/telemetry/util.d.ts +3 -0
  45. package/lib/lib/telemetry/util.js +29 -0
  46. package/oclif.manifest.json +406 -61
  47. package/package.json +6 -6
  48. package/lib/lib/run/line-transform.d.ts +0 -4
  49. package/lib/lib/run/line-transform.js +0 -26
package/README.md CHANGED
@@ -71,6 +71,7 @@ For other issues, [submit a support ticket](https://help.heroku.com/).
71
71
  * [`heroku spaces`](docs/spaces.md) - list available spaces
72
72
  * [`heroku status`](docs/status.md) - display current status of the Heroku platform
73
73
  * [`heroku teams`](docs/teams.md) - manage teams
74
+ * [`heroku telemetry`](docs/telemetry.md) - list telemetry drains
74
75
  * [`heroku update`](docs/update.md) - update the Heroku CLI
75
76
  * [`heroku version`](docs/version.md)
76
77
  * [`heroku webhooks`](docs/webhooks.md) - list webhooks on an app
@@ -48,7 +48,7 @@ function buildCollaboratorsArray(collaboratorsRaw, admins) {
48
48
  class AccessIndex extends command_1.Command {
49
49
  async run() {
50
50
  var _a, _b;
51
- const { flags, argv, args } = await this.parse(AccessIndex);
51
+ const { flags } = await this.parse(AccessIndex);
52
52
  const { app: appName, json } = flags;
53
53
  const { body: app } = await this.heroku.get(`/apps/${appName}`);
54
54
  let { body: collaborators } = await this.heroku.get(`/apps/${appName}/collaborators`);
@@ -37,7 +37,7 @@ const sumErrors = (errors) => {
37
37
  class Errors extends command_1.Command {
38
38
  async run() {
39
39
  const { flags } = await this.parse(Errors);
40
- const hours = Number.parseInt(flags.hours);
40
+ const hours = Number.parseInt(flags.hours, 10);
41
41
  const NOW = new Date().toISOString();
42
42
  const YESTERDAY = new Date(Date.now() - (hours * 60 * 60 * 1000)).toISOString();
43
43
  const DATE_QUERY = `start_time=${YESTERDAY}&end_time=${NOW}&step=1h`;
@@ -9,7 +9,7 @@ class Add extends command_1.Command {
9
9
  const { app } = flags;
10
10
  core_1.ux.action.start(`Adding ${color_1.default.app(app)} to favorites`);
11
11
  const { body: favorites } = await this.heroku.get('/favorites?type=app', { hostname: 'particleboard.heroku.com' });
12
- if (favorites.find(f => f.resource_name === app)) {
12
+ if (favorites.some(f => f.resource_name === app)) {
13
13
  throw new Error(`${color_1.default.app(app)} is already a favorite app.`);
14
14
  }
15
15
  try {
@@ -17,7 +17,7 @@ class Add extends command_1.Command {
17
17
  spliceIndex = buildpacks.length;
18
18
  }
19
19
  else {
20
- // eslint-disable-next-line unicorn/no-array-callback-reference, unicorn/no-array-method-this-argument
20
+ // eslint-disable-next-line unicorn/no-array-method-this-argument
21
21
  const foundIndex = buildpackCommand.findIndex(buildpacks, flags.index);
22
22
  spliceIndex = (foundIndex === -1) ? buildpacks.length : foundIndex;
23
23
  }
@@ -9,7 +9,7 @@ class Info extends command_1.Command {
9
9
  const { args } = await this.parse(Info);
10
10
  const registry = new buildpack_registry_1.BuildpackRegistry();
11
11
  true_myth_1.Result.match({
12
- Ok: _ => { },
12
+ Ok: () => { },
13
13
  Err: err => {
14
14
  this.error(`Could not publish the buildpack.\n${err}`);
15
15
  },
@@ -17,7 +17,7 @@ class Set extends command_1.Command {
17
17
  spliceIndex = 0;
18
18
  }
19
19
  else {
20
- // eslint-disable-next-line unicorn/no-array-callback-reference, unicorn/no-array-method-this-argument
20
+ // eslint-disable-next-line unicorn/no-array-method-this-argument
21
21
  const foundIndex = buildpackCommand.findIndex(buildpacks, flags.index);
22
22
  spliceIndex = (foundIndex === -1) ? buildpacks.length : foundIndex;
23
23
  }
@@ -13,7 +13,7 @@ class Versions extends command_1.Command {
13
13
  }
14
14
  const registry = new buildpack_registry_1.BuildpackRegistry();
15
15
  true_myth_1.Result.match({
16
- Ok: _ => { },
16
+ Ok: () => { },
17
17
  Err: err => {
18
18
  this.error(`Could not find the buildpack.\n${err}`);
19
19
  },
@@ -4,13 +4,15 @@ export default class Logs extends Command {
4
4
  static examples: string[];
5
5
  static flags: {
6
6
  app: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
7
- remote: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
7
+ 'dyno-name': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
8
+ 'force-colors': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
9
+ 'no-color': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
8
10
  num: import("@oclif/core/lib/interfaces").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
9
11
  ps: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
10
- dyno: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
12
+ remote: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
11
13
  source: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
12
14
  tail: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
13
- 'force-colors': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
15
+ 'process-type': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
14
16
  };
15
17
  run(): Promise<void>;
16
18
  }
@@ -1,45 +1,86 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- /* eslint-disable @typescript-eslint/ban-ts-comment */
4
- // tslint:disable:file-name-casing
5
3
  const color_1 = require("@heroku-cli/color");
6
4
  const command_1 = require("@heroku-cli/command");
7
5
  const completions_1 = require("@heroku-cli/command/lib/completions");
8
6
  const log_displayer_1 = require("../lib/run/log-displayer");
7
+ const tsheredoc_1 = require("tsheredoc");
9
8
  class Logs extends command_1.Command {
10
9
  async run() {
11
10
  const { flags } = await this.parse(Logs);
12
- color_1.default.enabled = flags['force-colors'] || color_1.default.enabled;
11
+ const { app, 'dyno-name': dyno, 'force-colors': forceColors, num, ps, source, tail, 'process-type': type } = flags;
12
+ if (forceColors)
13
+ color_1.default.enabled = true;
13
14
  await (0, log_displayer_1.default)(this.heroku, {
14
- app: flags.app,
15
- // @ts-ignore
16
- dyno: flags.dyno || flags.ps,
17
- lines: flags.num || 100,
18
- tail: flags.tail,
19
- source: flags.source,
15
+ app,
16
+ dyno,
17
+ lines: num || 100,
18
+ source,
19
+ tail,
20
+ type: type || ps,
20
21
  });
21
22
  }
22
23
  }
23
24
  exports.default = Logs;
24
- Logs.description = `display recent log output
25
- disable colors with --no-color, HEROKU_LOGS_COLOR=0, or HEROKU_COLOR=0`;
25
+ Logs.description = (0, tsheredoc_1.default) `
26
+ display recent log output
27
+ disable colors with --no-color, HEROKU_LOGS_COLOR=0, or HEROKU_COLOR=0
28
+ `;
26
29
  Logs.examples = [
27
- '$ heroku logs --app=my-app',
28
- '$ heroku logs --num=50',
29
- '$ heroku logs --dyno=web --app=my-app',
30
- '$ heroku logs --app=my-app --tail',
30
+ 'heroku logs --app=my-app',
31
+ 'heroku logs --num=50 --app=my-app',
32
+ 'heroku logs --dyno-name=web-123-456 --app=my-app',
33
+ 'heroku logs --process-type=web --app=my-app',
34
+ 'heroku logs --app=my-app --tail',
31
35
  ];
32
36
  Logs.flags = {
33
37
  app: command_1.flags.app({ required: true }),
34
- remote: command_1.flags.remote(),
35
- num: command_1.flags.integer({ char: 'n', description: 'number of lines to display' }),
36
- ps: command_1.flags.string({ char: 'p', description: 'hidden alias for dyno', hidden: true }),
37
- dyno: command_1.flags.string({
38
+ 'dyno-name': command_1.flags.string({
39
+ aliases: ['dyno'],
38
40
  char: 'd',
39
- description: 'only show output from this dyno type (such as "web" or "worker")',
41
+ description: 'only show output from this dyno (such as "web-123-456" or "worker.2")',
42
+ }),
43
+ 'force-colors': command_1.flags.boolean({
44
+ description: 'force use of colors (even on non-tty output)',
45
+ }),
46
+ // supports-color NPM package will parse ARGV looking for flag `--no-color`, but
47
+ // we need to define it here for OClif not to error out on an inexistent flag.
48
+ 'no-color': command_1.flags.boolean({
49
+ default: false,
50
+ hidden: true,
51
+ relationships: [
52
+ { type: 'none', flags: ['force-colors'] },
53
+ ],
54
+ }),
55
+ num: command_1.flags.integer({
56
+ char: 'n',
57
+ description: 'number of lines to display (ignored for Fir generation apps)',
58
+ }),
59
+ ps: command_1.flags.string({
60
+ char: 'p',
61
+ hidden: true,
62
+ description: 'hidden alias for type',
63
+ relationships: [
64
+ { type: 'none', flags: ['dyno-name'] },
65
+ ],
66
+ completion: completions_1.ProcessTypeCompletion,
67
+ }),
68
+ remote: command_1.flags.remote(),
69
+ source: command_1.flags.string({
70
+ char: 's',
71
+ description: 'only show output from this source (such as "app" or "heroku")',
72
+ }),
73
+ tail: command_1.flags.boolean({
74
+ char: 't',
75
+ default: false,
76
+ description: 'continually stream logs (defaults to true for Fir generation apps)',
77
+ }),
78
+ 'process-type': command_1.flags.string({
79
+ char: 'p',
80
+ description: 'only show output from this process type (such as "web" or "worker")',
81
+ relationships: [
82
+ { type: 'none', flags: ['dyno-name', 'ps'] },
83
+ ],
40
84
  completion: completions_1.ProcessTypeCompletion,
41
85
  }),
42
- source: command_1.flags.string({ char: 's', description: 'only show output from this source (such as "app" or "heroku")' }),
43
- tail: command_1.flags.boolean({ char: 't', description: 'continually stream logs' }),
44
- 'force-colors': command_1.flags.boolean({ description: 'force use of colors (even on non-tty output)' }),
45
86
  };
@@ -29,7 +29,7 @@ class MembersIndex extends command_1.Command {
29
29
  let teamInvites = [];
30
30
  if (teamInfo.type === 'team') {
31
31
  const { body: orgFeatures } = await this.heroku.get(`/teams/${team}/features`);
32
- if (orgFeatures.find((feature => feature.name === 'team-invite-acceptance' && feature.enabled))) {
32
+ if (orgFeatures.some((feature => feature.name === 'team-invite-acceptance' && feature.enabled))) {
33
33
  const invitesResponse = await this.heroku.get(`/teams/${team}/invitations`, { headers: {
34
34
  Accept: 'application/vnd.heroku+json; version=3.team-invitations',
35
35
  },
@@ -10,7 +10,7 @@ class OrgsOpen extends command_1.Command {
10
10
  await open(url);
11
11
  }
12
12
  async run() {
13
- const { flags, argv, args } = await this.parse(OrgsOpen);
13
+ const { flags } = await this.parse(OrgsOpen);
14
14
  const team = flags.team;
15
15
  const { body: org } = await this.heroku.get(`/teams/${team}`);
16
16
  await OrgsOpen.openUrl(`https://dashboard.heroku.com/teams/${org.name}`);
@@ -38,7 +38,7 @@ class Copy extends command_1.Command {
38
38
  const { flags, args } = await this.parse(Copy);
39
39
  const { 'wait-interval': waitInterval, verbose, confirm, app } = flags;
40
40
  const pgbackups = (0, backups_1.default)(app, this.heroku);
41
- const interval = Math.max(3, Number.parseInt(waitInterval || '0')) || 3;
41
+ const interval = Math.max(3, Number.parseInt(waitInterval || '0', 10)) || 3;
42
42
  const [source, target] = await Promise.all([getAttachmentInfo(this.heroku, args.source, app), getAttachmentInfo(this.heroku, args.target, app)]);
43
43
  if (source.url === target.url)
44
44
  throw new Error('Cannot copy database onto itself');
@@ -35,7 +35,7 @@ function isFailed(promotionTarget) {
35
35
  }
36
36
  function pollPromotionStatus(heroku, id, needsReleaseCommand) {
37
37
  return heroku.get(`/pipeline-promotions/${id}/promotion-targets`).then(function ({ body: targets }) {
38
- if (targets.every(isComplete)) { // eslint-disable-line unicorn/no-array-callback-reference
38
+ if (targets.every(isComplete)) {
39
39
  return targets;
40
40
  }
41
41
  //
@@ -98,7 +98,7 @@ async function getRelease(heroku, app, releaseId) {
98
98
  return release;
99
99
  }
100
100
  async function streamReleaseCommand(heroku, targets, promotion) {
101
- if (targets.length !== 1 || targets.every(isComplete)) { // eslint-disable-line unicorn/no-array-callback-reference
101
+ if (targets.length !== 1 || targets.every(isComplete)) {
102
102
  return pollPromotionStatus(heroku, promotion.id, false);
103
103
  }
104
104
  const target = targets[0];
@@ -190,7 +190,7 @@ class Promote extends command_1.Command {
190
190
  memo[app.name] = details;
191
191
  return memo;
192
192
  }, {});
193
- if (promotionTargets.every(isSucceeded)) { // eslint-disable-line unicorn/no-array-callback-reference
193
+ if (promotionTargets.every(isSucceeded)) {
194
194
  core_1.ux.log('\nPromotion successful');
195
195
  }
196
196
  else {
@@ -5,13 +5,14 @@ export default class Restart extends Command {
5
5
  static aliases: string[];
6
6
  static hiddenAliases: string[];
7
7
  static examples: string[];
8
- static help: string;
9
8
  static args: {
10
9
  dyno: import("@oclif/core/lib/interfaces/parser").Arg<string | undefined, Record<string, unknown>>;
11
10
  };
12
11
  static flags: {
13
12
  app: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
14
13
  remote: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
14
+ 'dyno-name': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
15
+ 'process-type': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
15
16
  };
16
17
  run(): Promise<void>;
17
18
  }
@@ -3,36 +3,68 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const command_1 = require("@heroku-cli/command");
4
4
  const color_1 = require("@heroku-cli/color");
5
5
  const core_1 = require("@oclif/core");
6
+ const completions_1 = require("@heroku-cli/command/lib/completions");
7
+ const tsheredoc_1 = require("tsheredoc");
6
8
  class Restart extends command_1.Command {
7
9
  async run() {
8
10
  const { args, flags } = await this.parse(Restart);
9
11
  const app = flags.app;
10
- const dyno = args.dyno;
12
+ const dyno = flags['dyno-name'] || args.dyno;
13
+ const type = flags['process-type'];
11
14
  let msg = 'Restarting';
12
- if (dyno)
13
- msg += ` ${color_1.default.cyan(dyno)}`;
14
- msg += (dyno && dyno.includes('.')) ? ' dyno' : ' dynos';
15
+ let restartUrl;
16
+ if (type) {
17
+ msg += ` all ${color_1.default.cyan(type)} dynos`;
18
+ restartUrl = `/apps/${app}/formations/${encodeURIComponent(type)}`;
19
+ }
20
+ else if (dyno) {
21
+ if (args.dyno) {
22
+ core_1.ux.warn(`DYNO is a deprecated argument. Use ${color_1.default.cmd('--dyno-name')} or ${color_1.default.cmd('--process-type')} instead.`);
23
+ }
24
+ msg += ` dyno ${color_1.default.cyan(dyno)}`;
25
+ restartUrl = `/apps/${app}/dynos/${encodeURIComponent(dyno)}`;
26
+ }
27
+ else {
28
+ msg += ' all dynos';
29
+ restartUrl = `/apps/${app}/dynos`;
30
+ }
15
31
  msg += ` on ${color_1.default.app(app)}`;
16
32
  core_1.ux.action.start(msg);
17
- await this.heroku.delete(dyno ? `/apps/${app}/dynos/${encodeURIComponent(dyno)}` : `/apps/${app}/dynos`);
33
+ await this.heroku.delete(restartUrl, {
34
+ headers: {
35
+ Accept: 'application/vnd.heroku+json; version=3.sdk',
36
+ },
37
+ });
18
38
  core_1.ux.action.stop();
19
39
  }
20
40
  }
21
41
  exports.default = Restart;
22
- Restart.description = 'restart app dynos';
42
+ Restart.description = (0, tsheredoc_1.default)(`
43
+ restart an app dyno or process type
44
+ if neither --dyno nor --type are specified, restarts all dynos on app
45
+ `);
23
46
  Restart.topic = 'ps';
24
47
  Restart.aliases = ['dyno:restart'];
25
48
  Restart.hiddenAliases = ['restart'];
26
49
  Restart.examples = [
27
- '$ heroku ps:restart web.1',
28
- '$ heroku ps:restart web',
29
- '$ heroku ps:restart',
50
+ '$ heroku ps:restart --app myapp --dyno-name web.1',
51
+ '$ heroku ps:restart --app myapp --process-type web',
52
+ '$ heroku ps:restart --app myapp',
30
53
  ];
31
- Restart.help = 'if DYNO is not specified, restarts all dynos on app';
32
54
  Restart.args = {
33
- dyno: core_1.Args.string({ required: false }),
55
+ dyno: core_1.Args.string({ description: 'name of the dyno to restart', required: false, deprecated: true }),
34
56
  };
35
57
  Restart.flags = {
36
58
  app: command_1.flags.app({ required: true }),
37
59
  remote: command_1.flags.remote(),
60
+ 'dyno-name': command_1.flags.string({
61
+ char: 'd',
62
+ description: 'name of the dyno to restart',
63
+ }),
64
+ 'process-type': command_1.flags.string({
65
+ char: 'p',
66
+ description: 'name of the process type to restart',
67
+ completion: completions_1.ProcessTypeCompletion,
68
+ exclusive: ['dyno-name'],
69
+ }),
38
70
  };
@@ -5,13 +5,14 @@ export default class Stop extends Command {
5
5
  static aliases: string[];
6
6
  static hiddenAliases: string[];
7
7
  static examples: string[];
8
- static help: string;
9
8
  static args: {
10
- dyno: import("@oclif/core/lib/interfaces/parser").Arg<string, Record<string, unknown>>;
9
+ dyno: import("@oclif/core/lib/interfaces/parser").Arg<string | undefined, Record<string, unknown>>;
11
10
  };
12
11
  static flags: {
13
12
  app: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
14
13
  remote: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
14
+ 'dyno-name': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
15
+ 'process-type': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
15
16
  };
16
17
  run(): Promise<void>;
17
18
  }
@@ -3,31 +3,62 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const command_1 = require("@heroku-cli/command");
4
4
  const color_1 = require("@heroku-cli/color");
5
5
  const core_1 = require("@oclif/core");
6
+ const completions_1 = require("@heroku-cli/command/lib/completions");
7
+ const tsheredoc_1 = require("tsheredoc");
6
8
  class Stop extends command_1.Command {
7
9
  async run() {
8
10
  const { args, flags } = await this.parse(Stop);
9
11
  const app = flags.app;
10
- const dyno = args.dyno;
11
- const type = dyno.includes('.') ? 'ps' : 'type';
12
- core_1.ux.action.start(`Stopping ${color_1.default.cyan(dyno)} ${type === 'ps' ? 'dyno' : 'dynos'} on ${color_1.default.app(app)}`);
13
- await this.heroku.post(`/apps/${app}/dynos/${dyno}/actions/stop`);
12
+ const dyno = flags['dyno-name'] || args.dyno;
13
+ const type = flags['process-type'];
14
+ let msg = 'Stopping';
15
+ let stopUrl = '';
16
+ if (type) {
17
+ msg += ` all ${color_1.default.cyan(type)} dynos`;
18
+ stopUrl = `/apps/${app}/formations/${encodeURIComponent(type)}/actions/stop`;
19
+ }
20
+ else if (dyno) {
21
+ if (args.dyno) {
22
+ core_1.ux.warn(`DYNO is a deprecated argument. Use ${color_1.default.cmd('--dyno-name')} or ${color_1.default.cmd('--process-type')} instead.`);
23
+ }
24
+ msg += ` dyno ${color_1.default.cyan(dyno)}`;
25
+ stopUrl = `/apps/${app}/dynos/${encodeURIComponent(dyno)}/actions/stop`;
26
+ }
27
+ else {
28
+ core_1.ux.error((0, tsheredoc_1.default)(`
29
+ Please specify a process type or dyno name to stop.
30
+ See more help with --help
31
+ `));
32
+ }
33
+ msg += ` on ${color_1.default.app(app)}`;
34
+ core_1.ux.action.start(msg);
35
+ await this.heroku.post(stopUrl, { headers: { Accept: 'application/vnd.heroku+json; version=3.sdk' } });
14
36
  core_1.ux.action.stop();
15
37
  }
16
38
  }
17
39
  exports.default = Stop;
18
- Stop.description = 'stop app dyno';
40
+ Stop.description = 'stop an app dyno or process type';
19
41
  Stop.topic = 'ps';
20
42
  Stop.aliases = ['dyno:stop', 'ps:kill', 'dyno:kill'];
21
43
  Stop.hiddenAliases = ['stop', 'kill'];
22
44
  Stop.examples = [
23
- '$ heroku ps:stop run.1828',
24
- '$ heroku ps:stop run',
45
+ '$ heroku ps:stop --app myapp --dyno-name run.1828',
46
+ '$ heroku ps:stop --app myapp --process-type run',
25
47
  ];
26
- Stop.help = 'stop app dyno or dyno type';
27
48
  Stop.args = {
28
- dyno: core_1.Args.string({ required: true }),
49
+ dyno: core_1.Args.string({ description: 'name of the dyno to stop', required: false, deprecated: true }),
29
50
  };
30
51
  Stop.flags = {
31
52
  app: command_1.flags.app({ required: true }),
32
53
  remote: command_1.flags.remote(),
54
+ 'dyno-name': command_1.flags.string({
55
+ char: 'd',
56
+ description: 'name of the dyno to stop',
57
+ }),
58
+ 'process-type': command_1.flags.string({
59
+ char: 'p',
60
+ description: 'name of the process type to stop',
61
+ completion: completions_1.ProcessTypeCompletion,
62
+ exclusive: ['dyno-name'],
63
+ }),
33
64
  };
@@ -51,7 +51,6 @@ const displayFormation = async (heroku, app) => {
51
51
  }
52
52
  return {
53
53
  // this rule does not realize `size` isn't used on an array
54
- /* eslint-disable unicorn/explicit-length-check */
55
54
  type: color_1.default.green(d.type || ''),
56
55
  size: color_1.default.cyan(d.size),
57
56
  qty: color_1.default.yellow(`${d.quantity}`),
@@ -73,7 +72,7 @@ const displayFormation = async (heroku, app) => {
73
72
  if (formation.length === 0) {
74
73
  throw emptyFormationErr(app);
75
74
  }
76
- core_1.ux.styledHeader('Dyno Types');
75
+ core_1.ux.styledHeader('Process Types');
77
76
  core_1.ux.table(formationTableData, {
78
77
  type: {},
79
78
  size: {},
@@ -81,6 +80,7 @@ const displayFormation = async (heroku, app) => {
81
80
  'cost/hour': {},
82
81
  'max cost/month': {},
83
82
  });
83
+ core_1.ux.log();
84
84
  core_1.ux.styledHeader('Dyno Totals');
85
85
  core_1.ux.table(dynoTotalsTableData, {
86
86
  type: {},
@@ -99,12 +99,12 @@ class Type extends command_1.Command {
99
99
  if (!argv || argv.length === 0)
100
100
  return [];
101
101
  const { body: formation } = await this.heroku.get(`/apps/${app}/formation`);
102
- if (argv.find(a => a.match(/=/))) {
102
+ if (argv.some(a => a.match(/=/))) {
103
103
  return (0, lodash_1.compact)(argv.map(arg => {
104
104
  const match = arg.match(/^([a-zA-Z0-9_]+)=([\w-]+)$/);
105
105
  const type = match && match[1];
106
106
  const size = match && match[2];
107
- if (!type || !size || !formation.find(p => p.type === type)) {
107
+ if (!type || !size || !formation.some(p => p.type === type)) {
108
108
  throw new Error(`Type ${color_1.default.red(type || '')} not found in process formation.\nTypes: ${color_1.default.yellow(formation.map(f => f.type)
109
109
  .join(', '))}`);
110
110
  }
@@ -4,15 +4,16 @@ export default class Create extends Command {
4
4
  static description: string;
5
5
  static examples: string[];
6
6
  static flags: {
7
- space: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
8
7
  channel: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
9
- region: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
8
+ cidr: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
9
+ 'data-cidr': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
10
10
  features: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
11
+ generation: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
12
+ 'kpi-url': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
11
13
  'log-drain-url': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
14
+ region: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
12
15
  shield: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
13
- cidr: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
14
- 'kpi-url': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
15
- 'data-cidr': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
16
+ space: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
16
17
  team: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
17
18
  };
18
19
  static args: {
@@ -10,7 +10,7 @@ const parsers_1 = require("../../lib/spaces/parsers");
10
10
  class Create extends command_1.Command {
11
11
  async run() {
12
12
  const { flags, args } = await this.parse(Create);
13
- const { channel, region, features, 'log-drain-url': logDrainUrl, shield, cidr, 'kpi-url': kpiUrl, 'data-cidr': dataCidr, team } = flags;
13
+ const { channel, region, features, generation, 'log-drain-url': logDrainUrl, shield, cidr, 'kpi-url': kpiUrl, 'data-cidr': dataCidr, team } = flags;
14
14
  const spaceName = flags.space || args.space;
15
15
  if (!spaceName) {
16
16
  core_1.ux.error((0, tsheredoc_1.default) `
@@ -23,9 +23,21 @@ class Create extends command_1.Command {
23
23
  const spaceType = shield ? 'Shield' : 'Standard';
24
24
  core_1.ux.action.start(`Creating space ${color_1.default.green(spaceName)} in team ${color_1.default.cyan(team)}`);
25
25
  const { body: space } = await this.heroku.post('/spaces', {
26
+ headers: {
27
+ Accept: 'application/vnd.heroku+json; version=3.sdk',
28
+ },
26
29
  body: {
27
- name: spaceName, team: team, channel_name: channel, region: region, features: (0, parsers_1.splitCsv)(features),
28
- log_drain_url: logDrainUrl, shield, cidr, kpi_url: kpiUrl, data_cidr: dataCidr,
30
+ channel_name: channel,
31
+ cidr,
32
+ data_cidr: dataCidr,
33
+ features: (0, parsers_1.splitCsv)(features),
34
+ generation,
35
+ kpi_url: kpiUrl,
36
+ log_drain_url: logDrainUrl,
37
+ name: spaceName,
38
+ region,
39
+ shield,
40
+ team,
29
41
  },
30
42
  });
31
43
  core_1.ux.action.stop();
@@ -33,8 +45,8 @@ class Create extends command_1.Command {
33
45
  core_1.ux.warn(`Use ${color_1.default.cmd('heroku spaces:wait')} to track allocation.`);
34
46
  core_1.ux.styledHeader(space.name);
35
47
  core_1.ux.styledObject({
36
- ID: space.id, Team: space.team.name, Region: space.region.name, CIDR: space.cidr, 'Data CIDR': space.data_cidr, State: space.state, Shield: (0, spaces_1.displayShieldState)(space), 'Created at': space.created_at,
37
- }, ['ID', 'Team', 'Region', 'CIDR', 'Data CIDR', 'State', 'Shield', 'Created at']);
48
+ ID: space.id, Team: space.team.name, Region: space.region.name, CIDR: space.cidr, 'Data CIDR': space.data_cidr, State: space.state, Shield: (0, spaces_1.displayShieldState)(space), Generation: space.generation, 'Created at': space.created_at,
49
+ }, ['ID', 'Team', 'Region', 'CIDR', 'Data CIDR', 'State', 'Shield', 'Generation', 'Created at']);
38
50
  }
39
51
  }
40
52
  exports.default = Create;
@@ -54,18 +66,20 @@ Create.examples = [(0, tsheredoc_1.default) `
54
66
  CIDR: 10.0.0.0/16
55
67
  Data CIDR: 172.23.0.0/20
56
68
  State: allocating
69
+ Generation: fir
57
70
  Created at: 2016-01-06T03:23:13Z
58
71
  `];
59
72
  Create.flags = {
60
- space: command_1.flags.string({ char: 's', description: 'name of space to create' }),
61
73
  channel: command_1.flags.string({ hidden: true }),
62
- region: command_1.flags.string({ description: 'region name', completion: completions_1.RegionCompletion }),
74
+ cidr: command_1.flags.string({ description: 'RFC-1918 CIDR the space will use' }),
75
+ 'data-cidr': command_1.flags.string({ description: 'RFC-1918 CIDR used by Heroku Data resources for the space' }),
63
76
  features: command_1.flags.string({ hidden: true, description: 'a list of features separated by commas' }),
77
+ generation: command_1.flags.string({ description: 'generation for space', default: 'cedar', options: ['cedar', 'fir'] }),
78
+ 'kpi-url': command_1.flags.string({ hidden: true, description: 'self-managed KPI endpoint to use' }),
64
79
  'log-drain-url': command_1.flags.string({ hidden: true, description: 'direct log drain url' }),
80
+ region: command_1.flags.string({ description: 'region name', completion: completions_1.RegionCompletion }),
65
81
  shield: command_1.flags.boolean({ hidden: true, description: 'create a Shield space' }),
66
- cidr: command_1.flags.string({ description: 'RFC-1918 CIDR the space will use' }),
67
- 'kpi-url': command_1.flags.string({ hidden: true, description: 'self-managed KPI endpoint to use' }),
68
- 'data-cidr': command_1.flags.string({ description: 'RFC-1918 CIDR used by Heroku Data resources for the space' }),
82
+ space: command_1.flags.string({ char: 's', description: 'name of space to create' }),
69
83
  team: command_1.flags.team({ required: true }),
70
84
  };
71
85
  Create.args = {
@@ -1,6 +1,6 @@
1
1
  import { Command } from '@heroku-cli/command';
2
- import * as Heroku from '@heroku-cli/schema';
3
- declare type SpaceArray = Array<Required<Heroku.Space>>;
2
+ import { Space } from '../../lib/types/fir';
3
+ declare type SpaceArray = Array<Required<Space>>;
4
4
  export default class Index extends Command {
5
5
  static topic: string;
6
6
  static description: string;
@@ -7,7 +7,11 @@ class Index extends command_1.Command {
7
7
  async run() {
8
8
  const { flags } = await this.parse(Index);
9
9
  const { team, json } = flags;
10
- let { body: spaces } = await this.heroku.get('/spaces');
10
+ let { body: spaces } = await this.heroku.get('/spaces', {
11
+ headers: {
12
+ Accept: 'application/vnd.heroku+json; version=3.sdk',
13
+ },
14
+ });
11
15
  if (team) {
12
16
  spaces = spaces.filter(s => s.team.name === team);
13
17
  }
@@ -39,6 +43,7 @@ class Index extends command_1.Command {
39
43
  Team: { get: space => space.team.name },
40
44
  Region: { get: space => space.region.name },
41
45
  State: { get: space => space.state },
46
+ Generation: { get: space => space.generation },
42
47
  createdAt: {
43
48
  header: 'Created At',
44
49
  get: space => space.created_at,