Merge branch 'master' into make-nginx-proxy-http-version-configurable

This commit is contained in:
Schlepptop
2026-10-22 11:37:55 +02:00
committed by GitHub
91 changed files with 561 additions and 202 deletions

View File

@@ -40,7 +40,7 @@ jobs:
- name: Install markdownlint-cli
run: npm install -g markdownlint-cli@0.35.0
- name: Run markdown-lint
run: markdownlint -c .github/linters/.markdown-lint.yml *.md **/*.md
run: markdownlint -c .github/linters/.markdown-lint.yml --ignore tests/apps '**/*.md'
packer:
name: packer

View File

@@ -1,7 +1,7 @@
GO_ARGS ?=
GO_PLUGIN_MAKE_TARGET ?= build
GO_REPO_ROOT := /go/src/github.com/dokku/dokku
BUILD_IMAGE := golang:1.26.2
BUILD_IMAGE := golang:1.27.1
GO_BUILD_CACHE ?= /tmp/dokku-go-build-cache
GO_MOD_CACHE ?= /tmp/dokku-go-mod-mod
GO_ROOT_MOUNT ?= $$PWD/../..:$(GO_REPO_ROOT)

View File

@@ -1,4 +1,4 @@
FROM python:3.15.0rc3-alpine
FROM python:3.16.0a1-alpine
WORKDIR /usr/src/app

View File

@@ -3,7 +3,7 @@ click==8.5.0
ghp-import==2.1.0
importlib-metadata==9.0.1
Jinja2==3.1.6
Markdown>=3.11,<3.12
Markdown>=3.11.1,<3.12
MarkupSafe==3.0.4
mergedeep==1.3.4
mkdocs==1.6.1
@@ -12,7 +12,7 @@ mkdocs-material==9.7.7
mkdocs-material-extensions==1.3.1
packaging==26.3
Pygments==2.21.0
pymdown-extensions==12.2
pymdown-extensions==12.3
pyparsing==3.3.3
python-dateutil==2.9.0.post0
PyYAML==6.0.3

View File

@@ -67,7 +67,7 @@ Sometimes it may be desirable to set a different path for a given app, e.g. when
dokku app-json:set node-js-app appjson-path .dokku/app.json
```
The value is the path to the desired file *relative* to the base search directory, and will never be treated as absolute paths in any context. If that file does not exist within the repository, Dokku will continue the build process as if the repository has no `app.json`.
The value is the path to the desired file _relative_ to the base search directory, and will never be treated as absolute paths in any context. If that file does not exist within the repository, Dokku will continue the build process as if the repository has no `app.json`.
The default value may be set by passing an empty value for the option:

View File

@@ -243,7 +243,7 @@ dokku registry:set --global push-on-release
When `push-on-release` is enabled, Dokku treats the remote registry as the canonical store for app images. If a local image disappears - for example because a `docker image prune` cron ran, the host rebooted, or an operator removed it manually - subsequent commands that need the image (`ps:restart`, `ps:scale`, `dokku run`, `domains:add`, `certs:add`, etc.) will pull the missing tag back from the registry automatically. Per-app registry credentials configured via `registry:login` are honored during the pull. This recovery covers the deployed numeric tag pushed by the registry plugin - a missing `latest` tag will be ignored.
### Push extra tags
### Push extra tags
To push the image on release with extra tags, set the `push-extra-tags` to a comma-separated list of tags via the `registry:set` command. The default value for this property is empty. Setting the property will result in the image being tagged with extra tags every release.
@@ -251,6 +251,7 @@ To push the image on release with extra tags, set the `push-extra-tags` to a com
# multiple-tags
dokku registry:set node-js-app push-extra-tags foo,bar
```
The `push-extra-tags` can be set to a single tag too.
```shell

View File

@@ -30,6 +30,8 @@ Valid resource options include:
- `--network-egress`
- `--nvidia-gpu`
Values for `--memory` and `--memory-swap` are validated when set, and invalid values are rejected.
See the [Supported Resource Management Properties](/docs/deployment/schedulers/docker-local.md#supported-resource-management-properties) section of the docker local scheduler documentation for more information on how each resource limit maps to Docker.
Resource reservations are applied only during the `run` and `deploy` phases of an application. Resource limits also apply during the `build` phase when explicitly configured against the `build` process type - see [Build-time Resource Limits](#build-time-resource-limits) below.

View File

@@ -6,11 +6,14 @@
- The default image used for Cloud Native Buildpack builds is now `heroku/builder:24`, and is based on both the `heroku-24` stack as well as Ubuntu 24.04. Users that wish to stick with the old, `heroku-22`/Ubuntu 22.04 builder may specify `heroku/buildpacks:22` as their builder image. Please see the [cloud native buildpack deployment documentation](/docs/deployment/builders/cloud-native-buildpacks.md#customizing-the-buildpack-stack-builder) for more information on how to specify a custom buildpack stack builder.
- The default image used for Herokuish Buildpack builds is now `gliderlabs/herokuish:latest-24`, and is based on both the `heroku-24` stack as well as Ubuntu 24.04. Users that wish to stick with the old, `heroku-22`/Ubuntu 22.04 builder may specify `gliderlabs/herokuish:latest-22` as their builder image. Please see the [herokuish buildpack deployment documentation](/docs/deployment/builders/herokuish-buildpacks.md#customizing-the-buildpack-stack-builder) for more information on how to specify a custom buildpack stack builder.
- The `vector` image used by Dokku for enhanced logging support has been upgraded from 0.39.x to 0.41.x. To take advantage of the new image, execute the following commands:
```
dokku logs:vector-stop
dokku logs:vector-start
```
- The `openresty` image used by Dokku for proxying via openresty has been upgraded from 0.8.0 to 0.9.0. To take advantage of the new image, execute the following commands:
```
dokku openresty:stop
dokku openresty:start

View File

@@ -90,6 +90,7 @@ Environment variables from `app.json` are processed during the first deploy, bef
4. **Optional variables without a value**: Skipped silently if no TTY is available
On subsequent deploys:
- Variables are NOT re-set unless `sync: true` is specified
- Variables with `sync: true` are always set to their configured value, overwriting any manual changes
- Variables that already have values are not modified
@@ -97,6 +98,7 @@ On subsequent deploys:
### Examples
**Simple default value:**
```json
{
"env": {
@@ -106,6 +108,7 @@ On subsequent deploys:
```
**Generated secret (recommended for API keys, tokens, etc.):**
```json
{
"env": {
@@ -118,6 +121,7 @@ On subsequent deploys:
```
**Required variable that must be provided:**
```json
{
"env": {
@@ -130,6 +134,7 @@ On subsequent deploys:
```
**Variable that stays in sync with app.json:**
```json
{
"env": {

View File

@@ -268,7 +268,6 @@ The following plugins are no longer maintained by their developers.
[calyhre]: https://github.com/calyhre
[cameron-martin]: https://github.com/cameron-martin
[candlewaster]: https://notabug.org/candlewaster
[cedricziel]: https://github.com/cedricziel
[cef]: https://github.com/cef
[cheif]: https://github.com/cheif
[cjblomqvist]: https://github.com/cjblomqvist

View File

@@ -207,7 +207,6 @@ See the [buildpack management documentation](/docs/deployment/builders/buildpack
See the [buildpack management documentation](/docs/deployment/builders/buildpack-management.md#using-a-specific-buildpack-version) for more information on how to using a specific buildpack version
### Displaying buildpack reports for an app
See the [buildpack management documentation](/docs/deployment/builders/buildpack-management.md#displaying-buildpack-reports-for-an-app) for more information on how to display buildpack reports for an app.
@@ -218,4 +217,4 @@ See the [buildpack management documentation](/docs/deployment/builders/buildpack
| Property | Scope | Default | Report flags | Description |
|---|---|---|---|---|
| `allowed` | app + global | `true` | `--builder-herokuish-allowed`, `--builder-herokuish-global-allowed`, `--builder-herokuish-computed-allowed` | When `false`, the herokuish builder is skipped during builder detection for this app |
| `allowed` | app + global | `true` | `--builder-herokuish-allowed`, `--builder-herokuish-global-allowed`, `--builder-herokuish-computed-allowed` | When `false`, the herokuish builder is skipped during builder detection for this app |

View File

@@ -13,14 +13,17 @@ Before using Railpacks, the following steps must be taken:
- Install the `railpack` cli: The `railpack` cli tool is not included by default with Dokku or as a dependency. It must also be installed as shown on [this page](https://railpack.com/installation).
- Create a `buildkit` builder: Railpack uses buildkit.
```shell
docker run --rm --privileged -d --name buildkit moby/buildkit
```
```shell
docker run --rm --privileged -d --name buildkit moby/buildkit
```
- Set the buildkit builder: Update the `/etc/default/dokku` file to set `BUILDKIT_HOST`:
```shell
touch /etc/default/dokku
echo "export BUILDKIT_HOST='docker-container://buildkit'" >> /etc/default/dokku
```
```shell
touch /etc/default/dokku
echo "export BUILDKIT_HOST='docker-container://buildkit'" >> /etc/default/dokku
```
### Detection

View File

@@ -26,4 +26,4 @@ steps:
```
- The standard `clone` stage is replaced with one that performs a complete clone of the repository (the default is a shallow clone, which dokku would reject).
- A `GIT_REMOTE_URL` and a `SSH_PRIVATE_KEY` (with help of the `from_secret` directive) suffice to carry out a deployment.
- A `GIT_REMOTE_URL` and a `SSH_PRIVATE_KEY` (with help of the `from_secret` directive) suffice to carry out a deployment.

