diff --git a/public/1-3-stable/.nojekyll b/public/1-3-stable/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/public/1-3-stable/README.md b/public/1-3-stable/README.md new file mode 100644 index 0000000..8dd5cf8 --- /dev/null +++ b/public/1-3-stable/README.md @@ -0,0 +1,733 @@ +

+
Portainer Stack Utils Docs
+ CLI Commands +

+
+ +

Table of contents

+ + + +- [Available actions](#available-actions) + - [Aliased actions](#aliased-actions) +- [Available options](#available-options) +- [Available environment variables](#available-environment-variables) +- [Actions in details](#actions-in-details) + - [`deploy`](#deploy) + - [`rm`](#rm) + - [`ls`](#ls) + - [`status`](#status) + - [`services`](#services) + - [`tasks`](#tasks) + - [`tasks:healthy`](#taskshealthy) + - [`containers`](#containers) + - [`login`](#login) + - [`lint`](#lint) + - [`inspect`](#inspect) + - [`system:info`](#systeminfo) + - [`actions`](#actions) + - [`help`](#help) + - [`version`](#version) +- [Options in details](#options-in-details) + - [Stack environment variables](#stack-environment-variables) + - [Verbose mode](#verbose-mode) + - [Debug mode](#debug-mode) + - [Strict mode](#strict-mode) + - [Quiet mode](#quiet-mode) + - [`detect-job` option](#detect-job-option) +- [Glossary](#glossary) + - [Job](#job) + + + +
+ +## Available actions + +| Name | Description | +| --------------------------------- | ----------- | +| [`deploy`](#deploy) | Deploy/update the given stack. | +| [`rm`](#rm) | Remove/undeploy the given stack. | +| [`ls`](#ls) | List stacks already deployed. | +| [`status`](#status) | Check if the stack is running/deployed correctly. | +| [`services`](#services) | List services already deployed in the current stack. | +| [`tasks`](#tasks) | List tasks in the current stack. | +| [`tasks:healthy`](#taskshealthy) | List tasks who are running correctly in the current stack. | +| [`containers`](#containers) | List containers running in the current stack. | +| [`login`](#login) | Log in to a Portainer instance. | +| [`lint`](#lint) | Validate the Docker compose/stack file. | +| [`inspect`](#inspect) | Display low-level information of the current stack. | +| [`system:info`](#systeminfo) | Display Docker system-wide information. | +| [`actions`](#actions) | List available actions for this program. | +| [`help`](#help) | Display help message. | +| [`version`](#version) | Display this program version. | + +### Aliased actions + +| Aliased action | Equivalent action | +| ------------------ | ---------------------------------- | +| `auth` | [`login`](#login) | +| `docker:info` | [`system:info`](#systeminfo) | +| `list` | [`ls`](#ls) | +| `ps` | [`tasks`](#tasks) | +| `ps:healthy` | [`tasks:healthy`](#taskshealthy) | +| `remove` | [`rm`](#rm) | +| `undeploy` | [`rm`](#rm) | +| `update` | [`deploy`](#deploy) | +| `validate` | [`lint`](#lint) | + +## Available options + + + +| Flag | Option | Description | Used in action(s) | +| -----------| -------------------------------- | ----------- | ----------------- | +| `-l` | `--url=URL` | URL of the Portainer instance | [deploy](#deploy), [rm](#rm), [ls](#ls), [status](#status), [services](#services), [tasks](#tasks), [tasks:healthy](#taskshealthy), [containers](#containers), [login](#login), [inspect](#inspect), [system:info](#systeminfo) | +| `-u` | `--user=USERNAME` | Username of the Portainer instance | [deploy](#deploy), [rm](#rm), [ls](#ls), [status](#status), [services](#services), [tasks](#tasks), [tasks:healthy](#taskshealthy), [containers](#containers), [login](#login), [inspect](#inspect), [system:info](#systeminfo) | +| `-p` | `--password=PASSWORD` | Password of the Portainer instance | [deploy](#deploy), [rm](#rm), [ls](#ls), [status](#status), [services](#services), [tasks](#tasks), [tasks:healthy](#taskshealthy), [containers](#containers), [login](#login), [inspect](#inspect), [system:info](#systeminfo) | +| `-A` | `--auth-token=[AUTH_TOKEN]` | Use a Portainer auth token instead of `--user` and `--password` options, you can get it with the `psu login` command. Defaults to `null` | [deploy](#deploy), [rm](#rm), [ls](#ls), [status](#status), [services](#services), [tasks](#tasks), [tasks:healthy](#taskshealthy), [containers](#containers), [login](#login), [inspect](#inspect), [system:info](#systeminfo) | +| `-n` | `--name=STACK_NAME` | Stack name | [deploy](#deploy), [rm](#rm), [status](#status), [services](#services), [tasks](#tasks), [tasks:healthy](#taskshealthy), [containers](#containers), [inspect](#inspect) | +| `-c`, `-f` | `--compose-file=FILE_PATH` | Path to docker compose/stack file (required if action=deploy) | [deploy](#deploy), [lint](#lint) | +| `-C`, `-F` | `--compose-file-base64=[BASE64]` | Content of docker compose/stack file, encoded in base64, useful with Docker in Docker (only used when action=deploy) | [deploy](#deploy), [lint](#lint) | +| `-g` | `--env-file=[FILE_PATH]` | Path to a file of environment variables, to be used by the stack (only used when action=deploy) | [deploy](#deploy) | +| `-G` | `--env-file-base64=[BASE64]` | Content of file with environment variables, encoded in base64, to be used by the stack, useful with Docker in Docker (only used when action=deploy) | [deploy](#deploy) | +| `-e` | `--endpoint=[ENDPOINT_ID]` | Which Docker endpoint to use. Defaults to `1` | [deploy](#deploy), [rm](#rm), [ls](#ls), [status](#status), [services](#services), [tasks](#tasks), [tasks:healthy](#taskshealthy), [containers](#containers), [login](#login), [inspect](#inspect), [system:info](#systeminfo) | +| `-r` | `--prune` | Whether to prune unused containers or not (only used when action=deploy). Defaults to `false` | [deploy](#deploy) | +| `-T` | `--timeout=[SECONDS]` | Timeout, number of seconds before thrown an error (only used when action=status\|tasks\|tasks:healthy). Defaults to `100` | [status](#status), [tasks](#tasks), [tasks:healthy](#taskshealthy) | +| `-j` | `--detect-job=[true\|false]` | Auto detect services who are jobs in the current stack. Defaults to `true` | [status](#status), [tasks](#tasks), [tasks:healthy](#taskshealthy) | +| `-S` | `--service=[SERVICE_NAME]` | Filtering by a service name of the current stack (only used when action=status\|tasks\|tasks:healthy\|containers) | [status](#status), [tasks](#tasks), [tasks:healthy](#taskshealthy), [containers](#containers) | +| `-i` | `--insecure` | Skip the host's SSL certificate verification, use at your own risk. Defaults to `false` | [deploy](#deploy), [rm](#rm), [ls](#ls), [status](#status), [services](#services), [tasks](#tasks), [tasks:healthy](#taskshealthy), [containers](#containers), [login](#login), [inspect](#inspect), [system:info](#systeminfo) | +| `-v` | `--verbose` | Increase the verbosity of messages. Defaults to `false` | [deploy](#deploy), [rm](#rm), [ls](#ls), [status](#status), [services](#services), [tasks](#tasks), [tasks:healthy](#taskshealthy), [containers](#containers), [login](#login), [lint](#lint), [inspect](#inspect), [system:info](#systeminfo), [actions](#actions) | +| `-d` | `--debug` | Print as much information as possible to help diagnosing a malfunction. Defaults to `false` | [deploy](#deploy), [rm](#rm), [ls](#ls), [status](#status), [services](#services), [tasks](#tasks), [tasks:healthy](#taskshealthy), [containers](#containers), [login](#login), [lint](#lint), [inspect](#inspect), [system:info](#systeminfo), [actions](#actions) | +| `-m` | `--masked-variables` | In debug/verbose mode, value of sensitive variables will be hidden, avoid leaking passwords/tokens in logs. Possible values: true\|extended\|false. Defaults to `false` | [deploy](#deploy), [rm](#rm), [ls](#ls), [status](#status), [services](#services), [tasks](#tasks), [tasks:healthy](#taskshealthy), [containers](#containers), [login](#login), [inspect](#inspect), [system:info](#systeminfo) | +| `-q` | `--quiet` | Display the minimum of information or nothing, UNIX/Linux friendly. Defaults to `false` | [ls](#ls), [services](#services), [tasks](#tasks), [tasks:healthy](#taskshealthy), [containers](#containers), [inspect](#inspect) | +| `-t` | `--strict` | Never updates an existent stack nor removes an inexistent one, and instead exits with an error. Defaults to `false` | [deploy](#deploy), [rm](#rm) | +| `-L` | `--lint=[true\|false]` | Validate the Docker compose/stack file before deploying the stack (only used when action=deploy). Defaults to `true` | [deploy](#deploy) | +| `-h` | `--help` | Display help message. To display help of a given action, run: `psu --help` | [deploy](#deploy), [rm](#rm), [ls](#ls), [status](#status), [services](#services), [tasks](#tasks), [tasks:healthy](#taskshealthy), [containers](#containers), [login](#login), [lint](#lint), [inspect](#inspect), [system:info](#systeminfo), [actions](#actions), [version](#version) | +| `-V` | `--version` | Display the version of this program | | +| `-s` | `--secure=[yes\|no]` | **DEPRECATED**: Use the `--insecure` option instead. Enable or disable the host's SSL certificate verification. Defaults to `yes` | [deploy](#deploy), [rm](#rm), [ls](#ls), [status](#status), [services](#services), [tasks](#tasks), [tasks:healthy](#taskshealthy), [containers](#containers), [login](#login), [inspect](#inspect), [system:info](#systeminfo) | +| `-a` | `--action=[ACTION_NAME]` | **DEPRECATED**: Use `` argument instead. The name of the action to execute | | + +## Available environment variables + +| Environment variable | Description | Used in action(s) | +| ------------------------------------------- | -------------- | ----------------- | +| `ACTION=ACTION_NAME` | The name of the action to execute | n/a | +| `PORTAINER_URL=URL` | URL of the Portainer instance | [deploy](#deploy), [rm](#rm), [ls](#ls), [status](#status), [services](#services), [tasks](#tasks), [tasks:healthy](#taskshealthy), [containers](#containers), [login](#login), [inspect](#inspect), [system:info](#systeminfo) | +| `PORTAINER_USER=USERNAME` | Username of the Portainer instance | [deploy](#deploy), [rm](#rm), [ls](#ls), [status](#status), [services](#services), [tasks](#tasks), [tasks:healthy](#taskshealthy), [containers](#containers), [login](#login), [inspect](#inspect), [system:info](#systeminfo) | +| `PORTAINER_PASSWORD=PASSWORD` | Password of the Portainer instance | [deploy](#deploy), [rm](#rm), [ls](#ls), [status](#status), [services](#services), [tasks](#tasks), [tasks:healthy](#taskshealthy), [containers](#containers), [login](#login), [inspect](#inspect), [system:info](#systeminfo) | +| `PORTAINER_AUTH_TOKEN=[AUTH_TOKEN]` | Use a Portainer auth token instead of `--user` and `--password` options, you can get it with the `psu login` command. Defaults to `null` | [deploy](#deploy), [rm](#rm), [ls](#ls), [status](#status), [services](#services), [tasks](#tasks), [tasks:healthy](#taskshealthy), [containers](#containers), [login](#login), [inspect](#inspect), [system:info](#systeminfo) | +| `PORTAINER_STACK_NAME=STACK_NAME` | Stack name | [deploy](#deploy), [rm](#rm), [status](#status), [services](#services), [tasks](#tasks), [tasks:healthy](#taskshealthy), [containers](#containers), [inspect](#inspect) | +| `DOCKER_COMPOSE_FILE=FILE_PATH` | Path to docker compose/stack file (required if action=deploy) | [deploy](#deploy), [lint](#lint) | +| `ENVIRONMENT_VARIABLES_FILE=[FILE_PATH]` | Path to a file of environment variables, to be used by the stack (only used when action=deploy) | [deploy](#deploy) | +| `PORTAINER_ENDPOINT=[ENDPOINT_ID]` | Which Docker endpoint to use. Defaults to `1` | [deploy](#deploy), [rm](#rm), [ls](#ls), [status](#status), [services](#services), [tasks](#tasks), [tasks:healthy](#taskshealthy), [containers](#containers), [login](#login), [inspect](#inspect), [system:info](#systeminfo) | +| `PORTAINER_PRUNE=[true\|false]` | Whether to prune unused containers or not (only used when action=deploy). Defaults to `false` | [deploy](#deploy) | +| `TIMEOUT=[SECONDS]` | Timeout, number of seconds before thrown an error (only used when action=status\|tasks\|tasks:healthy). Defaults to `100` | [status](#status), [tasks](#tasks), [tasks:healthy](#taskshealthy) | +| `AUTO_DETECT_JOB=[true\|false]` | Auto detect services who are jobs in the current stack. Defaults to `true` | [status](#status), [tasks](#tasks), [tasks:healthy](#taskshealthy) | +| `PORTAINER_SERVICE_NAME=[SERVICE_NAME]` | Filtering by a service name of the current stack (only used when action=status\|tasks\|tasks:healthy\|containers) | [status](#status), [tasks](#tasks), [tasks:healthy](#taskshealthy), [containers](#containers) | +| `HTTPIE_VERIFY_SSL=[yes\|no\|CA_BUNDLE_PATH]` | Enable or disable the host's SSL certificate verification. Defaults to `yes`. You can also set a custom CA bundle path | [deploy](#deploy), [rm](#rm), [ls](#ls), [status](#status), [services](#services), [tasks](#tasks), [tasks:healthy](#taskshealthy), [containers](#containers), [login](#login), [inspect](#inspect), [system:info](#systeminfo) | +| `VERBOSE_MODE=[true\|false]` | Increase the verbosity of messages. Defaults to `false` | [deploy](#deploy), [rm](#rm), [ls](#ls), [status](#status), [services](#services), [tasks](#tasks), [tasks:healthy](#taskshealthy), [containers](#containers), [login](#login), [lint](#lint), [inspect](#inspect), [system:info](#systeminfo), [actions](#actions) | +| `DEBUG_MODE=[true\|false]` | Print as much information as possible to help diagnosing a malfunction. Defaults to `false` | [deploy](#deploy), [rm](#rm), [ls](#ls), [status](#status), [services](#services), [tasks](#tasks), [tasks:healthy](#taskshealthy), [containers](#containers), [login](#login), [lint](#lint), [inspect](#inspect), [system:info](#systeminfo), [actions](#actions) | +| `MASKED_VARIABLES=[true\|extended\|false]` | In debug/verbose mode, value of sensitive variables will be hidden, avoid leaking passwords/tokens in logs. Possible values: true\|extended\|false. Defaults to `false` | [deploy](#deploy), [rm](#rm), [ls](#ls), [status](#status), [services](#services), [tasks](#tasks), [tasks:healthy](#taskshealthy), [containers](#containers), [login](#login), [inspect](#inspect), [system:info](#systeminfo) | +| `QUIET_MODE=[true\|false]` | Display the minimum of information or nothing, UNIX/Linux friendly. Defaults to `false` | [ls](#ls), [services](#services), [tasks](#tasks), [tasks:healthy](#taskshealthy), [containers](#containers), [inspect](#inspect) | +| `STRICT_MODE=[true\|false]` | Never updates an existent stack nor removes an inexistent one, and instead exits with an error. Defaults to `false` | [deploy](#deploy), [rm](#rm) | +| `DOCKER_COMPOSE_LINT=[true\|false]` | Validate the Docker compose/stack file before deploying the stack (only used when action=deploy). Defaults to `true` | [deploy](#deploy) | + + + + + +## Actions in details + +### `deploy` + +Deploy/update the given stack. + +#### Aliased action: +`update` + +#### Usage: +`psu deploy [options]` + +#### Examples: + +```bash +psu deploy --user admin --password password --url https://portainer.local --name mystack --compose-file /path/to/docker-compose.yml --env-file /path/to/env_vars_file +``` + +#### Required options: +| Flag | Option | Description | +| ---------- | -------------------------------- | ----------- | +| `-l` | `--url=URL` | URL of the Portainer instance | +| `-u` | `--user=USERNAME` | Username of the Portainer instance | +| `-p` | `--password=PASSWORD` | Password of the Portainer instance | +| `-n` | `--name=STACK_NAME` | Stack name | +| `-c`, `-f` | `--compose-file=FILE_PATH` | Path to docker compose/stack file (required if action=deploy) | + +#### Optional options: +| Flag | Option | Description | +| ---------- | -------------------------------- | ----------- | +| `-A` | `--auth-token=[AUTH_TOKEN]` | Use a Portainer auth token instead of `--user` and `--password` options, you can get it with the `psu login` command. Defaults to `null` | +| `-e` | `--endpoint=[ENDPOINT_ID]` | Which Docker endpoint to use. Defaults to `1` | +| `-L` | `--lint=[true\|false]` | Validate the Docker compose/stack file before deploying the stack (only used when action=deploy). Defaults to `true` | +| `-C`, `-F` | `--compose-file-base64=[BASE64]` | Content of docker compose/stack file, encoded in base64, useful with Docker in Docker (only used when action=deploy) | +| `-g` | `--env-file=[FILE_PATH]` | Path to a file of environment variables, to be used by the stack (only used when action=deploy) | +| `-G` | `--env-file-base64=[BASE64]` | Content of file with environment variables, encoded in base64, to be used by the stack, useful with Docker in Docker (only used when action=deploy) | +| `-r` | `--prune` | Whether to prune unused containers or not (only used when action=deploy). Defaults to `false` | +| `-i` | `--insecure` | Skip the host's SSL certificate verification, use at your own risk. Defaults to `false` | +| `-v` | `--verbose` | Increase the verbosity of messages. Defaults to `false` | +| `-d` | `--debug` | Print as much information as possible to help diagnosing a malfunction. Defaults to `false` | +| `-m` | `--masked-variables` | In debug/verbose mode, value of sensitive variables will be hidden, avoid leaking passwords/tokens in logs. Possible values: true\|extended\|false. Defaults to `false` | +| `-t` | `--strict` | Never updates an existent stack nor removes an inexistent one, and instead exits with an error. Defaults to `false` | +| `-h` | `--help` | Display help message. To display help of a given action, run: `psu --help` | + +### `rm` +Remove/undeploy the given stack. + +#### Aliased actions: +`remove`, `undeploy` + +#### Usage: +`psu rm [options]` + +#### Examples: + +```bash +psu rm --user admin --password password --url https://portainer.local --name mystack +``` + +#### Required options: +| Flag | Option | Description | +| ---------- | -------------------------------- | ----------- | +| `-l` | `--url=URL` | URL of the Portainer instance | +| `-u` | `--user=USERNAME` | Username of the Portainer instance | +| `-p` | `--password=PASSWORD` | Password of the Portainer instance | +| `-n` | `--name=STACK_NAME` | Stack name | + +#### Optional options: +| Flag | Option | Description | +| ---------- | -------------------------------- | ----------- | +| `-A` | `--auth-token=[AUTH_TOKEN]` | Use a Portainer auth token instead of `--user` and `--password` options, you can get it with the `psu login` command. Defaults to `null` | +| `-e` | `--endpoint=[ENDPOINT_ID]` | Which Docker endpoint to use. Defaults to `1` | +| `-i` | `--insecure` | Skip the host's SSL certificate verification, use at your own risk. Defaults to `false` | +| `-v` | `--verbose` | Increase the verbosity of messages. Defaults to `false` | +| `-d` | `--debug` | Print as much information as possible to help diagnosing a malfunction. Defaults to `false` | +| `-m` | `--masked-variables` | In debug/verbose mode, value of sensitive variables will be hidden, avoid leaking passwords/tokens in logs. Possible values: true\|extended\|false. Defaults to `false` | +| `-t` | `--strict` | Never updates an existent stack nor removes an inexistent one, and instead exits with an error. Defaults to `false` | +| `-h` | `--help` | Display help message. To display help of a given action, run: `psu --help` | + +### `ls` +List stacks already deployed. + +#### Aliased actions: +`list` + +#### Usage: +`psu ls [options]` + +#### Examples: + +```bash +psu ls --user admin --password password --url https://portainer.local +``` + +Output a JSON array of the stacks already deployed: +```json +[ + { + "Id": "mystack_jpofkc0i9uo9wtx1zesuk649w", + "Name": "mystack", + "Type": "1", + "EndpointID": "1", + "EntryPoint": "docker-compose.yml", + "SwarmID": "jpofkc0i9uo9wtx1zesuk649w", + "ProjectPath": "/data/compose/mystack_jpofkc0i9uo9wtx1zesuk649w", + "Env": [ + { + "name": "MYSQL_ROOT_PASSWORD", + "value": "password" + } + ] + }, + { + "Id": "mysecondstack_i0649w9uo9wtx1zesujpofkck", + "Name": "mysecondstack", + "Type": "1", + "EndpointID": "1", + "EntryPoint": "docker-compose.yml", + "SwarmID": "i0649w9uo9wtx1zesujpofkck", + "ProjectPath": "/data/compose/mysecondstack_i0649w9uo9wtx1zesujpofkck" + }, + { + "Id": "mythirdstack_w9uo9wtxi064ujpofkck91zes", + "Name": "mythirdstack", + "Type": "1", + "EndpointID": "1", + "EntryPoint": "docker-compose.yml", + "SwarmID": "mythirdstack_w9uo9wtxi064ujpofkck91zes", + "ProjectPath": "/data/compose/mythirdstack_mythirdstack_w9uo9wtxi064ujpofkck91zes" + }, +] +``` + +**With the `quiet` mode enabled**: +```bash +psu ls --user admin --password password --url https://portainer.local --quiet +``` + +Output the name of the stacks already deployed: +```bash +mystack +mysecondstack +mythirdstack +``` + +#### Required options: +| Flag | Option | Description | +| ---------- | -------------------------------- | ----------- | +| `-l` | `--url=URL` | URL of the Portainer instance | +| `-u` | `--user=USERNAME` | Username of the Portainer instance | +| `-p` | `--password=PASSWORD` | Password of the Portainer instance | + +#### Optional options: +| Flag | Option | Description | +| ---------- | -------------------------------- | ----------- | +| `-A` | `--auth-token=[AUTH_TOKEN]` | Use a Portainer auth token instead of `--user` and `--password` options, you can get it with the `psu login` command. Defaults to `null` | +| `-e` | `--endpoint=[ENDPOINT_ID]` | Which Docker endpoint to use. Defaults to `1` | +| `-q` | `--quiet` | Display the minimum of information or nothing, UNIX/Linux friendly. Defaults to `false` | +| `-i` | `--insecure` | Skip the host's SSL certificate verification, use at your own risk. Defaults to `false` | +| `-v` | `--verbose` | Increase the verbosity of messages. Defaults to `false` | +| `-d` | `--debug` | Print as much information as possible to help diagnosing a malfunction. Defaults to `false` | +| `-m` | `--masked-variables` | In debug/verbose mode, value of sensitive variables will be hidden, avoid leaking passwords/tokens in logs. Possible values: true\|extended\|false. Defaults to `false` | +| `-h` | `--help` | Display help message. To display help of a given action, run: `psu --help` | + +### `status` +Check if the stack is running/deployed correctly + +If your stack has some services who acts as [jobs](#job), see the [`--detect-job`](#detect-job-option) option for more details. + +This action is very useful in CI/CD pipelines, it's equivalent to the [`kubectl rollout status`](https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#-em-status-em-) command of Kubernetes. + +#### Usage: +`psu status [options]` + +#### Examples: + +```bash +psu status --user admin --password password --url https://portainer.local --name mystack +``` + +This command outputs nothing if the stack is correctly running or deployed. + +It also has an exit code (or exit status). +The exit code value return based on a command or program will successfully execute _(return 0)_ or not _(return 1 or higher)_. + +```bash +psu status --user admin --password password --url https://portainer.local --name mystack --timeout 20 + +if [ $? -eq 0 ]; then + echo "[OK] This stack is running/deployed correctly" +else + echo "[ERROR] This stack isn't running/deployed correctly!" +fi +``` + +For more informations about exit code, you can read this [article](https://tecadmin.net/tutorial/bash-scripting/bash-exit-codes/) and this [Wikipedia page](https://en.wikipedia.org/wiki/Exit_status) + +#### Required options: +| Flag | Option | Description | +| ---------- | -------------------------------- | ----------- | +| `-l` | `--url=URL` | URL of the Portainer instance | +| `-u` | `--user=USERNAME` | Username of the Portainer instance | +| `-p` | `--password=PASSWORD` | Password of the Portainer instance | +| `-n` | `--name=STACK_NAME` | Stack name | + +#### Optional options: +| Flag | Option | Description | +| ---------- | -------------------------------- | ----------- | +| `-A` | `--auth-token=[AUTH_TOKEN]` | Use a Portainer auth token instead of `--user` and `--password` options, you can get it with the `psu login` command. Defaults to `null` | +| `-e` | `--endpoint=[ENDPOINT_ID]` | Which Docker endpoint to use. Defaults to `1` | +| `-S` | `--service=[SERVICE_NAME]` | Filtering by a service name of the current stack (only used when action=status\|tasks\|tasks:healthy\|containers) | +| `-j` | `--detect-job=[true\|false]` | Auto detect services who are jobs in the current stack. Defaults to `true` | +| `-T` | `--timeout=[SECONDS]` | Timeout, number of seconds before thrown an error (only used when action=status\|tasks\|tasks:healthy). Defaults to `100` | +| `-i` | `--insecure` | Skip the host's SSL certificate verification, use at your own risk. Defaults to `false` | +| `-v` | `--verbose` | Increase the verbosity of messages. Defaults to `false` | +| `-d` | `--debug` | Print as much information as possible to help diagnosing a malfunction. Defaults to `false` | +| `-m` | `--masked-variables` | In debug/verbose mode, value of sensitive variables will be hidden, avoid leaking passwords/tokens in logs. Possible values: true\|extended\|false. Defaults to `false` | +| `-h` | `--help` | Display help message. To display help of a given action, run: `psu --help` | + +### `services` +List services already deployed in the current stack. + +#### Usage: +`psu services [options]` + +#### Required options: +| Flag | Option | Description | +| ---------- | -------------------------------- | ----------- | +| `-l` | `--url=URL` | URL of the Portainer instance | +| `-u` | `--user=USERNAME` | Username of the Portainer instance | +| `-p` | `--password=PASSWORD` | Password of the Portainer instance | +| `-n` | `--name=STACK_NAME` | Stack name | + +#### Optional options: +| Flag | Option | Description | +| ---------- | -------------------------------- | ----------- | +| `-A` | `--auth-token=[AUTH_TOKEN]` | Use a Portainer auth token instead of `--user` and `--password` options, you can get it with the `psu login` command. Defaults to `null` | +| `-e` | `--endpoint=[ENDPOINT_ID]` | Which Docker endpoint to use. Defaults to `1` | +| `-q` | `--quiet` | Display the minimum of information or nothing, UNIX/Linux friendly. Defaults to `false` | +| `-i` | `--insecure` | Skip the host's SSL certificate verification, use at your own risk. Defaults to `false` | +| `-v` | `--verbose` | Increase the verbosity of messages. Defaults to `false` | +| `-d` | `--debug` | Print as much information as possible to help diagnosing a malfunction. Defaults to `false` | +| `-m` | `--masked-variables` | In debug/verbose mode, value of sensitive variables will be hidden, avoid leaking passwords/tokens in logs. Possible values: true\|extended\|false. Defaults to `false` | +| `-h` | `--help` | Display help message. To display help of a given action, run: `psu --help` | + +### `tasks` +List tasks in the current stack. + +If your stack has some services who acts as [jobs](#job), see the [`--detect-job`](#detect-job-option) option for more details. + +#### Usage: +`psu tasks [options]` + +#### Aliased action: +`ps` + +#### Required options: +| Flag | Option | Description | +| ---------- | -------------------------------- | ----------- | +| `-l` | `--url=URL` | URL of the Portainer instance | +| `-u` | `--user=USERNAME` | Username of the Portainer instance | +| `-p` | `--password=PASSWORD` | Password of the Portainer instance | +| `-n` | `--name=STACK_NAME` | Stack name | + +#### Optional options: +| Flag | Option | Description | +| ---------- | -------------------------------- | ----------- | +| `-A` | `--auth-token=[AUTH_TOKEN]` | Use a Portainer auth token instead of `--user` and `--password` options, you can get it with the `psu login` command. Defaults to `null` | +| `-e` | `--endpoint=[ENDPOINT_ID]` | Which Docker endpoint to use. Defaults to `1` | +| `-S` | `--service=[SERVICE_NAME]` | Filtering by a service name of the current stack (only used when action=status\|tasks\|tasks:healthy\|containers) | +| `-j` | `--detect-job=[true\|false]` | Auto detect services who are jobs in the current stack. Defaults to `true` | +| `-T` | `--timeout=[SECONDS]` | Timeout, number of seconds before thrown an error (only used when action=status\|tasks\|tasks:healthy). Defaults to `100` | +| `-q` | `--quiet` | Display the minimum of information or nothing, UNIX/Linux friendly. Defaults to `false` | +| `-i` | `--insecure` | Skip the host's SSL certificate verification, use at your own risk. Defaults to `false` | +| `-v` | `--verbose` | Increase the verbosity of messages. Defaults to `false` | +| `-d` | `--debug` | Print as much information as possible to help diagnosing a malfunction. Defaults to `false` | +| `-m` | `--masked-variables` | In debug/verbose mode, value of sensitive variables will be hidden, avoid leaking passwords/tokens in logs. Possible values: true\|extended\|false. Defaults to `false` | +| `-h` | `--help` | Display help message. To display help of a given action, run: `psu --help` | + +### `tasks:healthy` + +List tasks who are running correctly in the current stack. + +If your stack has some services who acts as [jobs](#job), see the [`--detect-job`](#detect-job-option) option for more details. + +#### Usage: +`psu tasks:healthy [options]` + +#### Aliased action: +`ps:healthy` + +#### Required options: +| Flag | Option | Description | +| ---------- | -------------------------------- | ----------- | +| `-l` | `--url=URL` | URL of the Portainer instance | +| `-u` | `--user=USERNAME` | Username of the Portainer instance | +| `-p` | `--password=PASSWORD` | Password of the Portainer instance | +| `-n` | `--name=STACK_NAME` | Stack name | + +#### Optional options: +| Flag | Option | Description | +| ---------- | -------------------------------- | ----------- | +| `-A` | `--auth-token=[AUTH_TOKEN]` | Use a Portainer auth token instead of `--user` and `--password` options, you can get it with the `psu login` command. Defaults to `null` | +| `-e` | `--endpoint=[ENDPOINT_ID]` | Which Docker endpoint to use. Defaults to `1` | +| `-S` | `--service=[SERVICE_NAME]` | Filtering by a service name of the current stack (only used when action=status\|tasks\|tasks:healthy\|containers) | +| `-j` | `--detect-job=[true\|false]` | Auto detect services who are jobs in the current stack. Defaults to `true` | +| `-T` | `--timeout=[SECONDS]` | Timeout, number of seconds before thrown an error (only used when action=status\|tasks\|tasks:healthy). Defaults to `100` | +| `-q` | `--quiet` | Display the minimum of information or nothing, UNIX/Linux friendly. Defaults to `false` | +| `-i` | `--insecure` | Skip the host's SSL certificate verification, use at your own risk. Defaults to `false` | +| `-v` | `--verbose` | Increase the verbosity of messages. Defaults to `false` | +| `-d` | `--debug` | Print as much information as possible to help diagnosing a malfunction. Defaults to `false` | +| `-m` | `--masked-variables` | In debug/verbose mode, value of sensitive variables will be hidden, avoid leaking passwords/tokens in logs. Possible values: true\|extended\|false. Defaults to `false` | +| `-h` | `--help` | Display help message. To display help of a given action, run: `psu --help` | + +### `containers` +List containers running in the current stack. + +#### Usage: +`psu containers [options]` + +#### Required options: +| Flag | Option | Description | +| ---------- | -------------------------------- | ----------- | +| `-l` | `--url=URL` | URL of the Portainer instance | +| `-u` | `--user=USERNAME` | Username of the Portainer instance | +| `-p` | `--password=PASSWORD` | Password of the Portainer instance | +| `-n` | `--name=STACK_NAME` | Stack name | + +#### Optional options: +| Flag | Option | Description | +| ---------- | -------------------------------- | ----------- | +| `-A` | `--auth-token=[AUTH_TOKEN]` | Use a Portainer auth token instead of `--user` and `--password` options, you can get it with the `psu login` command. Defaults to `null` | +| `-e` | `--endpoint=[ENDPOINT_ID]` | Which Docker endpoint to use. Defaults to `1` | +| `-S` | `--service=[SERVICE_NAME]` | Filtering by a service name of the current stack (only used when action=status\|tasks\|tasks:healthy\|containers) | +| `-q` | `--quiet` | Display the minimum of information or nothing, UNIX/Linux friendly. Defaults to `false` | +| `-i` | `--insecure` | Skip the host's SSL certificate verification, use at your own risk. Defaults to `false` | +| `-v` | `--verbose` | Increase the verbosity of messages. Defaults to `false` | +| `-d` | `--debug` | Print as much information as possible to help diagnosing a malfunction. Defaults to `false` | +| `-m` | `--masked-variables` | In debug/verbose mode, value of sensitive variables will be hidden, avoid leaking passwords/tokens in logs. Possible values: true\|extended\|false. Defaults to `false` | +| `-h` | `--help` | Display help message. To display help of a given action, run: `psu --help` | + +### `login` +Log in to a Portainer instance. + +#### Usage: +`psu login [options]` + +#### Aliased action: +`auth` + +#### Required options: +| Flag | Option | Description | +| ---------- | -------------------------------- | ----------- | +| `-l` | `--url=URL` | URL of the Portainer instance | +| `-u` | `--user=USERNAME` | Username of the Portainer instance | +| `-p` | `--password=PASSWORD` | Password of the Portainer instance | + +#### Optional options: +| Flag | Option | Description | +| ---------- | -------------------------------- | ----------- | +| `-i` | `--insecure` | Skip the host's SSL certificate verification, use at your own risk. Defaults to `false` | +| `-v` | `--verbose` | Increase the verbosity of messages. Defaults to `false` | +| `-d` | `--debug` | Print as much information as possible to help diagnosing a malfunction. Defaults to `false` | +| `-m` | `--masked-variables` | In debug/verbose mode, value of sensitive variables will be hidden, avoid leaking passwords/tokens in logs. Possible values: true\|extended\|false. Defaults to `false` | +| `-h` | `--help` | Display help message. To display help of a given action, run: `psu --help` | + +### `lint` +Validate the Docker compose/stack file. + +#### Usage: +`psu lint [options]` + +#### Aliased action: +`validate` + +#### Required options: +| Flag | Option | Description | +| ---------- | -------------------------------- | ----------- | +| `-c`, `-f` | `--compose-file=FILE_PATH` | Path to docker compose/stack file (required if action=deploy) | + +#### Optional options: +| Flag | Option | Description | +| ---------- | -------------------------------- | ----------- | +| `-C`, `-F` | `--compose-file-base64=[BASE64]` | Content of docker compose/stack file, encoded in base64, useful with Docker in Docker (only used when action=deploy) | +| `-v` | `--verbose` | Increase the verbosity of messages. Defaults to `false` | +| `-d` | `--debug` | Print as much information as possible to help diagnosing a malfunction. Defaults to `false` | +| `-h` | `--help` | Display help message. To display help of a given action, run: `psu --help` | + +### `inspect` +Display low-level information of the current stack. + +#### Usage: +`psu inspect [options]` + +#### Examples: +```bash +psu inspect --user admin --password password --url https://portainer.local --name mystack +``` + +Output the JSON object of the stack if it's already deployed: +```json +{ + "Id": "mystack_jpofkc0i9uo9wtx1zesuk649w", + "Name": "mystack", + "Type": "1", + "EndpointID": "1", + "EntryPoint": "docker-compose.yml", + "SwarmID": "jpofkc0i9uo9wtx1zesuk649w", + "ProjectPath": "/data/compose/mystack_jpofkc0i9uo9wtx1zesuk649w", + "Env": [ + { + "name": "MYSQL_ROOT_PASSWORD", + "value": "password" + } + ] +} +``` + +**With the `quiet` mode enabled**: +```bash +psu inspect --user admin --password password --url https://portainer.local --name mystack --quiet +``` + +Output the stack name if it's already deployed: +```bash +mystack +``` + +**Check if the stack is already deployed**: +```bash +stack_exist=$(psu inspect --user admin --password password --url https://portainer.local --name mystack) + +if [ -n "$stack_exist" ]; then + echo OK +else + echo KO +fi + +## OR check the exit code of the last executed command: +stack_exist=$(psu inspect --user admin --password password --url https://portainer.local --name mystack) + +status=$? +if $(exit $status); then + echo OK +else + echo KO +fi +``` + +#### Required options: +| Flag | Option | Description | +| ---------- | -------------------------------- | ----------- | +| `-l` | `--url=URL` | URL of the Portainer instance | +| `-u` | `--user=USERNAME` | Username of the Portainer instance | +| `-p` | `--password=PASSWORD` | Password of the Portainer instance | +| `-n` | `--name=STACK_NAME` | Stack name | + +#### Optional options: +| Flag | Option | Description | +| ---------- | -------------------------------- | ----------- | +| `-A` | `--auth-token=[AUTH_TOKEN]` | Use a Portainer auth token instead of `--user` and `--password` options, you can get it with the `psu login` command. Defaults to `null` | +| `-e` | `--endpoint=[ENDPOINT_ID]` | Which Docker endpoint to use. Defaults to `1` | +| `-q` | `--quiet` | Display the minimum of information or nothing, UNIX/Linux friendly. Defaults to `false` | +| `-i` | `--insecure` | Skip the host's SSL certificate verification, use at your own risk. Defaults to `false` | +| `-v` | `--verbose` | Increase the verbosity of messages. Defaults to `false` | +| `-d` | `--debug` | Print as much information as possible to help diagnosing a malfunction. Defaults to `false` | +| `-m` | `--masked-variables` | In debug/verbose mode, value of sensitive variables will be hidden, avoid leaking passwords/tokens in logs. Possible values: true\|extended\|false. Defaults to `false` | +| `-h` | `--help` | Display help message. To display help of a given action, run: `psu --help` | + +### `system:info` +Display Docker system-wide information. + +#### Usage: +`psu system:info [options]` + +#### Aliased action: +`docker:info` + +#### Required options: +| Flag | Option | Description | +| ---------- | -------------------------------- | ----------- | +| `-l` | `--url=URL` | URL of the Portainer instance | +| `-u` | `--user=USERNAME` | Username of the Portainer instance | +| `-p` | `--password=PASSWORD` | Password of the Portainer instance | + +#### Optional options: +| Flag | Option | Description | +| ---------- | -------------------------------- | ----------- | +| `-A` | `--auth-token=[AUTH_TOKEN]` | Use a Portainer auth token instead of `--user` and `--password` options, you can get it with the `psu login` command. Defaults to `null` | +| `-e` | `--endpoint=[ENDPOINT_ID]` | Which Docker endpoint to use. Defaults to `1` | +| `-i` | `--insecure` | Skip the host's SSL certificate verification, use at your own risk. Defaults to `false` | +| `-v` | `--verbose` | Increase the verbosity of messages. Defaults to `false` | +| `-d` | `--debug` | Print as much information as possible to help diagnosing a malfunction. Defaults to `false` | +| `-m` | `--masked-variables` | In debug/verbose mode, value of sensitive variables will be hidden, avoid leaking passwords/tokens in logs. Possible values: true\|extended\|false. Defaults to `false` | +| `-h` | `--help` | Display help message. To display help of a given action, run: `psu --help` | + +### `actions` +List available actions for this program. + +#### Optional options: +| Flag | Option | Description | +| ---------- | -------------------------------- | ----------- | +| `-v` | `--verbose` | Increase the verbosity of messages. Defaults to `false` | +| `-d` | `--debug` | Print as much information as possible to help diagnosing a malfunction. Defaults to `false` | +| `-h` | `--help` | Display help message. To display help of a given action, run: `psu --help` | + +### `help` +Display help message. + +### `version` +Display this program version. + +#### Optional options: +| Flag | Option | Description | +| ---------- | -------------------------------- | ----------- | +| `-h` | `--help` | Display help message. To display help of a given action, run: `psu --help` | + +## Options in details + +### Stack environment variables + +There can be set environment variables for each stack, be it a new deployment or an update. For example: + +```bash +touch .env +echo "MYSQL_ROOT_PASSWORD=agoodpassword" >> .env +echo "ALLOWED_HOSTS=*" >> .env +psu deploy --user admin --password password --url https://portainer.local --name mystack --compose-file docker-compose.yml --env-file .env +``` + +Stack environment variables can be enabled through `ENVIRONMENT_VARIABLES_FILE` envvar or `--env-file` option or `-g` flag. + +### Verbose mode + +In verbose mode the script prints execution steps. + +```text +Getting auth token... +Getting stack mystack... +Stack mystack not found. +Getting Docker info... +Getting swarm cluster (if any)... +Swarm cluster found. +Preparing stack JSON... +Creating stack mystack... +``` + +Verbose mode can be enabled through `VERBOSE_MODE` envvar or `--verbose` option or `-v` flag. + +### Debug mode + +In debug mode the script prints as much information as possible to help diagnosing a malfunction. + +**WARNING**: Debug mode will print configuration values (with Portainer credentials) and Portainer API responses (with sensitive information like authentication token and stacks environment variables). Avoid using debug mode in CI/CD pipelines, as pipeline logs are usually recorded. + +Debug mode can be enabled through `DEBUG_MODE` envvar or `--debug` option or `-d` flag. + +### Strict mode + +In strict mode the script never updates an existent stack nor removes an inexistent one, and instead exits with an error. + +Strict mode can be enabled through `STRICT_MODE` envvar or `--strict` option or `-t` flag. + +### Quiet mode + +In quiet mode the script prints the minimum of informations or nothing. + +It's inspired by the `--quiet` option of [`docker images`](https://docs.docker.com/engine/reference/commandline/images/#options) command. + +Quiet mode can be enabled through `QUIET_MODE` envvar or `--quiet` option or `-q` flag. + +### `detect-job` option + +The `--detect-job` option (`true` by default) detects if a service has a restart policy set to `none` and considered this service as a [Job](#job). +If set to `false`, to considering a service as a [Job](#job), you need to set a container's [label](https://docs.docker.com/compose/compose-file/#labels-1) named `job-name` with the value you want (e.g. `my-job-service-name`) in the Docker compose/stack file. + +_See the [Job definition](#job) section for more details._ + +## Glossary + +### Job + +Docker (or Portainer) doesn't have a true [Job](https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/) mechanism like [Kubernetes](https://kubernetes.io). + +But `psu` use an equivalent Docker behavior, based on filtering tasks status with a specific container's [label](https://docs.docker.com/compose/compose-file/#labels-1) (`job-name`). +Or when, in your Docker compose/stack file, a service [`deploy.restart_policy.condition`](https://docs.docker.com/compose/compose-file/#restart_policy) option is set to `none`. + +The `psu` definition of a job is a Swarm [service](https://docs.docker.com/engine/swarm/how-swarm-mode-works/services/) who ensures that all its specified [task(s)](https://docs.docker.com/engine/swarm/how-swarm-mode-works/swarm-task-states/) successfully terminate. + +Using a job is useful when you want to have a service who run a script (e.g. database migration). +And shutdown this service when its script is successfully executed. + +See the service named `job` in the [`docker-stack-web-app.yml`](https://gitlab.com/psuapp/psu/tree/v1.3.0/tests/dockerfiles/docker-stack-web-app.yml) file, for a real use case. +It has both a container's label `job-name` and a restart policy set to `none`. diff --git a/public/1-3-stable/_coverpage.md b/public/1-3-stable/_coverpage.md new file mode 100644 index 0000000..a2c97c6 --- /dev/null +++ b/public/1-3-stable/_coverpage.md @@ -0,0 +1,6 @@ +# Portainer Stack Utils Documentation + +> Bash script to deploy/update/remove stacks in a [Portainer](https://portainer.io/) instance. + +[GitLab](https://gitlab.com/psuapp/psu/ ":target=_blank View source on GitLab") +Getting Started diff --git a/public/1-3-stable/_sidebar.md b/public/1-3-stable/_sidebar.md new file mode 100644 index 0000000..fffa15e --- /dev/null +++ b/public/1-3-stable/_sidebar.md @@ -0,0 +1,4 @@ +- [**Getting Started**](../README) +- [**CLI Commands**](docs/README) +- [**Changelog**](CHANGELOG) +- [**License**](LICENSE) diff --git a/public/1-3-stable/assets/docsify.min.js b/public/1-3-stable/assets/docsify.min.js new file mode 100644 index 0000000..8f2ba0d --- /dev/null +++ b/public/1-3-stable/assets/docsify.min.js @@ -0,0 +1 @@ +!function(){function s(n){var r=Object.create(null);return function(e){var t=c(e)?e:JSON.stringify(e);return r[t]||(r[t]=n(e))}}var o=s(function(e){return e.replace(/([A-Z])/g,function(e){return"-"+e.toLowerCase()})}),l=Object.prototype.hasOwnProperty,d=Object.assign||function(e){for(var t=arguments,n=1;n=a.length)i(r);else if("function"==typeof e)if(2===e.length)e(r,function(e){r=e,o(t+1)});else{var n=e(r);r=void 0===n?r:n,o(t+1)}else o(t+1)};o(0)}var f=!0,m=f&&document.body.clientWidth<=600,g=f&&window.history&&window.history.pushState&&window.history.replaceState&&!navigator.userAgent.match(/((iPod|iPhone|iPad).+\bOS\s+[1-4]\D|WebApps\/.+CFNetwork)/),n={};function v(e,t){if(void 0===t&&(t=!1),"string"==typeof e){if(void 0!==window.Vue)return x(e);e=t?x(e):n[e]||(n[e]=x(e))}return e}var b=f&&document,y=f&&b.body,k=f&&b.head;function x(e,t){return t?e.querySelector(t):b.querySelector(e)}function w(e,t){return[].slice.call(t?e.querySelectorAll(t):b.querySelectorAll(e))}function _(e,t){return e=b.createElement(e),t&&(e.innerHTML=t),e}function S(e,t){return e.appendChild(t)}function A(e,t){return e.insertBefore(t,e.children[0])}function C(e,t,n){u(t)?window.addEventListener(e,t):e.addEventListener(t,n)}function E(e,t,n){u(t)?window.removeEventListener(e,t):e.removeEventListener(t,n)}function $(e,t,n){e&&e.classList[n?t:"toggle"](n||t)}var L,T,e=Object.freeze({getNode:v,$:b,body:y,head:k,find:x,findAll:w,create:_,appendTo:S,before:A,on:C,off:E,toggleClass:$,style:function(e){S(k,_("style",e))}});function R(e,t){if(void 0===t&&(t='
    {inner}
'),!e||!e.length)return"";var n="";return e.forEach(function(e){n+='
  • '+e.title+"
  • ",e.children&&(n+=R(e.children,t))}),t.replace("{inner}",n)}function r(e,t){return'

    '+t.slice(5).trim()+"

    "}function P(e){var t,n,r=e.loaded,i=e.total,a=e.step;!L&&((n=_("div")).classList.add("progress"),S(y,n),L=n),t=a?80<(t=parseInt(L.style.width||0,10)+a)?80:t:Math.floor(r/i*100),L.style.opacity=1,L.style.width=95<=t?"100%":t+"%",95<=t&&(clearTimeout(T),T=setTimeout(function(e){L.style.opacity=0,L.style.width="0%"},200))}var O={};function F(a,e,t){void 0===e&&(e=!1),void 0===t&&(t={});var o=new XMLHttpRequest,n=function(){o.addEventListener.apply(o,arguments)},r=O[a];if(r)return{then:function(e){return e(r.content,r.opt)},abort:p};for(var i in o.open("GET",a),t)l.call(t,i)&&o.setRequestHeader(i,t[i]);return o.send(),{then:function(r,i){if(void 0===i&&(i=p),e){var t=setInterval(function(e){return P({step:Math.floor(5*Math.random()+1)})},500);n("progress",P),n("loadend",function(e){P(e),clearInterval(t)})}n("error",i),n("load",function(e){var t=e.target;if(400<=t.status)i(t);else{var n=O[a]={content:t.response,opt:{updatedAt:o.getResponseHeader("last-modified")}};r(n.content,n.opt)}})},abort:function(e){return 4!==o.readyState&&o.abort()}}}function j(e,t){e.innerHTML=e.innerHTML.replace(/var\(\s*--theme-color.*?\)/g,t)}var N=/([^{]*?)\w(?=\})/g,z={YYYY:"getFullYear",YY:"getYear",MM:function(e){return e.getMonth()+1},DD:"getDate",HH:"getHours",mm:"getMinutes",ss:"getSeconds"};var t="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{};function i(e,t){return e(t={exports:{}},t.exports),t.exports}var M=i(function(m,e){!function(e){var y={newline:/^\n+/,code:/^( {4}[^\n]+\n*)+/,fences:d,hr:/^ {0,3}((?:- *){3,}|(?:_ *){3,}|(?:\* *){3,})(?:\n+|$)/,heading:/^ *(#{1,6}) *([^\n]+?) *(?:#+ *)?(?:\n+|$)/,nptable:d,blockquote:/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,list:/^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,html:"^ {0,3}(?:<(script|pre|style)[\\s>][\\s\\S]*?(?:[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?\\?>\\n*|\\n*|\\n*|)[\\s\\S]*?(?:\\n{2,}|$)|<(?!script|pre|style)([a-z][\\w-]*)(?:attribute)*? */?>(?=\\h*\\n)[\\s\\S]*?(?:\\n{2,}|$)|(?=\\h*\\n)[\\s\\S]*?(?:\\n{2,}|$))",def:/^ {0,3}\[(label)\]: *\n? *]+)>?(?:(?: +\n? *| *\n *)(title))? *(?:\n+|$)/,table:d,lheading:/^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,paragraph:/^([^\n]+(?:\n(?!hr|heading|lheading| {0,3}>|<\/?(?:tag)(?: +|\n|\/?>)|<(?:script|pre|style|!--))[^\n]+)*)/,text:/^[^\n]+/};function l(e){this.tokens=[],this.tokens.links=Object.create(null),this.options=e||f.defaults,this.rules=y.normal,this.options.pedantic?this.rules=y.pedantic:this.options.gfm&&(this.options.tables?this.rules=y.tables:this.rules=y.gfm)}y._label=/(?!\s*\])(?:\\[\[\]]|[^\[\]])+/,y._title=/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/,y.def=t(y.def).replace("label",y._label).replace("title",y._title).getRegex(),y.bullet=/(?:[*+-]|\d+\.)/,y.item=/^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/,y.item=t(y.item,"gm").replace(/bull/g,y.bullet).getRegex(),y.list=t(y.list).replace(/bull/g,y.bullet).replace("hr","\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))").replace("def","\\n+(?="+y.def.source+")").getRegex(),y._tag="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul",y._comment=//,y.html=t(y.html,"i").replace("comment",y._comment).replace("tag",y._tag).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),y.paragraph=t(y.paragraph).replace("hr",y.hr).replace("heading",y.heading).replace("lheading",y.lheading).replace("tag",y._tag).getRegex(),y.blockquote=t(y.blockquote).replace("paragraph",y.paragraph).getRegex(),y.normal=g({},y),y.gfm=g({},y.normal,{fences:/^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\n? *\1 *(?:\n+|$)/,paragraph:/^/,heading:/^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/}),y.gfm.paragraph=t(y.paragraph).replace("(?!","(?!"+y.gfm.fences.source.replace("\\1","\\2")+"|"+y.list.source.replace("\\1","\\3")+"|").getRegex(),y.tables=g({},y.gfm,{nptable:/^ *([^|\n ].*\|.*)\n *([-:]+ *\|[-| :]*)(?:\n((?:.*[^>\n ].*(?:\n|$))*)\n*|$)/,table:/^ *\|(.+)\n *\|?( *[-:]+[-| :]*)(?:\n((?: *[^>\n ].*(?:\n|$))*)\n*|$)/}),y.pedantic=g({},y.normal,{html:t("^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+? *(?:\\n{2,}|\\s*$)|\\s]*)*?/?> *(?:\\n{2,}|\\s*$))").replace("comment",y._comment).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/}),l.rules=y,l.lex=function(e,t){return new l(t).lex(e)},l.prototype.lex=function(e){return e=e.replace(/\r\n|\r/g,"\n").replace(/\t/g," ").replace(/\u00a0/g," ").replace(/\u2424/g,"\n"),this.token(e,!0)},l.prototype.token=function(e,t){var n,r,i,a,o,s,l,c,u,p,h,d,g,f,m,v,b=this;for(e=e.replace(/^ +$/gm,"");e;)if((i=b.rules.newline.exec(e))&&(e=e.substring(i[0].length),1 ?/gm,""),b.token(i,t),b.tokens.push({type:"blockquote_end"});else if(i=b.rules.list.exec(e)){for(e=e.substring(i[0].length),l={type:"list_start",ordered:f=1<(a=i[2]).length,start:f?+a:"",loose:!1},b.tokens.push(l),n=!(c=[]),g=(i=i[0].match(b.rules.item)).length,h=0;h?@\[\]\\^_`{|}~])/,autolink:/^<(scheme:[^\s\x00-\x1f<>]*|email)>/,url:d,tag:"^comment|^|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^|^",link:/^!?\[(label)\]\(href(?:\s+(title))?\s*\)/,reflink:/^!?\[(label)\]\[(?!\s*\])((?:\\[\[\]]?|[^\[\]\\])+)\]/,nolink:/^!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?/,strong:/^__([^\s])__(?!_)|^\*\*([^\s])\*\*(?!\*)|^__([^\s][\s\S]*?[^\s])__(?!_)|^\*\*([^\s][\s\S]*?[^\s])\*\*(?!\*)/,em:/^_([^\s_])_(?!_)|^\*([^\s*"<\[])\*(?!\*)|^_([^\s][\s\S]*?[^\s_])_(?!_)|^_([^\s_][\s\S]*?[^\s])_(?!_)|^\*([^\s"<\[][\s\S]*?[^\s*])\*(?!\*)|^\*([^\s*"<\[][\s\S]*?[^\s])\*(?!\*)/,code:/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,br:/^( {2,}|\\)\n(?!\s*$)/,del:d,text:/^(`+|[^`])[\s\S]*?(?=[\\?@\[\]\\^_`{|}~])/g,n._scheme=/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/,n._email=/[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/,n.autolink=t(n.autolink).replace("scheme",n._scheme).replace("email",n._email).getRegex(),n._attribute=/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/,n.tag=t(n.tag).replace("comment",y._comment).replace("attribute",n._attribute).getRegex(),n._label=/(?:\[[^\[\]]*\]|\\[\[\]]?|`[^`]*`|[^\[\]\\])*?/,n._href=/\s*(<(?:\\[<>]?|[^\s<>\\])*>|(?:\\[()]?|\([^\s\x00-\x1f\\]*\)|[^\s\x00-\x1f()\\])*?)/,n._title=/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/,n.link=t(n.link).replace("label",n._label).replace("href",n._href).replace("title",n._title).getRegex(),n.reflink=t(n.reflink).replace("label",n._label).getRegex(),n.normal=g({},n),n.pedantic=g({},n.normal,{strong:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,em:/^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/,link:t(/^!?\[(label)\]\((.*?)\)/).replace("label",n._label).getRegex(),reflink:t(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label",n._label).getRegex()}),n.gfm=g({},n.normal,{escape:t(n.escape).replace("])","~|])").getRegex(),_extended_email:/[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/,url:/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,_backpedal:/(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,del:/^~+(?=\S)([\s\S]*?\S)~+/,text:t(n.text).replace("]|","~]|").replace("|$","|https?://|ftp://|www\\.|[a-zA-Z0-9.!#$%&'*+/=?^_`{\\|}~-]+@|$").getRegex()}),n.gfm.url=t(n.gfm.url).replace("email",n.gfm._extended_email).getRegex(),n.breaks=g({},n.gfm,{br:t(n.br).replace("{2,}","*").getRegex(),text:t(n.gfm.text).replace("{2,}","*").getRegex()}),c.rules=n,c.output=function(e,t,n){return new c(t,n).output(e)},c.prototype.output=function(e){for(var t,n,r,i,a,o,s=this,l="";e;)if(a=s.rules.escape.exec(e))e=e.substring(a[0].length),l+=a[1];else if(a=s.rules.autolink.exec(e))e=e.substring(a[0].length),r="@"===a[2]?"mailto:"+(n=p(s.mangle(a[1]))):n=p(a[1]),l+=s.renderer.link(r,null,n);else if(s.inLink||!(a=s.rules.url.exec(e))){if(a=s.rules.tag.exec(e))!s.inLink&&/^/i.test(a[0])&&(s.inLink=!1),!s.inRawBlock&&/^<(pre|code|kbd|script)(\s|>)/i.test(a[0])?s.inRawBlock=!0:s.inRawBlock&&/^<\/(pre|code|kbd|script)(\s|>)/i.test(a[0])&&(s.inRawBlock=!1),e=e.substring(a[0].length),l+=s.options.sanitize?s.options.sanitizer?s.options.sanitizer(a[0]):p(a[0]):a[0];else if(a=s.rules.link.exec(e))e=e.substring(a[0].length),s.inLink=!0,r=a[2],i=s.options.pedantic?(t=/^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(r))?(r=t[1],t[3]):"":a[3]?a[3].slice(1,-1):"",r=r.trim().replace(/^<([\s\S]*)>$/,"$1"),l+=s.outputLink(a,{href:c.escapes(r),title:c.escapes(i)}),s.inLink=!1;else if((a=s.rules.reflink.exec(e))||(a=s.rules.nolink.exec(e))){if(e=e.substring(a[0].length),t=(a[2]||a[1]).replace(/\s+/g," "),!(t=s.links[t.toLowerCase()])||!t.href){l+=a[0].charAt(0),e=a[0].substring(1)+e;continue}s.inLink=!0,l+=s.outputLink(a,t),s.inLink=!1}else if(a=s.rules.strong.exec(e))e=e.substring(a[0].length),l+=s.renderer.strong(s.output(a[4]||a[3]||a[2]||a[1]));else if(a=s.rules.em.exec(e))e=e.substring(a[0].length),l+=s.renderer.em(s.output(a[6]||a[5]||a[4]||a[3]||a[2]||a[1]));else if(a=s.rules.code.exec(e))e=e.substring(a[0].length),l+=s.renderer.codespan(p(a[2].trim(),!0));else if(a=s.rules.br.exec(e))e=e.substring(a[0].length),l+=s.renderer.br();else if(a=s.rules.del.exec(e))e=e.substring(a[0].length),l+=s.renderer.del(s.output(a[1]));else if(a=s.rules.text.exec(e))e=e.substring(a[0].length),s.inRawBlock?l+=s.renderer.text(a[0]):l+=s.renderer.text(p(s.smartypants(a[0])));else if(e)throw new Error("Infinite loop on byte: "+e.charCodeAt(0))}else{if("@"===a[2])r="mailto:"+(n=p(a[0]));else{for(;o=a[0],a[0]=s.rules._backpedal.exec(a[0])[0],o!==a[0];);n=p(a[0]),r="www."===a[1]?"http://"+n:n}e=e.substring(a[0].length),l+=s.renderer.link(r,null,n)}return l},c.escapes=function(e){return e?e.replace(c.rules._escapes,"$1"):e},c.prototype.outputLink=function(e,t){var n=t.href,r=t.title?p(t.title):null;return"!"!==e[0].charAt(0)?this.renderer.link(n,r,this.output(e[1])):this.renderer.image(n,r,p(e[1]))},c.prototype.smartypants=function(e){return this.options.smartypants?e.replace(/---/g,"—").replace(/--/g,"–").replace(/(^|[-\u2014/(\[{"\s])'/g,"$1‘").replace(/'/g,"’").replace(/(^|[-\u2014/(\[{\u2018\s])"/g,"$1“").replace(/"/g,"”").replace(/\.{3}/g,"…"):e},c.prototype.mangle=function(e){if(!this.options.mangle)return e;for(var t,n="",r=e.length,i=0;i'+(n?e:p(e,!0))+"\n":"
    "+(n?e:p(e,!0))+"
    "},r.prototype.blockquote=function(e){return"
    \n"+e+"
    \n"},r.prototype.html=function(e){return e},r.prototype.heading=function(e,t,n){return this.options.headerIds?"'+e+"\n":""+e+"\n"},r.prototype.hr=function(){return this.options.xhtml?"
    \n":"
    \n"},r.prototype.list=function(e,t,n){var r=t?"ol":"ul";return"<"+r+(t&&1!==n?' start="'+n+'"':"")+">\n"+e+"\n"},r.prototype.listitem=function(e){return"
  • "+e+"
  • \n"},r.prototype.checkbox=function(e){return" "},r.prototype.paragraph=function(e){return"

    "+e+"

    \n"},r.prototype.table=function(e,t){return t&&(t=""+t+""),"\n\n"+e+"\n"+t+"
    \n"},r.prototype.tablerow=function(e){return"\n"+e+"\n"},r.prototype.tablecell=function(e,t){var n=t.header?"th":"td";return(t.align?"<"+n+' align="'+t.align+'">':"<"+n+">")+e+"\n"},r.prototype.strong=function(e){return""+e+""},r.prototype.em=function(e){return""+e+""},r.prototype.codespan=function(e){return""+e+""},r.prototype.br=function(){return this.options.xhtml?"
    ":"
    "},r.prototype.del=function(e){return""+e+""},r.prototype.link=function(e,t,n){if(this.options.sanitize){try{var r=decodeURIComponent(h(e)).replace(/[^\w:]/g,"").toLowerCase()}catch(e){return n}if(0===r.indexOf("javascript:")||0===r.indexOf("vbscript:")||0===r.indexOf("data:"))return n}this.options.baseUrl&&!s.test(e)&&(e=a(this.options.baseUrl,e));try{e=encodeURI(e).replace(/%25/g,"%")}catch(e){return n}var i='
    "},r.prototype.image=function(e,t,n){this.options.baseUrl&&!s.test(e)&&(e=a(this.options.baseUrl,e));var r=''+n+'":">"},r.prototype.text=function(e){return e},i.prototype.strong=i.prototype.em=i.prototype.codespan=i.prototype.del=i.prototype.text=function(e){return e},i.prototype.link=i.prototype.image=function(e,t,n){return""+n},i.prototype.br=function(){return""},u.parse=function(e,t){return new u(t).parse(e)},u.prototype.parse=function(e){this.inline=new c(e.links,this.options),this.inlineText=new c(e.links,g({},this.options,{renderer:new i})),this.tokens=e.reverse();for(var t="";this.next();)t+=this.tok();return t},u.prototype.next=function(){return this.token=this.tokens.pop()},u.prototype.peek=function(){return this.tokens[this.tokens.length-1]||0},u.prototype.parseText=function(){for(var e=this.token.text;"text"===this.peek().type;)e+="\n"+this.next().text;return this.inline.output(e)},u.prototype.tok=function(){var e=this;switch(this.token.type){case"space":return"";case"hr":return this.renderer.hr();case"heading":return this.renderer.heading(this.inline.output(this.token.text),this.token.depth,h(this.inlineText.output(this.token.text)));case"code":return this.renderer.code(this.token.text,this.token.lang,this.token.escaped);case"table":var t,n,r,i,a="",o="";for(r="",t=0;t"']/,p.escapeReplace=/[&<>"']/g,p.replacements={"&":"&","<":"<",">":">",'"':""","'":"'"},p.escapeTestNoEncode=/[<>"']|&(?!#?\w+;)/,p.escapeReplaceNoEncode=/[<>"']|&(?!#?\w+;)/g;var o={},s=/^$|^[a-z][a-z0-9+.-]*:|^[?#]/i;function d(){}function g(e){for(var t,n,r=arguments,i=1;it)n.splice(t);else for(;n.lengthAn error occurred:

    "+p(e.message+"",!0)+"
    ";throw e}}d.exec=d,f.options=f.setOptions=function(e){return g(f.defaults,e),f},f.getDefaults=function(){return{baseUrl:null,breaks:!1,gfm:!0,headerIds:!0,headerPrefix:"",highlight:null,langPrefix:"language-",mangle:!0,pedantic:!1,renderer:new r,sanitize:!1,sanitizer:null,silent:!1,smartLists:!1,smartypants:!1,tables:!0,xhtml:!1}},f.defaults=f.getDefaults(),f.Parser=u,f.parser=u.parse,f.Renderer=r,f.TextRenderer=i,f.Lexer=l,f.lexer=l.lex,f.InlineLexer=c,f.inlineLexer=c.output,f.parse=f,m.exports=f}(t||"undefined"!=typeof window&&window)}),a=i(function(e){var c="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},u=function(){var l=/\blang(?:uage)?-([\w-]+)\b/i,t=0,P=c.Prism={manual:c.Prism&&c.Prism.manual,disableWorkerMessageHandler:c.Prism&&c.Prism.disableWorkerMessageHandler,util:{encode:function(e){return e instanceof o?new o(e.type,P.util.encode(e.content),e.alias):"Array"===P.util.type(e)?e.map(P.util.encode):e.replace(/&/g,"&").replace(/e.length)return;if(!(k instanceof s)){if(g&&b!=t.length-1){if(p.lastIndex=y,!(C=p.exec(e)))break;for(var x=C.index+(d?C[1].length:0),w=C.index+C[0].length,_=b,S=y,A=t.length;_"+r.content+""},!c.document)return c.addEventListener&&(P.disableWorkerMessageHandler||c.addEventListener("message",function(e){var t=JSON.parse(e.data),n=t.language,r=t.code,i=t.immediateClose;c.postMessage(P.highlight(r,P.languages[n],n)),i&&c.close()},!1)),c.Prism;var e=document.currentScript||[].slice.call(document.getElementsByTagName("script")).pop();return e&&(P.filename=e.src,P.manual||e.hasAttribute("data-manual")||("loading"!==document.readyState?window.requestAnimationFrame?window.requestAnimationFrame(P.highlightAll):window.setTimeout(P.highlightAll,16):document.addEventListener("DOMContentLoaded",P.highlightAll))),c.Prism}();e.exports&&(e.exports=u),void 0!==t&&(t.Prism=u),u.languages.markup={comment://,prolog:/<\?[\s\S]+?\?>/,doctype://i,cdata://i,tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|[^\s'">=]+))?)*\s*\/?>/i,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/i,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"attr-value":{pattern:/=(?:("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|[^\s'">=]+)/i,inside:{punctuation:[/^=/,{pattern:/(^|[^\\])["']/,lookbehind:!0}]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:/&#?[\da-z]{1,8};/i},u.languages.markup.tag.inside["attr-value"].inside.entity=u.languages.markup.entity,u.hooks.add("wrap",function(e){"entity"===e.type&&(e.attributes.title=e.content.replace(/&/,"&"))}),u.languages.xml=u.languages.markup,u.languages.html=u.languages.markup,u.languages.mathml=u.languages.markup,u.languages.svg=u.languages.markup,u.languages.css={comment:/\/\*[\s\S]*?\*\//,atrule:{pattern:/@[\w-]+?.*?(?:;|(?=\s*\{))/i,inside:{rule:/@[\w-]+/}},url:/url\((?:(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1|.*?)\)/i,selector:/[^{}\s][^{};]*?(?=\s*\{)/,string:{pattern:/("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},property:/[-_a-z\xA0-\uFFFF][-\w\xA0-\uFFFF]*(?=\s*:)/i,important:/\B!important\b/i,function:/[-a-z0-9]+(?=\()/i,punctuation:/[(){};:]/},u.languages.css.atrule.inside.rest=u.languages.css,u.languages.markup&&(u.languages.insertBefore("markup","tag",{style:{pattern:/()[\s\S]*?(?=<\/style>)/i,lookbehind:!0,inside:u.languages.css,alias:"language-css",greedy:!0}}),u.languages.insertBefore("inside","attr-value",{"style-attr":{pattern:/\s*style=("|')(?:\\[\s\S]|(?!\1)[^\\])*\1/i,inside:{"attr-name":{pattern:/^\s*style/i,inside:u.languages.markup.tag.inside},punctuation:/^\s*=\s*['"]|['"]\s*$/,"attr-value":{pattern:/.+/i,inside:u.languages.css}},alias:"language-css"}},u.languages.markup.tag)),u.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/((?:\b(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,boolean:/\b(?:true|false)\b/,function:/[a-z0-9_]+(?=\()/i,number:/\b0x[\da-f]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:e[+-]?\d+)?/i,operator:/--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&?|\|\|?|\?|\*|\/|~|\^|%/,punctuation:/[{}[\];(),.:]/},u.languages.javascript=u.languages.extend("clike",{keyword:/\b(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|var|void|while|with|yield)\b/,number:/\b(?:0[xX][\dA-Fa-f]+|0[bB][01]+|0[oO][0-7]+|NaN|Infinity)\b|(?:\b\d+\.?\d*|\B\.\d+)(?:[Ee][+-]?\d+)?/,function:/[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*\()/i,operator:/-[-=]?|\+[+=]?|!=?=?|<>?>?=?|=(?:==?|>)?|&[&=]?|\|[|=]?|\*\*?=?|\/=?|~|\^=?|%=?|\?|\.{3}/}),u.languages.insertBefore("javascript","keyword",{regex:{pattern:/((?:^|[^$\w\xA0-\uFFFF."'\])\s])\s*)\/(\[[^\]\r\n]+]|\\.|[^/\\\[\r\n])+\/[gimyu]{0,5}(?=\s*($|[\r\n,.;})\]]))/,lookbehind:!0,greedy:!0},"function-variable":{pattern:/[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*=\s*(?:function\b|(?:\([^()]*\)|[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*)\s*=>))/i,alias:"function"},constant:/\b[A-Z][A-Z\d_]*\b/}),u.languages.insertBefore("javascript","string",{"template-string":{pattern:/`(?:\\[\s\S]|\${[^}]+}|[^\\`])*`/,greedy:!0,inside:{interpolation:{pattern:/\${[^}]+}/,inside:{"interpolation-punctuation":{pattern:/^\${|}$/,alias:"punctuation"},rest:null}},string:/[\s\S]+/}}}),u.languages.javascript["template-string"].inside.interpolation.inside.rest=u.languages.javascript,u.languages.markup&&u.languages.insertBefore("markup","tag",{script:{pattern:/()[\s\S]*?(?=<\/script>)/i,lookbehind:!0,inside:u.languages.javascript,alias:"language-javascript",greedy:!0}}),u.languages.js=u.languages.javascript,"undefined"!=typeof self&&self.Prism&&self.document&&document.querySelector&&(self.Prism.fileHighlight=function(){var l={js:"javascript",py:"python",rb:"ruby",ps1:"powershell",psm1:"powershell",sh:"bash",bat:"batch",h:"c",tex:"latex"};Array.prototype.slice.call(document.querySelectorAll("pre[data-src]")).forEach(function(e){for(var t,n=e.getAttribute("data-src"),r=e,i=/\blang(?:uage)?-([\w-]+)\b/i;r&&!i.test(r.className);)r=r.parentNode;if(r&&(t=(e.className.match(i)||[,""])[1]),!t){var a=(n.match(/\.(\w+)$/)||[,""])[1];t=l[a]||a}var o=document.createElement("code");o.className="language-"+t,e.textContent="",o.textContent="Loading…",e.appendChild(o);var s=new XMLHttpRequest;s.open("GET",n,!0),s.onreadystatechange=function(){4==s.readyState&&(s.status<400&&s.responseText?(o.textContent=s.responseText,u.highlightElement(o)):400<=s.status?o.textContent="✖ Error "+s.status+" while fetching file: "+s.statusText:o.textContent="✖ Error: File does not exist or is empty")},s.send(null)}),u.plugins.toolbar&&u.plugins.toolbar.registerButton("download-file",function(e){var t=e.element.parentNode;if(t&&/pre/i.test(t.nodeName)&&t.hasAttribute("data-src")&&t.hasAttribute("data-download-link")){var n=t.getAttribute("data-src"),r=document.createElement("a");return r.textContent=t.getAttribute("data-download-link-label")||"Download",r.setAttribute("download",""),r.href=n,r}})},document.addEventListener("DOMContentLoaded",self.Prism.fileHighlight))});function q(e,r){var i=[],a={};return e.forEach(function(e){var t=e.level||1,n=t-1;r?@[\]^`{|}~]/g;function B(e){return e.toLowerCase()}function U(e){if("string"!=typeof e)return"";var t=e.trim().replace(/[A-Z]+/g,B).replace(/<[^>\d]+>/g,"").replace(I,"").replace(/\s/g,"-").replace(/-+/g,"-").replace(/^(\d)/,"_$1"),n=H[t];return n=l.call(H,t)?n+1:0,(H[t]=n)&&(t=t+"-"+n),t}function D(e,t){return''+t+''}U.clear=function(){H={}};var Z=decodeURIComponent,Y=encodeURIComponent;function W(e){var n={};return(e=e.trim().replace(/^(\?|#|&)/,""))&&e.split("&").forEach(function(e){var t=e.replace(/\+/g," ").split("=");n[t[0]]=t[1]&&Z(t[1])}),n}function G(e,t){void 0===t&&(t=[]);var n=[];for(var r in e)-1=g.length))for(var t=0;t=g.length)break}}else n.content&&"string"!=typeof n.content&&f(n.content)}};f(p.tokens)}}}});var te={};function ne(e){void 0===e&&(e="");var r={};return e&&(e=e.replace(/^'/,"").replace(/'$/,"").replace(/(?:^|\s):([\w-]+)=?([\w-]+)?/g,function(e,t,n){return r[t]=n&&n.replace(/"/g,"")||!0,""}).trim()),{str:e,config:r}}var re={markdown:function(e){return{url:e}},mermaid:function(e){return{url:e}},iframe:function(e,t){return{html:'"}},video:function(e,t){return{html:'"}},audio:function(e,t){return{html:'"}},code:function(e,t){var n=e.match(/\.(\w+)$/);return"md"===(n=t||n&&n[1])&&(n="markdown"),{url:e,lang:n}}},ie=function(i,e){var a=this;this.config=i,this.router=e,this.cacheTree={},this.toc=[],this.cacheTOC={},this.linkTarget=i.externalLinkTarget||"_blank",this.contentBase=e.getBasePath();var o,t=this._initRenderer(),n=i.markdown||{};o=u(n)?n(M,t):(M.setOptions(d(n,{renderer:d(t,n.renderer)})),M),this._marked=o,this.compile=function(n){var r=!0,e=s(function(e){r=!1;var t="";return n?(t=c(n)?o(n):o.parser(n),t=i.noEmoji?t:t.replace(/<(pre|template|code)[^>]*?>[\s\S]+?<\/(pre|template|code)>/g,function(e){return e.replace(/:/g,"__colon__")}).replace(/:(\w+?):/gi,f&&window.emojify||D).replace(/__colon__/g,":"),U.clear(),t):n})(n),t=a.router.parse().file;return r?a.toc=a.cacheTOC[t]:a.cacheTOC[t]=[].concat(a.toc),e}};ie.prototype.compileEmbed=function(e,t){var n,r=ne(t),i=r.str,a=r.config;if(t=i,a.include){var o;if(X(e)||(e=K(this.contentBase,Q(this.router.getCurrentPath()),e)),a.type&&(o=re[a.type]))(n=o.call(this,e,t)).type=a.type;else{var s="code";/\.(md|markdown)/.test(e)?s="markdown":/\.mmd/.test(e)?s="mermaid":/\.html?/.test(e)?s="iframe":/\.(mp4|ogg)/.test(e)?s="video":/\.mp3/.test(e)&&(s="audio"),(n=re[s].call(this,e,t)).type=s}return n.fragment=a.fragment,n}},ie.prototype._matchNotCompileLink=function(e){for(var t=this.config.noCompileLinks||[],n=0;n
    '+r+""},t.code=e.code=function(e,t){return void 0===t&&(t=""),e=e.replace(/@DOCSIFY_QM@/g,"`"),'
    '+a.highlight(e,a.languages[t]||a.languages.markup)+"
    "},t.link=e.link=function(e,t,n){void 0===t&&(t="");var r="",i=ne(t),a=i.str,o=i.config;return t=a,X(e)||l._matchNotCompileLink(e)||o.ignore?r+=0===e.indexOf("mailto:")?"":' target="'+s+'"':(e===l.config.homepage&&(e="README"),e=u.toURL(e,null,u.getCurrentPath())),o.target&&(r+=" target="+o.target),o.disabled&&(r+=" disabled",e="javascript:void(0)"),t&&(r+=' title="'+t+'"'),'"+n+""},t.paragraph=e.paragraph=function(e){return/^!>/.test(e)?r("tip",e):/^\?>/.test(e)?r("warn",e):"

    "+e+"

    "},t.image=e.image=function(e,t,n){var r=e,i="",a=ne(t),o=a.str,s=a.config;t=o,s["no-zoom"]&&(i+=" data-no-zoom"),t&&(i+=' title="'+t+'"');var l=s.size;if(l){var c=l.split("x");c[1]?i+="width="+c[0]+" height="+c[1]:i+="width="+c[0]}return X(e)||(r=K(p,Q(u.getCurrentPath()),e)),''+n+'"},t.list=e.list=function(e,t,n){var r=t?"ol":"ul";return"<"+r+" "+[/
  • /.test(e.split('class="task-list"')[0])?'class="task-list"':"",n&&1"+e+""},t.listitem=e.listitem=function(e){return/^(]*>)/.test(e)?'
  • ":"
  • "+e+"
  • "},e.origin=t,e},ie.prototype.sidebar=function(e,t){var n=this.toc,r=this.router.getCurrentPath(),i="";if(e)i=this.compile(e);else{for(var a=0;a{inner}"),this.cacheTree[r]=l}return i},ie.prototype.subSidebar=function(e){if(e){var t=this.router.getCurrentPath(),n=this.cacheTree,r=this.toc;r[0]&&r[0].ignoreAllSubs&&r.splice(0),r[0]&&1===r[0].level&&r.shift();for(var i=0;i=t||e.classList.contains("hidden")?$(y,"add","sticky"):$(y,"remove","sticky")}}function se(e,t,r,n){var i=[];null!=(t=v(t))&&(i=w(t,"a"));var a,o=decodeURI(e.toURL(e.getCurrentPath()));return i.sort(function(e,t){return t.href.length-e.href.length}).forEach(function(e){var t=e.getAttribute("href"),n=r?e.parentNode:e;0!==o.indexOf(t)||a?$(n,"remove","active"):(a=e,$(n,"add","active"))}),n&&(b.title=a?a.title||a.innerText+" - "+ae:ae),a}var le=function(){function r(e,t){for(var n=0;nthis.end&&e>=this.next}[this.direction]}},{key:"_defaultEase",value:function(e,t,n,r){return(e/=r/2)<1?n/2*e*e+t:-n/2*(--e*(e-2)-1)+t}}]),t}(),ue={},pe=!1,he=null,de=!0,ge=0;function fe(e){if(de){for(var t,n=v(".sidebar"),r=w(".anchor"),i=x(n,".sidebar-nav"),a=x(n,"li.active"),o=document.documentElement,s=(o&&o.scrollTop||document.body.scrollTop)-ge,l=0,c=r.length;ls){t||(t=u);break}t=u}if(t){var p=ue[me(decodeURIComponent(e),t.getAttribute("data-id"))];if(p&&p!==a&&(a&&a.classList.remove("active"),p.classList.add("active"),a=p,!pe&&y.classList.contains("sticky"))){var h=n.clientHeight,d=a.offsetTop+a.clientHeight+40,g=d-0=i.scrollTop&&d<=i.scrollTop+h?i.scrollTop:g?0:d-h;n.scrollTop=f}}}}function me(e,t){return e+"?id="+t}function ve(e,t){if(t){var n,r=x("#"+t);r&&(n=r,he&&he.stop(),de=!1,he=new ce({start:window.pageYOffset,end:n.getBoundingClientRect().top+window.pageYOffset,duration:500}).on("tick",function(e){return window.scrollTo(0,e)}).on("done",function(){de=!0,he=null}).begin());var i=ue[me(e,t)],a=x(v(".sidebar"),"li.active");a&&a.classList.remove("active"),i&&i.classList.add("active")}}var be=b.scrollingElement||b.documentElement;var ye={};function ke(e,i){var o=e.compiler,a=e.raw;void 0===a&&(a="");var t=e.fetch,n=ye[a];if(n){var r=n.slice();return r.links=n.links,i(r)}var s=o._marked,l=s.lexer(a),c=[],u=s.InlineLexer.rules.link,p=l.links;l.forEach(function(e,a){"paragraph"===e.type&&(e.text=e.text.replace(new RegExp(u.source,"g"),function(e,t,n,r){var i=o.compileEmbed(n,r);return i&&c.push({index:a,embed:i}),e}))});var h=0;!function(e,a){var t,n=e.embedTokens,o=e.compile,s=(e.fetch,0),l=1;if(!n.length)return a({});for(;t=n[s++];){var r=function(i){return function(e){var t;if(e)if("markdown"===i.embed.type)t=o.lexer(e);else if("code"===i.embed.type){if(i.embed.fragment){var n=i.embed.fragment,r=new RegExp("(?:###|\\/\\/\\/)\\s*\\["+n+"\\]([\\s\\S]*)(?:###|\\/\\/\\/)\\s*\\["+n+"\\]");e=((e.match(r)||[])[1]||"").trim()}t=o.lexer("```"+i.embed.lang+"\n"+e.replace(/`/g,"@DOCSIFY_QM@")+"\n```\n")}else"mermaid"===i.embed.type?(t=[{type:"html",text:'
    \n'+e+"\n
    "}]).links={}:(t=[{type:"html",text:e}]).links={};a({token:i,embedToken:t}),++l>=s&&a({})}}(t);t.embed.url?F(t.embed.url).then(r):r(t.embed.html)}}({compile:s,embedTokens:c,fetch:t},function(e){var t=e.embedToken,n=e.token;if(n){var r=n.index+h;d(p,t.links),l=l.slice(0,r).concat(t,l.slice(r+1)),h+=t.length-1}else ye[a]=l.concat(),l.links=ye[a].links=p,i(l)})}function xe(){var e=w(".markdown-section>script").filter(function(e){return!/template/.test(e.type)})[0];if(!e)return!1;var t=e.innerText.trim();if(!t)return!1;setTimeout(function(e){window.__EXECUTE_RESULT__=new Function(t)()},0)}function we(e,t,n){var r,i,a;return t="function"==typeof n?n(t):"string"==typeof n?(i=[],a=0,(r=n).replace(N,function(t,e,n){i.push(r.substring(a,n-1)),a=n+=t.length+1,i.push(function(e){return("00"+("string"==typeof z[t]?e[z[t]]():z[t](e))).slice(-t.length)})}),a!==r.length&&i.push(r.substring(a)),function(e){for(var t="",n=0,r=e||new Date;n'):""),t.coverpage&&(u+=(i=", 100%, 85%",'
    \x3c!--cover--\x3e
    ')),t.logo){var h=/^data:image/.test(t.logo),d=/(?:http[s]?:)?\/\//.test(t.logo),g=/^\./.test(t.logo);h||d||g||(t.logo=K(e.router.getBasePath(),t.logo))}u+=(r='',(m?r+"
    ":"
    "+r)+'
    \x3c!--main--\x3e
    '),e._renderTo(c,u,!0)}else e.rendered=!0;t.mergeNavbar&&m?p=x(".sidebar"):(l.classList.add("app-nav"),t.repo||l.classList.add("no-badge")),t.loadNavbar&&A(p,l),t.themeColor&&(b.head.appendChild(_("div",(o=t.themeColor,"")).firstElementChild),function(n){if(!(window.CSS&&window.CSS.supports&&window.CSS.supports("(--v:red)"))){var e=w("style:not(.inserted),link");[].forEach.call(e,function(e){if("STYLE"===e.nodeName)j(e,n);else if("LINK"===e.nodeName){var t=e.getAttribute("href");if(!/\.css$/.test(t))return;F(t).then(function(e){var t=_("style",e);k.appendChild(t),j(t,n)})}})}}(t.themeColor)),e._updateRender(),$(y,"ready")}var Ae={};var Ce=function(e){this.config=e};function Ee(e){var t=location.href.indexOf("#");location.replace(location.href.slice(0,0<=t?t:0)+"#"+e)}Ce.prototype.getBasePath=function(){return this.config.basePath},Ce.prototype.getFile=function(e,t){void 0===e&&(e=this.getCurrentPath());var n,r,i=this.config,a=this.getBasePath(),o="string"==typeof i.ext?i.ext:".md";return e=i.alias?function e(t,n,r){var i=Object.keys(n).filter(function(e){return(Ae[e]||(Ae[e]=new RegExp("^"+e+"$"))).test(t)&&t!==r})[0];return i?e(t.replace(Ae[i],n[i]),n,t):t}(e,i.alias):e,n=e,r=o,e=(e=new RegExp("\\.("+r.replace(/^\./,"")+"|html)$","g").test(n)?n:/\/$/g.test(n)?n+"README"+r:""+n+r)==="/README"+o&&i.homepage||e,e=X(e)?e:K(a,e),t&&(e=e.replace(new RegExp("^"+a),"")),e},Ce.prototype.onchange=function(e){void 0===e&&(e=p),e()},Ce.prototype.getCurrentPath=function(){},Ce.prototype.normalize=function(){},Ce.prototype.parse=function(){},Ce.prototype.toURL=function(e,t,n){var r=n&&"#"===e[0],i=this.parse(ee(e));if(i.query=d({},i.query,t),e=(e=i.path+G(i.query)).replace(/\.md(\?)|\.md$/,"$1"),r){var a=n.indexOf("?");e=(0([^<]*?)

    $');if(i){if("color"===i[2])n.style.background=i[1]+(i[3]||"");else{var a=i[1];$(n,"add","has-mask"),X(i[1])||(a=K(this.router.getBasePath(),i[1])),n.style.backgroundImage="url("+a+")",n.style.backgroundSize="cover",n.style.backgroundPosition="center center"}r=r.replace(i[0],"")}this._renderTo(".cover-main",r),oe()}else $(n,"remove","show")},Ne._updateRender=function(){!function(e){var t=v(".app-name-link"),n=e.config.nameLink,r=e.route.path;if(t)if(c(e.config.nameLink))t.setAttribute("href",n);else if("object"==typeof n){var i=Object.keys(n).filter(function(e){return-1":">",'"':""","'":"'","/":"/"};return String(e).replace(/[&<>"'/]/g,function(e){return n[e]})}function o(o,r){var e,n,t="auto"===o.paths,s=(e=o.namespace)?u.EXPIRE_KEY+"/"+e:u.EXPIRE_KEY,c=(n=o.namespace)?u.INDEX_KEY+"/"+n:u.INDEX_KEY,a=localStorage.getItem(s)l.length&&(o=l.length);var r="..."+h(l).substring(i,o).replace(t,''+e+"")+"...";c+=r}}),0\n

    '+e.title+"

    \n

    "+e.content+"

    \n\n"}),t.classList.add("show"),a.classList.add("show"),t.innerHTML=s||'

    '+d+"

    ",c.hideOtherSidebarContent&&(i.classList.add("hide"),o.classList.add("hide"))}function l(e){c=e}function r(e,n){var t,a,i,o,r=n.router.parse().query.s;l(e),Docsify.dom.style("\n.sidebar {\n padding-top: 0;\n}\n\n.search {\n margin-bottom: 20px;\n padding: 6px;\n border-bottom: 1px solid #eee;\n}\n\n.search .input-wrap {\n display: flex;\n align-items: center;\n}\n\n.search .results-panel {\n display: none;\n}\n\n.search .results-panel.show {\n display: block;\n}\n\n.search input {\n outline: none;\n border: none;\n width: 100%;\n padding: 0 7px;\n line-height: 36px;\n font-size: 14px;\n}\n\n.search input::-webkit-search-decoration,\n.search input::-webkit-search-cancel-button,\n.search input {\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n}\n.search .clear-button {\n width: 36px;\n text-align: right;\n display: none;\n}\n\n.search .clear-button.show {\n display: block;\n}\n\n.search .clear-button svg {\n transform: scale(.5);\n}\n\n.search h2 {\n font-size: 17px;\n margin: 10px 0;\n}\n\n.search a {\n text-decoration: none;\n color: inherit;\n}\n\n.search .matching-post {\n border-bottom: 1px solid #eee;\n}\n\n.search .matching-post:last-child {\n border-bottom: 0;\n}\n\n.search p {\n font-size: 14px;\n overflow: hidden;\n text-overflow: ellipsis;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n}\n\n.search p.empty {\n text-align: center;\n}\n\n.app-name.hide, .sidebar-nav.hide {\n display: none;\n}"),function(e){void 0===e&&(e="");var n='
    \n \n
    \n \n \n \n \n \n
    \n
    \n
    \n ',t=Docsify.dom.create("div",n),a=Docsify.dom.find("aside");Docsify.dom.toggleClass(t,"search"),Docsify.dom.before(a,t)}(r),a=Docsify.dom.find("div.search"),i=Docsify.dom.find(a,"input"),o=Docsify.dom.find(a,".input-wrap"),Docsify.dom.on(a,"click",function(e){return"A"!==e.target.tagName&&e.stopPropagation()}),Docsify.dom.on(i,"input",function(n){clearTimeout(t),t=setTimeout(function(e){return s(n.target.value.trim())},100)}),Docsify.dom.on(o,"click",function(e){"INPUT"!==e.target.tagName&&(i.value="",s())}),r&&setTimeout(function(e){return s(r)},500)}function p(e,n){l(e),function(e,n){var t=Docsify.dom.getNode('.search input[type="search"]');if(t)if("string"==typeof e)t.placeholder=e;else{var a=Object.keys(e).filter(function(e){return-1nav,body:not(.ready) [data-cloak]{display:none}div#app{font-size:30px;font-weight:lighter;margin:40vh auto;text-align:center}div#app:empty:before{content:"Loading..."}.emoji{height:1.2rem;vertical-align:middle}.progress{background-color:var(--theme-color,#42b983);height:2px;left:0;position:fixed;right:0;top:0;transition:width .2s,opacity .4s;width:0;z-index:5}.search .search-keyword,.search a:hover{color:var(--theme-color,#42b983)}.search .search-keyword{font-style:normal;font-weight:700}body,html{height:100%}body{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;color:#34495e;font-family:Source Sans Pro,Helvetica Neue,Arial,sans-serif;font-size:15px;letter-spacing:0;margin:0;overflow-x:hidden}img{max-width:100%}a[disabled]{cursor:not-allowed;opacity:.6}kbd{border:1px solid #ccc;border-radius:3px;display:inline-block;font-size:12px!important;line-height:12px;margin-bottom:3px;padding:3px 5px;vertical-align:middle}li input[type=checkbox]{margin:0 .2em .25em 0;vertical-align:middle}.app-nav{margin:25px 60px 0 0;position:absolute;right:0;text-align:right;z-index:2}.app-nav.no-badge{margin-right:25px}.app-nav p{margin:0}.app-nav>a{margin:0 1rem;padding:5px 0}.app-nav li,.app-nav ul{display:inline-block;list-style:none;margin:0}.app-nav a{color:inherit;font-size:16px;text-decoration:none;transition:color .3s}.app-nav a.active,.app-nav a:hover{color:var(--theme-color,#42b983)}.app-nav a.active{border-bottom:2px solid var(--theme-color,#42b983)}.app-nav li{display:inline-block;margin:0 1rem;padding:5px 0;position:relative}.app-nav li ul{background-color:#fff;border:1px solid #ddd;border-bottom-color:#ccc;border-radius:4px;box-sizing:border-box;display:none;max-height:calc(100vh - 61px);overflow-y:auto;padding:10px 0;position:absolute;right:-15px;text-align:left;top:100%;white-space:nowrap}.app-nav li ul li{display:block;font-size:14px;line-height:1rem;margin:0;margin:8px 14px;white-space:nowrap}.app-nav li ul a{display:block;font-size:inherit;margin:0;padding:0}.app-nav li ul a.active{border-bottom:0}.app-nav li:hover ul{display:block}.github-corner{border-bottom:0;position:fixed;right:0;text-decoration:none;top:0;z-index:1}.github-corner:hover .octo-arm{animation:a .56s ease-in-out}.github-corner svg{color:#fff;fill:var(--theme-color,#42b983);height:80px;width:80px}main{display:block;position:relative;width:100vw;height:100%;z-index:0}main.hidden{display:none}.anchor{display:inline-block;text-decoration:none;transition:all .3s}.anchor span{color:#34495e}.anchor:hover{text-decoration:underline}.sidebar{border-right:1px solid rgba(0,0,0,.07);overflow-y:auto;padding:40px 0 0;position:absolute;top:0;bottom:0;left:0;transition:transform .25s ease-out;width:300px;z-index:3}.sidebar>h1{margin:0 auto 1rem;font-size:1.5rem;font-weight:300;text-align:center}.sidebar>h1 a{color:inherit;text-decoration:none}.sidebar>h1 .app-nav{display:block;position:static}.sidebar .sidebar-nav{line-height:2em;padding-bottom:40px}.sidebar li.collapse .app-sub-sidebar{display:none}.sidebar ul{margin:0 0 0 15px;padding:0}.sidebar li>p{font-weight:700;margin:0}.sidebar ul,.sidebar ul li{list-style:none}.sidebar ul li a{border-bottom:none;display:block}.sidebar ul li ul{padding-left:20px}.sidebar::-webkit-scrollbar{width:4px}.sidebar::-webkit-scrollbar-thumb{background:transparent;border-radius:4px}.sidebar:hover::-webkit-scrollbar-thumb{background:hsla(0,0%,53%,.4)}.sidebar:hover::-webkit-scrollbar-track{background:hsla(0,0%,53%,.1)}.sidebar-toggle{background-color:transparent;background-color:hsla(0,0%,100%,.8);border:0;outline:none;padding:10px;position:absolute;bottom:0;left:0;text-align:center;transition:opacity .3s;width:284px;z-index:4}.sidebar-toggle .sidebar-toggle-button:hover{opacity:.4}.sidebar-toggle span{background-color:var(--theme-color,#42b983);display:block;margin-bottom:4px;width:16px;height:2px}body.sticky .sidebar,body.sticky .sidebar-toggle{position:fixed}.content{padding-top:60px;position:absolute;top:0;right:0;bottom:0;left:300px;transition:left .25s ease}.markdown-section{margin:0 auto;max-width:800px;padding:30px 15px 40px;position:relative}.markdown-section>*{box-sizing:border-box;font-size:inherit}.markdown-section>:first-child{margin-top:0!important}.markdown-section hr{border:none;border-bottom:1px solid #eee;margin:2em 0}.markdown-section iframe{border:1px solid #eee;width:1px;min-width:100%}.markdown-section table{border-collapse:collapse;border-spacing:0;display:block;margin-bottom:1rem;overflow:auto;width:100%}.markdown-section th{font-weight:700}.markdown-section td,.markdown-section th{border:1px solid #ddd;padding:6px 13px}.markdown-section tr{border-top:1px solid #ccc}.markdown-section p.tip,.markdown-section tr:nth-child(2n){background-color:#f8f8f8}.markdown-section p.tip{border-bottom-right-radius:2px;border-left:4px solid #f66;border-top-right-radius:2px;margin:2em 0;padding:12px 24px 12px 30px;position:relative}.markdown-section p.tip:before{background-color:#f66;border-radius:100%;color:#fff;content:"!";font-family:Dosis,Source Sans Pro,Helvetica Neue,Arial,sans-serif;font-size:14px;font-weight:700;left:-12px;line-height:20px;position:absolute;height:20px;width:20px;text-align:center;top:14px}.markdown-section p.tip code{background-color:#efefef}.markdown-section p.tip em{color:#34495e}.markdown-section p.warn{background:rgba(66,185,131,.1);border-radius:2px;padding:1rem}.markdown-section ul.task-list>li{list-style-type:none}body.close .sidebar{transform:translateX(-300px)}body.close .sidebar-toggle{width:auto}body.close .content{left:0}@media print{.app-nav,.github-corner,.sidebar,.sidebar-toggle{display:none}}@media screen and (max-width:768px){.github-corner,.sidebar,.sidebar-toggle{position:fixed}.app-nav{margin-top:16px}.app-nav li ul{top:30px}main{height:auto;overflow-x:hidden}.sidebar{left:-300px;transition:transform .25s ease-out}.content{left:0;max-width:100vw;position:static;padding-top:20px;transition:transform .25s ease}.app-nav,.github-corner{transition:transform .25s ease-out}.sidebar-toggle{background-color:transparent;width:auto;padding:30px 30px 10px 10px}body.close .sidebar{transform:translateX(300px)}body.close .sidebar-toggle{background-color:hsla(0,0%,100%,.8);transition:background-color 1s;width:284px;padding:10px}body.close .content{transform:translateX(300px)}body.close .app-nav,body.close .github-corner{display:none}.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:a .56s ease-in-out}}@keyframes a{0%,to{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}section.cover{-ms-flex-align:center;align-items:center;background-position:50%;background-repeat:no-repeat;background-size:cover;height:100vh;display:none}section.cover.show{display:-ms-flexbox;display:flex}section.cover.has-mask .mask{background-color:#fff;opacity:.8;position:absolute;top:0;height:100%;width:100%}section.cover .cover-main{-ms-flex:1;flex:1;margin:-20px 16px 0;text-align:center;z-index:1}section.cover a{color:inherit}section.cover a,section.cover a:hover{text-decoration:none}section.cover p{line-height:1.5rem;margin:1em 0}section.cover h1{color:inherit;font-size:2.5rem;font-weight:300;margin:.625rem 0 2.5rem;position:relative;text-align:center}section.cover h1 a{display:block}section.cover h1 small{bottom:-.4375rem;font-size:1rem;position:absolute}section.cover blockquote{font-size:1.5rem;text-align:center}section.cover ul{line-height:1.8;list-style-type:none;margin:1em auto;max-width:500px;padding:0}section.cover .cover-main>p:last-child a{border:1px solid var(--theme-color,#42b983);border-radius:2rem;box-sizing:border-box;color:var(--theme-color,#42b983);display:inline-block;font-size:1.05rem;letter-spacing:.1rem;margin:.5rem 1rem;padding:.75em 2rem;text-decoration:none;transition:all .15s ease}section.cover .cover-main>p:last-child a:last-child{background-color:var(--theme-color,#42b983);color:#fff}section.cover .cover-main>p:last-child a:last-child:hover{color:inherit;opacity:.8}section.cover .cover-main>p:last-child a:hover{color:inherit}section.cover blockquote>p>a{border-bottom:2px solid var(--theme-color,#42b983);transition:color .3s}section.cover blockquote>p>a:hover{color:var(--theme-color,#42b983)}.sidebar,body{background-color:#fff}.sidebar{color:#364149}.sidebar li{margin:6px 0}.sidebar ul li a{color:#505d6b;font-size:14px;font-weight:400;overflow:hidden;text-decoration:none;text-overflow:ellipsis;white-space:nowrap}.sidebar ul li a:hover{text-decoration:underline}.sidebar ul li ul{padding:0}.sidebar ul li.active>a{border-right:2px solid;color:var(--theme-color,#42b983);font-weight:600}.app-sub-sidebar li:before{content:"-";padding-right:4px;float:left}.markdown-section h1,.markdown-section h2,.markdown-section h3,.markdown-section h4,.markdown-section strong{color:#2c3e50;font-weight:600}.markdown-section a{color:var(--theme-color,#42b983);font-weight:600}.markdown-section h1{font-size:2rem;margin:0 0 1rem}.markdown-section h2{font-size:1.75rem;margin:45px 0 .8rem}.markdown-section h3{font-size:1.5rem;margin:40px 0 .6rem}.markdown-section h4{font-size:1.25rem}.markdown-section h5{font-size:1rem}.markdown-section h6{color:#777;font-size:1rem}.markdown-section figure,.markdown-section p{margin:1.2em 0}.markdown-section ol,.markdown-section p,.markdown-section ul{line-height:1.6rem;word-spacing:.05rem}.markdown-section ol,.markdown-section ul{padding-left:1.5rem}.markdown-section blockquote{border-left:4px solid var(--theme-color,#42b983);color:#858585;margin:2em 0;padding-left:20px}.markdown-section blockquote p{font-weight:600;margin-left:0}.markdown-section iframe{margin:1em 0}.markdown-section em{color:#7f8c8d}.markdown-section code{border-radius:2px;color:#e96900;font-size:.8rem;margin:0 2px;padding:3px 5px;white-space:pre-wrap}.markdown-section code,.markdown-section pre{background-color:#f8f8f8;font-family:Roboto Mono,Monaco,courier,monospace}.markdown-section pre{-moz-osx-font-smoothing:initial;-webkit-font-smoothing:initial;line-height:1.5rem;margin:1.2em 0;overflow:auto;padding:0 1.4rem;position:relative;word-wrap:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#8e908c}.token.namespace{opacity:.7}.token.boolean,.token.number{color:#c76b29}.token.punctuation{color:#525252}.token.property{color:#c08b30}.token.tag{color:#2973b7}.token.string{color:var(--theme-color,#42b983)}.token.selector{color:#6679cc}.token.attr-name{color:#2973b7}.language-css .token.string,.style .token.string,.token.entity,.token.url{color:#22a2c9}.token.attr-value,.token.control,.token.directive,.token.unit{color:var(--theme-color,#42b983)}.token.function,.token.keyword{color:#e96900}.token.atrule,.token.regex,.token.statement{color:#22a2c9}.token.placeholder,.token.variable{color:#3d8fd1}.token.deleted{text-decoration:line-through}.token.inserted{border-bottom:1px dotted #202746;text-decoration:none}.token.italic{font-style:italic}.token.bold,.token.important{font-weight:700}.token.important{color:#c94922}.token.entity{cursor:help}.markdown-section pre>code{-moz-osx-font-smoothing:initial;-webkit-font-smoothing:initial;background-color:#f8f8f8;border-radius:2px;color:#525252;display:block;font-family:Roboto Mono,Monaco,courier,monospace;font-size:.8rem;line-height:inherit;margin:0 2px;max-width:inherit;overflow:inherit;padding:2.2em 5px;white-space:inherit}.markdown-section code:after,.markdown-section code:before{letter-spacing:.05rem}code .token{-moz-osx-font-smoothing:initial;-webkit-font-smoothing:initial;min-height:1.5rem}pre:after{color:#ccc;content:attr(data-lang);font-size:.6rem;font-weight:600;height:15px;line-height:15px;padding:5px 10px 0;position:absolute;right:0;text-align:right;top:0} \ No newline at end of file diff --git a/public/1-3-stable/assets/prism-bash.min.js b/public/1-3-stable/assets/prism-bash.min.js new file mode 100644 index 0000000..bb68196 --- /dev/null +++ b/public/1-3-stable/assets/prism-bash.min.js @@ -0,0 +1 @@ +!function(e){var a={variable:[{pattern:/\$?\(\([\s\S]+?\)\)/,inside:{variable:[{pattern:/(^\$\(\([\s\S]+)\)\)/,lookbehind:!0},/^\$\(\(/],number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:[Ee]-?\d+)?/,operator:/--?|-=|\+\+?|\+=|!=?|~|\*\*?|\*=|\/=?|%=?|<<=?|>>=?|<=?|>=?|==?|&&?|&=|\^=?|\|\|?|\|=|\?|:/,punctuation:/\(\(?|\)\)?|,|;/}},{pattern:/\$\([^)]+\)|`[^`]+`/,greedy:!0,inside:{variable:/^\$\(|^`|\)$|`$/}},/\$(?:[\w#?*!@]+|\{[^}]+\})/i]};e.languages.bash={shebang:{pattern:/^#!\s*\/bin\/bash|^#!\s*\/bin\/sh/,alias:"important"},comment:{pattern:/(^|[^"{\\])#.*/,lookbehind:!0},string:[{pattern:/((?:^|[^<])<<\s*)["']?(\w+?)["']?\s*\r?\n(?:[\s\S])*?\r?\n\2/,lookbehind:!0,greedy:!0,inside:a},{pattern:/(["'])(?:\\[\s\S]|\$\([^)]+\)|`[^`]+`|(?!\1)[^\\])*\1/,greedy:!0,inside:a}],variable:a.variable,function:{pattern:/(^|[\s;|&])(?:add|alias|apropos|apt|apt-cache|apt-get|aptitude|aspell|automysqlbackup|awk|basename|bash|bc|bconsole|bg|builtin|bzip2|cal|cat|cd|cfdisk|chgrp|chkconfig|chmod|chown|chroot|cksum|clear|cmp|comm|command|cp|cron|crontab|csplit|curl|cut|date|dc|dd|ddrescue|debootstrap|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|du|egrep|eject|enable|env|ethtool|eval|exec|expand|expect|export|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|getopts|git|gparted|grep|groupadd|groupdel|groupmod|groups|grub-mkconfig|gzip|halt|hash|head|help|hg|history|host|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|ip|jobs|join|kill|killall|less|link|ln|locate|logname|logout|logrotate|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|lynx|make|man|mc|mdadm|mkconfig|mkdir|mke2fs|mkfifo|mkfs|mkisofs|mknod|mkswap|mmv|more|most|mount|mtools|mtr|mutt|mv|nano|nc|netstat|nice|nl|nohup|notify-send|npm|nslookup|op|open|parted|passwd|paste|pathchk|ping|pkill|pnpm|popd|pr|printcap|printenv|printf|ps|pushd|pv|pwd|quota|quotacheck|quotactl|ram|rar|rcp|read|readarray|readonly|reboot|remsync|rename|renice|rev|rm|rmdir|rpm|rsync|scp|screen|sdiff|sed|sendmail|seq|service|sftp|shift|shopt|shutdown|sleep|slocate|sort|source|split|ssh|stat|strace|su|sudo|sum|suspend|swapon|sync|tail|tar|tee|test|time|timeout|times|top|touch|tr|traceroute|trap|tsort|tty|type|ulimit|umask|umount|unalias|uname|unexpand|uniq|units|unrar|unshar|unzip|update-grub|uptime|useradd|userdel|usermod|users|uudecode|uuencode|vdir|vi|vim|virsh|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yarn|yes|zip|zypper)(?=$|[\s;|&])/,lookbehind:!0},keyword:{pattern:/(^|[\s;|&])(?:let|:|\.|if|then|else|elif|fi|for|break|continue|while|in|case|function|select|do|done|until|echo|exit|return|set|declare)(?=$|[\s;|&])/,lookbehind:!0},boolean:{pattern:/(^|[\s;|&])(?:true|false)(?=$|[\s;|&])/,lookbehind:!0},operator:/&&?|\|\|?|==?|!=?|<<>|<=?|>=?|=~/,punctuation:/\$?\(\(?|\)\)?|\.\.|[{}[\];]/};var t=a.variable[1].inside;t.string=e.languages.bash.string,t.function=e.languages.bash.function,t.keyword=e.languages.bash.keyword,t.boolean=e.languages.bash.boolean,t.operator=e.languages.bash.operator,t.punctuation=e.languages.bash.punctuation,e.languages.shell=e.languages.bash}(Prism); \ No newline at end of file diff --git a/public/1-3-stable/assets/prism-json.min.js b/public/1-3-stable/assets/prism-json.min.js new file mode 100644 index 0000000..6ea539d --- /dev/null +++ b/public/1-3-stable/assets/prism-json.min.js @@ -0,0 +1 @@ +Prism.languages.json={comment:/\/\/.*|\/\*[\s\S]*?(?:\*\/|$)/,property:{pattern:/"(?:\\.|[^\\"\r\n])*"(?=\s*:)/,greedy:!0},string:{pattern:/"(?:\\.|[^\\"\r\n])*"(?!\s*:)/,greedy:!0},number:/-?\d+\.?\d*(e[+-]?\d+)?/i,punctuation:/[{}[\],]/,operator:/:/,boolean:/\b(?:true|false)\b/,null:{pattern:/\bnull\b/,alias:"keyword"}}; \ No newline at end of file diff --git a/public/1-3-stable/index.html b/public/1-3-stable/index.html new file mode 100644 index 0000000..74c2f54 --- /dev/null +++ b/public/1-3-stable/index.html @@ -0,0 +1,91 @@ + + + + + Portainer Stack Utils Documentation + + + + + + + + +
    + + + + + + + + + + + + + + + + + + diff --git a/public/1-3-stable/repo/CHANGELOG.md b/public/1-3-stable/repo/CHANGELOG.md new file mode 100644 index 0000000..a304b2e --- /dev/null +++ b/public/1-3-stable/repo/CHANGELOG.md @@ -0,0 +1,212 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [1.3.0] - 2021-12-07 +### Added +- Add `linux/arm/v7` architecture to support Raspberry Pi + +### Changed +- Use Docker [Compose 2.2.2](https://github.com/docker/compose/releases/tag/v2.2.2) instead of Docker [Compose 2.1.1](https://github.com/docker/compose/releases/tag/v2.1.1) + +### Fixed +- `psu` was unusable when using a custom CA, with the `HTTPIE_VERIFY_SSL` env + +## [1.3.0-beta.1] - 2021-11-30 +### Added +- Docker images are now multi-architecture (`linux/amd64` and `linux/arm64` 🦾) +- [macOS](https://apple.com/macos) support +- [Windows](https://microsoft.com/windows) support, but it could be unstable ⚠️ +- Test PSU with Portainer CE [2.9.3](https://app.swaggerhub.com/apis/portainer/portainer-ce/2.9.3) API + +### Changed +- Upgrade Operating System of Docker based images, with [Alpine 3.15](https://hub.docker.com/_/alpine) +- Use Docker [Compose 2.1.1](https://github.com/docker/compose/releases/tag/v2.1.1) instead of Docker [Compose 1.x](https://github.com/docker/compose/releases/tag/1.28.0) +- Reduce Docker images size, based on Alpine and Debian, again +- Replace `master` by `main` git branch name in scripts. Reference: [New git default branch name](https://about.gitlab.com/blog/2021/03/10/new-git-default-branch-name/) + +### Fixed +- Fix documentation scrolling between pages, with the [`auto2top`](https://docsify.js.org/#/configuration?id=auto2top) option of [docsify](https://docsify.js.org) + +### Removed +- Remove parallel requests improvement, because it's buggy in some situations... +- Test PSU with Portainer [2.1.1](https://app.swaggerhub.com/apis/deviantony/Portainer/2.0.1) API + +## [1.3.0-alpha] - 2021-09-14 +### Changed +- **Breaking Change**: [HTTPie](https://httpie.io/) is replaced by [cURL](https://curl.se), for smaller Docker images, faster execution and to be more portable +- Boost performance for some actions like `status`, `tasks` and `tasks:healthy`, with parallel requests + +### Fixed +- Running concurrently `psu` commands should work now, by creating unique temporary file names +- Fix `psu tasks:healthy` action output, when an error occurs + +## [1.2.0] - 2021-09-14 +### Added +- Add tests for `actions`, `containers` and `services` actions +- Test PSU with Portainer [1.24.2](https://app.swaggerhub.com/apis/deviantony/Portainer/1.24.1) API + +### Changed +- Downgrade Docker Compose from [1.29.2](https://github.com/docker/compose/releases/tag/1.29.2) to [1.28.0](https://github.com/docker/compose/releases/tag/1.28.0) for Alpine image, to get faster builds 🚀 +- Reduce Docker images size based on Alpine, again +- Better documentation + +### Fixed +- Tests should run fine now with macOS + +### Removed +- Test PSU with Portainer [1.24.1](https://app.swaggerhub.com/apis/deviantony/Portainer/1.24.1) API +- Test PSU with Portainer [2.0.1](https://app.swaggerhub.com/apis/deviantony/Portainer/2.0.1) API + +## [1.2.0-beta.1] - 2021-09-03 +### Added +- Test PSU with Portainer CE [2.5.1](https://app.swaggerhub.com/apis/portainer/portainer-ce/2.5.1) API +- Test PSU with Portainer CE [2.6.3](https://app.swaggerhub.com/apis/portainer/portainer-ce/2.6.3) API + +### Changed +- Use Docker [Compose 1.29.2](https://github.com/docker/compose/releases/tag/1.29.2) instead of Docker [Compose 1.28.3](https://github.com/docker/compose/releases/tag/1.28.3) +- Upgrade Operating System of Docker based images, with [Alpine 3.14](https://hub.docker.com/_/alpine) and [Debian 11](https://hub.docker.com/_/debian) +- Reduce Docker images size +- Use [Traefik 2.5](https://doc.traefik.io/traefik/v2.5) instead of [Traefik 2.4](https://doc.traefik.io/traefik/v2.4) for testing + +### Fixed +- Fix [`rm`](docs/README.md#rm) (remove) action with Portainer CE 2.6 + +## [1.2.0-alpha] - 2021-02-19 +### Added +- Test PSU with Portainer CE [2.0.1](https://app.swaggerhub.com/apis/deviantony/Portainer/2.0.1) API +- Test PSU with Portainer CE [2.1.1](https://app.swaggerhub.com/apis/deviantony/Portainer/2.0.1) API + +### Changed +- Use Docker [Compose 1.28.3](https://github.com/docker/compose/releases/tag/1.28.3) instead of Docker [Compose 1.26.2](https://github.com/docker/compose/releases/tag/1.26.2) +- Use [Traefik 2.4](https://doc.traefik.io/traefik/v2.4) instead of [Traefik 2.2](https://doc.traefik.io/traefik/v2.2) for testing +- Upgrade Operating System of Docker based images, with [Alpine 3.13](https://hub.docker.com/_/alpine) + +### Removed +- Test PSU with Portainer [1.22.2](https://app.swaggerhub.com/apis/deviantony/Portainer/1.22.2) API +- Test PSU with Portainer [1.23.2](https://app.swaggerhub.com/apis/deviantony/Portainer/1.23.2) API + +## [1.1.0] - 2021-02-18 +### Changed +- Use [Traefik 2.2](https://doc.traefik.io/traefik/v2.2) instead of [Traefik 2.1](https://doc.traefik.io/traefik/v2.1) for testing + +### Fixed +- Changelog link for `psu` version `1.1.0-alpha` +- Fix `cryptography` building error + +## [1.1.0-alpha] - 2020-07-29 +### Changed +- Upgrade Operating System of Docker based images, with [Alpine 3.12](https://hub.docker.com/_/alpine) and [Debian 10](https://hub.docker.com/_/debian) + +### Fixed +- Docker build should fail if a shell command failed + +## [1.0.7] - 2021-02-16 +### Fixed +- Remove useless packages after building `docker-compose`, for the main Docker image + +## [1.0.6] - 2021-02-16 +### Fixed +- Docker build should fail if a shell command failed +- Fix `cryptography` building error + +## [1.0.5] - 2020-07-29 +### Added +- Test PSU with Portainer [1.24.1](https://app.swaggerhub.com/apis/deviantony/Portainer/1.24.1) API + +### Removed +- Test PSU with Portainer [1.21.0](https://app.swaggerhub.com/apis/deviantony/Portainer/1.21.0) API + +## [1.0.4] - 2020-01-27 +### Added +- Use the `$CLEANUP_REGISTRIES_ENABLED` CI variable for deleting Docker repository tags in bulk + +### Changed +- Remove unused git and Docker tags in `README.md` + +### Fixed +- Fix scheduled pipeline who update Docker images for the latest stable git tag + +## [1.0.3] - 2020-01-09 +### Added +- Cleaning old Docker repository builds tags via [GitLab API](https://docs.gitlab.com/12.6/ee/api/container_registry.html#delete-repository-tags-in-bulk) + +### Changed +- Use [Traefik 2.1](https://doc.traefik.io/traefik/v2.1) instead of [Traefik 1.7](https://doc.traefik.io/traefik/v1.7) for testing + +### Fixed +- Build script for the latest stable git tag of a given git branch + +## [1.0.2] - 2019-12-10 +### Added +- Test PSU with Portainer [1.23.0](https://app.swaggerhub.com/apis/deviantony/Portainer/1.23.0) API + +## [1.0.1] - 2019-10-29 +### Fixed +- If the `--insecure` option is set to `false` and the `HTTPIE_VERIFY_SSL` environment variable is set, we keep its value instead of overwrite it to `yes`. + Useful when we want to use Custom CA (e.g. `HTTPIE_VERIFY_SSL=/etc/ssl/certs/ca-certificates.crt`). For more information, you can read the [HTTPie docs](https://httpie.org/doc/1.0.3#custom-ca-bundle) + +## [1.0.0] - 2019-07-25 +### Added +- New actions: `ls`, `status`, `services`, `tasks`, `tasks:healthy`, `containers`, `login`, `lint`, `inspect`, `system:info`, `actions`, `help` and `version` +- New options: `--auth-token=[AUTH_TOKEN]`, `--compose-file-base64=[BASE64]`, `--env-file-base64=[BASE64]`, `--timeout=[SECONDS]`, `--detect-job=[true|false]`, `--service=[SERVICE_NAME]`, `--insecure`, `--masked-variables`, `--quiet`, `--lint`, `--help` and `--version` +- New flags: `-A`, `-C`, `-F`, `-G`, `-T`, `-j`, `-i`, `-S`, `-m`, `-q`, `-L`, `-h` and `-V` +- New environment variables: `PORTAINER_AUTH_TOKEN`, `TIMEOUT`, `AUTO_DETECT_JOB`, `PORTAINER_SERVICE_NAME`, `MASKED_VARIABLES`, `QUIET_MODE` and `DOCKER_COMPOSE_LINT` +- The Docker image include now `docker-compose` to be able to lint Docker compose/stack file +- The `core` Docker image variant doesn't include `docker-compose`, so it's a bit smaller. But you can't lint Docker compose/stack file before deploying a stack +- The `debian` and `debian-core` Docker image variants, use [Debian](https://www.debian.org) instead of [Alpine](https://alpinelinux.org/) as base image for `psu` +- Online documentation via [docsify](https://docsify.js.org) +- Tests who run automatically on each git push via [GitLab CI](https://docs.gitlab.com/ce/ci/) + +### Changed +- The `undeploy` action is now an aliased action. You should use `rm` action instead + +### Deprecated +- The `--secure=[yes|no]` option and `-s` flag are deprecated. Use the `--insecure` option instead (`psu ... --insecure`) +- The `--action=[ACTION_NAME]` option and `-a` flag are deprecated. Use `` argument instead (`psu ...`) + +## [0.1.2] - 2019-10-29 +### Changed +- Delegated compose file loading and escaping to jq [#33](https://gitlab.com/psuapp/psu/merge_requests/33) + +## [0.1.1] - 2019-06-05 +### Fixed +- Fixed error when environment variables loaded from file contain spaces in their values [#14](https://gitlab.com/psuapp/psu/merge_requests/14) + +## [0.1.0] - 2019-05-24 +### Added +- Stack deployment +- Stack update +- Stack undeployment +- Configuration through environment variables +- Configuration through flags +- Stack environment variables loading from file +- Optional SSL verification of Portainer instance +- Verbose mode +- Debug mode +- Strict mode + +[Unreleased]: https://gitlab.com/psuapp/psu/compare/v1.3.0...1-3-stable +[1.3.0]: https://gitlab.com/psuapp/psu/-/tags/v1.3.0 +[1.3.0-beta.1]: https://gitlab.com/psuapp/psu/-/tags/v1.3.0-beta.1 +[1.3.0-alpha]: https://gitlab.com/psuapp/psu/-/tags/v1.3.0-alpha +[1.2.0]: https://gitlab.com/psuapp/psu/-/tags/v1.2.0 +[1.2.0-beta.1]: https://gitlab.com/psuapp/psu/-/tags/v1.2.0-beta.1 +[1.2.0-alpha]: https://gitlab.com/psuapp/psu/-/tags/v1.2.0-alpha +[1.1.0]: https://gitlab.com/psuapp/psu/-/tags/v1.1.0 +[1.1.0-alpha]: https://gitlab.com/psuapp/psu/-/tags/v1.1.0-alpha +[1.0.7]: https://gitlab.com/psuapp/psu/-/tags/v1.0.7 +[1.0.6]: https://gitlab.com/psuapp/psu/-/tags/v1.0.6 +[1.0.5]: https://gitlab.com/psuapp/psu/-/tags/v1.0.5 +[1.0.4]: https://gitlab.com/psuapp/psu/-/tags/v1.0.4 +[1.0.3]: https://gitlab.com/psuapp/psu/-/tags/v1.0.3 +[1.0.2]: https://gitlab.com/psuapp/psu/-/tags/v1.0.2 +[1.0.1]: https://gitlab.com/psuapp/psu/-/tags/v1.0.1 +[1.0.0]: https://gitlab.com/psuapp/psu/-/tags/v1.0.0 +[0.1.2]: https://gitlab.com/psuapp/psu/-/tags/v0.1.2 +[0.1.1]: https://gitlab.com/psuapp/psu/-/tags/v0.1.1 +[0.1.0]: https://gitlab.com/psuapp/psu/-/tags/v0.1.0 diff --git a/public/1-3-stable/repo/LICENSE.md b/public/1-3-stable/repo/LICENSE.md new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/public/1-3-stable/repo/LICENSE.md @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/public/1-3-stable/repo/README.md b/public/1-3-stable/repo/README.md new file mode 100644 index 0000000..b13a018 --- /dev/null +++ b/public/1-3-stable/repo/README.md @@ -0,0 +1,311 @@ +

    Portainer Stack Utils

    +
    + +[![Docker Pulls](https://img.shields.io/docker/pulls/psuapp/psu.svg)](https://hub.docker.com/r/psuapp/psu/) +[![pipeline status](https://gitlab.com/psuapp/psu/badges/1-3-stable/pipeline.svg)](https://gitlab.com/psuapp/psu/commits/1-3-stable) + +Bash script to deploy/update/remove stacks in a [Portainer](https://portainer.io/) instance from a [docker-compose](https://docs.docker.com/compose) [yaml file](https://docs.docker.com/compose/compose-file). + +_Based on previous work by [@vladbabii](https://github.com/vladbabii) on [docker-how-to/portainer-bash-scripts](https://github.com/docker-how-to/portainer-bash-scripts)._ + +

    Table of contents

    + + + +- [How to install](#how-to-install) + - [Standalone](#standalone) + - [Docker image, variants and multi-architecture](#docker-image-variants-and-multi-architecture) +- [How to use](#how-to-use) + - [With options](#with-options) + - [With flags](#with-flags) + - [With envvars](#with-envvars) +- [Documentation](#documentation) +- [Supported Portainer API](#supported-portainer-api) +- [License](#license) + + +
    + +## How to install + +### Standalone + +> **Note**: The easiest way to install `psu` is to use [Docker method](#docker-image-and-variants), instead of this one + +Check the [Requirements](#requirements) section then [git] clone the repo and use the [bash] script below: + +```bash +git clone https://gitlab.com/psuapp/psu.git +cd psu/ +# Allow the 'psu' command to run everywhere: +export PATH="$(pwd):$PATH" +# Or if you want it permanent, with a super user account, run: +# ln -s $(pwd)/psu /usr/local/bin +# +# Then you can use psu, e.g. +psu deploy ... +``` + +For detailed instructions, see [How to use](#how-to-use) section. + +#### Requirements + +You will need these dependencies installed: + +##### [Linux] based systems ([Alpine], [Debian], [Ubuntu]...) +- [bash]\* (>= 4.4.23) +- [curl]\* (>= 7.64.0, but >= 7.76.0 is recommended) +- [jq]\* (>= 1.5.1) +- [uuidgen] recommended only for some OS (Alpine and Debian work fine without it) + +For [Debian] and similar apt-powered [Linux] systems, run: `apt install bash curl jq` + +##### [macOS] +- [bash]\* (>= 4.4.23) +- [curl]\* (>= 7.64.0, but >= 7.76.0 is recommended) +- [jq]\* (>= 1.5.1) +- [timeout]\* (included in the [coreutils] package) +- greadlink (included in the [coreutils] package) + +You should install [Homebrew], then run: `brew install bash coreutils jq` + +##### [Windows] +- [bash]\* (>= 4.4.23) +- [curl]\* (>= 7.64.0, but >= 7.76.0 is recommended) +- [jq]\* (>= 1.5.1) + +> **Note**: `psu`should work with [Windows], but it could be unstable ⚠️ + +You should download and install [Git](https://git-scm.com/download/win) and [jq](https://stedolan.github.io/jq/download) for [Windows] + +##### For all systems +- [docker-compose] is recommended but not required (useful for linting docker compose/stack files) + +\* = required + +### Docker image, variants and multi-architecture + +If you don't want or can't install `psu` and its dependencies, you can run it with the default [published Docker image](https://hub.docker.com/r/psuapp/psu), like this: +```bash +docker run psuapp/psu:1.3 deploy ... +``` +> **Note**: Docker images are also available on [GitLab](https://gitlab.com/psuapp/psu/container_registry). + +For detailed instructions, see [How to use](#how-to-use) section. + +#### Supported tags + +Published Docker images are [tagged](https://hub.docker.com/r/psuapp/psu/tags) matching [GitLab tags](https://gitlab.com/psuapp/psu/-/tags): + + + +- `1`, `1.3`, `1.3.0` -> [`v1.3.0`](https://gitlab.com/psuapp/psu/-/tags/v1.3.0) +- `1.3.0-beta.1` -> [`v1.3.0-beta.1`](https://gitlab.com/psuapp/psu/-/tags/v1.3.0-beta.1) +- `1.3.0-alpha` -> [`v1.3.0-alpha`](https://gitlab.com/psuapp/psu/-/tags/v1.3.0-alpha) +- `1.2`, `1.2.0` -> [`v1.2.0`](https://gitlab.com/psuapp/psu/-/tags/v1.2.0) +- `1.2.0-beta.1` -> [`v1.2.0-beta.1`](https://gitlab.com/psuapp/psu/-/tags/v1.2.0-beta.1) +- `1.2.0-alpha` -> [`v1.2.0-alpha`](https://gitlab.com/psuapp/psu/-/tags/v1.2.0-alpha) +- `1.1`, `1.1.0` -> [`v1.1.0`](https://gitlab.com/psuapp/psu/-/tags/v1.1.0) +- `1.1.0-alpha` -> [`v1.1.0-alpha`](https://gitlab.com/psuapp/psu/-/tags/v1.1.0-alpha) +- `1.0`, `1.0.7` -> [`v1.0.7`](https://gitlab.com/psuapp/psu/-/tags/v1.0.7) +- `1.0.6` -> [`v1.0.6`](https://gitlab.com/psuapp/psu/-/tags/v1.0.6) +- `1.0.5` -> [`v1.0.5`](https://gitlab.com/psuapp/psu/-/tags/v1.0.5) +- `1.0.4` -> [`v1.0.4`](https://gitlab.com/psuapp/psu/-/tags/v1.0.4) +- `1.0.3` -> [`v1.0.3`](https://gitlab.com/psuapp/psu/-/tags/v1.0.3) +- `1.0.2` -> [`v1.0.2`](https://gitlab.com/psuapp/psu/-/tags/v1.0.2) +- `1.0.1` -> [`v1.0.1`](https://gitlab.com/psuapp/psu/-/tags/v1.0.1) +- `1.0.0` -> [`v1.0.0`](https://gitlab.com/psuapp/psu/-/tags/v1.0.0) +- `0.1.2` -> [`v0.1.2`](https://gitlab.com/psuapp/psu/-/tags/v0.1.2) +- `0.1.1` -> [`v0.1.1`](https://gitlab.com/psuapp/psu/-/tags/v0.1.1) +- `0.1.0` -> [`v0.1.0`](https://gitlab.com/psuapp/psu/-/tags/v0.1.0) + +##### Variants + +The `core` variant doesn't include `docker-compose`, so it's a bit smaller. +But you can't lint Docker compose/stack file before deploying a stack. + + +- `1-core`, `1.3-core`, `1.3.0-core` -> [`v1.3.0`](https://gitlab.com/psuapp/psu/-/tags/v1.3.0) +- `1.2-core`, `1.2.0-core` -> [`v1.2.0`](https://gitlab.com/psuapp/psu/-/tags/v1.2.0) +- `1.1-core`, `1.1.0-core` -> [`v1.1.0`](https://gitlab.com/psuapp/psu/-/tags/v1.1.0) +- `1.0-core`, `1.0.7-core` -> [`v1.0.7`](https://gitlab.com/psuapp/psu/-/tags/v1.0.7) + +The `debian` and `debian-core` variants use [Debian](https://www.debian.org) instead of [Alpine](https://alpinelinux.org/) as base image for `psu`. + + +- `1-debian`, `1.3-debian`, `1.3.0-debian` -> [`v1.3.0`](https://gitlab.com/psuapp/psu/-/tags/v1.3.0) +- `1-debian-core`, `1.3-debian-core`, `1.3.0-debian-core` -> [`v1.3.0`](https://gitlab.com/psuapp/psu/-/tags/v1.3.0) +- `1.2-debian`, `1.2.0-debian` -> [`v1.2.0`](https://gitlab.com/psuapp/psu/-/tags/v1.2.0) +- `1.2-debian-core`, `1.2.0-debian-core` -> [`v1.2.0`](https://gitlab.com/psuapp/psu/-/tags/v1.2.0) +- `1.1-debian`, `1.1.0-debian` -> [`v1.1.0`](https://gitlab.com/psuapp/psu/-/tags/v1.1.0) +- `1.1-debian-core`, `1.1.0-debian-core` -> [`v1.1.0`](https://gitlab.com/psuapp/psu/-/tags/v1.1.0) +- `1.0-debian`, `1.0.7-debian` -> [`v1.0.7`](https://gitlab.com/psuapp/psu/-/tags/v1.0.7) +- `1.0-debian-core`, `1.0.7-debian-core` -> [`v1.0.7`](https://gitlab.com/psuapp/psu/-/tags/v1.0.7) + +##### Multi-Architecture + +The Docker images support multi-architecture: `linux/amd64`, `linux/arm64` and `linux/arm/v7`. + +On ARM machines, if you get this error when running a `psu` Docker image: +``` +standard_init_linux.go:228: exec user process caused: exec format error +``` + +You need to install `linux/amd64` QEMU binary, like this: +```bash +docker run --privileged --rm tonistiigi/binfmt --install linux/amd64 +``` +Then run your `psu` Docker image again and it should work 🤞 + +And if you want to uninstall this QEMU binary, run this command: +```bash +docker run --privileged --rm tonistiigi/binfmt --uninstall linux/amd64 +``` + +#### Testing/debugging: + +For testing/debugging, you can use this Docker image in interactive mode, to run any commands inside the container: +```bash +docker run -v $(pwd)/docker-compose.yml:/docker-compose.yml -it --rm --entrypoint bash psuapp/psu:1.3 +# Run any commands here! E.g. +$ psu --version +Portainer Stack Utils, version 1.3.0 + License GPLv3: GNU GPL version 3 +``` + +## How to use + +The provided `psu` script allows to deploy/update/remove... Portainer stacks. Settings can be passed through envvars and/or options and/or flags. Both envvars, options and flags can be mixed but options or flags will always overwrite envvar values. When deploying a stack, if it doesn't exist a new one is created, otherwise it's updated (unless strict mode is active). + +### With options + +This is more suitable for standalone script usage. + +- `` ("deploy", "rm", "ls"..., required): Whether to deploy, remove, list... the stack, _not an option but an argument_ +- `--user` (string, required): Username +- `--password` (string, required): Password +- `--url` (string, required): URL to Portainer +- `--name` (string, required): Stack name +- `--compose-file` (string, required if action=deploy): Path to docker-compose file + +For detailed instructions, see the full [options list](docs/README.md#available-options). + +#### Examples + +```bash +psu deploy --user admin --password password --url https://portainer.local --name mystack --compose-file /path/to/docker-compose.yml --env-file /path/to/env_vars_file +``` + +```bash +psu rm --user admin --password password --url https://portainer.local --name mystack +``` + +**With Docker:** +```bash +docker run -v $(pwd)/docker-compose.yml:/docker-compose.yml -v $(pwd)/.env:/.env psuapp/psu:1.3 deploy --user admin --password password --url https://portainer.local --name mystack --compose-file docker-compose.yml --env-file .env +``` + +### With flags + +This is more suitable for standalone script usage. + +- `` ("deploy", "rm", "ls"..., required): Whether to deploy, remove, list... the stack, _not a flag but an argument_ +- `-u` (string, required): Username +- `-p` (string, required): Password +- `-l` (string, required): URL to Portainer +- `-n` (string, required): Stack name +- `-c` (string, required if action=deploy): Path to docker-compose file + +For detailed instructions, see the full [flags list](docs/README.md#available-options). + +#### Examples + +```bash +psu deploy -u admin -p password -l https://portainer.local -n mystack -c /path/to/docker-compose.yml -g /path/to/env_vars_file +``` + +```bash +psu rm -u admin -p password -l https://portainer.local -n mystack +``` + +**With Docker:** +```bash +docker run -v $(pwd)/docker-compose.yml:/docker-compose.yml -v $(pwd)/.env:/.env psuapp/psu:1.3 deploy -u admin -p password -l https://portainer.local -n mystack -c docker-compose.yml -g .env +``` + +### With envvars + +This is particularly useful for [CI](https://en.wikipedia.org/wiki/Continuous_integration)/[CD](https://en.wikipedia.org/wiki/Continuous_deployment) pipelines using Docker containers. + +- `ACTION` ("deploy", "rm", "ls"..., required): Whether to deploy, remove, list... the stack +- `PORTAINER_USER` (string, required): Username +- `PORTAINER_PASSWORD` (string, required): Password +- `PORTAINER_URL` (string, required): URL to Portainer +- `PORTAINER_STACK_NAME` (string, required): Stack name +- `DOCKER_COMPOSE_FILE` (string, required if action=deploy): Path to docker-compose file + +For detailed instructions, see the full [envvars list](docs/README.md#available-environment-variables). + +#### Examples + +```bash +export ACTION="deploy" +export PORTAINER_USER="admin" +export PORTAINER_PASSWORD="password" +export PORTAINER_URL="https://portainer.local" +export PORTAINER_STACK_NAME="mystack" +export DOCKER_COMPOSE_FILE="/path/to/docker-compose.yml" +export ENVIRONMENT_VARIABLES_FILE="/path/to/env_vars_file" + +psu +``` + +```bash +export ACTION="rm" +export PORTAINER_USER="admin" +export PORTAINER_PASSWORD="password" +export PORTAINER_URL="https://portainer.local" +export PORTAINER_STACK_NAME="mystack" + +psu +``` + +**With Docker:** +```bash +docker run -v $(pwd)/docker-compose.yml:/docker-compose.yml -v $(pwd)/.env:/.env -e ACTION="deploy" -e PORTAINER_USER="admin" -e PORTAINER_PASSWORD="password" -e PORTAINER_URL="https://portainer.local" -e PORTAINER_STACK_NAME="mystack" -e DOCKER_COMPOSE_FILE="docker-compose.yml" -e ENVIRONMENT_VARIABLES_FILE=".env" psuapp/psu:1.3 +``` + +## Documentation + +
    +For advanced usage, see the full PSU documentation. +
    + +For detailed instructions, see the [CLI Commands](docs/README.md) documentation. + +## Supported Portainer API + +PSU was created for the latest versions of Portainer API, which at the time of writing are [1.24.2](https://app.swaggerhub.com/apis/deviantony/Portainer/1.24.1), [2.5.1](https://app.swaggerhub.com/apis/portainer/portainer-ce/2.5.1), [2.6.3](https://app.swaggerhub.com/apis/portainer/portainer-ce/2.6.3) and [2.9.3](https://app.swaggerhub.com/apis/portainer/portainer-ce/2.9.3). + +## License + +Source code contained by this project is licensed under the [GNU General Public License version 3](https://www.gnu.org/licenses/gpl-3.0.en.html). + +See [LICENSE](LICENSE) file for reference. + +[Linux]: https://kernel.org +[Alpine]: https://alpinelinux.org +[Debian]: https://debian.org +[Ubuntu]: https://ubuntu.com/ +[macOS]: https://apple.com/macos +[Homebrew]: https://brew.sh +[coreutils]: https://formulae.brew.sh/formula/coreutils +[Windows]: https://microsoft.com/windows +[bash]: https://www.gnu.org/software/bash +[curl]: https://curl.se +[jq]: https://stedolan.github.io/jq +[timeout]: https://man7.org/linux/man-pages/man1/timeout.1.html +[uuidgen]: https://man7.org/linux/man-pages/man1/uuidgen.1.html +[docker-compose]: https://docs.docker.com/compose/install +[git]: https://git-scm.com/ \ No newline at end of file