bump-cli 2.9.1 → 2.9.3

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
@@ -5,16 +5,17 @@
5
5
  </p>
6
6
 
7
7
  <p align="center">
8
- <a href="https://help.bump.sh/">Help</a> |
8
+ <a href="https://docs.bump.sh/help">Help</a> |
9
9
  <a href="https://bump.sh/users/sign_up">Sign up</a>
10
10
  </p>
11
11
 
12
- The Bump.sh CLI is used to interact with your API documentation or hubs hosted on Bump.sh. With any API definition of your choice (from Swagger, OpenAPI or AsyncAPI), it can help you to:
12
+ The Bump.sh CLI is used to interact with API documentation and hubs hosted on Bump.sh from your choice of popular API description formats: OpenAPI, Swagger, or AsyncAPI.
13
13
 
14
- - Validate an API document before publishing it to your documentation
15
- - Publish an API document to your Bump.sh documentation or hubs
16
- - Compare two API documents to generate a human-readable diff from your API definitions
14
+ Using [OpenAPI](https://github.com/OAI/OpenAPI-Specification) (v3.x and v2.0) or [AsyncAPI](https://www.asyncapi.com/docs/reference/specification/latest) (2.x), you can do any of the following:
17
15
 
16
+ - Validate an API document before publishing to your documentation.
17
+ - Publish an API document to your Bump.sh documentation or hubs.
18
+ - Compare two API documents to generate a human-readable diff from your API definition.
18
19
  Under the hood, it uses the API of [developers.bump.sh](https://developers.bump.sh). And is built with the [`oclif`](https://oclif.io) framework in Typescript.
19
20
 
20
21
  [![Version](https://img.shields.io/npm/v/bump-cli.svg)](https://npmjs.org/package/bump-cli)
@@ -34,47 +35,47 @@ Under the hood, it uses the API of [developers.bump.sh](https://developers.bump.
34
35
 
35
36
  The Bump.sh CLI is a node package currently distributed via NPM. This means you must have the Node v20+ interpreter installed on your computer or CI servers.
36
37
 
37
- _If you are looking to use Bump.sh in a continuous integration environment you might be interested by [our Github Action](https://github.com/marketplace/actions/api-documentation-on-bump)._
38
+ _If you are looking to use Bump.sh in a continuous integration environment you might be interested by [our Github Action](https://github.com/marketplace/actions/bump-sh-api-documentation-changelog)._
38
39
 
39
40
  > You can download a standalone package directly from the latest
40
- > GitHub release assets if you don’t use Node.
41
+ > Github release assets if you don’t use Node.
41
42
  {: .info}
42
43
 
43
44
  ### Global installation
44
45
 
45
- To install it globally, run the following command with NPM
46
+ To install it globally, run the following command with NPM:
46
47
 
47
- ```sh-session
48
+ ```shell
48
49
  npm install -g bump-cli
49
50
  ```
50
51
 
51
- Or, with Yarn via
52
+ Or, with Yarn via:
52
53
 
53
- ```sh-session
54
+ ```shell
54
55
  yarn global add bump-cli
55
56
  ```
56
57
 
57
- ### Add Bump.sh to your node project
58
+ ### Add Bump.sh to your Node project
58
59
 
59
- As our CLI is a node package, you can easily embed it into your project by adding the package to your `package.json` file, either with NPM
60
+ As our CLI is a node package, you can easily embed it to your project by adding the package to your `package.json` file, either with NPM:
60
61
 
61
- ```sh-session
62
+ ```shell
62
63
  npm install --save-dev bump-cli
63
64
  ```
64
65
 
65
- Or with Yarn via
66
+ Or with Yarn via:
66
67
 
67
- ```sh-session
68
+ ```shell
68
69
  yarn add --dev bump-cli
69
70
  ```
70
71
 
71
- You can then use any Bump.sh commands with `npx` (same as `npm exec`)
72
+ You can then use any Bump.sh commands with `npx` (same as `npm exec`):
72
73
 
73
- ```sh-session
74
+ ```shell
74
75
  npx bump --help
75
76
  ```
76
77
 
77
- ### How should I do if I'm not using npm ?
78
+ ### Can I install Bump.sh CLI without using NodeJS?
78
79
 
79
80
  Unfortunately, at the moment we only support the Node environment. However, you can download a standalone package directly from the [latest Github release](https://github.com/bump-sh/cli/releases) assets which you can run as a standalone binary. Or you can push your documentation using [our API](https://developers.bump.sh/) (advanced usage only).
80
81
 
@@ -82,12 +83,12 @@ Unfortunately, at the moment we only support the Node environment. However, you
82
83
 
83
84
  To list all the available commands, just type `bump` in your command line environment.
84
85
 
85
- ```sh-session
86
+ ```shell
86
87
  $ bump --help
87
88
  The Bump.sh CLI is used to interact with your API documentation hosted on Bump.sh by using the API of developers.bump.sh
88
89
 
89
90
  VERSION
90
- bump-cli/2.8.0 linux-x64 node-v16.19.0
91
+ bump-cli/2.9.2 linux-x64 node-v20.18.1
91
92
 
92
93
  USAGE
93
94
  $ bump [COMMAND]
@@ -102,7 +103,7 @@ COMMANDS
102
103
 
103
104
  You can also get some help anytime by adding `--help` to any command. Example: `bump deploy --help`.
104
105
 
105
- ## Prepare your Bump.sh account
106
+ ### Prepare your Bump.sh account
106
107
 
107
108
  While some commands don't need any API token (`preview` or `diff`) you will need an access key if you want to interact with your Bump.sh documentation.
108
109
 
@@ -110,16 +111,16 @@ Head over to your Documentation settings in the “CI deployment” section or y
110
111
 
111
112
  ## Commands
112
113
 
113
- * [`bump deploy [FILE]`](#bump-deploy-file)
114
- * [`bump diff [FILE]`](#bump-diff-file)
115
- * [`bump preview [FILE]`](#bump-preview-file)
116
- * [`bump overlay [DEFINITION_FILE] [OVERLAY_FILE]`](#bump-overlay-definition_file-overlay_file)
114
+ * [`bump deploy [FILE]`](#the-deploy-command)
115
+ * [`bump diff [FILE]`](#the-diff-command)
116
+ * [`bump preview [FILE]`](#the-preview-command)
117
+ * [`bump overlay [DEFINITION_FILE] [OVERLAY_FILE]`](#the-overlay-command)
117
118
 
118
- ### `bump deploy [FILE]`
119
+ ### The `deploy` command
119
120
 
120
- When you update your API, you also want its documentation to be up to date for your API users. This is what the deploy command is for.
121
+ When an API is updated, the documentation should be updated at the same time. This is what the deploy command is for.
121
122
 
122
- ```sh-session
123
+ ```shell
123
124
  bump deploy path/to/api-document.yml --doc my-documentation --token $DOC_TOKEN
124
125
  ```
125
126
 
@@ -128,7 +129,7 @@ bump deploy path/to/api-document.yml --doc my-documentation --token $DOC_TOKEN
128
129
 
129
130
  You can also deploy a given API document to a different branch of your documentation with the `--branch <branch-name>` parameter. Please note the branch will be created if it doesn’t exist. More details about the branching feature are available on [this dedicated help page](https://docs.bump.sh/help/branching). E.g. deploy the API document to the `staging` branch of the documentation:
130
131
 
131
- ```sh-session
132
+ ```shell
132
133
  bump deploy path/to/api-document.yml --doc my-documentation --token $DOC_TOKEN --branch staging
133
134
  ```
134
135
 
@@ -136,7 +137,7 @@ bump deploy path/to/api-document.yml --doc my-documentation --token $DOC_TOKEN -
136
137
 
137
138
  If you already have a hub in your [Bump.sh](https://bump.sh) account, you can automatically create documentation and deploy it into that hub by publishing a whole directory containing multiple API documents in a single command:
138
139
 
139
- ```sh-session
140
+ ```shell
140
141
  bump deploy dir/path/to/apis/ --auto-create --hub my-hub --token $HUB_TOKEN
141
142
  ```
142
143
 
@@ -168,66 +169,81 @@ bump deploy path/to/apis/ --hub my-hub --filename-pattern '*-api-{slug}-service'
168
169
 
169
170
  Simulate your API document's deployment to ensure it is valid by adding the `--dry-run` flag to the `deploy` command. It is handy in a Continuous Integration environment running a test deployment outside your main branch:
170
171
 
171
- ```sh-session
172
+ ```shell
172
173
  bump deploy path/to/api-document.yml --dry-run --doc my-documentation --token $DOC_TOKEN
173
174
  ```
174
175
 
175
176
  Please check `bump deploy --help` for more usage details.
176
177
 
177
- ### `bump diff [FILE]`
178
-
179
- _If you want to receive automatic `bump diff` results on your Github Pull Requests you might be interested by [our Github Action](https://github.com/marketplace/actions/api-documentation-on-bump#api-diff-on-pull-requests) diff command._
178
+ ### The `diff` command
180
179
 
181
- Please note that by default the command will always exit with a
182
- successful return code. If you want to use this command in a CI
183
- environment and want the command to fail **in case of a breaking
184
- change**, you will need to add the `--fail-on-breaking` flag to your
185
- diff command.
180
+ Using the `diff` command can help to spot differences between the local API
181
+ document and the latest deployed version.
186
182
 
187
183
  #### Public API diffs
188
184
 
189
- From any two API documents or URLs, you can retrieve a comprehensive changelog of what has changed between them.
185
+ From any two API documents or URLs, you can retrieve a comprehensive changelog
186
+ of what has changed between them.
190
187
 
191
- ```sh-session
188
+ ```shell
192
189
  $ bump diff path/to/your/file.yml path/to/your/second_file.yml
193
190
  * Comparing the two given definition files... done
194
191
  Modified: GET /consommations
195
192
  Response modified: 200
196
193
  [Breaking] Body attribute modified: energie
197
194
  ```
198
- > You can create as many diffs as you like without being authenticated. This is a **free and unlimited service** provided as long as you use the service fairly.
199
- {: .info}
200
195
 
201
- _Note: You can also test this feature in our dedicated web application at <https://api-diff.io/>._
196
+ By default the command will always exit with a successful return code. If you
197
+ want to use this command in a CI environment and want the command to fail **in
198
+ case of a breaking change**, you will need to add the `--fail-on-breaking` flag
199
+ to your diff command.
200
+
201
+ By default if the environment variable `CI=1` is present (in most continuous
202
+ integration environment), the flag will be enabled. In that case you can disable
203
+ the failures with `--no-fail-on-breaking` flag.
204
+
205
+ You can also test this feature in our dedicated web application at
206
+ <https://api-diff.io/>.
207
+
208
+ #### GitHub Integration
209
+
210
+ If you want to receive automatic `bump diff` results on Github Pull Requests you
211
+ might be interested by [our Github
212
+ Action](https://github.com/marketplace/actions/bump-sh-api-documentation-changelog#deploy-documentation--diff-on-pull-requests)
213
+ which has support for the diff command.
202
214
 
203
215
  #### Authenticated diffs related to your Bump.sh documentation
204
216
 
205
- From an existing Bump.sh documentation, the `diff` command will retrieve a comparison changelog between your latest published documentation and the given file or URL:
217
+ From an existing Bump.sh documentation, the `diff` command will retrieve a
218
+ comparison changelog between your latest published documentation and the given
219
+ file or URL:
206
220
 
207
- ```sh-session
221
+ ```shell
208
222
  bump diff path/to/your/file.yml --doc my-documentation --token $DOC_TOKEN
209
223
  ```
210
224
 
211
225
  If you want to compare two unpublished versions of your API document, the `diff` command can retrieve a comparison changelog between two given file or URL, “as simple as `git diff`”:
212
226
 
213
- ```sh-session
227
+ ```shell
214
228
  bump diff path/to/your/file.yml path/to/your/next-file.yml --doc my-documentation --token $DOC_TOKEN
215
229
  ```
216
230
 
217
231
  Please check `bump diff --help` for full usage details.
218
232
 
219
- ### `bump preview [FILE]`
233
+ ### The `preview` command
220
234
 
235
+ When writing documentation, you might want to preview how it renders on Bump.sh.
236
+ This is precisely the goal of the `preview` command: it will create temporary
237
+ documentation with a unique URL, which will be available for a short period (30
238
+ minutes).
221
239
 
222
- When writing documentation, you might want to preview how it renders on Bump.sh. This is precisely the goal of the `preview` command: it will create temporary documentation with a unique URL, which will be available for a short period (30 minutes).
223
-
224
- Usage from a local OpenAPI or AsyncAPI file
240
+ Usage from a local OpenAPI or AsyncAPI document:
225
241
 
226
242
  ```shell
227
243
  bump preview path/to/file.json
228
244
  ```
229
245
 
230
- You can also preview a file available from a URL
246
+ You can also preview a document available via a URL:
231
247
 
232
248
  ```shell
233
249
  bump preview https://developers.bump.sh/source.yaml
@@ -240,37 +256,48 @@ By using the `--live` flag you can stay focused on API design (OpenAPI or AsyncA
240
256
  - Launch the live preview command in your terminal
241
257
 
242
258
  ```shell
243
- bump preview --live --open openapi-definition.json
259
+ bump preview --live --open api-document.yaml
244
260
  ```
245
261
 
246
- - Edit your `openapi-definition.json` file in your favorite text editor
262
+ - Edit your `api-document.yaml` file in your favorite text editor.
247
263
  - Watch the live preview being updated each time you save your file.
264
+ - The additional `--open` flag helps to automatically open the preview URL in your browser.
248
265
 
249
266
  > You can create as many previews as you like without being authenticated. This is a **free and unlimited service**.
250
267
  {: .info}
251
268
 
252
- _Note: the additional `--open` flag helps to automatically open the preview URL in your browser._
253
-
254
269
  Please check `bump preview --help` for more usage details
255
270
 
256
- ### `bump overlay [DEFINITION_FILE] [OVERLAY_FILE]`
271
+ ### The `overlay` command
257
272
 
258
- > This feature implements the [OpenAPI Overlay specification](https://github.com/OAI/Overlay-Specification). It is possible to apply an Overlay to any kind of document, be it an OpenAPI or AsyncAPI definition file.
273
+ The [Overlay Specification](https://spec.openapis.org/overlay/v1.0.0.html) from the OpenAPI Initiative makes it possible to modify the content of an API definition by adding a layer on top of it. That layer helps adding, removing or changing some or all of the content of the original definition.
259
274
 
260
- The Overlay specification of OpenAPI makes it possible to modify the content of an API definition file by adding a layer on top of it. That layer helps add, remove, or change some or all of the content of the original definition.
275
+ The `bump overlay` command takes an original API document, applies the changes from the overlay document, and outputs a modified version. No changes are made directly to the original document.
261
276
 
262
- Technically, the `bump overlay` command will output a modified version of the `[DEFINITION_FILE]` (an OpenAPI or AsyncAPI document) by applying the operations described in the `[OVERLAY_FILE]` Overlay file to the original API document.
277
+ ```shell
278
+ bump overlay api-document.yaml overlay.yaml
279
+ ```
280
+
281
+ To redirect the output of the command to a new file you can run:
282
+
283
+ ```shell
284
+ bump overlay api-document.yaml overlay.yaml > modified-api-document.yaml
285
+ ```
263
286
 
264
- To redirect the output of the command to a new file you can run the following:
287
+ You can also apply the overlay using the [`deploy` command](#the-deploy-command) with the `--overlay` flag:
265
288
 
266
289
  ```shell
267
- bump overlay api-document.yaml overlay-file.yaml > api-overlayed-document.yaml
290
+ bump deploy api-document.yaml --doc my-doc --token my-token --overlay overlay.yaml
268
291
  ```
269
292
 
270
- _Note: you can also apply the overlay during the [`bump deploy` command]((#bump-deploy-file)) with the new `--overlay` flag:_
293
+ If there are multiple overlays which need to be applied, the `--overlay` can be passed multiple times.
271
294
 
272
295
  ```shell
273
- bump deploy api-document.yaml --doc my-doc --token my-token --overlay overlay-file.yaml
296
+ bump deploy api-document.yaml \
297
+ --doc my-doc \
298
+ --token my-token \
299
+ --overlay overlay1.yaml \
300
+ --overlay overlay2.yaml
274
301
  ```
275
302
 
276
303
  ## Development
@@ -279,54 +306,44 @@ Make sure to have Node.js (At least v20) installed on your machine.
279
306
 
280
307
  - Install node dependencies with
281
308
 
282
- ```sh-session
309
+ ```shell
283
310
  npm install
284
311
  ```
285
312
 
286
313
  - Compile the Typescript code
287
314
 
288
- ```sh-session
315
+
316
+ ```shell
289
317
  npm run build
290
- npm run clean # to remove build artifacts
318
+ npm run clean # Remove build artifacts
291
319
  ```
292
320
 
293
321
  - Format the codebase to comply with the linter rules
294
322
 
295
- ```sh-session
323
+ ```shell
296
324
  npm run fmt
297
325
  ```
298
326
 
299
327
  - Run the test suites
300
-
301
- ```sh-session
328
+
329
+ ```shell
302
330
  npm run test
303
331
  npm run test-coverage # Run tests with coverage
304
332
  ```
305
333
 
306
- ## Compatible specification types
334
+ ## License
307
335
 
308
- We currently support [OpenAPI](https://github.com/OAI/OpenAPI-Specification) from 2.0 (called Swagger) to 3.1 and [AsyncAPI 2.x](https://www.asyncapi.com/docs/reference/specification/latest) specification file types. Both YAML and JSON file formats are accepted file inputs to the CLI.
336
+ The Bump CLI project is released under the [MIT License](http://opensource.org/licenses/MIT).
309
337
 
310
338
  ## Contributing
311
339
 
312
340
  Bug reports and pull requests are welcome on GitHub at <https://github.com/bump-sh/cli>. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
313
341
 
314
- ## Thanks
315
-
316
- - [Lorna Mitchel](https://github.com/lornajane/) for [openapi-overlay-js](https://github.com/lornajane/openapi-overlays-js)
317
-
318
- ## License
319
-
320
- The Bump CLI project is released under the [MIT License](http://opensource.org/licenses/MIT).
321
-
322
342
  ## Code of Conduct
323
343
 
324
344
  Everyone interacting in the Bump-CLI project codebases, issue trackers, chat rooms, and mailing lists is expected to follow the [code of conduct](https://github.com/bump-sh/.github/blob/main/CODE_OF_CONDUCT.md).
325
345
 
326
- ## Versioning
327
-
328
- This npm package starts at v2.0.0 for two main reasons:
329
-
330
- - Our [first version](https://github.com/bump-sh/bump-cli) of the Bump CLI was written in Ruby, starting at v2.0.0, which makes it clear we are working on our second version of the Bump CLI
346
+ ## Thanks
331
347
 
332
- - The `bump-cli` package used to be [owned by Rico](https://github.com/rstacruz) which already published v1.x packages. If you are looking for the old npm package please head to [`@rstacruz/bump-cli` package](https://www.npmjs.com/package/@rstacruz/bump-cli). _A big thanks to Rico for transferring the ownership of the `bump-cli` package name!_
348
+ - [Lorna Mitchel](https://github.com/lornajane/) for [openapi-overlay-js](https://github.com/lornajane/openapi-overlays-js).
349
+ - [Rico](https://github.com/rstacruz) for transferring the ownership of the `bump-cli` package name.
@@ -2,7 +2,7 @@ import { Config } from '@oclif/core';
2
2
  import { AxiosInstance, AxiosResponse } from 'axios';
3
3
  import { DiffRequest, DiffResponse, PingResponse, PreviewRequest, PreviewResponse, VersionRequest, VersionResponse, WithDiff } from './models.js';
4
4
  declare class BumpApi {
5
- protected config: Config;
5
+ protected config?: Config | undefined;
6
6
  protected readonly client: AxiosInstance;
7
7
  getDiff: (diffId: string, format: string) => Promise<AxiosResponse<DiffResponse>>;
8
8
  getPing: () => Promise<AxiosResponse<PingResponse>>;
@@ -15,7 +15,7 @@ declare class BumpApi {
15
15
  private authorizationHeader;
16
16
  private handleError;
17
17
  private initializeResponseInterceptor;
18
- constructor(config: Config);
18
+ constructor(config?: Config | undefined);
19
19
  }
20
20
  export { default as APIError } from './error.js';
21
21
  export { BumpApi };
package/dist/api/index.js CHANGED
@@ -31,8 +31,9 @@ class BumpApi {
31
31
  constructor(config) {
32
32
  this.config = config;
33
33
  const baseURL = `${vars.apiUrl}${vars.apiBasePath}`;
34
+ const userAgent = config?.userAgent || 'bump-cli';
34
35
  const headers = {
35
- 'User-Agent': vars.apiUserAgent(config.userAgent),
36
+ 'User-Agent': vars.apiUserAgent(userAgent),
36
37
  };
37
38
  this.client = axios.create({
38
39
  baseURL,
@@ -15,10 +15,10 @@ export default class Deploy extends BaseCommand<typeof Deploy> {
15
15
  'filename-pattern': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
16
16
  hub: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
17
17
  interactive: import("@oclif/core/interfaces").BooleanFlag<boolean>;
18
- overlay: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
18
+ overlay: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
19
19
  token: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
20
20
  };
21
21
  protected deployDirectory(dir: string, dryRun: boolean, token: string, hub: string, autoCreate: boolean, interactive: boolean, filenamePattern: string, documentationName: string | undefined, branch: string | undefined): Promise<void>;
22
- protected deploySingleFile(api: API, dryRun: boolean, documentation: string, token: string, hub: string | undefined, autoCreate: boolean, documentationName: string | undefined, branch: string | undefined, overlay?: string | undefined): Promise<void>;
22
+ protected deploySingleFile(api: API, dryRun: boolean, documentation: string, token: string, hub: string | undefined, autoCreate: boolean, documentationName: string | undefined, branch: string | undefined, overlay?: string[] | undefined): Promise<void>;
23
23
  run(): Promise<void>;
24
24
  }
@@ -45,7 +45,7 @@ export default class Diff extends BaseCommand {
45
45
  branch: flagsBuilder.branch(),
46
46
  doc: flagsBuilder.doc(),
47
47
  expires: flagsBuilder.expires(),
48
- 'fail-on-breaking': flagsBuilder.failOnBreaking(),
48
+ 'fail-on-breaking': flagsBuilder.failOnBreaking({ allowNo: true }),
49
49
  format: flagsBuilder.format(),
50
50
  hub: flagsBuilder.hub(),
51
51
  token: flagsBuilder.token({ required: false }),
@@ -98,7 +98,7 @@ export default class Diff extends BaseCommand {
98
98
  throw new CLIError('Please provide a second file argument or login with an existing token');
99
99
  }
100
100
  ux.action.status = '...diff on Bump.sh in progress';
101
- const diff = await new CoreDiff(this.bump).run(args.file, args.otherFile, documentation, hub, branch, token, format, expires);
101
+ const diff = await new CoreDiff(this.config).run(args.file, args.otherFile, documentation, hub, branch, token, format, expires);
102
102
  ux.action.stop();
103
103
  if (diff) {
104
104
  await this.displayCompareResult(diff, format, flags['fail-on-breaking']);
@@ -6,6 +6,6 @@ export declare class Deploy {
6
6
  constructor(bumpClient: BumpApi);
7
7
  protected createVersion(request: VersionRequest, token: string): Promise<VersionResponse | undefined>;
8
8
  d(formatter: any, ...args: any[]): void;
9
- run(api: API, dryRun: boolean, documentation: string, token: string, hub: string | undefined, autoCreate: boolean, documentationName: string | undefined, branch: string | undefined, overlay?: string | undefined): Promise<VersionResponse | undefined>;
9
+ run(api: API, dryRun: boolean, documentation: string, token: string, hub: string | undefined, autoCreate: boolean, documentationName: string | undefined, branch: string | undefined, overlay?: string[] | undefined): Promise<VersionResponse | undefined>;
10
10
  validateVersion(version: VersionRequest, token: string): Promise<undefined>;
11
11
  }
@@ -29,7 +29,13 @@ export class Deploy {
29
29
  async run(api, dryRun, documentation, token, hub, autoCreate, documentationName, branch, overlay) {
30
30
  let version;
31
31
  if (overlay) {
32
- await api.applyOverlay(overlay);
32
+ /* eslint-disable no-await-in-loop */
33
+ // Alternatively we can apply all overlays in parallel
34
+ // https://stackoverflow.com/questions/48957022/unexpected-await-inside-a-loop-no-await-in-loop
35
+ for (const overlayFile of overlay) {
36
+ await api.applyOverlay(overlayFile);
37
+ }
38
+ /* eslint-enable no-await-in-loop */
33
39
  }
34
40
  const [definition, references] = api.extractDefinition();
35
41
  const request = {
@@ -1,9 +1,12 @@
1
+ import { Config } from '@oclif/core';
1
2
  import { BumpApi } from '../api/index.js';
2
3
  import { DiffResponse, VersionResponse, WithDiff } from '../api/models.js';
3
4
  export declare class Diff {
4
5
  static readonly TIMEOUT = 120;
5
6
  private _bump;
6
- constructor(bumpClient: BumpApi);
7
+ private _config;
8
+ constructor(config?: Config);
9
+ get bumpClient(): BumpApi;
7
10
  get pollingPeriod(): number;
8
11
  createDiff(file1: string, file2: string, expires: string | undefined): Promise<DiffResponse | undefined>;
9
12
  createVersion(file: string, documentation: string, token: string, hub: string | undefined, branch_name: string | undefined, previous_version_id?: string | undefined): Promise<VersionResponse | undefined>;
package/dist/core/diff.js CHANGED
@@ -1,12 +1,22 @@
1
+ import { Config } from '@oclif/core';
1
2
  import { CLIError } from '@oclif/core/errors';
2
3
  import debug from 'debug';
4
+ import { BumpApi } from '../api/index.js';
3
5
  import { API } from '../definition.js';
4
6
  export class Diff {
5
7
  // 120 seconds = 2 minutes
6
8
  static TIMEOUT = 120;
7
9
  _bump;
8
- constructor(bumpClient) {
9
- this._bump = bumpClient;
10
+ _config;
11
+ constructor(config) {
12
+ if (config) {
13
+ this._config = config;
14
+ }
15
+ }
16
+ get bumpClient() {
17
+ if (!this._bump)
18
+ this._bump = new BumpApi(this._config);
19
+ return this._bump;
10
20
  }
11
21
  get pollingPeriod() {
12
22
  return process.env.BUMP_POLLING_PERIOD ? Number(process.env.BUMP_POLLING_PERIOD) : 1000;
@@ -23,7 +33,7 @@ export class Diff {
23
33
  previous_references,
24
34
  references,
25
35
  };
26
- const response = await this._bump.postDiff(request);
36
+ const response = await this.bumpClient.postDiff(request);
27
37
  switch (response.status) {
28
38
  case 201: {
29
39
  this.d(`Diff created with ID ${response.data.id}`);
@@ -48,7 +58,7 @@ export class Diff {
48
58
  references,
49
59
  unpublished: true,
50
60
  };
51
- const response = await this._bump.postVersion(request, token);
61
+ const response = await this.bumpClient.postVersion(request, token);
52
62
  switch (response.status) {
53
63
  case 201: {
54
64
  this.d(`Unpublished version created with ID ${response.data.id}`);
@@ -88,6 +98,8 @@ export class Diff {
88
98
  await this.delay(this.pollingPeriod);
89
99
  }
90
100
  async run(file1, file2, documentation, hub, branch, token, format, expires) {
101
+ if (!this._config)
102
+ this._config = await Config.load('../../');
91
103
  let diffVersion;
92
104
  if (file2 && (!documentation || !token)) {
93
105
  diffVersion = await this.createDiff(file1, file2, expires);
@@ -111,8 +123,8 @@ export class Diff {
111
123
  }
112
124
  async waitResult(result, token, opts) {
113
125
  const pollingResponse = await (this.isVersion(result) && token
114
- ? this._bump.getVersion(result.id, token)
115
- : this._bump.getDiff(result.id, opts.format));
126
+ ? this.bumpClient.getVersion(result.id, token)
127
+ : this.bumpClient.getDiff(result.id, opts.format));
116
128
  if (opts.timeout <= 0) {
117
129
  throw new CLIError('We were unable to compute your documentation diff. Sorry about that. Please try again later. If the error persists, please contact support at https://bump.sh.');
118
130
  }
@@ -2,4 +2,8 @@ import { APIDefinition, OpenAPIOverlay } from '../definition.js';
2
2
  export declare class Overlay {
3
3
  d(formatter: any, ...args: any[]): void;
4
4
  run(spec: APIDefinition, overlay: OpenAPIOverlay): APIDefinition;
5
+ private executeAction;
6
+ private humanName;
7
+ private remove;
8
+ private update;
5
9
  }
@@ -1,6 +1,5 @@
1
1
  import debug from 'debug';
2
- /* eslint-disable-next-line import/default */
3
- import jsonpath from 'jsonpath';
2
+ import * as jsonpath from 'jsonpathly';
4
3
  import { mergician } from 'mergician';
5
4
  export class Overlay {
6
5
  // WIP @github.com/lornajane/openapi-overlays-js
@@ -19,63 +18,104 @@ export class Overlay {
19
18
  // If you make any changes here, PLEASE ALSO MAKE THEM UPSTREAM.
20
19
  run(spec, overlay) {
21
20
  // Use jsonpath.apply to do the changes
22
- if (overlay.actions && overlay.actions.length > 0)
21
+ if (overlay.actions && overlay.actions.length > 0) {
23
22
  for (const a of overlay.actions) {
24
23
  const action = a;
25
24
  if (!action.target) {
26
- process.stderr.write('Action with a missing target\n');
25
+ process.stderr.write(`WARNING: ${this.humanName(action)} has an empty target\n`);
27
26
  continue;
28
27
  }
29
28
  const target = action.target;
30
- // Is it a remove?
31
- if (Object.hasOwn(action, 'remove')) {
32
- /* eslint-disable-next-line no-constant-condition */
33
- while (true) {
34
- const path = jsonpath.paths(spec, target);
35
- if (path.length === 0) {
36
- break;
37
- }
38
- const parent = jsonpath.parent(spec, target);
39
- const thingToRemove = path[0].at(-1);
40
- if (thingToRemove !== undefined) {
41
- if (Array.isArray(parent)) {
42
- parent.splice(thingToRemove, 1);
43
- }
44
- else {
45
- delete parent[thingToRemove];
46
- }
47
- }
48
- }
29
+ // jsonpathly's paths are strings. They represent a “Path
30
+ // expression” which represents the absolute path in the objet
31
+ // tree reached by our `target`.
32
+ //
33
+ // E.g. '$["store"]["book"][0]["price"]'
34
+ const paths = jsonpath.paths(spec, target);
35
+ if (paths.length === 0) {
36
+ process.stderr.write(`WARNING: Action target '${target}' has no matching elements\n`);
37
+ continue;
49
38
  }
50
- else {
51
- try {
52
- // It must be an update
53
- // Deep merge objects using a module (built-in spread operator is only shallow)
54
- const merger = mergician({ appendArrays: true });
55
- if (target === '$') {
56
- // You can't actually merge an update on a root object
57
- // target with the jsonpath lib, this is just us merging
58
- // the given update with the whole spec.
59
- spec = merger(spec, action.update);
60
- }
61
- else {
62
- jsonpath.apply(spec, target, (chunk) => {
63
- if (typeof chunk === 'object' && typeof action.update === 'object') {
64
- if (Array.isArray(chunk) && Array.isArray(action.update)) {
65
- return [...chunk, ...action.update];
66
- }
67
- return merger(chunk, action.update);
68
- }
69
- return action.update;
70
- });
71
- }
72
- }
73
- catch (error) {
74
- process.stderr.write(`Error applying overlay: ${error.message}\n`);
75
- // return chunk
76
- }
39
+ for (const path of paths) {
40
+ // The 'executeAction' will mutate the passed spec object in
41
+ // place.
42
+ this.executeAction(spec, action, path);
77
43
  }
78
44
  }
45
+ }
46
+ else {
47
+ process.stderr.write('WARNING: No actions found in your overlay\n');
48
+ }
79
49
  return spec;
80
50
  }
51
+ /* Mutates the given 'spec' object with the 'action' given and
52
+ * targeting a unique 'pat ' within the spec object. We don't check
53
+ * if the path is valid in the object as this is the role of the
54
+ * jsonpathly lib which we used previously to extract the target
55
+ * paths. */
56
+ executeAction(spec, action, path) {
57
+ const explodedPath = path.split(/(?:]\[|\$\[)+/);
58
+ // Remove root
59
+ explodedPath.shift();
60
+ // Take last element from path (which is the thing to act
61
+ // upon)
62
+ let thingToActUpon = explodedPath.pop();
63
+ // The last element (e.g. '"price"]' or '0]') contains a final ']'
64
+ // so we need to remove it AND we need to parse the element to
65
+ // transform the string in either a string or a number
66
+ thingToActUpon =
67
+ thingToActUpon === undefined ? '$' : (thingToActUpon = JSON.parse(thingToActUpon.slice(0, -1)));
68
+ // Reconstruct the stringified path expression targeting the parent
69
+ const parentPath = explodedPath.join('][');
70
+ const parent = parentPath.length > 0 ? jsonpath.query(spec, `$[${parentPath}]`) : spec;
71
+ // Do the overlay action
72
+ // Is it a remove?
73
+ if (Object.hasOwn(action, 'remove')) {
74
+ this.remove(parent, thingToActUpon);
75
+ }
76
+ else if (Object.hasOwn(action, 'update')) {
77
+ this.update(spec, parent, action.update, thingToActUpon);
78
+ }
79
+ else {
80
+ process.stderr.write(`WARNING: ${this.humanName(action)} needs either a 'remove' or an 'update' property\n`);
81
+ }
82
+ }
83
+ humanName(action) {
84
+ return action.description ? `Action '${action.description}'` : 'Action';
85
+ }
86
+ remove(parent, property_or_index) {
87
+ if (Array.isArray(parent)) {
88
+ parent.splice(property_or_index, 1);
89
+ }
90
+ else {
91
+ delete parent[property_or_index];
92
+ }
93
+ }
94
+ update(spec, parent, update, property_or_index) {
95
+ try {
96
+ // Deep merge objects using a module (built-in spread operator is only shallow)
97
+ const merger = mergician({ appendArrays: true });
98
+ if (property_or_index === '$') {
99
+ // You can't actually merge an update on a root object
100
+ // target with the jsonpathly lib, this is just us merging
101
+ // the given update with the whole spec.
102
+ spec = merger(spec, update);
103
+ }
104
+ else if (property_or_index) {
105
+ const targetObject = parent[property_or_index];
106
+ if (typeof targetObject === 'object' && typeof update === 'object') {
107
+ parent[property_or_index] =
108
+ Array.isArray(targetObject) && Array.isArray(update)
109
+ ? [...targetObject, ...update]
110
+ : merger(targetObject, update);
111
+ }
112
+ else {
113
+ parent[property_or_index] = update;
114
+ }
115
+ }
116
+ }
117
+ catch (error) {
118
+ process.stderr.write(`Error applying overlay: ${error.message}\n`);
119
+ }
120
+ }
81
121
  }
@@ -1,7 +1,7 @@
1
1
  import { default as $RefParser, getJsonSchemaRefParserDefaultOptions } from '@apidevtools/json-schema-ref-parser';
2
2
  import asyncapi from '@asyncapi/specs';
3
3
  import { CLIError } from '@oclif/core/errors';
4
- import { safeStringify } from '@stoplight/yaml';
4
+ import { parseWithPointers, safeStringify } from '@stoplight/yaml';
5
5
  import debug from 'debug';
6
6
  import { createRequire } from 'node:module';
7
7
  import { default as nodePath } from 'node:path';
@@ -120,10 +120,11 @@ class API {
120
120
  async applyOverlay(overlayPath) {
121
121
  const overlay = await API.load(overlayPath);
122
122
  const overlayDefinition = overlay.definition;
123
+ const currentDefinition = this.overlayedDefinition || this.definition;
123
124
  if (!API.isOpenAPIOverlay(overlayDefinition)) {
124
125
  throw new Error(`${overlayPath} does not look like an OpenAPI overlay`);
125
126
  }
126
- this.overlayedDefinition = await new Overlay().run(this.definition, overlayDefinition);
127
+ this.overlayedDefinition = await new Overlay().run(currentDefinition, overlayDefinition);
127
128
  }
128
129
  extractDefinition(outputPath) {
129
130
  const references = [];
@@ -218,9 +219,11 @@ class API {
218
219
  }
219
220
  serializeDefinition(outputPath) {
220
221
  if (this.overlayedDefinition) {
222
+ const { comments } = parseWithPointers(this.rawDefinition, { attachComments: true });
223
+ const dumpOptions = { comments, lineWidth: Number.POSITIVE_INFINITY };
221
224
  return this.guessFormat(outputPath) === 'json'
222
225
  ? JSON.stringify(this.overlayedDefinition)
223
- : safeStringify(this.overlayedDefinition);
226
+ : safeStringify(this.overlayedDefinition, dumpOptions);
224
227
  }
225
228
  return this.rawDefinition;
226
229
  }
package/dist/flags.d.ts CHANGED
@@ -41,8 +41,8 @@ declare const out: Interfaces.FlagDefinition<string, Interfaces.CustomOptions, {
41
41
  multiple: false;
42
42
  requiredOrDefaulted: false;
43
43
  }>;
44
- declare const overlay: Interfaces.FlagDefinition<string, Interfaces.CustomOptions, {
45
- multiple: false;
44
+ declare const overlay: Interfaces.FlagDefinition<string[], Interfaces.CustomOptions, {
45
+ multiple: true;
46
46
  requiredOrDefaulted: false;
47
47
  }>;
48
48
  export { autoCreate, branch, doc, docName, dryRun, expires, failOnBreaking, filenamePattern, format, hub, interactive, live, open, out, overlay, token, };
package/dist/flags.js CHANGED
@@ -1,7 +1,4 @@
1
1
  import { Flags } from '@oclif/core';
2
- // import * as Parser from '@oclif/parser';
3
- // Re-export oclif flags https://oclif.io/docs/flags
4
- // export * from '@oclif/command/lib/flags';
5
2
  // Custom flags for bump-cli
6
3
  const doc = Flags.custom({
7
4
  char: 'd',
@@ -89,7 +86,7 @@ const failOnBreaking = (opts = {}) => {
89
86
  }
90
87
  return false;
91
88
  },
92
- description: 'Fail when diff contains a breaking change',
89
+ description: 'Fail when diff contains a breaking change. Defaults to false locally. In CI environments where the env variable CI=1 is set, it defaults to true.',
93
90
  });
94
91
  };
95
92
  const live = (opts = {}) => {
@@ -115,6 +112,7 @@ const out = Flags.custom({
115
112
  });
116
113
  const overlay = Flags.custom({
117
114
  char: 'o',
118
- description: 'Path or URL of an overlay file to apply before deploying',
115
+ description: 'Path or URL of overlay file(s) to apply before deploying',
116
+ multiple: true,
119
117
  });
120
118
  export { autoCreate, branch, doc, docName, dryRun, expires, failOnBreaking, filenamePattern, format, hub, interactive, live, open, out, overlay, token, };
@@ -86,10 +86,10 @@
86
86
  },
87
87
  "overlay": {
88
88
  "char": "o",
89
- "description": "Path or URL of an overlay file to apply before deploying",
89
+ "description": "Path or URL of overlay file(s) to apply before deploying",
90
90
  "name": "overlay",
91
91
  "hasDynamicHelp": false,
92
- "multiple": false,
92
+ "multiple": true,
93
93
  "type": "option"
94
94
  },
95
95
  "token": {
@@ -97,7 +97,6 @@
97
97
  "description": "Documentation or Hub token. Can be provided via BUMP_TOKEN environment variable",
98
98
  "name": "token",
99
99
  "required": true,
100
- "default": "99f52837852249b328c0a00249f846a3",
101
100
  "hasDynamicHelp": false,
102
101
  "multiple": false,
103
102
  "type": "option"
@@ -158,9 +157,9 @@
158
157
  },
159
158
  "fail-on-breaking": {
160
159
  "char": "F",
161
- "description": "Fail when diff contains a breaking change",
160
+ "description": "Fail when diff contains a breaking change. Defaults to false locally. In CI environments where the env variable CI=1 is set, it defaults to true.",
162
161
  "name": "fail-on-breaking",
163
- "allowNo": false,
162
+ "allowNo": true,
164
163
  "type": "boolean"
165
164
  },
166
165
  "format": {
@@ -191,7 +190,6 @@
191
190
  "description": "Documentation or Hub token. Can be provided via BUMP_TOKEN environment variable",
192
191
  "name": "token",
193
192
  "required": false,
194
- "default": "99f52837852249b328c0a00249f846a3",
195
193
  "hasDynamicHelp": false,
196
194
  "multiple": false,
197
195
  "type": "option"
@@ -279,5 +277,5 @@
279
277
  "strict": true
280
278
  }
281
279
  },
282
- "version": "2.9.1"
280
+ "version": "2.9.3"
283
281
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "bump-cli",
3
3
  "description": "The Bump CLI is used to interact with your API documentation hosted on Bump.sh by using the API of developers.bump.sh",
4
- "version": "2.9.1",
4
+ "version": "2.9.3",
5
5
  "author": "Paul Bonaud <paulr@bump.sh>",
6
6
  "bin": {
7
7
  "bump": "./bin/run.js"
@@ -10,20 +10,20 @@
10
10
  "devDependencies": {
11
11
  "@oclif/prettier-config": "^0.2.1",
12
12
  "@oclif/test": "^4",
13
- "@types/chai": "^4",
13
+ "@types/chai": "^5",
14
14
  "@types/debug": "^4.1.12",
15
15
  "@types/jsonpath": "^0.2.4",
16
16
  "@types/mocha": "^10",
17
- "@types/node": "^18",
17
+ "@types/node": "^22",
18
18
  "@types/sinon": "^17.0.3",
19
19
  "@typescript-eslint/eslint-plugin": "^8.13.0",
20
- "chai": "^4.5.0",
20
+ "chai": "^5.1.2",
21
21
  "eslint": "^8",
22
22
  "eslint-config-oclif": "^5",
23
23
  "eslint-config-oclif-typescript": "^3",
24
- "eslint-config-prettier": "^9.1.0",
24
+ "eslint-config-prettier": "^10.0.1",
25
25
  "eslint-plugin-prettier": "^5.2.1",
26
- "mocha": "^10",
26
+ "mocha": "^11",
27
27
  "mock-stdin": "^1.0.0",
28
28
  "nock": "^14.0.0-beta.16",
29
29
  "np": "^10.1.0",
@@ -77,6 +77,7 @@
77
77
  "clean": "rm -rf dist/ oclif.manifest.json",
78
78
  "lint": "eslint . --ext .ts",
79
79
  "fmt": "eslint --fix . --ext .ts",
80
+ "pack": "oclif pack tarballs",
80
81
  "postpack": "shx rm -f oclif.manifest.json",
81
82
  "posttest": "npm run lint",
82
83
  "prepack": "npm run clean && npm run build && oclif manifest && oclif readme",
@@ -91,7 +92,7 @@
91
92
  "dependencies": {
92
93
  "@apidevtools/json-schema-ref-parser": "^11.7.2",
93
94
  "@asyncapi/specs": "^6.8.0",
94
- "@clack/prompts": "^0.7.0",
95
+ "@clack/prompts": "^0.10.0",
95
96
  "@oclif/core": "^4",
96
97
  "@oclif/plugin-help": "^6",
97
98
  "@oclif/plugin-warn-if-update-available": "^3.1.20",
@@ -100,7 +101,7 @@
100
101
  "axios": "^1.7.7",
101
102
  "chalk": "^5.3.0",
102
103
  "debug": "^4.3.7",
103
- "jsonpath": "^1.1.1",
104
+ "jsonpathly": "^2.0.2",
104
105
  "mergician": "^2.0.2",
105
106
  "oas-schemas": "git+https://git@github.com/OAI/OpenAPI-Specification.git#882d1caedb0bff825a1fd10728e7e3dc43912d37",
106
107
  "open": "^10.1.0"