View File

@@ -205,16 +205,16 @@ The `docker-local` scheduler supports a minimal list of resource _limits_ and _r
- cpu: (docker option: `--cpus`), is specified in number of CPUs a process can access.
- See the ["CPU" section](https://docs.docker.com/config/containers/resource_constraints/#cpu) of the Docker Runtime Options documentation for more information.
- memory: (docker option: `--memory`) should be specified with a suffix of `b` (bytes), `k` (kilobytes), `m` (megabytes), `g` (gigabytes). Default unit is `m` (megabytes).
- memory: (docker option: `--memory`) should be specified with a suffix of `b` (bytes), `k` (kilobytes), `m` (megabytes), `g` (gigabytes), `t` (terabytes) or `p` (petabytes). Suffixes are case-insensitive and may be followed by `i` and/or `b`, such as `512M`, `1G`, or `1GiB`. Default unit is `m` (megabytes).
- See the ["Memory" section](https://docs.docker.com/config/containers/resource_constraints/#memory) of the Docker Runtime Options documentation for more information.
- memory-swap: (docker option: `--memory-swap`) should be specified with a suffix of `b` (bytes), `k` (kilobytes), `m` (megabytes), `g` (gigabytes)
- memory-swap: (docker option: `--memory-swap`) should be specified with the same suffixes as `memory`, or `-1` for unlimited swap. Values without a suffix are in bytes.
- See the ["Memory" section](https://docs.docker.com/config/containers/resource_constraints/#memory) of the Docker Runtime Options documentation for more information.
- nvidia-gpus: (docker option: `--gpus`), is specified in number of Nvidia GPUs a process can access.
- See the ["GPU" section](https://docs.docker.com/config/containers/resource_constraints/#gpu) of the Docker Runtime Options documentation for more information.
#### Resource Reservations
- memory: (docker option: `--memory-reservation`) should be specified with a suffix of `b` (bytes), `k` (kilobytes), `m` (megabytes), `g` (gigabytes). Default unit is `m` (megabytes).
- memory: (docker option: `--memory-reservation`) should be specified with the same suffixes as the `memory` limit. Default unit is `m` (megabytes).
- See the ["Memory" section](https://docs.docker.com/config/containers/resource_constraints/#memory) of the Docker Runtime Options documentation for more information.
## Properties

View File

@@ -957,7 +957,7 @@ dokku docker-options:add node-js-app deploy "--sysctl net.ipv4.ip_unprivileged_p
Passing a non-namespaced sysctl this way fails the deploy rather than silently dropping the value, since it provably cannot take effect within a pod. Note this differs from the `docker-local` scheduler, where such an option is passed straight through to `docker run`.
Kubernetes further splits namespaced sysctls into a *safe* list that any pod may set, and everything else. A sysctl outside the safe list - `net.core.somaxconn`, for example - is rejected at pod admission unless the node's kubelet was started with a matching `allowed-unsafe-sysctls` value, which can be supplied at cluster initialization or when joining a node.
Kubernetes further splits namespaced sysctls into a _safe_ list that any pod may set, and everything else. A sysctl outside the safe list - `net.core.somaxconn`, for example - is rejected at pod admission unless the node's kubelet was started with a matching `allowed-unsafe-sysctls` value, which can be supplied at cluster initialization or when joining a node.
```shell
dokku scheduler-k3s:initialize --kubelet-args allowed-unsafe-sysctls=net.core.somaxconn
@@ -1293,7 +1293,7 @@ Two differences are worth noting:
The `k3s` scheduler supports a minimal list of resource _limits_ and _reservations_:
- cpu: is specified in number of CPUs a process can access.
- memory: should be specified with a suffix of `b` (bytes), `Ki` (kilobytes), `Mi` (megabytes), `Gi` (gigabytes). Default unit is `Mi` (megabytes).
- memory: should be specified with a suffix of `b` (bytes), `k` (kilobytes), `m` (megabytes), `g` (gigabytes), `t` (terabytes) or `p` (petabytes). Suffixes are case-insensitive and may be followed by `i` and/or `b`, such as `512Mi`, `1G`, or `1GiB`. Units are binary, so `1G` and `1Gi` are equivalent. Default unit is `Mi` (megabytes).
If unspecified for any task, the default reservation will be `.1` CPU and `128Mi` RAM, with no limit set for either CPU or RAM. This is to avoid issues with overscheduling pods on a cluster. To avoid issues, set more specific values for at least resource reservations. If unbounded utilization is desired, set CPU and Memory to `0m` and `0Mi`, respectively.

View File

@@ -97,6 +97,7 @@ free
echo "/var/swap.img none swap sw 0 0" >> /etc/fstab
```
Note: it may be necessary to call swapoff, mkswap and swapon explicitly: `sudo /sbin/swapoff /var/swap.img`, etc.
[Reference](https://www.digitalocean.com/community/tutorials/how-to-configure-virtual-memory-swap-file-on-a-vps)

View File

@@ -226,22 +226,20 @@ sudo ufw disable
### I can't connect to my application because the server is sending an invalid response, or can't provide a secure connection
This is normally a config problem with your app, rather than an issue with Dokku.
This is normally a config problem with your app, rather than an issue with Dokku.
One common cause is an application configured to enforce secure connections/HSTS, but SSL is not set up. In Ruby on Rails, if your `application.rb` or `config/environments/production.rb` include the line `configure.force_ssl = true`, try commenting that line out and redeploying. If this solves the issue temporarily, longer-term you should consider [configuring SSL](/docs/configuration/ssl.md).
### I deployed a new application, but an existing application is being served when I visit it
This problem has the same cause as the previous issue: your application is attempting to enforce SSL, but SSL is not configured. Disabling SSL enforcement should solve the problem.
The underlying cause is best understood with an example. Let's say you already have `https://apples.example.com/` working, and you're trying to deploy `bananas.example.com/`. But whenever you visit `bananas.example.com` you see `apples.example.com` instead. This is caused by `bananas.example.com` forcing SSL:
The underlying cause is best understood with an example. Let's say you already have `https://apples.example.com/` working, and you're trying to deploy `bananas.example.com/`. But whenever you visit `bananas.example.com` you see `apples.example.com` instead. This is caused by `bananas.example.com` forcing SSL:
1. Your browser sends a request to `http://bananas.example.com`.
1. `bananas.example.com` issues a redirect to `https://bananas.example.com`.
1. Your browser sends a request to `https://bananas.example.com`. But you haven't configured SSL for `bananas.example.com` yet! So this request ends up routed to `https://apples.example.com`, which _does_ have an SSL config.
### My application deploys properly, but won't load in browser "connection refused"
This could be a result of a bad proxy configuration (`http:5000:5000` may be incorrect). Run `dokku ports:report node-js-app` to check if your app has the correct proxy configuration. It should show something like the following.

View File

@@ -241,22 +241,22 @@ By default, Traefik uses TLS-ALPN-01 challenge for obtaining certificates. To sw
1. Set the challenge mode to `dns`:
```shell
dokku traefik:set --global challenge-mode dns
```
```shell
dokku traefik:set --global challenge-mode dns
```
2. Set your DNS provider:
```shell
dokku traefik:set --global dns-provider cloudflare
```
```shell
dokku traefik:set --global dns-provider cloudflare
```
3. Configure the required environment variables for your DNS provider. Each DNS provider requires specific environment variables. The variable names should be prefixed with `dns-provider-`:
```shell
dokku traefik:set --global dns-provider-cf_api_email user@example.com
dokku traefik:set --global dns-provider-cf_api_key your-api-key
```
```shell
dokku traefik:set --global dns-provider-cf_api_email user@example.com
dokku traefik:set --global dns-provider-cf_api_key your-api-key
```
The `dns-provider-` prefix will be stripped and the variable name will be uppercased when passed to the Traefik container. For example, `dns-provider-cf_api_email` becomes `CF_API_EMAIL`.

View File

@@ -31,7 +31,6 @@ One off containers are removed at the end of process execution.
In addition, one-off containers also run for a max of 24 hours (86400 seconds) by default, after which they are reaped. This can be changed by setting the `--ttl-seconds` argument:
```shell
# runs for 10 minutes
dokku run --ttl-seconds 600 node-js-app npm run mytask

View File

@@ -127,7 +127,7 @@ The `ps` plugin provides a number of settings that can be used to managed deploy
| Name | Description | Global Default |
|-----------------------|---------------------------------------------------|--------------------|
| `stop-timeout` | Configurable grace period given to the `docker stop` command. If a container has not stopped by this time, a `kill -9` signal or equivalent is sent in order to force-terminate the container. Both the `ps:stop` and `apps:destroy` commands *also* respect this value. If not specified, the Docker defaults for the [`docker stop` command](https://docs.docker.com/engine/reference/commandline/stop/) will be used. | `30` |
| `stop-timeout` | Configurable grace period given to the `docker stop` command. If a container has not stopped by this time, a `kill -9` signal or equivalent is sent in order to force-terminate the container. Both the `ps:stop` and `apps:destroy` commands _also_ respect this value. If not specified, the Docker defaults for the [`docker stop` command](https://docs.docker.com/engine/reference/commandline/stop/) will be used. | `30` |
All settings can be set via the `ps:set` command. Using `stop-timeout` as an example:
@@ -216,7 +216,7 @@ Sometimes it may be desirable to set a different path for a given app, e.g. when
dokku ps:set node-js-app procfile-path .dokku/Procfile
```
The value is the path to the desired file *relative* to the base search directory, and will never be treated as absolute paths in any context. If that file does not exist within the repository, Dokku will continue the build process as if the repository has no `Procfile`.
The value is the path to the desired file _relative_ to the base search directory, and will never be treated as absolute paths in any context. If that file does not exist within the repository, Dokku will continue the build process as if the repository has no `Procfile`.
The default value may be set by passing an empty value for the option:

View File

@@ -40,7 +40,6 @@ A cron task takes the following properties:
- `schedule`: A [cron-compatible](https://en.wikipedia.org/wiki/Cron#Overview) scheduling definition upon which to run the command. Seconds are generally not supported.
- `concurrency_policy`: A string (default: `allow`), that controls whether the cron task can be run concurrently with another invocation of itself. Valid options are `allow` (allow concurrency), `forbid` (exit the new cron task if there is an existing one), `replace` (delete any existing cron task and start the new one).
Zero or more cron tasks can be specified per app. Cron tasks are validated after the build artifact is created but before the app is deployed, and the cron schedule is updated during the post-deploy phase.
Cron tasks can run for a maximum of 24 hours, after which they are reaped from the system. The `docker-local` scheduler reaps expired tasks via the `dokku ps:retire` pass that runs every 5 minutes, so a task may overrun its deadline by up to 5 minutes. The `k3s` scheduler enforces the deadline directly through the job's `activeDeadlineSeconds`.

View File

@@ -1,4 +1,4 @@
go 1.26.2
go 1.27.1
use (
./plugins/app-json

View File

@@ -1,6 +1,6 @@
module github.com/dokku/dokku/plugins/app-json
go 1.26.2
go 1.27.1
require (
github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000

View File

@@ -1,6 +1,6 @@
module github.com/dokku/dokku/plugins/apps
go 1.26.2
go 1.27.1
require (
github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000

View File

@@ -1,6 +1,6 @@
module github.com/dokku/dokku/plugins/builder-dockerfile
go 1.26.2
go 1.27.1
require (
github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000

View File

@@ -1,6 +1,6 @@
module github.com/dokku/dokku/plugins/builder-herokuish
go 1.26.2
go 1.27.1
require (
github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000

View File

@@ -1,6 +1,6 @@
module github.com/dokku/dokku/plugins/builder-lambda
go 1.26.2
go 1.27.1
require (
github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000

View File

@@ -1,6 +1,6 @@
module github.com/dokku/dokku/plugins/builder-nixpacks
go 1.26.2
go 1.27.1
require (
github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000

View File

@@ -1,6 +1,6 @@
module github.com/dokku/dokku/plugins/builder-pack
go 1.26.2
go 1.27.1
require (
github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000

View File

@@ -1,6 +1,6 @@
module github.com/dokku/dokku/plugins/builder-railpack
go 1.26.2
go 1.27.1
require (
github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000

View File

@@ -1,6 +1,6 @@
module github.com/dokku/dokku/plugins/builder
go 1.26.2
go 1.27.1
require (
github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000

View File

@@ -15,10 +15,10 @@ func ReportSingleApp(appName string, format string, infoFlag string) error {
var flags map[string]common.ReportFunc
if appName == "--global" {
flags = map[string]common.ReportFunc{
"--builder-global-selected": reportGlobalSelected,
"--builder-global-build-dir": reportGlobalBuildDir,
"--builder-global-skip-cleanup": reportGlobalSkipCleanup,
"--builder-computed-skip-cleanup": reportComputedSkipCleanup,
"--builder-global-selected": reportGlobalSelected,
"--builder-global-build-dir": reportGlobalBuildDir,
"--builder-global-skip-cleanup": reportGlobalSkipCleanup,
"--builder-computed-skip-cleanup": reportComputedSkipCleanup,
}
} else {
flags = map[string]common.ReportFunc{

View File

@@ -1,6 +1,6 @@
module github.com/dokku/dokku/plugins/buildpacks
go 1.26.2
go 1.27.1
require (
github.com/dokku/dokku/plugins/app-json v0.0.0-00010101000000-000000000000

View File

@@ -36,7 +36,7 @@ func main() {
args.Parse(os.Args[2:])
appName := args.Arg(0)
if *branch == "" {
*branch = common.PropertyGet("git", appName, "deploy-branch")
*branch = common.PropertyGet("git", appName, "deploy-branch")
}
err = buildpacks.CommandDetect(appName, *branch)
case "list":

View File

@@ -39,9 +39,9 @@ func CommandDetect(appName string, branch string) (err error) {
workDir := common.AppRoot(appName)
checkedOutDir, err := checkoutBareGitRepo(workDir, branch)
if err != nil {
return err
}
if err != nil {
return err
}
defer func() {
if err := os.RemoveAll(checkedOutDir); err != nil {
common.LogWarn(fmt.Sprintf("Failed to remove temporary directory %s: %v", checkedOutDir, err))

View File

@@ -1,6 +1,6 @@
module github.com/dokku/dokku/plugins/builds
go 1.26.2
go 1.27.1
require (
github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000

View File

@@ -1,6 +1,6 @@
module github.com/dokku/dokku/plugins/caddy-vhosts
go 1.26.2
go 1.27.1
require (
github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000

View File

@@ -1,6 +1,6 @@
module github.com/dokku/dokku/plugins/certs
go 1.26.2
go 1.27.1
require (
github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000

View File

@@ -1,6 +1,6 @@
module github.com/dokku/dokku/plugins/checks
go 1.26.2
go 1.27.1
require (
github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000

View File

@@ -1,6 +1,6 @@
module github.com/dokku/dokku/plugins/common
go 1.26.2
go 1.27.1
require (
github.com/alexellis/go-execute/v2 v2.2.1

61
plugins/common/memory.go Normal file
View File

@@ -0,0 +1,61 @@
package common
import (
"fmt"
"regexp"
"strconv"
"strings"
)
// memoryValueRegex matches a docker-compatible memory value: a number with an
// optional unit (b, k, m, g, t, p in either case) optionally followed by i and/or b
var memoryValueRegex = regexp.MustCompile(`^(\d+(?:\.\d+)?)(?:([kKmMgGtTpP])[iI]?)?([bB])?$`)
// IsValidMemoryValue returns true if the value is a docker-compatible memory value
func IsValidMemoryValue(value string) bool {
return memoryValueRegex.MatchString(value)
}
// IsUnitlessMemoryValue returns true if the value is a valid memory value without any unit suffix
func IsUnitlessMemoryValue(value string) bool {
matches := memoryValueRegex.FindStringSubmatch(value)
if matches == nil {
return false
}
return matches[2] == "" && matches[3] == ""
}
// ParseMemoryBytes converts a docker-compatible memory value into bytes.
// Units are binary, and a value without a unit is treated as megabytes
func ParseMemoryBytes(value string) (int64, error) {
matches := memoryValueRegex.FindStringSubmatch(value)
if matches == nil {
return 0, fmt.Errorf("Invalid memory value '%s'", value)
}
size, err := strconv.ParseFloat(matches[1], 64)
if err != nil {
return 0, fmt.Errorf("Invalid memory value '%s': %w", value, err)
}
multipliers := map[string]float64{
"k": 1 << 10,
"m": 1 << 20,
"g": 1 << 30,
"t": 1 << 40,
"p": 1 << 50,
}
unit := strings.ToLower(matches[2])
if unit == "" && matches[3] == "" {
unit = "m"
}
multiplier := float64(1)
if unit != "" {
multiplier = multipliers[unit]
}
return int64(size * multiplier), nil
}

View File

@@ -0,0 +1,66 @@
package common
import (
"testing"
. "github.com/onsi/gomega"
)
func TestCommonIsValidMemoryValue(t *testing.T) {
RegisterTestingT(t)
valid := []string{"0", "100", "1.5", "100b", "100B", "512k", "512K", "512kb", "512m", "512M", "512MB", "512Mi", "512MiB", "1g", "1G", "1GB", "1Gi", "1gib", "1t", "1T", "1p", "1P"}
for _, value := range valid {
Expect(IsValidMemoryValue(value)).To(BeTrue(), value)
}
invalid := []string{"", "-1", "abc", "1x", "1Gm", "1i", "1ib", "1 G", "1.2.3", ".5g", "100G --foo", "1E", "1e9"}
for _, value := range invalid {
Expect(IsValidMemoryValue(value)).To(BeFalse(), value)
}
}
func TestCommonIsUnitlessMemoryValue(t *testing.T) {
RegisterTestingT(t)
Expect(IsUnitlessMemoryValue("100")).To(BeTrue())
Expect(IsUnitlessMemoryValue("1.5")).To(BeTrue())
Expect(IsUnitlessMemoryValue("100b")).To(BeFalse())
Expect(IsUnitlessMemoryValue("1G")).To(BeFalse())
Expect(IsUnitlessMemoryValue("1Gi")).To(BeFalse())
Expect(IsUnitlessMemoryValue("abc")).To(BeFalse())
}
func TestCommonParseMemoryBytes(t *testing.T) {
RegisterTestingT(t)
expected := map[string]int64{
"0": 0,
"512": 536870912,
"512m": 536870912,
"512M": 536870912,
"512MB": 536870912,
"512Mi": 536870912,
"512MiB": 536870912,
"1g": 1073741824,
"1G": 1073741824,
"1GB": 1073741824,
"1Gi": 1073741824,
"1.5g": 1610612736,
"1024K": 1048576,
"100b": 100,
"100B": 100,
"1t": 1099511627776,
"1p": 1125899906842624,
}
for value, bytes := range expected {
parsed, err := ParseMemoryBytes(value)
Expect(err).NotTo(HaveOccurred(), value)
Expect(parsed).To(Equal(bytes), value)
}
for _, value := range []string{"", "-1", "1x", "1Gm", "100G --foo"} {
_, err := ParseMemoryBytes(value)
Expect(err).To(HaveOccurred(), value)
}
}

View File

@@ -208,8 +208,8 @@ func TestReportSingleAppJSONNonPluginPrefixKey(t *testing.T) {
// Keys that don't start with --<reportType>- should pass through with
// only the leading "--" stripped, regardless of TrimPrefix.
infoFlags := map[string]string{
"--build-id": "abc123",
"--builds-retention": "5",
"--build-id": "abc123",
"--builds-retention": "5",
}
out := captureStdout(t, func() {

View File

@@ -1,6 +1,6 @@
module github.com/dokku/dokku/plugins/config
go 1.26.2
go 1.27.1
require (
github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000

View File

@@ -1,6 +1,6 @@
module github.com/dokku/dokku/plugins/cron
go 1.26.2
go 1.27.1
require (
github.com/dokku/dokku/plugins/app-json v0.0.0-00010101000000-000000000000

View File

@@ -154,9 +154,12 @@ func joinShellTokens(tokens []string) string {
// quoteShellArg returns s wrapped in single quotes when it contains characters
// the shell would otherwise interpret (whitespace, quotes, expansion sigils,
// globs, redirections, etc.). Embedded single quotes are escaped with the
// standard `'\''` close-escape-open sequence. Tokens free of such characters
// are returned verbatim so the stored representation stays human-readable for
// the common case.
// standard close-escape-open sequence:
//
// '\''
//
// Tokens free of such characters are returned verbatim so the stored
// representation stays human-readable for the common case.
func quoteShellArg(s string) string {
if s == "" {
return "''"

View File

@@ -1,6 +1,6 @@
module github.com/dokku/dokku/plugins/docker-options
go 1.26.2
go 1.27.1
require (
github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000

View File

@@ -1,6 +1,6 @@
module github.com/dokku/dokku/plugins/domains
go 1.26.2
go 1.27.1
require (
github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000

View File

@@ -1,6 +1,6 @@
module github.com/dokku/dokku/plugins/git
go 1.26.2
go 1.27.1
require (
github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000

View File

@@ -1,6 +1,6 @@
module github.com/dokku/dokku/plugins/haproxy-vhosts
go 1.26.2
go 1.27.1
require (
github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000

View File

@@ -1,6 +1,6 @@
module github.com/dokku/dokku/plugins/logs
go 1.26.2
go 1.27.1
require (
github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000

View File

@@ -1,6 +1,6 @@
module github.com/dokku/dokku/plugins/network
go 1.26.2
go 1.27.1
require (
github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000

View File

@@ -1,6 +1,6 @@
module github.com/dokku/dokku/plugins/nginx-vhosts
go 1.26.2
go 1.27.1
require (
github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000

View File

@@ -1,6 +1,6 @@
module github.com/dokku/dokku/plugins/openresty-vhosts
go 1.26.2
go 1.27.1
require (
github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000

View File

@@ -1,6 +1,6 @@
module github.com/dokku/dokku/plugins/plugin
go 1.26.2
go 1.27.1
require (
github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000

View File

@@ -1,6 +1,6 @@
module github.com/dokku/dokku/plugins/ports
go 1.26.2
go 1.27.1
require (
github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000

View File

@@ -4,7 +4,6 @@ import (
"fmt"
)
// PortMap is a struct that contains a scheme:host-port:container-port mapping
type PortMap struct {
// ContainerPort is the port on the container

View File

@@ -1,6 +1,6 @@
module github.com/dokku/dokku/plugins/proxy
go 1.26.2
go 1.27.1
require (
github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000

View File

@@ -1,6 +1,6 @@
module github.com/dokku/dokku/plugins/ps
go 1.26.2
go 1.27.1
require (
github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000

View File

@@ -30,27 +30,27 @@ func ReportSingleApp(appName string, format string, infoFlag string) error {
}
} else {
flags = map[string]common.ReportFunc{
"--deployed": reportDeployed,
"--processes": reportProcesses,
"--ps-can-scale": reportCanScale,
"--ps-computed-dockerfile-start-cmd": reportComputedDockerfileStartCmd,
"--ps-computed-procfile-path": reportComputedProcfilePath,
"--ps-computed-restart-policy": reportComputedRestartPolicy,
"--ps-computed-skip-deploy": reportComputedSkipDeploy,
"--ps-computed-start-cmd": reportComputedStartCmd,
"--ps-computed-stop-timeout-seconds": reportComputedStopTimeoutSeconds,
"--ps-dockerfile-start-cmd": reportDockerfileStartCmd,
"--ps-global-procfile-path": reportGlobalProcfilePath,
"--ps-global-restart-policy": reportGlobalRestartPolicy,
"--ps-global-skip-deploy": reportGlobalSkipDeploy,
"--ps-global-stop-timeout-seconds": reportGlobalStopTimeoutSeconds,
"--ps-procfile-path": reportProcfilePath,
"--ps-restart-policy": reportRestartPolicy,
"--ps-skip-deploy": reportSkipDeploy,
"--ps-start-cmd": reportStartCmd,
"--ps-stop-timeout-seconds": reportStopTimeoutSeconds,
"--restore": reportRestore,
"--running": reportRunningState,
"--deployed": reportDeployed,
"--processes": reportProcesses,
"--ps-can-scale": reportCanScale,
"--ps-computed-dockerfile-start-cmd": reportComputedDockerfileStartCmd,
"--ps-computed-procfile-path": reportComputedProcfilePath,
"--ps-computed-restart-policy": reportComputedRestartPolicy,
"--ps-computed-skip-deploy": reportComputedSkipDeploy,
"--ps-computed-start-cmd": reportComputedStartCmd,
"--ps-computed-stop-timeout-seconds": reportComputedStopTimeoutSeconds,
"--ps-dockerfile-start-cmd": reportDockerfileStartCmd,
"--ps-global-procfile-path": reportGlobalProcfilePath,
"--ps-global-restart-policy": reportGlobalRestartPolicy,
"--ps-global-skip-deploy": reportGlobalSkipDeploy,
"--ps-global-stop-timeout-seconds": reportGlobalStopTimeoutSeconds,
"--ps-procfile-path": reportProcfilePath,
"--ps-restart-policy": reportRestartPolicy,
"--ps-skip-deploy": reportSkipDeploy,
"--ps-start-cmd": reportStartCmd,
"--ps-stop-timeout-seconds": reportStopTimeoutSeconds,
"--restore": reportRestore,
"--running": reportRunningState,
}
extraFlags := addStatusFlags(appName, infoFlag)

View File

@@ -1,6 +1,6 @@
module github.com/dokku/dokku/plugins/registry
go 1.26.2
go 1.27.1
require (
github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000

View File

@@ -1,6 +1,6 @@
module github.com/dokku/dokku/plugins/repo
go 1.26.2
go 1.27.1
require (
github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000

View File

@@ -2,25 +2,38 @@ package resource
import (
"fmt"
"strings"
"github.com/dokku/dokku/plugins/common"
)
func addMemorySuffixForDocker(key string, value string) string {
if key == "memory" {
hasSuffix := false
suffixes := []string{"b", "k", "m", "g", "KB", "MB", "GB", "B"}
for _, suffix := range suffixes {
if strings.HasSuffix(value, suffix) {
hasSuffix = true
}
// validateResourceValue returns an error if the value is not valid for the given resource key
func validateResourceValue(key string, value string) error {
switch key {
case "memory":
if !common.IsValidMemoryValue(value) {
return fmt.Errorf("Invalid memory value '%s': must be a number with an optional unit suffix of b, k, m, g, t or p", value)
}
if !hasSuffix {
value = value + "m"
case "memory-swap":
if value != "-1" && !common.IsValidMemoryValue(value) {
return fmt.Errorf("Invalid memory-swap value '%s': must be -1 or a number with an optional unit suffix of b, k, m, g, t or p", value)
}
}
return value
return nil
}
// formatResourceValueForDocker validates a resource value and formats it for use as a docker flag value.
// Memory values without a unit default to megabytes
func formatResourceValueForDocker(key string, value string) (string, error) {
if err := validateResourceValue(key, value); err != nil {
return "", err
}
if key == "memory" && common.IsUnitlessMemoryValue(value) {
value = value + "m"
}
return value, nil
}
func clearByResourceType(appName string, processType string, resourceType string) {
@@ -88,6 +101,16 @@ func setResourceType(appName string, processType string, r Resource, resourceTyp
return nil
}
for key, value := range resources {
if value == "" || value == "clear" {
continue
}
if err := validateResourceValue(key, value); err != nil {
return err
}
}
noun := "limits"
if resourceType == "reserve" {
noun = "reservation"

View File

@@ -0,0 +1,55 @@
package resource
import (
"testing"
)
func TestFormatResourceValueForDocker(t *testing.T) {
testCases := []struct {
name string
key string
value string
expected string
wantErr bool
}{
{name: "unitless memory defaults to megabytes", key: "memory", value: "100", expected: "100m"},
{name: "unitless decimal memory defaults to megabytes", key: "memory", value: "1.5", expected: "1.5m"},
{name: "lowercase memory unit", key: "memory", value: "512m", expected: "512m"},
{name: "uppercase megabyte unit", key: "memory", value: "512M", expected: "512M"},
{name: "uppercase gigabyte unit", key: "memory", value: "1G", expected: "1G"},
{name: "uppercase kilobyte unit", key: "memory", value: "1024K", expected: "1024K"},
{name: "terabyte unit", key: "memory", value: "1t", expected: "1t"},
{name: "two letter unit", key: "memory", value: "512MB", expected: "512MB"},
{name: "binary unit", key: "memory", value: "1GiB", expected: "1GiB"},
{name: "byte unit", key: "memory", value: "100b", expected: "100b"},
{name: "memory rejects negative values", key: "memory", value: "-1", wantErr: true},
{name: "memory rejects extra arguments", key: "memory", value: "100G --foo", wantErr: true},
{name: "memory rejects invalid units", key: "memory", value: "1Gm", wantErr: true},
{name: "unlimited memory-swap", key: "memory-swap", value: "-1", expected: "-1"},
{name: "unitless memory-swap stays in bytes", key: "memory-swap", value: "512", expected: "512"},
{name: "uppercase memory-swap unit", key: "memory-swap", value: "2G", expected: "2G"},
{name: "memory-swap rejects invalid units", key: "memory-swap", value: "1x", wantErr: true},
{name: "memory-swap rejects other negative values", key: "memory-swap", value: "-2", wantErr: true},
{name: "other keys are passed through", key: "cpus", value: "1.5", expected: "1.5"},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
value, err := formatResourceValueForDocker(testCase.key, testCase.value)
if testCase.wantErr {
if err == nil {
t.Fatalf("expected an error for %s=%s, got %s", testCase.key, testCase.value, value)
}
return
}
if err != nil {
t.Fatalf("unexpected error for %s=%s: %v", testCase.key, testCase.value, err)
}
if value != testCase.expected {
t.Fatalf("expected %s, got %s", testCase.expected, value)
}
})
}
}

View File

@@ -1,6 +1,6 @@
module github.com/dokku/dokku/plugins/resource
go 1.26.2
go 1.27.1
require (
github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000

View File

@@ -71,22 +71,30 @@ func TriggerDockerArgsProcessDeploy(appName string, processType string) error {
}
}
var args strings.Builder
for key, value := range limits {
if value == "" {
continue
}
value = addMemorySuffixForDocker(key, value)
fmt.Printf(" --%s=%s ", key, value)
value, err := formatResourceValueForDocker(key, value)
if err != nil {
return fmt.Errorf("Unable to apply resource limits for %s: %w", appName, err)
}
fmt.Fprintf(&args, " --%s=%s ", key, value)
}
for key, value := range reservations {
if value == "" {
continue
}
value = addMemorySuffixForDocker(key, value)
fmt.Printf(" --%s-reservation=%s ", key, value)
value, err := formatResourceValueForDocker(key, value)
if err != nil {
return fmt.Errorf("Unable to apply resource reservations for %s: %w", appName, err)
}
fmt.Fprintf(&args, " --%s-reservation=%s ", key, value)
}
fmt.Print(args.String())
fmt.Print(string(stdin))
return nil
}
@@ -136,14 +144,19 @@ func TriggerDockerArgsProcessBuild(appName string, builderType string) error {
limits[flagName] = value
}
var args strings.Builder
for key, value := range limits {
if value == "" {
continue
}
value = addMemorySuffixForDocker(key, value)
fmt.Printf(" --%s=%s ", key, value)
value, err := formatResourceValueForDocker(key, value)
if err != nil {
return fmt.Errorf("Unable to apply build resource limits for %s: %w", appName, err)
}
fmt.Fprintf(&args, " --%s=%s ", key, value)
}
fmt.Print(args.String())
fmt.Print(string(stdin))
return nil
}

View File

@@ -1,6 +1,6 @@
module github.com/dokku/dokku/plugins/scheduler-docker-local
go 1.26.2
go 1.27.1
require (
github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000

View File

@@ -1950,7 +1950,7 @@ func getProcessResources(appName string, processType string) (ProcessResourcesMa
if err != nil {
return ProcessResourcesMap{}, fmt.Errorf("Error parsing memory limit: %w", err)
}
if quantity != "0Mi" {
if quantity != "0" {
processResources.Limits.Memory = quantity
} else {
processResources.Limits.Memory = ""
@@ -1981,7 +1981,7 @@ func getProcessResources(appName string, processType string) (ProcessResourcesMa
if err != nil {
return ProcessResourcesMap{}, fmt.Errorf("Error parsing memory request: %w", err)
}
if quantity != "0Mi" {
if quantity != "0" {
processResources.Requests.Memory = quantity
} else {
processResources.Requests.Memory = ""
@@ -2724,17 +2724,14 @@ func cronIDLabelValue(cronID string) string {
return hex.EncodeToString(sum[:])
}
// parseMemoryQuantity parses a string into a valid memory quantity
// parseMemoryQuantity parses a docker-compatible memory value into a binary memory quantity
func parseMemoryQuantity(input string) (string, error) {
if _, err := strconv.ParseInt(input, 10, 64); err == nil {
input = fmt.Sprintf("%sMi", input)
}
quantity, err := resource.ParseQuantity(input)
bytes, err := common.ParseMemoryBytes(input)
if err != nil {
return "", err
}
return quantity.String(), nil
return resource.NewQuantity(bytes, resource.BinarySI).String(), nil
}
func uninstallHelperCommands(ctx context.Context) error {

View File

@@ -487,6 +487,47 @@ func TestDomainSlug(t *testing.T) {
}
}
func TestParseMemoryQuantity(t *testing.T) {
cases := []struct {
name string
input string
want string
wantErr bool
}{
{name: "unitless value defaults to megabytes", input: "512", want: "512Mi"},
{name: "lowercase megabytes are not millibytes", input: "256m", want: "256Mi"},
{name: "uppercase gigabytes are binary", input: "1G", want: "1Gi"},
{name: "lowercase gigabytes", input: "1g", want: "1Gi"},
{name: "kubernetes binary unit", input: "1Gi", want: "1Gi"},
{name: "two letter unit", input: "512MB", want: "512Mi"},
{name: "decimal value", input: "1.5g", want: "1536Mi"},
{name: "bytes", input: "100b", want: "100"},
{name: "zero", input: "0Mi", want: "0"},
{name: "invalid unit", input: "1x", wantErr: true},
{name: "kubernetes exponent", input: "1e9", wantErr: true},
}
for _, tc := range cases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
got, err := parseMemoryQuantity(tc.input)
if tc.wantErr {
if err == nil {
t.Fatalf("parseMemoryQuantity(%q) = %q, want error", tc.input, got)
}
return
}
if err != nil {
t.Fatalf("parseMemoryQuantity(%q) unexpected error: %v", tc.input, err)
}
if got != tc.want {
t.Errorf("parseMemoryQuantity(%q) = %q, want %q", tc.input, got, tc.want)
}
})
}
}
func TestDomainSlugDistinguishesWildcardFromApex(t *testing.T) {
// A kubernetes wildcard host matches exactly one label, so *.example.com does not
// cover example.com and both are commonly added to the same app. The generated

View File

@@ -1,6 +1,6 @@
module github.com/dokku/dokku/plugins/scheduler-k3s
go 1.26.2
go 1.27.1
require (
github.com/Masterminds/semver/v3 v3.5.0
@@ -16,7 +16,7 @@ require (
github.com/dokku/dokku/plugins/registry v0.0.0-00010101000000-000000000000
github.com/dokku/dokku/plugins/storage v0.0.0-00010101000000-000000000000
github.com/fatih/color v1.19.0
github.com/fluxcd/pkg/kustomize v1.41.0
github.com/fluxcd/pkg/kustomize v1.43.0
github.com/go-openapi/jsonpointer v1.0.2
github.com/go-resty/resty/v2 v2.17.2
github.com/gosimple/slug v1.15.0
@@ -26,11 +26,11 @@ require (
github.com/onsi/gomega v1.44.0
github.com/ryanuber/columnize v2.1.2+incompatible
github.com/spf13/pflag v1.0.10
github.com/traefik/traefik/v2 v2.11.58
github.com/traefik/traefik/v2 v2.11.59
golang.org/x/sync v0.24.0
gopkg.in/yaml.v2 v2.4.0
gopkg.in/yaml.v3 v3.0.1
helm.sh/helm/v3 v3.22.0
helm.sh/helm/v3 v3.22.1
k8s.io/api v0.37.1
k8s.io/apimachinery v0.37.1
k8s.io/client-go v0.37.1
@@ -153,7 +153,7 @@ require (
go.yaml.in/yaml/v3 v3.0.5 // indirect
golang.org/x/crypto v0.58.0 // indirect
golang.org/x/mod v0.41.0 // indirect
golang.org/x/net v0.60.0 // indirect
golang.org/x/net v0.61.0 // indirect
golang.org/x/oauth2 v0.37.0 // indirect
golang.org/x/sys v0.49.0 // indirect
golang.org/x/term v0.47.0 // indirect
@@ -164,15 +164,15 @@ require (
google.golang.org/protobuf v1.36.12 // indirect
gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
k8s.io/apiextensions-apiserver v0.37.0 // indirect
k8s.io/apiserver v0.37.0 // indirect
k8s.io/apiextensions-apiserver v0.37.1 // indirect
k8s.io/apiserver v0.37.1 // indirect
k8s.io/cli-runtime v0.37.1 // indirect
k8s.io/component-base v0.37.1 // indirect
k8s.io/klog/v2 v2.140.0 // indirect
k8s.io/kube-openapi v0.0.0-20260821135717-be32def86098 // indirect
k8s.io/streaming v0.37.1 // indirect
oras.land/oras-go/v2 v2.6.2 // indirect
sigs.k8s.io/controller-runtime v0.25.0 // indirect
sigs.k8s.io/controller-runtime v0.25.2 // indirect
sigs.k8s.io/gateway-api v1.6.0 // indirect
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect
sigs.k8s.io/kustomize/kyaml v0.21.2 // indirect

View File

@@ -35,8 +35,6 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
github.com/bshuster-repo/logrus-logstash-hook v1.1.0 h1:o2FzZifLg+z/DN1OFmzTWzZZx/roaqt8IPZCIVco8r4=
github.com/bshuster-repo/logrus-logstash-hook v1.1.0/go.mod h1:Q2aXOe7rNuPgbBtPCOzYyWDvKX7+FpxE5sRdvcPoui0=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
@@ -62,8 +60,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/distribution/distribution/v3 v3.1.1 h1:KUbk7C8CfaLXy8kbf/hGq9cad/wCoLB6dbWH6DMbmX0=
github.com/distribution/distribution/v3 v3.1.1/go.mod h1:d7lXwZpph0bVcOj4Aqn0nMrWHIwRQGdiV5TLeI+/w6Y=
github.com/distribution/distribution/v3 v3.1.2 h1:/Bv2YIqqSR00HiO49FT93hovy6r9IlrzwUDsJjCN5qg=
github.com/distribution/distribution/v3 v3.1.2/go.mod h1:Oz0Drs2Tx3iTXzK3DhUD4otfTfqlCxlWVC7QJeXWBP0=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
@@ -72,8 +70,8 @@ github.com/docker/docker-credential-helpers v0.9.5 h1:EFNN8DHvaiK8zVqFA2DT6BjXE0
github.com/docker/docker-credential-helpers v0.9.5/go.mod h1:v1S+hepowrQXITkEfw6o4+BMbGot02wiKpzWhGUZK6c=
github.com/docker/go-events v0.0.0-20250808211157-605354379745 h1:yOn6Ze6IbYI/KAw2lw/83ELYvZh6hvsygTVkD0dzMC4=
github.com/docker/go-events v0.0.0-20250808211157-605354379745/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8=
github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw=
github.com/docker/go-metrics v0.1.0 h1:r76KPNpstz+IvQKSWpYegSkkyzex0V3A1ZGVx6bhGlY=
github.com/docker/go-metrics v0.1.0/go.mod h1:PciI3sONtB051kXALN1JoIlpcu54E1FuPh+4DuqEzyw=
github.com/dustin/go-jsonpointer v0.0.0-20160814072949-ba0abeacc3dc h1:tP7tkU+vIsEOKiK+l/NSLN4uUtkyuxc6hgYpQeCWAeI=
github.com/dustin/go-jsonpointer v0.0.0-20160814072949-ba0abeacc3dc/go.mod h1:ORH5Qp2bskd9NzSfKqAF7tKfONsEkCarTE5ESr/RVBw=
github.com/dustin/gojson v0.0.0-20160307161227-2e71ec9dd5ad h1:Qk76DOWdOp+GlyDKBAG3Klr9cn7N+LcYc82AZ2S7+cA=
@@ -94,8 +92,8 @@ github.com/fatih/color v1.19.0 h1:Zp3PiM21/9Ld6FzSKyL5c/BULoe/ONr9KlbYVOfG8+w=
github.com/fatih/color v1.19.0/go.mod h1:zNk67I0ZUT1bEGsSGyCZYZNrHuTkJJB+r6Q9VuMi0LE=
github.com/felixge/httpsnoop v1.1.0 h1:3YtUj32ZZkqZtt3sZZsClsymw/QDuVfpNhoA31zeORc=
github.com/felixge/httpsnoop v1.1.0/go.mod h1:Zqxgdd+1Rkcz8euOqdr7lqgCRJztwr5hp9vDSi5UZCE=
github.com/fluxcd/pkg/kustomize v1.41.0 h1:ShntVMiX8ZvvQCM3MNIaxZbYT4T4ehV2wIWC73rzBrg=
github.com/fluxcd/pkg/kustomize v1.41.0/go.mod h1:fjTYKu3tdKid84b4nEeSc+9DVmRgtxcx8UtyhS0yzOw=
github.com/fluxcd/pkg/kustomize v1.43.0 h1:WNa1+KaoNvR1GNafPP6lCj+PZssOWycYIJBE/3h+yxI=
github.com/fluxcd/pkg/kustomize v1.43.0/go.mod h1:V/hHWuJyD0aqwA9tZJC6jPQHUuOJYTn0kaY3V8FGkiQ=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/foxcpp/go-mockdns v1.2.0 h1:omK3OrHRD1IWJz1FuFBCFquhXslXoF17OvBS6JPzZF0=
@@ -359,8 +357,8 @@ github.com/tailscale/hujson v0.0.0-20250605163823-992244df8c5a h1:a6TNDN9CgG+cYj
github.com/tailscale/hujson v0.0.0-20250605163823-992244df8c5a/go.mod h1:EbW0wDK/qEUYI0A5bqq0C2kF8JTQwWONmGDBbzsxxHo=
github.com/traefik/paerser v0.2.2 h1:cpzW/ZrQrBh3mdwD/jnp6aXASiUFKOVr6ldP+keJTcQ=
github.com/traefik/paerser v0.2.2/go.mod h1:7BBDd4FANoVgaTZG+yh26jI6CA2nds7D/4VTEdIsh24=
github.com/traefik/traefik/v2 v2.11.58 h1:dz6rq+1kp43XHjz3Nal0uJenfxuvKpCP2dYPO8GbVnE=
github.com/traefik/traefik/v2 v2.11.58/go.mod h1:Q9mczqrf6K8G9BGkEHvX13+8mXWi1jvrMYyNrFIi5Ro=
github.com/traefik/traefik/v2 v2.11.59 h1:vUyoFQM7a7rYRSDSfwAvvQMvoOrRg1DK7UR+ebnHz3U=
github.com/traefik/traefik/v2 v2.11.59/go.mod h1:tnle1HBnPg47Bw2q9NDegW2P61ULztKQBw9AR/NMDMc=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ=
@@ -375,10 +373,10 @@ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.71.0 h1:3g7B90U
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.71.0/go.mod h1:Ef8SuTh59BT7+ofpDxN9z+yOlc4t2GjLmKDgYNJL/NU=
go.opentelemetry.io/otel v1.46.0 h1:FHt5/CDyVxi/8IM1CH7VE/rRgq3kLHa2mSTVMO8AWyc=
go.opentelemetry.io/otel v1.46.0/go.mod h1:Gj3SEScelsNC45tp4nSxRYlS+f5iez7W8XPMCt905kE=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.19.0 h1:Dn8rkudDzY6KV9dr/D/bTUuWgqDf9xe0rr4G2elrn0Y=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.19.0/go.mod h1:gMk9F0xDgyN9M/3Ed5Y1wKcx/9mlU91NXY2SNq7RQuU=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.19.0 h1:HIBTQ3VO5aupLKjC90JgMqpezVXwFuq6Ryjn0/izoag=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.19.0/go.mod h1:ji9vId85hMxqfvICA0Jt8JqEdrXaAkcpkI9HPXya0ro=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.21.0 h1:WseeVYf5dJZTsyPiyW5L14k5qsSibqXAMTSiFEDiWr0=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.21.0/go.mod h1:SiLZnQS6Qk2eCpvr2CH/XMAOa64TWGXxEZJZCpD2Lmc=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.21.0 h1:fvNHGyo3CdRv/DQveXqhqBxnKTDyRaC5sMSQxilX/A0=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.21.0/go.mod h1:zyGrjRKL2B/6+Jc/m4/otPoZqV2MY9ZjC/aBraRO7zc=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.46.0 h1:qkDYCAFiZXLcs1L4aY+tP2wguQ4kURANqHOQMA2et2s=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.46.0/go.mod h1:tkipS4DRzmpAmvg+Gw4++O1IdDq6TVDnvnYU6cmbQVs=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.46.0 h1:AP23h/mFgb/lc7tdck1Kfn9qxsM8TAeNPCU5C3pzaps=
@@ -387,24 +385,24 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.46.0 h1:OFnwLJr+pF3iHrlGSzb
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.46.0/go.mod h1:716wFneO0ov19A2beH5hjfh9AK5z/VWNAtDijp1Y0/g=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.46.0 h1:w53CDeOA/Kurp7yRsegSr6pbbr759dOvJ+yNmWM6Hxs=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.46.0/go.mod h1:BOmGMCbAtvcJiSJ+hLuhgPLdDbimnraSl8irz3iY8sY=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 h1:3iZJKlCZufyRzPzlQhUIWVmfltrXuGyfjREgGP3UUjc=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0/go.mod h1:/G+nUPfhq2e+qiXMGxMwumDrP5jtzU+mWN7/sjT2rak=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.45.0 h1:QBajQ2SrwQijzHyZbQlPsuIzpl/ll8DY6wPWsajeGcI=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.45.0/go.mod h1:08ZQLjrPLQ6R4kAXvuOvODEer5Yh4CoFvll5qB2BCI8=
go.opentelemetry.io/otel/exporters/prometheus v0.65.0 h1:jOveH/b4lU9HT7y+Gfamf18BqlOuz2PWEvs8yM7Q6XE=
go.opentelemetry.io/otel/exporters/prometheus v0.65.0/go.mod h1:i1P8pcumauPtUI4YNopea1dhzEMuEqWP1xoUZDylLHo=
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.19.0 h1:GJkybS+crDMdExT/BUNCEgfrmfboztcS6PhvSo88HKM=
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.19.0/go.mod h1:NuAyxRYIG2lKX3YQkB+83StTxM7s52PUUkRRiC0wnYI=
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.21.0 h1:2lpf4hnrasYIsUyEXwnTZq5lsxrMm4T2Bwb06IctAZQ=
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.21.0/go.mod h1:YWOW6h7jwApz9Pl76ie/izUsSPj0s2MdIlpqbPqaf3U=
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.43.0 h1:TC+BewnDpeiAmcscXbGMfxkO+mwYUwE/VySwvw88PfA=
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.43.0/go.mod h1:J/ZyF4vfPwsSr9xJSPyQ4LqtcTPULFR64KwTikGLe+A=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.43.0 h1:mS47AX77OtFfKG4vtp+84kuGSFZHTyxtXIN269vChY0=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.43.0/go.mod h1:PJnsC41lAGncJlPUniSwM81gc80GkgWJWr3cu2nKEtU=
go.opentelemetry.io/otel/log v0.19.0 h1:KUZs/GOsw79TBBMfDWsXS+KZ4g2Ckzksd1ymzsIEbo4=
go.opentelemetry.io/otel/log v0.19.0/go.mod h1:5DQYeGmxVIr4n0/BcJvF4upsraHjg6vudJJpnkL6Ipk=
go.opentelemetry.io/otel/log v0.21.0 h1:SLsVDGmtyBrdw8/a2Z0bOIxou/+bN4z56GebH7T0LvA=
go.opentelemetry.io/otel/log v0.21.0/go.mod h1:iReetQrZL9Wyg84cCkOoCmqDHS5RCFfyxC7J+r8fn8g=
go.opentelemetry.io/otel/metric v1.46.0 h1:yBnkXvgV7AXFILZc5K6IZe/CBFF3OS7BJ8ov6/lj0K8=
go.opentelemetry.io/otel/metric v1.46.0/go.mod h1:iPmdWqifKUdzziPkvvzIJXITl56fQx2mGM/DHLB3/2o=
go.opentelemetry.io/otel/sdk v1.46.0 h1:h5CNQQjEbuQXY/JfZtgt3i7HVFV3aHPO2OAwO2eTYPI=
go.opentelemetry.io/otel/sdk v1.46.0/go.mod h1:GAERFXFt5SYCEB+YiKUbMBeza6UaDH7GmGOZEfh2gSM=
go.opentelemetry.io/otel/sdk/log v0.19.0 h1:scYVLqT22D2gqXItnWiocLUKGH9yvkkeql5dBDiXyko=
go.opentelemetry.io/otel/sdk/log v0.19.0/go.mod h1:vFBowwXGLlW9AvpuF7bMgnNI95LiW10szrOdvzBHlAg=
go.opentelemetry.io/otel/sdk/log v0.21.0 h1:QsE7XSR0ktQdKmRKGnR+f1ObGF32WG+7MER/P9KgmYc=
go.opentelemetry.io/otel/sdk/log v0.21.0/go.mod h1:m9mApjCoD2/1QuKCAptjv+BrG9WKOvQLVdNx+iBldTo=
go.opentelemetry.io/otel/sdk/metric v1.46.0 h1:0piZ26EG4RBfebb2jhDH6ERCYHoVWduc3kLgPCwSnSE=
go.opentelemetry.io/otel/sdk/metric v1.46.0/go.mod h1:I1PbKrdVc8Qu8HYVDNtqVIwLwjNrhsV/uFuxfwg8mO4=
go.opentelemetry.io/otel/trace v1.46.0 h1:OULy7ccdJnZtJ0UDYFOIGaCmiWzJ8Vi2G/Rsu60qs1c=
@@ -428,8 +426,8 @@ golang.org/x/crypto v0.58.0 h1:COkYLr4k7nDI4r6QtMML2AfzeIswWHAJthLS6K/M/54=
golang.org/x/crypto v0.58.0/go.mod h1:Xh+kl5A+M0gMiWDytH2Hhr5Z7WbNCpv/eB/EFgfSk+w=
golang.org/x/mod v0.41.0 h1:qJmnOUb4YB+FsEuM3HcWucdZASCPGhsX6uljO6pog0c=
golang.org/x/mod v0.41.0/go.mod h1:Ek9pY8RKWXwsWvd3rQiHYtMqkjSUV+s1Rj7j4H5Ur6o=
golang.org/x/net v0.60.0 h1:79p50tfZlm0J9YfoDsSi639qSXNGVwEzOPLCxM2FsYU=
golang.org/x/net v0.60.0/go.mod h1:2DA/G1UfVbCpQPeWTmMPGY7Cs2PkBkwu743bVX5PIVg=
golang.org/x/net v0.61.0 h1:RR+6j/BTBCrggOLugxa+66R8FvoN6MHlzDlZIbN9YFw=
golang.org/x/net v0.61.0/go.mod h1:WgDCOTH8iwtB66T4/GfI94AHo/hhdb7Hah9NDseQfiI=
golang.org/x/oauth2 v0.37.0 h1:JUlcxA8oAtauLfiH8FX2/FkAWHAdi0QtGCGc+hofE98=
golang.org/x/oauth2 v0.37.0/go.mod h1:IxwZNxUULJmpBFf9K/9NTMSIfZZuvuTy1gGxhigP/58=
golang.org/x/sync v0.24.0 h1:iqiDrGoDgyuvAKrhLQthUEzU/R378N78gXbBjxed7oA=
@@ -468,16 +466,16 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
helm.sh/helm/v3 v3.22.0 h1:n1if5iQgHYsujPAcO5oonH/KiSNUmqmUF0iGVjSF3AU=
helm.sh/helm/v3 v3.22.0/go.mod h1:EVl/147Ai2z13JOykbO1Jn9HRaXyU7uHlbAJmODq/Fg=
helm.sh/helm/v3 v3.22.1 h1:uo2SouzAxMkKZTNzZ1lLP/c/Bu7xfUJKYDaYMxMHvk8=
helm.sh/helm/v3 v3.22.1/go.mod h1:FNQoawxnIIReGrTytJc55tKakylfpaC3pGf64BGo1rI=
k8s.io/api v0.37.1 h1:l6N77U7tjwB5L056bgrBTJIEdevac/naBZ3iSvDNfpM=
k8s.io/api v0.37.1/go.mod h1:zSlbB1YpJ1YQlFVQy20UYll81UJSJJUMLhkhvg6Z78M=
k8s.io/apiextensions-apiserver v0.37.0 h1:zRMQ3+/LIE5oZ0tVvXwYHC+dIkSP5cjNWju7AZU1LOI=
k8s.io/apiextensions-apiserver v0.37.0/go.mod h1:HU0PfSBwchHL5iDau6jjt9zU6ryWkDDlaVUiq91NK80=
k8s.io/apiextensions-apiserver v0.37.1 h1:7fIQG8eThDSTVYBWg/DOpI8v5wYfKCo0N8/TDMjj+zY=
k8s.io/apiextensions-apiserver v0.37.1/go.mod h1:1Q3ujWwHgnhBoGsdmGORflwK1sDFmuaqH1OsMDWk2Gs=
k8s.io/apimachinery v0.37.1 h1:hGCYyvKHCwtwMitj2vU4vYx0Z16N9GyZk9BBnz0wDAE=
k8s.io/apimachinery v0.37.1/go.mod h1:jF84AyUi/IRIXRot5f+lm6MpxoWI+F1XgjaMmwCdTFw=
k8s.io/apiserver v0.37.0 h1:TXg7OxsOWrAH8J4Zi/gBAZuMw1Dfdd+6cca2h4qjRqo=
k8s.io/apiserver v0.37.0/go.mod h1:OddHDF4gy9qyIb8o/3+qaeP6S0vEObWLgOygVqXksv0=
k8s.io/apiserver v0.37.1 h1:dUsNwjsvItyVKNpC1N0AhQ0OBSiUJKfWz004vPifOe0=
k8s.io/apiserver v0.37.1/go.mod h1:EWXW6PntGfOC2uD9GGVobnOExgFoX1z0hZo7f7Rs7Ng=
k8s.io/cli-runtime v0.37.1 h1:3mir5bM4XjMJHW3SMRk++3Ylf4YQne0XFFsW+IGT85U=
k8s.io/cli-runtime v0.37.1/go.mod h1:g3VQOm71f//aNbp79g0az9jBRTrvPjAHz7WxVysbZ4M=
k8s.io/client-go v0.37.1 h1:QTv/5ha4jAHtW9qxxVBkQVFBRDb4jHfFopQqqMdc+wM=
@@ -500,8 +498,8 @@ mvdan.cc/sh/v3 v3.14.1 h1:bXkhQWNHCs0KZEChF8hYS6FC+T2N9mUZLbQv9blditI=
mvdan.cc/sh/v3 v3.14.1/go.mod h1:syYCoFET8w9tvevxiXUtY8/ICrU+l26jHmhJDra3Vwo=
oras.land/oras-go/v2 v2.6.2 h1:N04RXngAp1LJKTG6ifz3xHPipasEkWr+hFmInja5YKo=
oras.land/oras-go/v2 v2.6.2/go.mod h1:PlTtg4JTDJkDe8yVHpM2wz7/YDc00GVas+i4jAW2TZ4=
sigs.k8s.io/controller-runtime v0.25.0 h1:44KgRUPew331KSJpNu8zJow3iTR5W0p/SfrHdw3lV40=
sigs.k8s.io/controller-runtime v0.25.0/go.mod h1:4QqLdT6z/L6Olj8JJCtvztid4/fnIiYsfaTFScegctc=
sigs.k8s.io/controller-runtime v0.25.2 h1:bEkK3PVOIVK9X8QWLGVhJgmFc++47vfT6wakSzAOLsQ=
sigs.k8s.io/controller-runtime v0.25.2/go.mod h1:4QqLdT6z/L6Olj8JJCtvztid4/fnIiYsfaTFScegctc=
sigs.k8s.io/gateway-api v1.6.0 h1:735YBRj5NXFrOGX0GoSjwzUIzbz8kiEOfADsqHFmHgE=
sigs.k8s.io/gateway-api v1.6.0/go.mod h1:FVfx3t389ybeXOqvDghLbdvJdSCfI/PReqCUI3lu3mY=
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg=

View File

@@ -41,11 +41,11 @@ func TestGetLowestNodeVersion(t *testing.T) {
}
cases := []struct {
name string
nodes []*corev1.Node
selector string
want string
wantErr string
name string
nodes []*corev1.Node
selector string
want string
wantErr string
}{
{
name: "single control-plane node returns its kubelet version",

View File

@@ -88,7 +88,7 @@ func TestMigrateChartPropertiesToMapFormatPreservesExistingNonOverlappingKeys(t
setupChartMigrationTest(t)
Expect(common.PropertyMapWrite("scheduler-k3s", "--global", "chart-overrides.cert-manager", map[string]string{
"installCRDs": "true",
"installCRDs": "true",
"service.annotations.prometheus.io/scrape": "true",
})).To(Succeed())
Expect(common.PropertyWrite("scheduler-k3s", "--global", "chart.cert-manager.installCRDs", "false")).To(Succeed())
@@ -99,9 +99,9 @@ func TestMigrateChartPropertiesToMapFormatPreservesExistingNonOverlappingKeys(t
got, err := common.PropertyMapGet("scheduler-k3s", "--global", "chart-overrides.cert-manager")
Expect(err).NotTo(HaveOccurred())
Expect(got).To(Equal(map[string]string{
"installCRDs": "false",
"installCRDs": "false",
"service.annotations.prometheus.io/scrape": "true",
"version": "1.13.3",
"version": "1.13.3",
}))
}

View File

@@ -1,6 +1,6 @@
module github.com/dokku/dokku/plugins/scheduler
go 1.26.2
go 1.27.1
require (
github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000

View File

@@ -1,6 +1,6 @@
module github.com/dokku/dokku/plugins/storage
go 1.26.2
go 1.27.1
require (
github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000

View File

@@ -1 +1 @@
FROM traefik:v3.7.14
FROM traefik:v3.7.15

View File

@@ -1,6 +1,6 @@
module github.com/dokku/dokku/plugins/traefik-vhosts
go 1.26.2
go 1.27.1
require (
github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000

View File

@@ -188,6 +188,7 @@ go-tests:
@$(MAKE) go-test-plugin PLUGIN_NAME=nginx-vhosts
@$(MAKE) go-test-plugin PLUGIN_NAME=ps
@$(MAKE) go-test-plugin PLUGIN_NAME=registry
@$(MAKE) go-test-plugin PLUGIN_NAME=resource
@$(MAKE) go-test-plugin PLUGIN_NAME=buildpacks
@$(MAKE) go-test-plugin PLUGIN_NAME=scheduler-k3s
@$(MAKE) go-test-plugin PLUGIN_NAME=storage

View File

@@ -1,4 +1,4 @@
FROM golang:1.27.1
FROM golang:1.27.2
EXPOSE 3000/tcp

View File

@@ -1,4 +1,4 @@
FROM golang:1.27.1
FROM golang:1.27.2
EXPOSE 3000/tcp

View File

@@ -1,4 +1,4 @@
FROM golang:1.27.1
FROM golang:1.27.2
RUN mkdir /app
WORKDIR /app

View File

@@ -1,6 +1,6 @@
module github.com/dokku/dokko/tests/apps/gorpc
go 1.26.2
go 1.27.1
require (
golang.org/x/net v0.58.0 // indirect

View File

@@ -11,7 +11,7 @@
"license": "ISC",
"dependencies": {
"bootstrap": "^5.3.8",
"sass": "^1.105.1"
"sass": "^1.105.2"
},
"engines": {
"node": "24.x.x",
@@ -432,9 +432,9 @@
}
},
"node_modules/sass": {
"version": "1.105.1",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.105.1.tgz",
"integrity": "sha512-1CnAWPyrrnVQzXGB/DUep1vYCKCm1CIBr+YxjjiW6wk9qtzemnGP4qicH56T2F9S4Hjtv/Ne3jDz8JqfdDU4oA==",
"version": "1.105.2",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.105.2.tgz",
"integrity": "sha512-KxW6ZKZiBKWK3ziQ4YZ3cpqo8/1TlHXE8t9nBNvGDZFoBFbk2MD7RacxYFs8zy8hzeFwpFYkVyAhboi47uYPEQ==",
"license": "MIT",
"dependencies": {
"chokidar": "^5.0.0",

View File

@@ -2,7 +2,7 @@
"author": "Al Johri",
"dependencies": {
"bootstrap": "^5.3.8",
"sass": "^1.105.1"
"sass": "^1.105.2"
},
"description": "Test application for heroku multi buildpack.",
"engines": {

View File

@@ -1,3 +1,3 @@
module dokku.me/web
go 1.26.2
go 1.27.1

View File

@@ -1,4 +1,4 @@
FROM golang:1.27.1
FROM golang:1.27.2
ADD . /go/src/github.com/dokku/apps/web
WORKDIR /go/src/github.com/dokku/apps/web

View File

@@ -1,3 +1,3 @@
module dokku.me/web
go 1.26.2
go 1.27.1

View File

@@ -1,4 +1,4 @@
FROM golang:1.27.1
FROM golang:1.27.2
ADD . /go/src/github.com/dokku/apps/web
WORKDIR /go/src/github.com/dokku/apps/web

View File

@@ -1,3 +1,3 @@
module dokku.me/web
go 1.26.2
go 1.27.1

View File

@@ -59,6 +59,22 @@ teardown() {
echo "status: $status"
assert_output "536870912"
run /bin/bash -c "dokku resource:limit --memory 1G $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku ps:rebuild $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
CID=$(<$DOKKU_ROOT/$TEST_APP/CONTAINER.web.1)
run /bin/bash -c "docker inspect --format '{{.HostConfig.Memory}}' $CID"
echo "output: $output"
echo "status: $status"
assert_output "1073741824"
run /bin/bash -c "dokku resource:limit --memory 512 $TEST_APP"
echo "output: $output"
echo "status: $status"

View File

@@ -131,3 +131,80 @@ teardown() {
echo "status: $status"
assert_failure
}
@test "(resource) resource:limit uppercase memory units" {
run /bin/bash -c "dokku resource:limit --memory 1G --memory-swap 2G $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku resource:reserve --memory 512M $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
run_plugin_script resource docker-args-process-deploy "$TEST_APP" herokuish "dokku/$TEST_APP:latest" web "< /dev/null"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "--memory=1G "
assert_output_contains "--memory-swap=2G "
assert_output_contains "--memory-reservation=512M "
assert_output_not_contains "1Gm"
assert_output_not_contains "512Mm"
run /bin/bash -c "dokku resource:limit --memory 1G --process-type build $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
run_plugn_trigger docker-args-process-build "$TEST_APP" herokuish
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "--memory=1G "
assert_output_not_contains "1Gm"
}
@test "(resource) resource:limit rejects invalid memory values" {
run /bin/bash -c "dokku resource:limit --memory '100G --foo' $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_failure
run /bin/bash -c "dokku resource:limit --memory 1x $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_failure
run /bin/bash -c "dokku resource:limit --memory-swap 1x $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_failure
run /bin/bash -c "dokku resource:reserve --memory 1Gm $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_failure
run /bin/bash -c "dokku resource:report --resource-_default_.limit.memory $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_failure
run /bin/bash -c "dokku resource:report --resource-_default_.reserve.memory $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_failure
run /bin/bash -c "dokku resource:limit --memory-swap -1 $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku resource:report --resource-_default_.limit.memory-swap $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "-1"
}