heroku 10.2.0 → 10.3.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 CHANGED
@@ -96,7 +96,7 @@ Run all tests with `yarn test`.
96
96
 
97
97
  ## Debugging
98
98
 
99
- Using WebStorm (from Jetbrains / IntelliJ), you can run/debug an individual test case.
99
+ Using WebStorm (from JetBrains / IntelliJ), you can run/debug an individual test case.
100
100
 
101
101
  - Create a new run/debug configuration
102
102
  - Select the 'Mocha' type
@@ -14,18 +14,27 @@ class Index extends command_1.Command {
14
14
  Accept: 'application/vnd.heroku+json; version=3.sdk',
15
15
  },
16
16
  });
17
- const buildpacks = await buildpacksCommand.fetch(flags.app, (0, generation_1.getGeneration)(app) === 'fir');
17
+ const isFirApp = (0, generation_1.getGeneration)(app) === 'fir';
18
+ const buildpacks = await buildpacksCommand.fetch(flags.app, isFirApp);
18
19
  if (buildpacks.length === 0) {
19
20
  this.log(`${color_1.default.app(flags.app)} has no Buildpacks.`);
20
21
  }
21
22
  else {
22
- core_1.ux.styledHeader(`${color_1.default.app(flags.app)} Buildpack${buildpacks.length > 1 ? 's' : ''}`);
23
+ const pluralizedBuildpacks = buildpacks.length > 1 ? 'Buildpacks' : 'Buildpack';
24
+ let header = `${color_1.default.app(flags.app)}`;
25
+ if (isFirApp) {
26
+ header += ` Cloud Native ${pluralizedBuildpacks} (from the latest release's OCI image)`;
27
+ }
28
+ else {
29
+ header += ` Classic ${pluralizedBuildpacks} (from the Heroku Buildpack Registry)`;
30
+ }
31
+ core_1.ux.styledHeader(header);
23
32
  buildpacksCommand.display(buildpacks, '');
24
33
  }
25
34
  }
26
35
  }
27
36
  exports.default = Index;
