heroku 9.3.2-beta.0 → 10.0.0-alpha.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.
Files changed (45) 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 +61 -22
  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/type.js +2 -3
  16. package/lib/commands/spaces/create.d.ts +6 -6
  17. package/lib/commands/spaces/create.js +24 -12
  18. package/lib/commands/spaces/index.d.ts +2 -2
  19. package/lib/commands/spaces/index.js +6 -1
  20. package/lib/commands/spaces/info.js +5 -3
  21. package/lib/commands/spaces/wait.js +5 -3
  22. package/lib/commands/telemetry/add.d.ts +18 -0
  23. package/lib/commands/telemetry/add.js +70 -0
  24. package/lib/commands/telemetry/index.d.ts +13 -0
  25. package/lib/commands/telemetry/index.js +43 -0
  26. package/lib/commands/telemetry/info.d.ts +10 -0
  27. package/lib/commands/telemetry/info.js +24 -0
  28. package/lib/commands/telemetry/remove.d.ts +15 -0
  29. package/lib/commands/telemetry/remove.js +63 -0
  30. package/lib/commands/telemetry/update.d.ts +16 -0
  31. package/lib/commands/telemetry/update.js +60 -0
  32. package/lib/file.js +0 -2
  33. package/lib/lib/apps/generation.d.ts +4 -0
  34. package/lib/lib/apps/generation.js +24 -0
  35. package/lib/lib/run/colorize.js +1 -1
  36. package/lib/lib/run/log-displayer.d.ts +3 -2
  37. package/lib/lib/run/log-displayer.js +41 -33
  38. package/lib/lib/spaces/spaces.d.ts +4 -2
  39. package/lib/lib/spaces/spaces.js +2 -1
  40. package/lib/lib/telemetry/util.d.ts +3 -0
  41. package/lib/lib/telemetry/util.js +29 -0
  42. package/oclif.manifest.json +348 -53
  43. package/package.json +6 -6
  44. package/lib/lib/run/line-transform.d.ts +0 -4
  45. 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: 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
+ 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,84 @@
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, 'force-colors': forceColors, num, ps, source, tail, 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=web-123-456 --app=my-app',
33
+ 'heroku logs --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
38
  dyno: command_1.flags.string({
38
39
  char: 'd',
39
- description: 'only show output from this dyno type (such as "web" or "worker")',
40
+ description: 'only show output from this dyno (such as "web-123-456" or "worker.2")',
41
+ }),
42
+ 'force-colors': command_1.flags.boolean({
43
+ description: 'force use of colors (even on non-tty output)',
44
+ }),
45
+ // supports-color NPM package will parse ARGV looking for flag `--no-color`, but
46
+ // we need to define it here for OClif not to error out on an inexistent flag.
47
+ 'no-color': command_1.flags.boolean({
48
+ default: false,
49
+ hidden: true,
50
+ relationships: [
51
+ { type: 'none', flags: ['force-colors'] },
52
+ ],
53
+ }),
54
+ num: command_1.flags.integer({
55
+ char: 'n',
56
+ description: 'number of lines to display (ignored for Fir generation apps)',
57
+ }),
58
+ ps: command_1.flags.string({
59
+ char: 'p',
60
+ hidden: true,
61
+ description: 'hidden alias for type',
62
+ relationships: [
63
+ { type: 'none', flags: ['dyno'] },
64
+ ],
65
+ completion: completions_1.ProcessTypeCompletion,
66
+ }),
67
+ remote: command_1.flags.remote(),
68
+ source: command_1.flags.string({
69
+ char: 's',
70
+ description: 'only show output from this source (such as "app" or "heroku")',
71
+ }),
72
+ tail: command_1.flags.boolean({
73
+ char: 't',
74
+ default: false,
75
+ description: 'continually stream logs (defaults to true for Fir generation apps)',
76
+ }),
77
+ type: command_1.flags.string({
78
+ description: 'only show output from this process type (such as "web" or "worker")',
79
+ relationships: [
80
+ { type: 'none', flags: ['dyno', 'ps'] },
81
+ ],
40
82
  completion: completions_1.ProcessTypeCompletion,
41
83
  }),
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
84
  };
@@ -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 {
@@ -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}`),
@@ -99,12 +98,12 @@ class Type extends command_1.Command {
99
98
  if (!argv || argv.length === 0)
100
99
  return [];
101
100
  const { body: formation } = await this.heroku.get(`/apps/${app}/formation`);
102
- if (argv.find(a => a.match(/=/))) {
101
+ if (argv.some(a => a.match(/=/))) {
103
102
  return (0, lodash_1.compact)(argv.map(arg => {
104
103
  const match = arg.match(/^([a-zA-Z0-9_]+)=([\w-]+)$/);
105
104
  const type = match && match[1];
106
105
  const size = match && match[2];
107
- if (!type || !size || !formation.find(p => p.type === type)) {
106
+ if (!type || !size || !formation.some(p => p.type === type)) {
108
107
  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
108
  .join(', '))}`);
