kibana/packages/kbn-dev-cli-runner
Alex Szabo 7f82102d72
[Ops] ES Serverless image verification pipeline (#166054)
## Summary
Prepares the serverless FTR tests to be runnable with a custom ES image.
(`--esServerlessImage` cli arg)
Creates a pipeline for testing and promoting ES Serverless docker
releases.

The job can be triggered here:
https://buildkite.com/elastic/kibana-elasticsearch-serverless-verify-and-promote
The three main env variables it takes:
- BUILDKITE_BRANCH: the kibana branch to test with (maybe not as
important)
 - BUILDKITE_COMMIT: the kibana commit to test with
- ES_SERVERLESS_IMAGE: the elasticsearch serverless image, or tag to use
from this repo:
`docker.elastic.co/elasticsearch-ci/elasticsearch-serverless`

## TODOS:
 - [x] set `latest_verified` with full img path as default
- [x] ~~find other CLIs that might need the `esServerlessImage` argument
(if the docker runner has multiple usages)~~ | I confused the `yarn es
docker` with this, because I thought we only run ES serverless in a
docker container, but `elasticsearch` can also be run in docker.
- [x] set `latest-compatible` or similar flag in a manifest in gcs for
Elastic's use-case
- [ ] ensure we can only verify "forward" (ie.: to avoid a
parameterization on old versions to set our pointers back) [on a second
thought, this might be kept as a feature to roll back (if we should ever
need that)]


There are two confusing things I couldn't sort out just yet:
#### Ambiguity in --esServerlessImage 
We can either have 2 CLI args: one for an image tag, one for an image
repo/image url, or we can have one (like I have it now) and interpret
that in the code, it can be either the image url, or the tag. It's more
flexible, but it's two things in one. Is it ok this way, or is it too
confusing?
e.g.:
```
node scripts/functional_tests --esFrom serverless --esServerlessImage docker.elastic.co/elasticsearch-ci/elasticsearch-serverless:git-8fc8f941bd4d --bail --config x-pack/test_serverless/functional/test_suites/security/config.ts

# or
node scripts/functional_tests  --esFrom serverless --esServerlessImage latest --bail --config x-pack/test_serverless/functional/test_suites/security/config.ts
```

#### Ambiguity in the default image path
The published ES Serverless images will sit on this image path:
`docker.elastic.co/elasticsearch-ci/elasticsearch-serverless`, however,
our one exception is the `latest-verified` which we will be tagging
under a different path, where we have write rights:
`docker.elastic.co/kibana-ci/elasticsearch-serverless:latest-verified`.

Is it okay, that by default, we're searching in the `elasticsearch-ci`
images for any tags as parameters (after all, all the new images will be
published there), however our grand default will ultimately be
`docker.elastic.co/kibana-ci/elasticsearch-serverless:latest-verified`.


## Links
Buildkite:
https://buildkite.com/elastic/kibana-elasticsearch-serverless-verify-and-promote
eg.:
https://buildkite.com/elastic/kibana-elasticsearch-serverless-verify-and-promote/builds/24
Closes: https://github.com/elastic/kibana/issues/162931

---------

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
2023-09-25 09:49:20 -07:00
..
src [Ops] ES Serverless image verification pipeline (#166054) 2023-09-25 09:49:20 -07:00
index.ts [ftr] add first-class support for playwrite journeys (#140680) 2022-09-22 01:06:46 -07:00
jest.config.js [@kbn/dev-utils] break out more pieces (#132292) 2022-05-17 11:19:20 -05:00
kibana.jsonc Transpile packages on demand, validate all TS projects (#146212) 2022-12-22 19:00:29 -06:00
package.json Transpile packages on demand, validate all TS projects (#146212) 2022-12-22 19:00:29 -06:00
README.mdx [kbn/pm] rewrite to avoid needing a build process (#136207) 2022-07-18 08:46:13 -07:00
tsconfig.json Transpile packages on demand, validate all TS projects (#146212) 2022-12-22 19:00:29 -06:00

---
id: kibDevDocsOpsDevCliRunner
slug: /kibana-dev-docs/ops/kbn-dev-cli-runner
title: "@kbn/dev-cli-runner"
description: 'Helper functions for writing little scripts for random build/ci/dev tasks'
date: 2022-07-14
tags: ['kibana', 'dev', 'contributor', 'operations', 'packages', 'scripts', 'cli']
---

## @kbn/dev-cli-runner

Helper functions for writing little scripts for random build/ci/dev tasks.

### Usage

Define the function that should validate the CLI arguments and call your task fn:

```ts
// dev/my_task/run_my_task.ts
import { createFlagError, run } from '@kbn/dev-cli-runner';

run(
  async ({ flags, log }) => {
    if (typeof flags.path !== 'string') {
      throw createFlagError('please provide a single --path flag');
    }

    await runTask(flags.path);
    log.success('task complete');
  },
  {
    description: `
      Run my special task
    `,
    flags: {
      string: ['path'],
      help: `
        --path             Required, path to the file to operate on
      `
    },
  }
);
```

Define the script which will setup node and load the script source:

```js
// scripts/my_task.js

require('../src/setup_node_env');
require('../src/dev/my_task/run_my_task');
```

Try out the script:

```sh
$ node scripts/my_task

# ERROR please provide a single --path flag
# 
#   node scripts/my_task.js
# 
#   Run my special task
# 
#   Options:
#     --path             Required, path to the file to operate on
#     --verbose, -v      Log verbosely
#     --debug            Log debug messages (less than verbose)
#     --quiet            Only log errors
#     --silent           Don't log anything
#     --help             Show this message
#
```

### API

- ***`run(fn: async ({ flags: Flags, log: ToolingLog, addCleanupTask }) => Promise<void>, options: Options)`***
  
    Execte an async function, passing it the parsed flags and a tooling log that is configured to the requested logging level. If the returned promise is rejected with an error created by `createFailError(...)` or `createFlagError(...)` the process will exit as described by the error, otherwise the process will exit with code 1.
    
    **`fn` Params:**
    - *[`log: ToolingLog`](../../../packages/kbn-dev-utils/src/tooling_log/tooling_log.js)*:

      An instance of the `ToolingLog` that is configured with the standard flags: `--verbose`, `--quiet`, `--silent`, and `--debug`

    - *[`flags: Flags`](flags.ts)*:

      The parsed CLI flags, created by [`getopts`](https://www.npmjs.com/package/getopts). Includes the default flags for controlling the log level of the ToolingLog, and `flags.unexpected`, which is an array of flag names which were passed but not expected.

    - *`addCleanupTask: (task: CleanupTask) => void`*:

      A function that registers a task to be called __once__ as soon as one of the following occurs:

      1. `fn` resolve/rejects
      2. something calls `process.exit()`
      3. the user hits <kbd>ctrl</kbd>+<kbd>c</kbd> in their terminal causing the SIGINT signal to be sent to the process

    **`Options`:**
    - *`usage: string`*

      A bit of text to replace the default usage in the `--help` text.

    - *`description: string`*

      A bit of text to replace the default description in the `--help` text.

    - *`flags.help: string`*

      A bit of text included at the top of the `Options:` section of the `--help` text.

    - *`flags.string: string[]`*

      An array of flag names that are expected to have a string value.

    - *`flags.boolean: string[]`*

      An array of flag names that are expected to have a boolean value.

    - *`flags.alias: { [short: string], string }`*

      A map of short flag names to long flag names, used to expand short flags like `-v` to `--verbose`.

    - *`flags.default: { [name: string]: string | string[] | boolean | undefined }`*

      A map of flag names to their default value. If the flag is not defined this value will be set in the flags object passed to the run `fn`.

    - *`flags.allowUnexpected: boolean`*

      By default, any flag that is passed but not mentioned in `flags.string`, `flags.boolean`, `flags.alias` or `flags.default` will trigger an error, preventing the run function from calling its first argument. If you have a reason to disable this behavior set this option to `true`. Unexpected flags will be collected from argv into `flags.unexpected`. To parse these flags and guess at their types, you can additionally pass `flags.guessTypesForUnexpectedFlags` but that's not recommended.


- ***`createFailError(reason: string, options: { exitCode: number, showHelp: boolean }): FailError`***
    
    Create and return an error object that, when thrown within `run(...)` can customize the failure behavior of the CLI. `reason` is printed instead of a stacktrace, `options.exitCode` customizes the exit code of the process, and `options.showHelp` will print the help text before exiting.

- ***`createFlagError(reason: string)`***

    Shortcut for calling `createFailError()` with `options.showHelp`, as errors caused by invalid flags should print the help message to help users debug their usage.

- ***`isFailError(error: any)`***

    Determine if a value is an error created by `createFailError(...)`.