heroku 9.1.0 → 9.2.0-beta.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.
@@ -42,12 +42,17 @@ function parseConfig(args) {
42
42
  class Create extends command_1.Command {
43
43
  async run() {
44
44
  var _a;
45
+ this.allowArbitraryFlags = true;
45
46
  const _b = await this.parse(Create), { flags, args } = _b, restParse = tslib_1.__rest(_b, ["flags", "args"]);
46
47
  const { app, name, as, wait, confirm } = flags;
47
48
  const servicePlan = args['service:plan'];
48
49
  const argv = restParse.argv
49
50
  // oclif duplicates specified args in argv
50
51
  .filter(arg => arg !== servicePlan);
52
+ if (restParse.nonExistentFlags && restParse.nonExistentFlags.length > 0) {
53
+ process.stderr.write(` ${color_1.default.yellow('›')} For example: ${color_1.default.cyan(`heroku addons:create -a ${app} ${restParse.raw[0].input} -- ${restParse.nonExistentFlags.join(' ')}`)}`);
54
+ process.stderr.write(` ${color_1.default.yellow('›')} See https://devcenter.heroku.com/changelog-items/2925 for more info.\n`);
55
+ }
51
56
  const config = parseConfig(argv);
52
57
  let addon;
53
58
  try {
@@ -8,7 +8,7 @@ class AuthorizationsCreate extends command_1.Command {
8
8
  async run() {
9
9
  const { flags } = await this.parse(AuthorizationsCreate);
10
10
  core_1.ux.action.start('Creating OAuth Authorization');
11
- const { body: auth, headers } = await this.heroku.post('/oauth/authorizations', {
11
+ const { body: auth } = await this.heroku.post('/oauth/authorizations', {
12
12
  body: {
13
13
  description: flags.description,
14
14
  scope: flags.scope ? flags.scope.split(',') : undefined,
@@ -16,10 +16,6 @@ class AuthorizationsCreate extends command_1.Command {
16
16
  },
17
17
  });
18
18
  core_1.ux.action.stop();
19
- const apiWarnings = headers['warning-message'] || '';
20
- if (apiWarnings) {
21
- core_1.ux.warn(apiWarnings);
22
- }
23
19
  if (flags.short) {
24
20
  core_1.ux.log(auth.access_token && auth.access_token.token);
25
21
  }
@@ -6,11 +6,7 @@ const authorizations_1 = require("../../lib/authorizations/authorizations");
6
6
  class AuthorizationsInfo extends command_1.Command {
7
7
  async run() {
8
8
  const { args, flags } = await this.parse(AuthorizationsInfo);
9
- const { body: authentication, headers } = await this.heroku.get(`/oauth/authorizations/${args.id}`);
10
- const apiWarnings = headers['warning-message'] || '';
11
- if (apiWarnings) {
12
- core_1.ux.warn(apiWarnings);
13
- }
9
+ const { body: authentication } = await this.heroku.get(`/oauth/authorizations/${args.id}`);
14
10
  if (flags.json) {
15
11
  core_1.ux.styledJSON(authentication);
16
12
  }
@@ -7,11 +7,7 @@ class AuthorizationsRevoke extends command_1.Command {
7
7
  async run() {
8
8
  const { args } = await this.parse(AuthorizationsRevoke);
9
9
  core_1.ux.action.start('Revoking OAuth Authorization');
10
- const { body: auth, headers } = await this.heroku.delete(`/oauth/authorizations/${encodeURIComponent(args.id)}`);
11
- const apiWarnings = headers['warning-message'] || '';
12
- if (apiWarnings) {
13
- core_1.ux.warn(apiWarnings);
14
- }
10
+ const { body: auth } = await this.heroku.delete(`/oauth/authorizations/${encodeURIComponent(args.id)}`);
15
11
  core_1.ux.action.stop(`done, revoked authorization from ${color_1.default.cyan(auth.description)}`);
16
12
  }
17
13
  }
@@ -7,11 +7,7 @@ class AuthorizationsRotate extends command_1.Command {
7
7
  async run() {
8
8
  const { args } = await this.parse(AuthorizationsRotate);
9
9
  core_1.ux.action.start('Rotating OAuth Authorization');
10
- const { body: authorization, headers } = await this.heroku.post(`/oauth/authorizations/${encodeURIComponent(args.id)}/actions/regenerate-tokens`);
11
- const apiWarnings = headers['warning-message'] || '';
12
- if (apiWarnings) {
13
- core_1.ux.warn(apiWarnings);
14
- }
10
+ const { body: authorization } = await this.heroku.post(`/oauth/authorizations/${encodeURIComponent(args.id)}/actions/regenerate-tokens`);
15
11
  core_1.ux.action.stop();
16
12
  (0, authorizations_1.display)(authorization);
17
13
  }
@@ -14,16 +14,12 @@ class AuthorizationsUpdate extends command_1.Command {
14
14
  secret: flags['client-secret'],
15
15
  };
16
16
  }
17
- const { body: authentication, headers } = await this.heroku.patch(`/oauth/authorizations/${args.id}`, {
17
+ const { body: authentication } = await this.heroku.patch(`/oauth/authorizations/${args.id}`, {
18
18
  body: {
19
19
  description: flags.description,
20
20
  client,
21
21
  },
22
22
  });
23
- const apiWarnings = headers['warning-message'] || '';
24
- if (apiWarnings) {
25
- core_1.ux.warn(apiWarnings);
26
- }
27
23
  core_1.ux.action.stop();
28
24
  (0, authorizations_1.display)(authentication);
29
25
  }
@@ -18,7 +18,7 @@ CiIndex.examples = [
18
18
  `,
19
19
  ];
20
20
  CiIndex.flags = {
21
- app: command_1.flags.string({ char: 'a', description: 'app name' }),
21
+ app: command_1.flags.app(),
22
22
  remote: command_1.flags.remote(),
23
23
  watch: command_1.flags.boolean({ description: 'keep running and watch for new and update tests', required: false }),
24
24
  pipeline: command_1.flags.pipeline({ required: false }),
@@ -20,7 +20,7 @@ CiInfo.examples = [
20
20
  `,
21
21
  ];
22
22
  CiInfo.flags = {
23
- app: command_1.flags.string({ char: 'a', description: 'app name' }),
23
+ app: command_1.flags.app(),
24
24
  remote: command_1.flags.remote(),
25
25
  node: command_1.flags.string({ description: 'the node number to show its setup and output', required: false }),
26
26
  pipeline: command_1.flags.pipeline({ required: false }),
@@ -25,7 +25,7 @@ CiLast.examples = [
25
25
  `,
26
26
  ];
27
27
  CiLast.flags = {
28
- app: command_1.flags.string({ char: 'a', description: 'app name' }),
28
+ app: command_1.flags.app(),
29
29
  remote: command_1.flags.remote(),
30
30
  node: command_1.flags.string({ description: 'the node number to show its setup and output', required: false }),
31
31
  pipeline: command_1.flags.pipeline({ required: false }),
@@ -45,7 +45,7 @@ CiReRun.examples = [
45
45
  `,
46
46
  ];
47
47
  CiReRun.flags = {
48
- app: command_1.flags.string({ char: 'a', description: 'app name' }),
48
+ app: command_1.flags.app(),
49
49
  remote: command_1.flags.remote(),
50
50
  pipeline: command_1.flags.pipeline({ required: false }),
51
51
  };
@@ -4,6 +4,7 @@ export default class CiRun extends Command {
4
4
  static examples: string[];
5
5
  static flags: {
6
6
  app: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, 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
8
  pipeline: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
8
9
  };
9
10
  run(): Promise<void>;
@@ -37,6 +37,7 @@ CiRun.examples = [
37
37
  `,
38
38
  ];
39
39
  CiRun.flags = {
40
- app: command_1.flags.string({ char: 'a', description: 'app name' }),
40
+ app: command_1.flags.app(),
41
+ remote: command_1.flags.remote(),
41
42
  pipeline: command_1.flags.pipeline({ required: false }),
42
43
  };
@@ -4,12 +4,14 @@ const completions_1 = require("@heroku-cli/command/lib/completions");
4
4
  const core_1 = require("@oclif/core");
5
5
  const color_1 = require("@heroku-cli/color");
6
6
  const fork_foreman_1 = require("../../lib/local/fork-foreman");
7
+ const helpers_1 = require("../../lib/run/helpers");
7
8
  const fs = require("fs");
8
9
  class Run extends core_1.Command {
9
10
  async run() {
10
11
  const execArgv = ['run'];
11
12
  const { argv, flags } = await this.parse(Run);
12
- if (argv.length === 0) {
13
+ const userArgvInputOrder = (0, helpers_1.revertSortedArgs)(process.argv, argv);
14
+ if (userArgvInputOrder.length === 0) {
13
15
  const errorMessage = 'Usage: heroku local:run [COMMAND]\nMust specify command to run';
14
16
  this.error(errorMessage, { exit: -1 });
15
17
  }
@@ -22,7 +24,7 @@ class Run extends core_1.Command {
22
24
  if (flags.port)
23
25
  execArgv.push('--port', flags.port);
24
26
  execArgv.push('--'); // disable node-foreman flag parsing
25
- execArgv.push(...argv); // eslint-disable-line unicorn/no-array-push-push
27
+ execArgv.push(...userArgvInputOrder); // eslint-disable-line unicorn/no-array-push-push
26
28
  await (0, fork_foreman_1.fork)(execArgv);
27
29
  }
28
30
  }
@@ -24,18 +24,12 @@ class Schedule extends command_1.Command {
24
24
  constructor() {
25
25
  super(...arguments);
26
26
  this.parseDate = function (at) {
27
- const m = at.match(/^([0-2]?[0-9]):00 ?(\S*)$/);
28
- if (!m)
29
- throw new Error("Invalid schedule format: expected --at '[HOUR]:00 [TIMEZONE]'");
30
- const [, hour, timezone] = m;
31
- let scheduledTZ = TZ[timezone.toUpperCase()];
32
- if (!scheduledTZ) {
33
- scheduledTZ = 'UTC';
34
- if (timezone) {
35
- core_1.ux.warn(`Unknown timezone ${color_1.default.yellow(timezone)}. Defaulting to UTC.`);
36
- }
27
+ const m = at.match(/^(0?\d|1\d|2[0-3]):00 ?(\S*)$/);
28
+ if (m) {
29
+ const [, hour, timezone] = m;
30
+ return { hour, timezone: TZ[timezone.toUpperCase()] || timezone || 'UTC' };
37
31
  }
38
- return { hour, timezone: scheduledTZ };
32
+ return core_1.ux.error("Invalid schedule format: expected --at '[HOUR]:00 [TIMEZONE]'", { exit: 1 });
39
33
  };
40
34
  }
41
35
  async run() {
@@ -48,7 +42,7 @@ class Schedule extends command_1.Command {
48
42
  const db = attachment.addon;
49
43
  const at = color_1.default.cyan(`${schedule.hour}:00 ${schedule.timezone}`);
50
44
  const pgResponse = await this.heroku.get(`/client/v11/databases/${db.id}`, { hostname: (0, host_1.default)() })
51
- .catch(error => {
45
+ .catch((error) => {
52
46
  if (error.statusCode !== 404)
53
47
  throw error;
54
48
  core_1.ux.error(`${color_1.default.yellow(db.name)} is not yet provisioned.\nRun ${color_1.default.cyan.bold('heroku addons:wait')} to wait until the db is provisioned.`, { exit: 1 });
@@ -8,6 +8,7 @@ export default class Rotate extends Command {
8
8
  confirm: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
9
9
  force: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
10
10
  app: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
11
+ remote: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
11
12
  };
12
13
  static args: {
13
14
  database: import("@oclif/core/lib/interfaces/parser").Arg<string | undefined, Record<string, unknown>>;
@@ -76,6 +76,7 @@ Rotate.flags = {
76
76
  confirm: command_1.flags.string({ char: 'c' }),
77
77
  force: command_1.flags.boolean({ description: 'forces rotating the targeted credentials' }),
78
78
  app: command_1.flags.app({ required: true }),
79
+ remote: command_1.flags.remote(),
79
80
  };
80
81
  Rotate.args = {
81
82
  database: core_1.Args.string(),
@@ -5,10 +5,7 @@ export default class LogMinDuration extends PGSettingsCommand {
5
5
  static description: string;
6
6
  static args: {
7
7
  database: import("@oclif/core/lib/interfaces/parser").Arg<string | undefined, Record<string, unknown>>;
8
- value: import("@oclif/core/lib/interfaces/parser").Arg<number | undefined, {
9
- min?: number | undefined;
10
- max?: number | undefined;
11
- }>;
8
+ value: import("@oclif/core/lib/interfaces/parser").Arg<string | undefined, Record<string, unknown>>;
12
9
  };
13
10
  protected settingKey: SettingKey;
14
11
  protected convertValue(val: string): number;
@@ -29,5 +29,5 @@ LogMinDuration.description = (0, tsheredoc_1.default)(`
29
29
  `);
30
30
  LogMinDuration.args = {
31
31
  database: core_1.Args.string(),
32
- value: core_1.Args.integer(),
32
+ value: core_1.Args.string(),
33
33
  };
@@ -4,10 +4,7 @@ export default class LogMinDurationStatement extends PGSettingsCommand {
4
4
  static description: string;
5
5
  static args: {
6
6
  database: import("@oclif/core/lib/interfaces/parser").Arg<string | undefined, Record<string, unknown>>;
7
- value: import("@oclif/core/lib/interfaces/parser").Arg<number | undefined, {
8
- min?: number | undefined;
9
- max?: number | undefined;
10
- }>;
7
+ value: import("@oclif/core/lib/interfaces/parser").Arg<string | undefined, Record<string, unknown>>;
11
8
  };
12
9
  protected settingKey: SettingKey;
13
10
  protected convertValue(val: unknown): number;
@@ -29,5 +29,5 @@ LogMinDurationStatement.description = (0, tsheredoc_1.default)(`
29
29
  `);
30
30
  LogMinDurationStatement.args = {
31
31
  database: core_1.Args.string(),
32
- value: core_1.Args.integer(),
32
+ value: core_1.Args.string(),
33
33
  };
@@ -14,16 +14,6 @@ class Scale extends command_1.Command {
14
14
  const _a = await this.parse(Scale), { flags } = _a, restParse = tslib_1.__rest(_a, ["flags"]);
15
15
  const argv = restParse.argv;
16
16
  const { app } = flags;
17
- // will remove this flag once we have
18
- // successfully launched larger dyno sizes
19
- let isLargerDyno = false;
20
- const { body: largerDynoFeatureFlag } = await this.heroku.get('/account/features/frontend-larger-dynos')
21
- .catch((error) => {
22
- if (error.statusCode === 404) {
23
- return { body: { enabled: false } };
24
- }
25
- throw error;
26
- });
27
17
  function parse(args) {
28
18
  return (0, lodash_1.compact)(args.map(arg => {
29
19
  const change = arg.match(/^([\w-]+)([=+-]\d+)(?::([\w-]+))?$/);
@@ -36,18 +26,6 @@ class Scale extends command_1.Command {
36
26
  }));
37
27
  }
38
28
  const changes = parse(argv);
39
- // checks for larger dyno sizes
40
- // if the feature is not enabled
41
- if (!largerDynoFeatureFlag.enabled) {
42
- changes.forEach(({ size }) => {
43
- const largerDynoNames = /^(?!standard-[12]x$)(performance|private|shield)-(l-ram|xl|2xl)$/i;
44
- isLargerDyno = largerDynoNames.test(size);
45
- if (isLargerDyno) {
46
- const availableDynoSizes = 'eco, basic, standard-1x, standard-2x, performance-m, performance-l, private-s, private-m, private-l, shield-s, shield-m, shield-l';
47
- core_1.ux.error(`No such size as ${size}. Use ${availableDynoSizes}.`, { exit: 1 });
48
- }
49
- });
50
- }
51
29
  if (changes.length === 0) {
52
30
  const { body: formation } = await this.heroku.get(`/apps/${app}/formation`);
53
31
  const { body: appProps } = await this.heroku.get(`/apps/${app}`);
@@ -95,16 +95,6 @@ class Type extends command_1.Command {
95
95
  const _a = await this.parse(Type), { flags } = _a, restParse = tslib_1.__rest(_a, ["flags"]);
96
96
  const argv = restParse.argv;
97
97
  const { app } = flags;
98
- // will remove this flag once we have
99
- // successfully launched larger dyno sizes
100
- let isLargerDyno = false;
101
- const { body: largerDynoFeatureFlag } = await this.heroku.get('/account/features/frontend-larger-dynos')
102
- .catch((error) => {
103
- if (error.statusCode === 404) {
104
- return { body: { enabled: false } };
105
- }
106
- throw error;
107
- });
108
98
  const parse = async () => {
109
99
  if (!argv || argv.length === 0)
110
100
  return [];
@@ -124,18 +114,6 @@ class Type extends command_1.Command {
124
114
  return formation.map(p => ({ type: p.type, size: argv[0] }));
125
115
  };
126
116
  const changes = await parse();
127
- // checks for larger dyno sizes
128
- // if the feature is not enabled
129
- if (!largerDynoFeatureFlag.enabled) {
130
- changes.forEach(({ size }) => {
131
- const largerDynoNames = /^(?!standard-[12]x$)(performance|private|shield)-(l-ram|xl|2xl)$/i;
132
- isLargerDyno = largerDynoNames.test(size);
133
- if (isLargerDyno) {
134
- const availableDynoSizes = 'eco, basic, standard-1x, standard-2x, performance-m, performance-l, private-s, private-m, private-l, shield-s, shield-m, shield-l';
135
- core_1.ux.error(`No such size as ${size}. Use ${availableDynoSizes}.`, { exit: 1 });
136
- }
137
- });
138
- }
139
117
  if (changes.length > 0) {
140
118
  core_1.ux.action.start(`Scaling dynos on ${color_1.default.magenta(app)}`);
141
119
  await this.heroku.patch(`/apps/${app}/formation`, { body: { updates: changes } });
@@ -99,7 +99,6 @@ async function bastionConnect(uri, bastions, config, preferNativeTls) {
99
99
  const tunnel = await new Promise(resolve => {
100
100
  var _a;
101
101
  const ssh2 = new ssh2_1.Client();
102
- resolve(ssh2);
103
102
  ssh2.once('ready', () => resolve(ssh2));
104
103
  ssh2.connect({
105
104
  host: bastions.split(',')[0],
@@ -108,7 +107,7 @@ async function bastionConnect(uri, bastions, config, preferNativeTls) {
108
107
  });
109
108
  });
110
109
  const localPort = await portfinder.getPortPromise({ startPort: 49152, stopPort: 65535 });
111
- const stream = await (0, node_util_1.promisify)(tunnel.forwardOut)('localhost', localPort, uri.hostname, Number.parseInt(uri.port, 10));
110
+ const stream = await (0, node_util_1.promisify)(tunnel.forwardOut.bind(tunnel))('localhost', localPort, uri.hostname, Number.parseInt(uri.port, 10));
112
111
  let client = stream;
113
112
  if (preferNativeTls) {
114
113
  client = tls.connect({
@@ -10,12 +10,13 @@ const debug = (0, debug_1.default)('heroku:run');
10
10
  class Run extends command_1.Command {
11
11
  async run() {
12
12
  const { argv, flags } = await this.parse(Run);
13
+ const userArgvInputOrder = (0, helpers_1.revertSortedArgs)(process.argv, argv);
13
14
  const opts = {
14
15
  'exit-code': flags['exit-code'],
15
16
  'no-tty': flags['no-tty'],
16
17
  app: flags.app,
17
18
  attach: true,
18
- command: (0, helpers_1.buildCommand)(argv),
19
+ command: (0, helpers_1.buildCommand)(userArgvInputOrder),
19
20
  env: flags.env,
20
21
  heroku: this.heroku,
21
22
  listen: flags.listen,
@@ -1,2 +1,3 @@
1
+ export declare function revertSortedArgs(processArgs: Array<string>, argv: Array<string>): string[];
1
2
  export declare function buildCommand(args: Array<string>): string;
2
3
  export declare function buildEnvFromFlag(flag: string): {};
@@ -1,8 +1,20 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.buildEnvFromFlag = exports.buildCommand = void 0;
3
+ exports.buildEnvFromFlag = exports.buildCommand = exports.revertSortedArgs = void 0;
4
4
  /* eslint-disable @typescript-eslint/ban-ts-comment */
5
5
  const core_1 = require("@oclif/core");
6
+ // this function exists because oclif sorts argv
7
+ function revertSortedArgs(processArgs, argv) {
8
+ const originalInputOrder = [];
9
+ // this reorders the arguments in the order the user inputted
10
+ for (const processArg of processArgs) {
11
+ if (argv.includes(processArg)) {
12
+ originalInputOrder.push(processArg);
13
+ }
14
+ }
15
+ return originalInputOrder;
16
+ }
17
+ exports.revertSortedArgs = revertSortedArgs;
6
18
  function buildCommand(args) {
7
19
  if (args.length === 1) {
8
20
  // do not add quotes around arguments if there is only one argument