heroku 9.2.0-beta.1 → 9.2.1-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.
@@ -60,7 +60,13 @@ class Push extends command_1.Command {
60
60
  else {
61
61
  core_1.ux.styledHeader(`Building ${job.name} (${job.dockerfile})`);
62
62
  }
63
- await DockerHelper.buildImage(job.dockerfile, job.resource, buildArgs, contextPath);
63
+ await DockerHelper.buildImage({
64
+ dockerfile: job.dockerfile,
65
+ resource: job.resource,
66
+ buildArgs,
67
+ path: contextPath,
68
+ arch: this.config.arch,
69
+ });
64
70
  }
65
71
  }
66
72
  catch (error) {
@@ -4,14 +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");
8
7
  const fs = require("fs");
9
8
  class Run extends core_1.Command {
10
9
  async run() {
11
10
  const execArgv = ['run'];
12
11
  const { argv, flags } = await this.parse(Run);
13
- const userArgvInputOrder = (0, helpers_1.revertSortedArgs)(process.argv, argv);
14
- if (userArgvInputOrder.length === 0) {
12
+ const maybeOptionsIndex = process.argv.indexOf('--');
13
+ const commandArgs = (maybeOptionsIndex === -1 ? argv : process.argv.slice(maybeOptionsIndex + 1));
14
+ if (commandArgs.length === 0) {
15
15
  const errorMessage = 'Usage: heroku local:run [COMMAND]\nMust specify command to run';
16
16
  this.error(errorMessage, { exit: -1 });
17
17
  }
@@ -24,7 +24,7 @@ class Run extends core_1.Command {
24
24
  if (flags.port)
25
25
  execArgv.push('--port', flags.port);
26
26
  execArgv.push('--'); // disable node-foreman flag parsing
27
- execArgv.push(...userArgvInputOrder); // eslint-disable-line unicorn/no-array-push-push
27
+ execArgv.push(...commandArgs); // eslint-disable-line unicorn/no-array-push-push
28
28
  await (0, fork_foreman_1.fork)(execArgv);
29
29
  }
30
30
  }
@@ -17,36 +17,36 @@ class Promote extends command_1.Command {
17
17
  core_1.ux.action.start(`Ensuring an alternate alias for existing ${color_1.default.green('DATABASE_URL')}`);
18
18
  const { body: attachments } = await this.heroku.get(`/apps/${app}/addon-attachments`);
19
19
  const current = attachments.find(a => a.name === 'DATABASE');
20
- if (!current)
21
- return;
22
- // eslint-disable-next-line eqeqeq
23
- if (((_a = current.addon) === null || _a === void 0 ? void 0 : _a.name) === attachment.addon.name && current.namespace == attachment.namespace) {
24
- if (attachment.namespace) {
25
- core_1.ux.error(`${color_1.default.cyan(attachment.name)} is already promoted on ${color_1.default.app(app)}`);
20
+ if (current) {
21
+ // eslint-disable-next-line eqeqeq
22
+ if (((_a = current.addon) === null || _a === void 0 ? void 0 : _a.name) === attachment.addon.name && current.namespace == attachment.namespace) {
23
+ if (attachment.namespace) {
24
+ core_1.ux.error(`${color_1.default.cyan(attachment.name)} is already promoted on ${color_1.default.app(app)}`);
25
+ }
26
+ else {
27
+ core_1.ux.error(`${color_1.default.addon(attachment.addon.name)} is already promoted on ${color_1.default.app(app)}`);
28
+ }
29
+ }
30
+ const existing = attachments.filter(a => { var _a, _b; return ((_a = a.addon) === null || _a === void 0 ? void 0 : _a.id) === ((_b = current.addon) === null || _b === void 0 ? void 0 : _b.id) && a.namespace === current.namespace; })
31
+ .find(a => a.name !== 'DATABASE');
32
+ if (existing) {
33
+ core_1.ux.action.stop(color_1.default.green(existing.name + '_URL'));
26
34
  }
27
35
  else {
28
- core_1.ux.error(`${color_1.default.addon(attachment.addon.name)} is already promoted on ${color_1.default.app(app)}`);
36
+ // The current add-on occupying the DATABASE attachment has no
37
+ // other attachments. In order to promote this database without
38
+ // error, we can create a secondary attachment, just-in-time.
39
+ const { body: backup } = await this.heroku.post('/addon-attachments', {
40
+ body: {
41
+ app: { name: app },
42
+ addon: { name: (_b = current.addon) === null || _b === void 0 ? void 0 : _b.name },
43
+ namespace: current.namespace,
44
+ confirm: app,
45
+ },
46
+ });
47
+ core_1.ux.action.stop(color_1.default.green(backup.name + '_URL'));
29
48
  }
30
49
  }
31
- const existing = attachments.filter(a => { var _a, _b; return ((_a = a.addon) === null || _a === void 0 ? void 0 : _a.id) === ((_b = current.addon) === null || _b === void 0 ? void 0 : _b.id) && a.namespace === current.namespace; })
32
- .find(a => a.name !== 'DATABASE');
33
- if (existing) {
34
- core_1.ux.action.stop(color_1.default.green(existing.name + '_URL'));
35
- }
36
- else {
37
- // The current add-on occupying the DATABASE attachment has no
38
- // other attachments. In order to promote this database without
39
- // error, we can create a secondary attachment, just-in-time.
40
- const { body: backup } = await this.heroku.post('/addon-attachments', {
41
- body: {
42
- app: { name: app },
43
- addon: { name: (_b = current.addon) === null || _b === void 0 ? void 0 : _b.name },
44
- namespace: current.namespace,
45
- confirm: app,
46
- },
47
- });
48
- core_1.ux.action.stop(color_1.default.green(backup.name + '_URL'));
49
- }
50
50
  if (!force) {
51
51
  const { body: status } = await this.heroku.get(`/client/v11/databases/${attachment.addon.id}/wait_status`, {
52
52
  hostname: (0, host_1.default)(),
@@ -54,9 +54,9 @@ class Promote extends command_1.Command {
54
54
  if (status['waiting?']) {
55
55
  core_1.ux.error((0, tsheredoc_1.default)(`
56
56
  Database cannot be promoted while in state: ${status.message}
57
-
57
+
58
58
  Promoting this database can lead to application errors and outage. Please run ${color_1.default.cmd('heroku pg:wait')} to wait for database to become available.
59
-
59
+
60
60
  To ignore this error, you can pass the --force flag to promote the database and risk application issues.
61
61
  `));
62
62
  }
@@ -79,7 +79,7 @@ class Promote extends command_1.Command {
79
79
  },
80
80
  });
81
81
  core_1.ux.action.stop();
82
- const currentPooler = attachments.find(a => { var _a, _b; return a.namespace === 'connection-pooling:default' && ((_a = a.addon) === null || _a === void 0 ? void 0 : _a.id) === ((_b = current.addon) === null || _b === void 0 ? void 0 : _b.id) && a.name === 'DATABASE_CONNECTION_POOL'; });
82
+ const currentPooler = attachments.find(a => { var _a, _b; return a.namespace === 'connection-pooling:default' && ((_a = a.addon) === null || _a === void 0 ? void 0 : _a.id) === ((_b = current === null || current === void 0 ? void 0 : current.addon) === null || _b === void 0 ? void 0 : _b.id) && a.name === 'DATABASE_CONNECTION_POOL'; });
83
83
  if (currentPooler) {
84
84
  core_1.ux.action.start('Reattaching pooler to new leader');
85
85
  await this.heroku.post('/addon-attachments', {
@@ -100,9 +100,9 @@ class Promote extends command_1.Command {
100
100
  const unfollowLeaderCmd = `heroku pg:unfollow ${attachment.addon.name}`;
101
101
  core_1.ux.warn((0, tsheredoc_1.default)(`
102
102
  Your database has been promoted but it is currently a follower database in read-only mode.
103
-
103
+
104
104
  Promoting a database with ${color_1.default.cmd('heroku pg:promote')} doesn't automatically unfollow its leader.
105
-
105
+
106
106
  Use ${color_1.default.cmd(unfollowLeaderCmd)} to stop this follower from replicating from its leader (${color_1.default.yellow(promotedDatabaseDetails.leader)}) and convert it into a writable database.
107
107
  `));
108
108
  }
@@ -141,7 +141,7 @@ class Promote extends command_1.Command {
141
141
  msg += 'without an attached DATABASE_URL.';
142
142
  }
143
143
  else {
144
- msg += `with ${(_c = current.addon) === null || _c === void 0 ? void 0 : _c.name} attached as DATABASE_URL.`;
144
+ msg += `with ${(_c = current === null || current === void 0 ? void 0 : current.addon) === null || _c === void 0 ? void 0 : _c.name} attached as DATABASE_URL.`;
145
145
  }
146
146
  msg += ' Check your release phase logs for failure causes.';
147
147
  core_1.ux.action.stop(msg);
@@ -10,13 +10,14 @@ 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
+ const maybeOptionsIndex = process.argv.indexOf('--');
14
+ const command = (0, helpers_1.buildCommand)((maybeOptionsIndex === -1 ? argv : process.argv.slice(maybeOptionsIndex + 1)));
14
15
  const opts = {
15
16
  'exit-code': flags['exit-code'],
16
17
  'no-tty': flags['no-tty'],
17
18
  app: flags.app,
18
19
  attach: true,
19
- command: (0, helpers_1.buildCommand)(userArgvInputOrder),
20
+ command,
20
21
  env: flags.env,
21
22
  heroku: this.heroku,
22
23
  listen: flags.listen,
@@ -19,6 +19,14 @@ export declare type groupedDockerJobs = {
19
19
  export declare const getJobs: (resourceRoot: string, dockerfiles: string[]) => groupedDockerJobs;
20
20
  export declare const filterByProcessType: (jobs: groupedDockerJobs, processTypes: string[]) => groupedDockerJobs;
21
21
  export declare const chooseJobs: (jobs: groupedDockerJobs) => Promise<dockerJob[]>;
22
- export declare const buildImage: (dockerfile: string, resource: string, buildArgs: string[], path?: string) => Promise<string>;
22
+ declare type BuildImageParams = {
23
+ dockerfile: string;
24
+ resource: string;
25
+ buildArgs: string[];
26
+ path?: string;
27
+ arch?: string;
28
+ };
29
+ export declare const buildImage: ({ dockerfile, resource, buildArgs, path, arch }: BuildImageParams) => Promise<string>;
23
30
  export declare const pushImage: (resource: string) => Promise<string>;
24
31
  export declare const runImage: (resource: string, command: string, port: number) => Promise<string>;
32
+ export {};
@@ -7,6 +7,7 @@ const glob = require("glob");
7
7
  const Path = require("path");
8
8
  const inquirer = require("inquirer");
9
9
  const os = require("os");
10
+ const core_1 = require("@oclif/core");
10
11
  const DOCKERFILE_REGEX = /\bDockerfile(.\w*)?$/;
11
12
  const cmd = async function (cmd, args, options = {}) {
12
13
  (0, debug_1.debug)(cmd, args);
@@ -114,6 +115,10 @@ const chooseJobs = async function (jobs) {
114
115
  for (const processType in jobs) {
115
116
  if (Object.prototype.hasOwnProperty.call(jobs, processType)) {
116
117
  const group = jobs[processType];
118
+ if (group === undefined) {
119
+ core_1.ux.warn(`Dockerfile.${processType} not found`);
120
+ continue;
121
+ }
117
122
  if (group.length > 1) {
118
123
  const prompt = [{
119
124
  type: 'list',
@@ -135,9 +140,13 @@ const chooseJobs = async function (jobs) {
135
140
  return chosenJobs;
136
141
  };
137
142
  exports.chooseJobs = chooseJobs;
138
- const buildImage = async function (dockerfile, resource, buildArgs, path) {
143
+ const buildImage = async function ({ dockerfile, resource, buildArgs, path, arch }) {
139
144
  const cwd = path || Path.dirname(dockerfile);
140
- const args = ['build', '-f', dockerfile, '-t', resource, '--platform', 'linux/amd64'];
145
+ const args = ['build', '-f', dockerfile, '-t', resource];
146
+ // Older Docker versions don't allow for this flag, but we are
147
+ // adding it here when necessary to allow for pushing a docker build from m1/m2 Macs.
148
+ if (arch === 'arm64')
149
+ args.push('--platform', 'linux/amd64');
141
150
  for (const element of buildArgs) {
142
151
  if (element.length > 0) {
143
152
  args.push('--build-arg', element);
@@ -1,3 +1,2 @@
1
- export declare function revertSortedArgs(processArgs: Array<string>, argv: Array<string>): string[];
2
1
  export declare function buildCommand(args: Array<string>): string;
3
2
  export declare function buildEnvFromFlag(flag: string): {};
@@ -1,20 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.buildEnvFromFlag = exports.buildCommand = exports.revertSortedArgs = void 0;
3
+ exports.buildEnvFromFlag = exports.buildCommand = 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;
18
6
  function buildCommand(args) {
19
7
  if (args.length === 1) {
20
8
  // do not add quotes around arguments if there is only one argument