28
- Index.description = 'display the buildpacks for an app';
37
+ Index.description = 'list the buildpacks on an app';
29
38
  Index.flags = {
30
39
  app: command_1.flags.app({ required: true }),
31
40
  remote: command_1.flags.remote(),
@@ -51,36 +51,37 @@ class Outliers extends command_1.Command {
51
51
  const truncatedQueryString = truncate ? (0, tsheredoc_1.default) `
52
52
  CASE WHEN length(query) <= 40 THEN query ELSE substr(query, 0, 39) || '…' END
53
53
  ` : 'query';
54
+ let totalExecTimeField = '';
54
55
  if (version && Number.parseInt(version, 10) >= 13) {
55
- return (0, tsheredoc_1.default) `
56
+ totalExecTimeField = 'total_exec_time';
57
+ }
58
+ else {
59
+ totalExecTimeField = 'total_time';
60
+ }
61
+ let blkReadTimeField = '';
62
+ let blkWriteTimeField = '';
63
+ if (version && Number.parseInt(version, 10) >= 17) {
64
+ blkReadTimeField = 'shared_blk_read_time';
65
+ blkWriteTimeField = 'shared_blk_write_time';
66
+ }
67
+ else {
68
+ blkReadTimeField = 'blk_read_time';
69
+ blkWriteTimeField = 'blk_write_time';
70
+ }
71
+ return (0, tsheredoc_1.default) `
56
72
  SELECT
57
- interval '1 millisecond' * total_exec_time AS total_exec_time,
58
- to_char((total_exec_time/sum(total_exec_time) OVER()) * 100, 'FM90D0') || '%' AS prop_exec_time,
73
+ interval '1 millisecond' * ${totalExecTimeField} AS total_exec_time,
74
+ to_char((${totalExecTimeField}/sum(${totalExecTimeField}) OVER()) * 100, 'FM90D0') || '%' AS prop_exec_time,
59
75
  to_char(calls, 'FM999G999G999G990') AS ncalls,
60
- interval '1 millisecond' * (blk_read_time + blk_write_time) AS sync_io_time,
76
+ interval '1 millisecond' * (${blkReadTimeField} + ${blkWriteTimeField}) AS sync_io_time,
61
77
  ${truncatedQueryString} AS query
62
78
  FROM pg_stat_statements
63
79
  WHERE userid = (
64
80
  SELECT usesysid FROM pg_user WHERE usename = current_user LIMIT 1
65
81
  )
66
- ORDER BY total_exec_time DESC
82
+ ORDER BY ${totalExecTimeField} DESC
67
83
  LIMIT ${limit};
68
84
  `;
69
- }
70
- return (0, tsheredoc_1.default) `
71
- SELECT
72
- interval '1 millisecond' * total_time AS total_exec_time,
73
- to_char((total_time/sum(total_time) OVER()) * 100, 'FM90D0') || '%' AS prop_exec_time,
74
- to_char(calls, 'FM999G999G999G990') AS ncalls,
75
- interval '1 millisecond' * (blk_read_time + blk_write_time) AS sync_io_time,
76
- ${truncatedQueryString} AS query
77
- FROM pg_stat_statements
78
- WHERE userid = (
79
- SELECT usesysid FROM pg_user WHERE usename = current_user LIMIT 1
80
- )
81
- ORDER BY total_time DESC
82
- LIMIT ${limit};
83
- `;
84
85
  }
85
86
  }
86
87
  exports.default = Outliers;
@@ -8,6 +8,7 @@ const inquirer_1 = require("inquirer");
8
8
  const api_1 = require("../../lib/api");
9
9
  const infer_1 = require("../../lib/pipelines/infer");
10
10
  const stages_1 = require("../../lib/pipelines/stages");
11
+ const generation_1 = require("../../lib/apps/generation");
11
12
  class Create extends command_1.Command {
12
13
  async run() {
13
14
  const { args, flags } = await this.parse(Create);
@@ -43,8 +44,8 @@ class Create extends command_1.Command {
43
44
  const teamName = flags.team;
44
45
  const ownerType = teamName ? 'team' : 'user';
45
46
  // If team or org is not specified, we assign ownership to the user creating
46
- owner = teamName ? await (0, api_1.getTeam)(this.heroku, teamName) : await (0, api_1.getAccountInfo)(this.heroku);
47
- owner = owner.body;
47
+ const response = teamName ? await (0, api_1.getTeam)(this.heroku, teamName) : await (0, api_1.getAccountInfo)(this.heroku);
48
+ owner = response.body;
48
49
  const ownerID = owner.id;
49
50
  owner = { id: ownerID, type: ownerType };
50
51
  const answers = await (0, inquirer_1.prompt)(questions);
@@ -53,7 +54,8 @@ class Create extends command_1.Command {
53
54
  if (answers.stage)
54
55
  stage = answers.stage;
55
56
  core_1.ux.action.start(`Creating ${name} pipeline`);
56
- const { body: pipeline } = await (0, api_1.createPipeline)(this.heroku, name, owner);
57
+ const generation = await (0, generation_1.getGenerationByAppId)(app, this.heroku);
58
+ const { body: pipeline } = await (0, api_1.createPipeline)(this.heroku, name, owner, generation);
57
59
  core_1.ux.action.stop();
58
60
  core_1.ux.action.start(`Adding ${color_1.default.app(app)} to ${color_1.default.pipeline(pipeline.name)} pipeline as ${stage}`);
59
61
  await (0, api_1.createCoupling)(this.heroku, pipeline, app, stage);
@@ -11,7 +11,7 @@ class Credentials extends command_1.Command {
11
11
  const addon = await (0, api_1.default)(app, database, false, this.heroku).getRedisAddon();
12
12
  if (reset) {
13
13
  core_1.ux.log(`Resetting credentials for ${addon.name}`);
14
- await (0, api_1.default)(app, database, false, this.heroku).request(`/redis/v0/databases/${addon.name}/credentials_rotation`, 'POST');
14
+ await (0, api_1.default)(app, database, false, this.heroku).request(`/redis/v0/databases/${addon.name}/credentials_rotation`, 'POST', {});
15
15
  }
16
16
  else {
17
17
  const { body: redis } = await (0, api_1.default)(app, database, false, this.heroku).request(`/redis/v0/databases/${addon.name}`);
@@ -19,7 +19,7 @@ class StatsReset extends command_1.Command {
19
19
  await (0, confirmCommand_1.default)(app, confirm, warning);
20
20
  core_1.ux.action.start(`Resetting stats on ${color_1.default.addon(addon.name || '')}`);
21
21
  const { body: response } = await (0, api_1.default)(app, database, false, this.heroku)
22
- .request(`/redis/v0/databases/${addon.id}/stats/reset`, 'POST');
22
+ .request(`/redis/v0/databases/${addon.id}/stats/reset`, 'POST', {});
23
23
  core_1.ux.action.stop(response.message);
24
24
  }
25
25
  }
@@ -22,7 +22,7 @@ class Wait extends command_1.Command {
22
22
  let waiting = false;
23
23
  while (true) {
24
24
  try {
25
- status = await api.request(`/redis/v0/databases/${addon.name}/wait`, 'GET').then(response => response.body);
25
+ status = await api.request(`/redis/v0/databases/${addon.name}/wait`).then(response => response.body);
26
26
  }
27
27
  catch (error) {
28
28
  const httpError = error;
@@ -56,7 +56,7 @@ class Create extends command_1.Command {
56
56
  },
57
57
  });
58
58
  core_1.ux.action.stop();
59
- core_1.ux.warn(`${color_1.default.bold('Spend Alert.')} During the limited GA period, each Heroku ${spaceType} Private Space costs ~${dollarAmountHourly}/hour (max ${dollarAmountMonthly}/month), pro-rated to the second.`);
59
+ core_1.ux.warn(`${color_1.default.bold('Spend Alert.')} Each Heroku ${spaceType} Private Space costs ~${dollarAmountHourly}/hour (max ${dollarAmountMonthly}/month), pro-rated to the second.`);
60
60
  core_1.ux.warn(`Use ${color_1.default.cmd('heroku spaces:wait')} to track allocation.`);
61
61
  core_1.ux.styledHeader(space.name);
62
62
  core_1.ux.styledObject({
@@ -44,6 +44,6 @@ Index.topic = 'telemetry';
44
44
  Index.description = 'list telemetry drains';
45
45
  Index.flags = {
46
46
  space: command_1.flags.string({ char: 's', description: 'filter by space name', exactlyOne: ['app', 'space'] }),
47
- app: command_1.flags.string({ description: 'filter by app name' }),
47
+ app: command_1.flags.string({ char: 'a', description: 'filter by app name' }),
48
48
  };
49
49
  Index.example = '$ heroku telemetry';
package/lib/lib/api.d.ts CHANGED
@@ -5,12 +5,13 @@ export declare const V3_HEADER = "application/vnd.heroku+json; version=3";
5
5
  export declare const SDK_HEADER = "application/vnd.heroku+json; version=3.sdk";
6
6
  export declare const FILTERS_HEADER: string;
7
7
  export declare const PIPELINES_HEADER: string;
8
+ export declare type Owner = Pick<Heroku.Account, 'id' | 'type'> | Pick<Heroku.Team, 'id' | 'type'>;
8
9
  export declare function createAppSetup(heroku: APIClient, body: {
9
10
  body: any;
10
11
  }): Promise<import("@heroku/http-call").HTTP<Heroku.AppSetup>>;
11
12
  export declare function postCoupling(heroku: APIClient, pipeline: any, app: any, stage: string): Promise<import("@heroku/http-call").HTTP<unknown>>;
12
13
  export declare function createCoupling(heroku: APIClient, pipeline: any, app: string, stage: string): Promise<import("@heroku/http-call").HTTP<unknown>>;
13
- export declare function createPipeline(heroku: APIClient, name: any, owner: any): Promise<import("@heroku/http-call").HTTP<Heroku.Pipeline>>;
14
+ export declare function createPipeline(heroku: APIClient, name: string, owner: Owner, generationName?: string): Promise<import("@heroku/http-call").HTTP<Heroku.Pipeline>>;
14
15
  export declare function createPipelineTransfer(heroku: APIClient, pipeline: Heroku.Pipeline): Promise<import("@heroku/http-call").HTTP<unknown>>;
15
16
  export declare function destroyPipeline(heroku: APIClient, name: any, pipelineId: any): Promise<import("@heroku/http-call").HTTP<unknown>>;
16
17
  export declare function findPipelineByName(heroku: APIClient, idOrName: string): Promise<import("@heroku/http-call").HTTP<Heroku.Pipeline[]>>;
package/lib/lib/api.js CHANGED
@@ -20,11 +20,11 @@ function createCoupling(heroku, pipeline, app, stage) {
20
20
  return postCoupling(heroku, pipeline.id, app, stage);
21
21
  }
22
22
  exports.createCoupling = createCoupling;
23
- function createPipeline(heroku, name, owner) {
23
+ function createPipeline(heroku, name, owner, generationName = 'cedar') {
24
24
  return heroku.request('/pipelines', {
25
25
  method: 'POST',
26
26
  headers: { Accept: exports.PIPELINES_HEADER },
27
- body: { name, owner },
27
+ body: { name, owner, generation: { name: generationName } },
28
28
  });
29
29
  }
30
30
  exports.createPipeline = createPipeline;
@@ -57,7 +57,7 @@ export declare type RedisFormationWaitResponse = {
57
57
  };
58
58
  declare type HttpVerb = 'GET' | 'POST' | 'PATCH' | 'DELETE' | 'PUT';
59
59
  declare const _default: (app: string, database: string | undefined, json: boolean, heroku: APIClient) => {
60
- request<T>(path: string, method?: HttpVerb, body?: {}): Promise<import("@heroku/http-call").HTTP<T>>;
60
+ request<T>(path: string, method?: HttpVerb, body?: unknown): Promise<import("@heroku/http-call").HTTP<T>>;
61
61
  makeAddonsFilter(filter: string | undefined): (addons: Required<Heroku.AddOn>[]) => Required<Heroku.AddOn>[];
62
62
  getRedisAddon(addons?: Required<Heroku.AddOn>[]): Promise<Required<Heroku.AddOn>>;
63
63
  info(): Promise<void>;
@@ -6,8 +6,8 @@ exports.default = (app, database, json, heroku) => {
6
6
  const HOST = process.env.HEROKU_REDIS_HOST || 'api.data.heroku.com';
7
7
  const ADDON = process.env.HEROKU_REDIS_ADDON_NAME || 'heroku-redis';
8
8
  return {
9
- request(path, method = 'GET', body = {}) {
10
- const headers = { Accept: 'application/json' };
9
+ request(path, method = 'GET', body = null) {
10
+ const headers = {};
11
11
  if (process.env.HEROKU_HEADERS) {
12
12
  Object.assign(headers, JSON.parse(process.env.HEROKU_HEADERS));
13
13
  }