110
109
  }
@@ -4,15 +4,15 @@ 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>;
10
- features: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
11
- 'log-drain-url': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
12
- shield: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
13
8
  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
9
  'data-cidr': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
10
+ generation: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
11
+ 'kpi-url': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
12
+ 'log-drain-url': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
13
+ region: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
14
+ shield: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
15
+ space: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
16
16
  team: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
17
17
  };
18
18
  static args: {
@@ -6,11 +6,10 @@ const core_1 = require("@oclif/core");
6
6
  const tsheredoc_1 = require("tsheredoc");
7
7
  const spaces_1 = require("../../lib/spaces/spaces");
8
8
  const completions_1 = require("../../lib/autocomplete/completions");
9
- const parsers_1 = require("../../lib/spaces/parsers");
10
9
  class Create extends command_1.Command {
11
10
  async run() {
12
11
  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;
12
+ const { channel, region, features, generation, 'log-drain-url': logDrainUrl, shield, cidr, 'kpi-url': kpiUrl, 'data-cidr': dataCidr, team } = flags;
14
13
  const spaceName = flags.space || args.space;
15
14
  if (!spaceName) {
16
15
  core_1.ux.error((0, tsheredoc_1.default) `
@@ -23,9 +22,21 @@ class Create extends command_1.Command {
23
22
  const spaceType = shield ? 'Shield' : 'Standard';
24
23
  core_1.ux.action.start(`Creating space ${color_1.default.green(spaceName)} in team ${color_1.default.cyan(team)}`);
25
24
  const { body: space } = await this.heroku.post('/spaces', {
25
+ headers: {
26
+ Accept: 'application/vnd.heroku+json; version=3.sdk',
27
+ },
26
28
  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,
29
+ channel_name: channel,
30
+ cidr,
31
+ data_cidr: dataCidr,
32
+ // features: splitCsv(features),
33
+ generation,
34
+ kpi_url: kpiUrl,
35
+ log_drain_url: logDrainUrl,
36
+ name: spaceName,
37
+ region,
38
+ shield,
39
+ team,
29
40
  },
30
41
  });
31
42
  core_1.ux.action.stop();
@@ -33,8 +44,8 @@ class Create extends command_1.Command {
33
44
  core_1.ux.warn(`Use ${color_1.default.cmd('heroku spaces:wait')} to track allocation.`);
34
45
  core_1.ux.styledHeader(space.name);
35
46
  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']);
47
+ 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,
48
+ }, ['ID', 'Team', 'Region', 'CIDR', 'Data CIDR', 'State', 'Shield', 'Generation', 'Created at']);
38
49
  }
39
50
  }
40
51
  exports.default = Create;
@@ -57,15 +68,16 @@ Create.examples = [(0, tsheredoc_1.default) `
57
68
  Created at: 2016-01-06T03:23:13Z
58
69
  `];
59
70
  Create.flags = {
60
- space: command_1.flags.string({ char: 's', description: 'name of space to create' }),
61
71
  channel: command_1.flags.string({ hidden: true }),
62
- region: command_1.flags.string({ description: 'region name', completion: completions_1.RegionCompletion }),
63
- features: command_1.flags.string({ hidden: true, description: 'a list of features separated by commas' }),
64
- 'log-drain-url': command_1.flags.string({ hidden: true, description: 'direct log drain url' }),
65
- shield: command_1.flags.boolean({ hidden: true, description: 'create a Shield space' }),
66
72
  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
73
  'data-cidr': command_1.flags.string({ description: 'RFC-1918 CIDR used by Heroku Data resources for the space' }),
74
+ // features: flags.string({hidden: true, description: 'a list of features separated by commas'}),
75
+ generation: command_1.flags.string({ description: 'generation for space', default: 'cedar', options: ['cedar', 'fir'] }),
76
+ 'kpi-url': command_1.flags.string({ hidden: true, description: 'self-managed KPI endpoint to use' }),
77
+ 'log-drain-url': command_1.flags.string({ hidden: true, description: 'direct log drain url' }),
78
+ region: command_1.flags.string({ description: 'region name', completion: completions_1.RegionCompletion }),
79
+ shield: command_1.flags.boolean({ hidden: true, description: 'create a Shield space' }),
80
+ space: command_1.flags.string({ char: 's', description: 'name of space to create' }),
69
81
  team: command_1.flags.team({ required: true }),
70
82
  };
71
83
  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,
@@ -17,14 +17,16 @@ class Info extends command_1.Command {
17
17
  See more help with --help
18
18
  `));
19
19
  }
20
- let headers = {};
20
+ const headers = {
21
+ Accept: 'application/vnd.heroku+json; version=3.fir',
22
+ };
21
23
  if (!flags.json) {
22
- headers = { 'Accept-Expansion': 'region' };
24
+ headers['Accept-Expansion'] = 'region';
23
25
  }
24
26
  const { body: space } = await this.heroku.get(`/spaces/${spaceName}`, { headers });
25
27
  if (space.state === 'allocated') {
26
28
  try {
27
- const { body: outbound_ips } = await this.heroku.get(`/spaces/${spaceName}/nat`);
29
+ const { body: outbound_ips } = await this.heroku.get(`/spaces/${spaceName}/nat`, { headers: { Accept: 'application/vnd.heroku+json; version=3.fir' } });
28
30
  space.outbound_ips = outbound_ips;
29
31
  }
30
32
  catch (error) {
@@ -25,9 +25,11 @@ class Wait extends command_1.Command {
25
25
  const deadline = new Date(Date.now() + timeout);
26
26
  const action = new spinner_1.default();
27
27
  action.start(`Waiting for space ${color_1.default.green(spaceName)} to allocate`);
28
- let headers = {};
28
+ const headers = {
29
+ Accept: 'application/vnd.heroku+json; version=3.fir',
30
+ };
29
31
  if (!flags.json) {
30
- headers = { 'Accept-Expansion': 'region' };
32
+ headers['Accept-Expansion'] = 'region';
31
33
  }
32
34
  let { body: space } = await this.heroku.get(`/spaces/${spaceName}`, { headers });
33
35
  while (space.state === 'allocating') {
@@ -39,7 +41,7 @@ class Wait extends command_1.Command {
39
41
  space = updatedSpace;
40
42
  }
41
43
  try {
42
- const { body: nat } = await this.heroku.get(`/spaces/${spaceName}/nat`);
44
+ const { body: nat } = await this.heroku.get(`/spaces/${spaceName}/nat`, { headers: { Accept: 'application/vnd.heroku+json; version=3.fir' } });
43
45
  space.outbound_ips = nat;
44
46
  }
45
47
  catch (error) {
@@ -0,0 +1,18 @@
1
+ import { Command } from '@heroku-cli/command';
2
+ export default class Add extends Command {
3
+ static description: string;
4
+ static flags: {
5
+ app: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
6
+ remote: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
7
+ space: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
8
+ signals: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
9
+ endpoint: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
10
+ transport: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
11
+ };
12
+ static args: {
13
+ headers: import("@oclif/core/lib/interfaces/parser").Arg<string, Record<string, unknown>>;
14
+ };
15
+ static example: string;
16
+ private getTypeAndName;
17
+ run(): Promise<void>;
18
+ }
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const command_1 = require("@heroku-cli/command");
4
+ const core_1 = require("@oclif/core");
5
+ const tsheredoc_1 = require("tsheredoc");
6
+ const util_1 = require("../../lib/telemetry/util");
7
+ class Add extends command_1.Command {
8
+ constructor() {
9
+ super(...arguments);
10
+ this.getTypeAndName = function (app, space) {
11
+ if (app) {
12
+ return { type: 'app', name: app };
13
+ }
14
+ return { type: 'space', name: space };
15
+ };
16
+ }
17
+ async run() {
18
+ const { flags, args } = await this.parse(Add);
19
+ const { app, space, signals, endpoint, transport } = flags;
20
+ const { headers } = args;
21
+ const typeAndName = this.getTypeAndName(app, space);
22
+ const drainConfig = {
23
+ owner: {
24
+ type: typeAndName.type,
25
+ id: typeAndName.name,
26
+ },
27
+ signals: (0, util_1.validateAndFormatSignals)(signals),
28
+ exporter: {
29
+ endpoint,
30
+ type: `otlp${transport}`,
31
+ headers: JSON.parse(headers),
32
+ },
33
+ };
34
+ if (app) {
35
+ const { body: drain } = await this.heroku.post(`/apps/${app}/telemetry-drains`, {
36
+ body: drainConfig,
37
+ headers: {
38
+ Accept: 'application/vnd.heroku+json; version=3.sdk',
39
+ },
40
+ });
41
+ core_1.ux.log(`successfully added drain ${drain.exporter.endpoint}`);
42
+ }
43
+ else if (space) {
44
+ const { body: drain } = await this.heroku.post(`/spaces/${space}/telemetry-drains`, {
45
+ body: drainConfig,
46
+ headers: {
47
+ Accept: 'application/vnd.heroku+json; version=3.sdk',
48
+ },
49
+ });
50
+ core_1.ux.log(`successfully added drain ${drain.exporter.endpoint}`);
51
+ }
52
+ }
53
+ }
54
+ exports.default = Add;
55
+ Add.description = 'Add and configure a new telemetry drain. Defaults to collecting all telemetry unless otherwise specified.';
56
+ Add.flags = {
57
+ app: command_1.flags.app({ exactlyOne: ['app', 'remote', 'space'], description: 'app to add a drain to' }),
58
+ remote: command_1.flags.remote({ description: 'git remote of app to add a drain to' }),
59
+ space: command_1.flags.string({ char: 's', description: 'space to add a drain to' }),
60
+ signals: command_1.flags.string({ default: 'all', description: 'comma-delimited list of signals to collect (traces, metrics, logs). Use "all" to collect all signals.' }),
61
+ endpoint: command_1.flags.string({ required: true, description: 'drain url' }),
62
+ transport: command_1.flags.string({ required: true, options: ['http', 'grpc'], description: 'transport protocol for the drain' }),
63
+ };
64
+ Add.args = {
65
+ headers: core_1.Args.string({ required: true, description: 'custom headers to configure the drain in json format' }),
66
+ };
67
+ Add.example = (0, tsheredoc_1.default)(`
68
+ Add a telemetry drain to an app to collect logs and traces:
69
+ $ heroku telemetry:add --signals logs,traces --endpoint https://my-endpoint.com --transport http 'x-drain-example-team: API_KEY x-drain-example-dataset: METRICS_DATASET'
70
+ `);
@@ -0,0 +1,13 @@
1
+ import { Command } from '@heroku-cli/command';
2
+ import { TelemetryDrains } from '../../lib/types/telemetry';
3
+ export default class Index extends Command {
4
+ static topic: string;
5
+ static description: string;
6
+ static flags: {
7
+ space: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
8
+ app: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
9
+ };
10
+ static example: string;
11
+ run(): Promise<void>;
12
+ protected display(telemetryDrains: TelemetryDrains, ownerType: 'App' | 'Space'): void;
13
+ }
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const command_1 = require("@heroku-cli/command");
4
+ const core_1 = require("@oclif/core");
5
+ class Index extends command_1.Command {
6
+ async run() {
7
+ const { flags } = await this.parse(Index);
8
+ const { app, space } = flags;
9
+ if (app) {
10
+ const { body: appTelemetryDrains } = await this.heroku.get(`/apps/${app}/telemetry-drains`, {
11
+ headers: {
12
+ Accept: 'application/vnd.heroku+json; version=3.sdk',
13
+ },
14
+ });
15
+ this.display(appTelemetryDrains, 'App');
16
+ }
17
+ else if (space) {
18
+ const { body: spaceTelemetryDrains } = await this.heroku.get(`/spaces/${space}/telemetry-drains`, {
19
+ headers: {
20
+ Accept: 'application/vnd.heroku+json; version=3.sdk',
21
+ },
22
+ });
23
+ this.display(spaceTelemetryDrains, 'Space');
24
+ }
25
+ }
26
+ display(telemetryDrains, ownerType) {
27
+ core_1.ux.styledHeader(`${ownerType} Telemetry Drains`);
28
+ core_1.ux.table(telemetryDrains, {
29
+ ID: { get: telemetryDrain => telemetryDrain.id },
30
+ Signals: { get: telemetryDrain => telemetryDrain.signals },
31
+ Endpoint: { get: telemetryDrain => telemetryDrain.exporter.endpoint },
32
+ [ownerType]: { get: telemetryDrain => telemetryDrain.owner.name },
33
+ });
34
+ }
35
+ }
36
+ exports.default = Index;
37
+ Index.topic = 'telemetry';
38
+ Index.description = 'list telemetry drains';
39
+ Index.flags = {
40
+ space: command_1.flags.string({ char: 's', description: 'filter by space name', exactlyOne: ['app', 'space'] }),
41
+ app: command_1.flags.app({ description: 'filter by app name' }),
42
+ };
43
+ Index.example = '$ heroku telemetry';
@@ -0,0 +1,10 @@
1
+ import { Command } from '@heroku-cli/command';
2
+ export default class Info extends Command {
3
+ static topic: string;
4
+ static description: string;
5
+ static args: {
6
+ telemetry_drain_id: import("@oclif/core/lib/interfaces/parser").Arg<string, Record<string, unknown>>;
7
+ };
8
+ static example: string;
9
+ run(): Promise<void>;
10
+ }