diff --git a/.drone.yml b/.drone.yml deleted file mode 100644 index 4f78db2..0000000 --- a/.drone.yml +++ /dev/null @@ -1,96 +0,0 @@ ---- -kind: pipeline -type: docker -name: lint - -platform: - os: linux - arch: arm64 - -steps: -- name: helm lint - pull: always - image: alpine:3.17 - commands: - - apk add --no-cache -X http://dl-cdn.alpinelinux.org/alpine/edge/testing helm - - helm lint - -- name: helm template - pull: always - image: alpine:3.17 - commands: - - apk add --no-cache -X http://dl-cdn.alpinelinux.org/alpine/edge/testing helm - - helm dependency update - - helm template --debug gitea-helm . - -- name: helm unittests - pull: always - image: alpine:3.17 - commands: - - apk add --no-cache -X http://dl-cdn.alpinelinux.org/alpine/edge/testing make helm git bash - - helm plugin install https://github.com/heyhabito/helm-unittest - - helm dependency update - - make unittests - -- name: verify readme - pull: always - image: alpine:3.17 - commands: - - apk add --no-cache -X http://dl-cdn.alpinelinux.org/alpine/edge/testing make npm git - - make readme - - git diff --exit-code --name-only README.md - -- name: discord - pull: always - image: appleboy/drone-discord:1.2.4 - environment: - DISCORD_WEBHOOK_ID: - from_secret: discord_webhook_id - DISCORD_WEBHOOK_TOKEN: - from_secret: discord_webhook_token - when: - status: - - changed - - failure - - ---- -kind: pipeline -type: docker -name: release-version - -platform: - os: linux - arch: arm64 - -trigger: - event: - - tag - -steps: -- name: generate-chart - pull: always - image: alpine:3.17 - commands: - - apk add --no-cache -X http://dl-cdn.alpinelinux.org/alpine/edge/testing helm - - apk add --no-cache curl - - helm dependency update - - helm package --version "${DRONE_TAG##v}" ./ - - mkdir gitea - - mv gitea*.tgz gitea/ - - curl -L -o gitea/index.yaml https://dl.gitea.io/charts/index.yaml - - helm repo index gitea/ --url https://dl.gitea.io/charts --merge gitea/index.yaml - -- name: upload-chart - pull: always - image: plugins/s3:latest - settings: - bucket: gitea-artifacts - endpoint: https://ams3.digitaloceanspaces.com - access_key: - from_secret: aws_access_key_id - secret_key: - from_secret: aws_secret_access_key - source: gitea/* - target: /charts - strip_prefix: gitea/ diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..8f5d808 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = false +insert_final_newline = true diff --git a/.forgejo/actions/setup-docker/action.yml b/.forgejo/actions/setup-docker/action.yml new file mode 100644 index 0000000..a8aa1fa --- /dev/null +++ b/.forgejo/actions/setup-docker/action.yml @@ -0,0 +1,26 @@ +# action.yml +name: setup-docker +description: 'setup docker' + +runs: + using: 'composite' + steps: + - shell: bash + name: create cache + run: | + install -m 0755 -d /etc/apt/keyrings + curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg + chmod a+r /etc/apt/keyrings/docker.gpg + echo \ + "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \ + $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \ + tee /etc/apt/sources.list.d/docker.list > /dev/null + apt-get update -qq + apt-get -q install -qq \ + containerd.io \ + docker-ce \ + docker-ce-cli \ + ; + + - shell: bash + run: docker info diff --git a/.forgejo/actions/setup-k3s/action.yml b/.forgejo/actions/setup-k3s/action.yml new file mode 100644 index 0000000..4c237b0 --- /dev/null +++ b/.forgejo/actions/setup-k3s/action.yml @@ -0,0 +1,25 @@ +# action.yml +name: setup-k3s +description: 'setup k3s' + +inputs: + version: + description: 'k3s version' + required: true + +runs: + using: 'composite' + steps: + - shell: bash + name: install k3s + run: | + curl -sfL https://get.k3s.io | INSTALL_K3S_VERSION=${INPUT_VERSION} K3S_KUBECONFIG_MODE=640 sh -s - server + echo "KUBECONFIG=/etc/rancher/k3s/k3s.yaml" >> $GITHUB_ENV + - shell: bash + name: check k3s + run: kubectl cluster-info + - shell: bash + name: wait for nodes ready + run: | + sleep 3 + kubectl wait --for=condition=Ready nodes --all --timeout=600s diff --git a/.forgejo/actions/setup-node/action.yml b/.forgejo/actions/setup-node/action.yml new file mode 100644 index 0000000..5ab39be --- /dev/null +++ b/.forgejo/actions/setup-node/action.yml @@ -0,0 +1,19 @@ +# action.yml +name: setup-node +description: 'setup node' + +runs: + using: 'composite' + steps: + - name: Setup pnpm + uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0 + with: + standalone: true + + - uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 + with: + node-version-file: .node-version + cache: 'pnpm' + + - shell: bash + run: pnpm install --frozen-lockfile diff --git a/.forgejo/actions/setup/action.yml b/.forgejo/actions/setup/action.yml new file mode 100644 index 0000000..fdc4d23 --- /dev/null +++ b/.forgejo/actions/setup/action.yml @@ -0,0 +1,27 @@ +# action.yml +name: setup +description: 'setup system' + +runs: + using: 'composite' + steps: + - shell: bash + name: create cache + run: | + mkdir -p /opt/hostedtoolcache + mkdir -p /srv/forgejo-renovate/.cache/act/tool_cache + - shell: bash + name: install deps + run: | + apt-get update -qq + apt-get -q install -qq \ + ca-certificates \ + curl \ + gnupg \ + make \ + python3 \ + python3-wheel \ + python3-venv \ + unzip \ + wget \ + ; diff --git a/.forgejo/renovate/k3s.json b/.forgejo/renovate/k3s.json new file mode 100644 index 0000000..edb593d --- /dev/null +++ b/.forgejo/renovate/k3s.json @@ -0,0 +1,57 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "packageRules": [ + { + "description": "Separate minor and patch updates for k3s", + "matchDatasources": ["github-releases"], + "matchPackageNames": ["k3s-io/k3s"], + "separateMultipleMinor": true, + "separateMinorPatch": true, + "branchTopic": "{{{depNameSanitized}}}{{#if isMinor}}-minor{{/if}}-{{{newMajor}}}{{#if isPatch}}.{{{newMinor}}}{{/if}}.x{{#if isLockfileUpdate}}-lockfile{{/if}}", + "commitMessageSuffix": "{{#if isMinor}}(minor){{/if}}{{#if isPatch}}(patch){{/if}}" + }, + { + "description": "No automerge for k3s major and minor updates", + "matchDatasources": ["github-releases"], + "matchPackageNames": ["k3s-io/k3s"], + "matchUpdateTypes": ["major", "minor"], + "automerge": false + }, + { + "description": "Group k3s patch updates", + "matchDatasources": ["github-releases"], + "matchPackageNames": ["k3s-io/k3s"], + "matchUpdateTypes": ["patch"], + "groupName": "k3s" + }, + { + "description": "Disable k3s major and minor updates for old versions", + "matchDatasources": ["github-releases"], + "matchFileNames": [".forgejo/workflows/**"], + "matchPackageNames": ["k3s-io/k3s"], + "matchUpdateTypes": ["major", "minor"], + "matchCurrentValue": "!/^v1.32/", + "enabled": false + } + ], + "customDatasources": { + "k3s": { + "defaultRegistryUrlTemplate": "https://update.k3s.io/v1-release/channels", + "transformTemplates": [ + "($isVersion:=function($name){$contains($name,/^v\\d+.\\d+$/)};{\"releases\":[data[$isVersion(name)].{\"version\":latest}],\"sourceUrl\":\"https://github.com/k3s-io/k3s\",\"homepage\":\"https://k3s.io/\"})" + ] + } + }, + "customManagers": [ + { + "customType": "regex", + "fileMatch": [".forgejo/renovate/k3s.json"], + "matchStrings": [ + "matchCurrentValue\": \"!\\/^v(?\\d+\\.\\d+)\\/" + ], + "depNameTemplate": "k3s", + "versioningTemplate": "npm", + "datasourceTemplate": "custom.k3s" + } + ] +} diff --git a/.forgejo/workflows/build.yml b/.forgejo/workflows/build.yml new file mode 100644 index 0000000..5418491 --- /dev/null +++ b/.forgejo/workflows/build.yml @@ -0,0 +1,205 @@ +name: build + +on: + pull_request: + push: + branches: + - main + - maint/** + tags: + - v* + workflow_dispatch: + +permissions: + contents: read + +env: + HELM_VERSION: v3.17.2 # renovate: datasource=github-releases depName=helm packageName=helm/helm + HELM_UNITTEST_VERSION: v0.7.2 # renovate: datasource=github-releases depName=helm-unittest packageName=helm-unittest/helm-unittest + HELM_CHART_TESTING_VERSION: v3.12.0 # renovate: datasource=github-releases depName=chart-testing packageName=helm/chart-testing + KUBECTL_VERSION: v1.32.3 # renovate: datasource=github-releases depName=kubectl packageName=kubernetes/kubernetes + CT_GITHUB_GROUPS: true + +jobs: + lint-node: + runs-on: docker + steps: + - run: cat /etc/os-release + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + show-progress: false + fetch-depth: 0 # Important for changelog + filter: blob:none # We don't need all blobs + + - uses: ./.forgejo/actions/setup + - uses: ./.forgejo/actions/setup-node + + - run: pnpm prettier + - run: pnpm markdownlint . + - run: make readme + - run: git diff --exit-code --name-only README.md + + - name: changelog + run: | + pnpm changelog ${{ github.ref_type == 'tag' && 'true' || '' }} + + lint-helm: + runs-on: docker + steps: + - run: cat /etc/os-release + + - run: ps axf + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + show-progress: false + fetch-depth: 0 + filter: blob:none # We don't need all blobs + + - uses: ./.forgejo/actions/setup + + - name: install chart-testing + uses: helm/chart-testing-action@0d28d3144d3a25ea2cc349d6e59901c4ff469b3b # v2.7.0 + with: + version: ${{ env.HELM_CHART_TESTING_VERSION }} + + - name: install helm + uses: azure/setup-helm@b9e51907a09c216f16ebe8536097933489208112 # v4.3.0 + with: + version: ${{ env.HELM_VERSION }} + + - name: install helm-unittest + run: helm plugin install --version ${{ env.HELM_UNITTEST_VERSION }} https://github.com/helm-unittest/helm-unittest + + - run: helm dependency build + + - run: yamllint -f colored . + - run: helm lint + - run: helm template --debug gitea-helm . + - run: make unittests + - run: ct lint --config tools/ct.yml --charts . + + e2e: + needs: + - lint-node + - lint-helm + runs-on: k8s + + strategy: + matrix: + k3s: + # https://github.com/k3s-io/k3s/branches + # oldest supported version + - v1.28.15+k3s1 # renovate: k3s + # https://github.com/k3s-io/k3s/blob/master/channel.yaml#L3-L4 + # stable version + - v1.31.6+k3s1 # renovate: k3s + # newest version + - v1.32.2+k3s1 # renovate: k3s + + steps: + - run: cat /etc/os-release + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + show-progress: false + fetch-depth: 0 + filter: blob:none # We don't need all blobs + + - uses: ./.forgejo/actions/setup + + - name: install helm + uses: azure/setup-helm@b9e51907a09c216f16ebe8536097933489208112 # v4.3.0 + with: + version: ${{ env.HELM_VERSION }} + + - name: Install chart-testing + uses: helm/chart-testing-action@0d28d3144d3a25ea2cc349d6e59901c4ff469b3b # v2.7.0 + with: + version: ${{ env.HELM_CHART_TESTING_VERSION }} + + - uses: ./.forgejo/actions/setup-k3s + with: + version: ${{ matrix.k3s }} + + - run: kubectl get no -o wide + + - name: install chart + uses: https://github.com/nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3.0.2 + with: + timeout_minutes: 15 + max_attempts: 3 + retry_on: error + retry_wait_seconds: 120 + polling_interval_seconds: 5 + command: ct install --config tools/ct.yml --charts . + + # # Catch-all required check for test matrix + test-success: + needs: + - lint-node + - lint-helm + - e2e + runs-on: docker + timeout-minutes: 1 + if: always() + steps: + - name: Fail for failed or cancelled lint-node + if: | + needs.lint-node.result == 'failure' || + needs.lint-node.result == 'cancelled' + run: exit 1 + - name: Fail for failed or cancelled lint-helm + if: | + needs.lint-helm.result == 'failure' || + needs.lint-helm.result == 'cancelled' + run: exit 1 + - name: Fail for failed or cancelled e2e + if: | + needs.e2e.result == 'failure' || + needs.e2e.result == 'cancelled' + run: exit 1 + + publish: + runs-on: docker + needs: + - test-success + + if: ${{ github.ref_type == 'tag' }} + + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + show-progress: false + fetch-depth: 0 # Important for changelog + filter: blob:none # We don't need all blobs + + - uses: ./.forgejo/actions/setup + - uses: ./.forgejo/actions/setup-node + + - name: install helm + uses: https://github.com/azure/setup-helm@b9e51907a09c216f16ebe8536097933489208112 # v4.3.0 + with: + version: ${{ env.HELM_VERSION }} + + - run: helm dependency build + - run: helm package --version "${GITHUB_REF_NAME#v}" -d tmp/ ./ + + - name: login to registries + run: | + echo ${CODEBERG_TOKEN} | helm registry login -u viceice --password-stdin codeberg.org/forgejo-contrib + echo ${FORGEJO_TOKEN} | helm registry login -u viceice --password-stdin code.forgejo.org/forgejo-contrib + echo ${FORGEJO_TOKEN} | helm registry login -u viceice --password-stdin code.forgejo.org/forgejo-helm + env: + CODEBERG_TOKEN: ${{secrets.API_TOKEN}} + FORGEJO_TOKEN: ${{secrets.FORGEJO_API_TOKEN}} + + - name: publish forgejo helm chart + run: | + helm push tmp/forgejo-${GITHUB_REF_NAME#v}.tgz oci://codeberg.org/forgejo-contrib + helm push tmp/forgejo-${GITHUB_REF_NAME#v}.tgz oci://code.forgejo.org/forgejo-contrib + helm push tmp/forgejo-${GITHUB_REF_NAME#v}.tgz oci://code.forgejo.org/forgejo-helm + + - name: publish forgejo release + run: pnpm forgejo:release diff --git a/.forgejo/workflows/mirror.yml b/.forgejo/workflows/mirror.yml new file mode 100644 index 0000000..0e7c901 --- /dev/null +++ b/.forgejo/workflows/mirror.yml @@ -0,0 +1,26 @@ +on: + schedule: + - cron: '@hourly' + + push: + branches: + - 'main' + + workflow_dispatch: + +jobs: + mirror: + runs-on: docker + steps: + - name: git mirror branches {main,maint/*] & tags + run: | + git init --bare . + git remote add origin https://code.forgejo.org/${{ env.GITHUB_REPOSITORY }} + git fetch origin refs/heads/main:refs/mirror/main --tags + git ls-remote origin refs/heads/main/* | while read sha full_ref ; do + ref=${full_ref#refs/heads/} + git fetch origin $full_ref:refs/mirror/$ref + done + git push --force https://any:$CODEBERG_TOKEN@codeberg.org/forgejo-contrib/forgejo-helm refs/mirror/*:refs/heads/* --tags + env: + CODEBERG_TOKEN: ${{secrets.CODEBERG_TOKEN}} diff --git a/.gitea/PULL_REQUEST_TEMPLATE.md b/.gitea/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index 1121296..0000000 --- a/.gitea/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,41 +0,0 @@ - - -### Description of the change - - - -### Benefits - - - -### Possible drawbacks - - - -### Applicable issues - - - - fixes # - -### Additional information - - - -### ⚠ BREAKING - - - -### Checklist - - - -- [ ] Parameters are documented in the `values.yaml` and added to the `README.md` using [readme-generator-for-helm](https://github.com/bitnami-labs/readme-generator-for-helm) -- [ ] Breaking changes are documented in the `README.md` diff --git a/.gitignore b/.gitignore index 39a5450..e3bc7df 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,5 @@ node_modules/ unittests/*/__snapshot__/ tmp/ tmpcharts/ + +.pnpm-store/ diff --git a/.helmignore b/.helmignore index 4aefb35..f181c13 100644 --- a/.helmignore +++ b/.helmignore @@ -43,3 +43,23 @@ unittests/ .woodpecker/ tmp/ artifacthub-repo.yml + +ci/ +.forgejo/ +e2e/ +.husky/ +tools/ +.git/ +.editorconfig +.lintstagedrc.json +.editorconfig +.gitignore +.helmignore +.node-version +.prettier* +.yamllint +artifacthub* +renovate.json + +pnpm-lock.yaml +.pnpm-store/ diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 0000000..46a1655 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,3 @@ +#!/bin/sh + +pnpm lint-staged diff --git a/.lintstagedrc.json b/.lintstagedrc.json new file mode 100644 index 0000000..5bebd7c --- /dev/null +++ b/.lintstagedrc.json @@ -0,0 +1,6 @@ +{ + "*.sh": "shellcheck", + ".husky/*": "shellcheck", + "!*.{sh,md}": "prettier --cache --ignore-unknown --write", + "*.md": ["markdownlint --fix", "prettier --cache --write"] +} diff --git a/.markdownlint.yaml b/.markdownlint.yaml index 6320f35..fbc1c15 100644 --- a/.markdownlint.yaml +++ b/.markdownlint.yaml @@ -10,11 +10,11 @@ extends: null # MD003/heading-style/header-style - Heading style MD003: # Heading style - style: "atx" + style: 'atx' # MD004/ul-style - Unordered list style MD004: - style: "dash" + style: 'dash' # MD007/ul-indent - Unordered list indentation MD007: @@ -47,7 +47,7 @@ MD013: # Number of characters line_length: 200 # Number of characters for headings - heading_line_length: 80 + heading_line_length: 100 # Number of characters for code blocks code_block_line_length: 80 # Include code blocks @@ -56,8 +56,6 @@ MD013: tables: false # Include headings headings: true - # Include headings - headers: true # Strict length checking strict: false # Stern length checking @@ -73,7 +71,7 @@ MD022: # MD024/no-duplicate-heading/no-duplicate-header - Multiple headings with the same content MD024: # Only check sibling headings - allow_different_nesting: true + siblings_only: true # MD025/single-title/single-h1 - Multiple top-level headings in the same document MD025: @@ -85,12 +83,12 @@ MD025: # MD026/no-trailing-punctuation - Trailing punctuation in heading MD026: # Punctuation characters - punctuation: ".,;:!。,;:!" + punctuation: '.,;:!。,;:!' # MD029/ol-prefix - Ordered list item prefix MD029: # List style - style: "one_or_ordered" + style: 'one_or_ordered' # MD030/list-marker-space - Spaces after list markers MD030: @@ -106,17 +104,17 @@ MD030: # MD033/no-inline-html - Inline HTML MD033: # Allowed elements - allowed_elements: [] + allowed_elements: [details, summary] # MD035/hr-style - Horizontal rule style MD035: # Horizontal rule style - style: "---" + style: '---' # MD036/no-emphasis-as-heading/no-emphasis-as-header - Emphasis used instead of a heading MD036: # Punctuation characters - punctuation: ".,;:!?。,;:!?" + punctuation: '.,;:!?。,;:!?' # MD041/first-line-heading/first-line-h1 - First line in a file should be a top-level heading MD041: @@ -129,23 +127,22 @@ MD041: MD044: # List of proper names names: - - Gitea - - PostgreSQL - - MariaDB - - MySQL - - Memcached - - Prometheus - - Git - - GitOps + - Gitea + - PostgreSQL + - Memcached + - Prometheus + - Git + - GitOps + - Forgejo # Include code blocks code_blocks: false # MD046/code-block-style - Code block style MD046: # Block style - style: "fenced" + style: 'fenced' # MD048/code-fence-style - Code fence style MD048: # Code fence syle - style: "backtick" + style: 'backtick' diff --git a/.markdownlintignore b/.markdownlintignore index 7aee9a3..0fbc475 100644 --- a/.markdownlintignore +++ b/.markdownlintignore @@ -1,4 +1,7 @@ .gitea/ node_modules/ charts/ -.helmignore \ No newline at end of file +.helmignore +Chart.lock + +.pnpm-store/ diff --git a/.node-version b/.node-version new file mode 100644 index 0000000..7d41c73 --- /dev/null +++ b/.node-version @@ -0,0 +1 @@ +22.14.0 diff --git a/.npmrc b/.npmrc index b6f27f1..e4b16a8 100644 --- a/.npmrc +++ b/.npmrc @@ -1 +1,5 @@ engine-strict=true + +# pnpm run settings +# https://pnpm.io/cli/run +shell-emulator = true diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..9845d1c --- /dev/null +++ b/.prettierignore @@ -0,0 +1,7 @@ +Chart.lock +node_modules/ +pnpm-lock.yaml +.pnpm-store/ + +# won't work +templates/**/*.yaml diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..a20502b --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,4 @@ +{ + "singleQuote": true, + "trailingComma": "all" +} diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..4a9bace --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,8 @@ +{ + "recommendations": [ + "yzhang.markdown-all-in-one", + "DavidAnson.vscode-markdownlint", + "Tim-Koehler.helm-intellisense", + "esbenp.prettier-vscode" + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..da15f96 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,12 @@ +{ + "yaml.schemas": { + "https://json.schemastore.org/github-workflow.json": [ + ".github/workflows/*", + ".forgejo/workflows/*" + ], + "https://raw.githubusercontent.com/helm-unittest/helm-unittest/v0.7.2/schema/helm-testsuite.json": [ + "/unittests/**/*.yaml" + ] + }, + "yaml.schemaStore.enable": true +} diff --git a/.woodpecker/lint.yml b/.woodpecker/lint.yml deleted file mode 100644 index 2bf1ddd..0000000 --- a/.woodpecker/lint.yml +++ /dev/null @@ -1,50 +0,0 @@ -platform: linux/amd64 - -when: - event: - - pull_request - - tag - - push - branch: - - main - - release/** - -pipeline: - deps: - image: alpine:3.17.1 - pull: true - commands: - - apk add --no-cache helm - - helm repo add bitnami https://raw.githubusercontent.com/bitnami/charts/archive-full-index/bitnami - - helm dependency build - - helm-lint: - image: alpine:3.17.1 - pull: true - commands: - - apk add --no-cache helm - - helm lint - - helm-template: - image: alpine:3.17.1 - pull: true - commands: - - apk add --no-cache helm - - helm template --debug gitea-helm . - - helm-unittests: - image: alpine:3.17.1 - pull: true - commands: - - apk add --no-cache make helm git bash - - helm plugin install https://github.com/quintush/helm-unittest - - helm dependency update - - make unittests - - verify-readme: - image: alpine:3.17.1 - pull: true - commands: - - apk add --no-cache make nodejs npm git - - make readme - - git diff --exit-code --name-only README.md diff --git a/.woodpecker/release-version.yml b/.woodpecker/release-version.yml deleted file mode 100644 index cab8625..0000000 --- a/.woodpecker/release-version.yml +++ /dev/null @@ -1,46 +0,0 @@ -platform: linux/amd64 - -depends_on: - - lint - -when: - event: - - tag - tag: v* - -pipeline: - generate-chart: - image: alpine:3.17.1 - pull: true - commands: - - apk add --no-cache git nodejs npm helm - - helm repo add bitnami https://raw.githubusercontent.com/bitnami/charts/archive-full-index/bitnami - - helm dependency build - - rm -rf tmp/ - - helm package --version "${CI_COMMIT_TAG##v}" -d tmp/ ./ - - npm ci - - npm run changelog "${CI_COMMIT_TAG##v}" tmp/changelog.md - secrets: - - token - - publish-release: - image: plugins/gitea-release - pull: true - settings: - base_url: https://codeberg.org - api_key: - from_secret: token - files: tmp/*.tgz - title: ${CI_COMMIT_TAG##v} - file_exists: fail - note: tmp/changelog.md - - publish-chart: - image: alpine:3.17.1 - pull: true - commands: - - apk add --no-cache helm - - echo $${TOKEN} | helm registry login -u viceice --password-stdin codeberg.org/forgejo-contrib - - helm push tmp/forgejo-${CI_COMMIT_TAG##v}.tgz oci://codeberg.org/forgejo-contrib - secrets: - - token diff --git a/.woodpecker/renovate.yml b/.woodpecker/renovate.yml deleted file mode 100644 index a1e8545..0000000 --- a/.woodpecker/renovate.yml +++ /dev/null @@ -1,25 +0,0 @@ -platform: linux/amd64 - -when: - event: - - cron - -pipeline: - renovate: - image: ghcr.io/visualon/renovate:34.105.6 - pull: true - commands: - - renovate $${CI_REPO} - environment: - RENOVATE_PLATFORM: gitea - RENOVATE_ENDPOINT: https://codeberg.org - LOG_LEVEL: debug - secrets: - - source: token - target: renovate_token - - source: gh_token - target: github_com_token - when: - - event: - - cron - cron: renovate diff --git a/.yamllint b/.yamllint new file mode 100644 index 0000000..90128be --- /dev/null +++ b/.yamllint @@ -0,0 +1,20 @@ +--- +extends: default + +ignore: | + .yamllint + node_modules + templates + + +rules: + truthy: + allowed-values: ['true', 'false'] + check-keys: False + level: error + line-length: disable + document-start: disable + comments: + min-spaces-from-content: 1 + braces: + max-spaces-inside: 2 \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 78f77d9..d4c06e8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -9,20 +9,16 @@ refactorings for easier maintainability or documentation improvements. - [`helm`](https://helm.sh/docs/intro/install/) - `make` is optional; you may call the commands directly -When using Visual Studio Code as IDE, following plugins might be useful: - -- [Markdown All in One](https://marketplace.visualstudio.com/items?itemName=yzhang.markdown-all-in-one) -- [markdownlint](https://marketplace.visualstudio.com/items?itemName=DavidAnson.vscode-markdownlint) -- [Helm Intellisense](https://marketplace.visualstudio.com/items?itemName=Tim-Koehler.helm-intellisense) +When using Visual Studio Code as IDE, a [ready-to-use profile](.vscode/) is available. ## Documentation Requirements -The `README.md` must include all configuration options. The parameters section -is generated by extracting the parameter annotations from the `values.yaml` file, -by using [this tool](https://github.com/bitnami-labs/readme-generator-for-helm). +The `README.md` must include all configuration options. +The parameters section is generated by extracting the parameter annotations from the `values.yaml` file, by using [this tool](https://github.com/bitnami-labs/readme-generator-for-helm). -If changes were made on configuration options, run `make readme` to update the -README file. +If changes were made on configuration options, run `make readme` to update the README file. + +The ToC is created via the VSCode [Markdown All in One](https://marketplace.visualstudio.com/items?itemName=yzhang.markdown-all-in-one) extension which can/must also be used used to update it. ## Pull Request Requirements @@ -40,23 +36,30 @@ For local development and testing of pull requests, the following workflow can be used: 1. Install `minikube` and `helm`. -2. Start a `minikube` cluster via `minikube start`. -3. From the `gitea/helm-chart` directory execute the following command. This - will install the dependencies listed in `Chart.yml` and deploy the current - state of the helm chart found locally. If you want to test a branch, make - sure to switch to the respective branch first. - `helm install --dependency-update gitea . -f values.yaml`. -4. Gitea is now deployed in `minikube`. To access it, it's port needs to be - forwarded first from `minikube` to localhost first via `kubectl --namespace - default port-forward svc/gitea-http 3000:3000`. Now Gitea is accessible at - [http://localhost:3000](http://localhost:3000). +1. Start a `minikube` cluster via `minikube start`. +1. From the `forgejo-contrib/forgejo-helm` directory execute the following command. + This will install the dependencies listed in `Chart.yml` and deploy the current state of the helm chart found locally. + If you want to test a branch, make sure to switch to the respective branch first. + `helm install --dependency-update forgejo . -f values.yaml`. +1. Forgejo is now deployed in `minikube`. + To access it, it's port needs to be forwarded first from `minikube` to localhost first via `kubectl --namespace +default port-forward svc/gitea-http 3000:3000`. + Now Forgejo is accessible at [http://localhost:3000](http://localhost:3000). ### Unit tests ```bash # install the unittest plugin -$ helm plugin install https://github.com/heyhabito/helm-unittest +$ helm plugin install https://github.com/helm-unittest/helm-unittest # run the unittests make unittests ``` + +See [plugin documentation](https://github.com/helm-unittest/helm-unittest/blob/main/DOCUMENT.md) for usage instructions. + +## Release process + +1. Create a tag following the tagging schema +1. Push the tag +1. Let CI do it's work diff --git a/Chart.lock b/Chart.lock index 8516a0e..bff1098 100644 --- a/Chart.lock +++ b/Chart.lock @@ -1,15 +1,18 @@ dependencies: -- name: memcached - repository: https://raw.githubusercontent.com/bitnami/charts/archive-full-index/bitnami - version: 6.3.5 -- name: mysql - repository: https://raw.githubusercontent.com/bitnami/charts/archive-full-index/bitnami - version: 9.4.6 +- name: common + repository: oci://ghcr.io/visualon/bitnamicharts + version: 2.30.0 - name: postgresql - repository: https://raw.githubusercontent.com/bitnami/charts/archive-full-index/bitnami - version: 12.1.9 -- name: mariadb - repository: https://raw.githubusercontent.com/bitnami/charts/archive-full-index/bitnami - version: 11.4.4 -digest: sha256:9d5f8b986b2cc244d32ceb6165399deaae5a4a6a6df955e2a7b0e8f36c0146a9 -generated: "2023-01-19T11:57:21.482881836Z" + repository: oci://ghcr.io/visualon/bitnamicharts + version: 16.5.6 +- name: postgresql-ha + repository: oci://ghcr.io/visualon/bitnamicharts + version: 15.3.8 +- name: redis-cluster + repository: oci://ghcr.io/visualon/bitnamicharts + version: 11.4.6 +- name: redis + repository: oci://ghcr.io/visualon/bitnamicharts + version: 20.11.4 +digest: sha256:a9c9f0779663336dd22ca4896f22bb64427e28f20aa567aee2f18474f8e31a23 +generated: "2025-03-26T15:31:33.532188569Z" diff --git a/Chart.yaml b/Chart.yaml index d958ee4..8218677 100644 --- a/Chart.yaml +++ b/Chart.yaml @@ -3,8 +3,8 @@ name: forgejo description: Forgejo Helm chart for Kubernetes type: application version: 0.0.0 -appVersion: 1.18.1-0 -icon: https://design.codeberg.org/logo-kit/icon.svg +appVersion: 10.0.3 +icon: https://code.forgejo.org/forgejo/forgejo/raw/branch/forgejo/assets/logo.svg home: https://forgejo.org/ keywords: @@ -16,27 +16,41 @@ keywords: - gitea - gogs sources: - - https://codeberg.org/forgejo-contrib/forgejo-helm + - https://code.forgejo.org/forgejo-helm/forgejo-helm - https://codeberg.org/forgejo/forgejo maintainers: - name: Michael Kriese email: michael.kriese@visualon.de -# Bitnami charts are served from GitHub CDN - See https://github.com/bitnami/charts/issues/10833 for details +# Bitnami charts are served from ghcr mirror because of rate limiting on Docker Hub +# https://hub.docker.com/u/bitnamicharts +# https://blog.bitnami.com/2023/01/bitnami-helm-charts-available-as-oci.html +# https://github.com/bitnami/charts/issues/30853 +# https://code.forgejo.org/forgejo-helm/forgejo-helm/issues/1045 dependencies: -- name: memcached - repository: https://raw.githubusercontent.com/bitnami/charts/archive-full-index/bitnami - version: 6.3.5 - condition: memcached.enabled -- name: mysql - repository: https://raw.githubusercontent.com/bitnami/charts/archive-full-index/bitnami - version: 9.4.6 - condition: mysql.enabled -- name: postgresql - repository: https://raw.githubusercontent.com/bitnami/charts/archive-full-index/bitnami - version: 12.1.9 - condition: postgresql.enabled -- name: mariadb - repository: https://raw.githubusercontent.com/bitnami/charts/archive-full-index/bitnami - version: 11.4.4 - condition: mariadb.enabled + # https://github.com/bitnami/charts/blob/main/bitnami/common/Chart.yaml + - name: common + repository: oci://ghcr.io/visualon/bitnamicharts + tags: + - bitnami-common + version: 2.30.0 + # https://github.com/bitnami/charts/blob/main/bitnami/postgresql/Chart.yaml + - name: postgresql + repository: oci://ghcr.io/visualon/bitnamicharts + version: 16.5.6 + condition: postgresql.enabled + # https://github.com/bitnami/charts/blob/main/bitnami/postgresql-ha/Chart.yaml + - name: postgresql-ha + repository: oci://ghcr.io/visualon/bitnamicharts + version: 15.3.8 + condition: postgresql-ha.enabled + # https://github.com/bitnami/charts/blob/main/bitnami/redis-cluster/Chart.yaml + - name: redis-cluster + repository: oci://ghcr.io/visualon/bitnamicharts + version: 11.4.6 + condition: redis-cluster.enabled + # https://github.com/bitnami/charts/blob/main/bitnami/redis/Chart.yaml + - name: redis + repository: oci://ghcr.io/visualon/bitnamicharts + version: 20.11.4 + condition: redis.enabled diff --git a/LICENSE b/LICENSE index bbf54de..b073755 100644 --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,6 @@ MIT License +Copyright (c) 2023 The Forgejo Authors Copyright (c) 2020 The Gitea Authors Copyright (c) 2020 NOVUM-RGI Copyright (c) 2019 - 2020 Charlie Drage diff --git a/Makefile b/Makefile index 2b61849..dd97d84 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,17 @@ .PHONY: prepare-environment prepare-environment: - npm install + pnpm install .PHONY: readme readme: prepare-environment - npm run readme:parameters - npm run readme:lint + pnpm readme:parameters + pnpm readme:lint .PHONY: unittests unittests: - helm unittest --helm3 --strict -f 'unittests/**/*.yaml' ./ + helm unittest --strict -f 'unittests/**/*.yaml' ./ + +.PHONY: helm +update-helm-dependencies: + helm dependency update + \ No newline at end of file diff --git a/README.md b/README.md index d94e8ba..8a448fa 100644 --- a/README.md +++ b/README.md @@ -1,73 +1,189 @@ -# Forgejo Helm Chart +# Forgejo Helm Chart -[Forgejo](https://forgejo.org/) is a community managed lightweight code hosting -solution written in Go. It is published under the MIT license. +- [Introduction](#introduction) +- [Update and versioning policy](#update-and-versioning-policy) +- [Dependencies](#dependencies) + - [HA Dependencies](#ha-dependencies) + - [Non-HA Dependencies](#non-ha-dependencies) + - [Dependency Versioning](#dependency-versioning) +- [Installing](#installing) +- [High Availability](#high-availability) +- [Configuration](#configuration) + - [Default Configuration](#default-configuration) + - [Database defaults](#database-defaults) + - [Server defaults](#server-defaults) + - [Metrics defaults](#metrics-defaults) + - [Rootless Defaults](#rootless-defaults) + - [Session, Cache and Queue](#session-cache-and-queue) + - [Single-Pod Configurations](#single-pod-configurations) + - [Additional _app.ini_ settings](#additional-appini-settings) + - [User defined environment variables in app.ini](#user-defined-environment-variables-in-appini) + - [External Database](#external-database) + - [Ports and external url](#ports-and-external-url) + - [SSH and Ingress](#ssh-and-ingress) + - [SSH on crio based kubernetes cluster](#ssh-on-crio-based-kubernetes-cluster) + - [Cache](#cache) + - [Persistence](#persistence) + - [Admin User](#admin-user) + - [LDAP Settings](#ldap-settings) + - [OAuth2 Settings](#oauth2-settings) +- [Configure commit signing](#configure-commit-signing) +- [Metrics and profiling](#metrics-and-profiling) +- [Pod annotations](#pod-annotations) +- [Themes](#themes) +- [Renovate](#renovate) +- [Parameters](#parameters) + - [Global](#global) + - [strategy](#strategy) + - [Image](#image) + - [Security](#security) + - [Service](#service) + - [Ingress](#ingress) + - [deployment](#deployment) + - [ServiceAccount](#serviceaccount) + - [Persistence](#persistence-1) + - [Init](#init) + - [Signing](#signing) + - [Gitea](#gitea) + - [`app.ini` overrides](#appini-overrides) + - [LivenessProbe](#livenessprobe) + - [ReadinessProbe](#readinessprobe) + - [StartupProbe](#startupprobe) + - [Redis® Cluster](#redis-cluster) + - [Redis®](#redis) + - [PostgreSQL HA](#postgresql-ha) + - [PostgreSQL](#postgresql) + - [Advanced](#advanced) +- [Contributing](#contributing) +- [Upgrading](#upgrading) + - [To v11](#to-v11) + - [To v10](#to-v10) + - [To v9](#to-v9) + - [To v8](#to-v8) + - [To v7](#to-v7) + - [To v6](#to-v6) + +[Forgejo](https://forgejo.org/) is a community managed lightweight code hosting solution written in Go. +It is published under the MIT license. ## Introduction -This helm chart is based on official [Gitea helm chart](https://gitea.com/gitea/helm-chart). -Additionally, this chart provides LDAP and admin user configuration with values, -as well as being deployed as a statefulset to retain stored repositories. +This Helm chart is based on the [Gitea chart](https://gitea.com/gitea/helm-chart). +Yet it takes a completely different approach in providing a database and cache with dependencies. +Additionally, this chart allows to provide LDAP and admin user configuration with values. + +## Update and versioning policy + +The Forgejo helm chart versioning does not follow Forgejo's versioning. +The latest chart version can be looked up in or in the [repository releases](https://code.forgejo.org/forgejo-helm/forgejo-helm/releases). + +The chart aims to follow Forgejo's releases closely. +There might be times when the chart is behind the latest Forgejo release. +This might be caused by different reasons, most often due to time constraints of the maintainers (remember, all work here is done voluntarily in the spare time of people). +If you're eager to use the latest Forgejo version earlier than this chart catches up, then change the tag in `values.yaml` to the latest Forgejo version. +This is due to Forgejo not strictly following [semantic versioning](https://semver.org/#summary) as breaking changes do not increase the major version. +I.e., "minor" version bumps are considered "major". +Yet most often no issues will be encountered and the chart maintainers aim to communicate early/upfront if this would be the case. ## Dependencies -Forgejo can be run with an external database and cache. This chart provides those -dependencies, which can be enabled, or disabled via -configuration. +Forgejo can be run with an external database and cache. +This chart provides those dependencies, which can be enabled, or disabled via configuration. -Dependencies: +### HA Dependencies -- PostgreSQL ([configuration](#postgresql)) -- Memcached ([configuration](#memcached)) -- MySQL ([configuration](#mysql)) -- MariaDB ([configuration](#mariadb)) +These dependencies are enabled by default: + +- PostgreSQL HA ([Bitnami PostgreSQL-HA](https://github.com/bitnami/charts/blob/main/bitnami/postgresql-ha/Chart.yaml)) +- Redis-Cluster ([Bitnami Redis-Cluster](https://github.com/bitnami/charts/blob/main/bitnami/redis-cluster/Chart.yaml)) + +### Non-HA Dependencies + +Alternatively, the following non-HA replacements are available: + +- PostgreSQL ([Bitnami PostgreSQL](https://github.com/bitnami/charts/blob/main/bitnami/postgresql/Chart.yaml)) +- Redis ([Bitnami Redis](https://github.com/bitnami/charts/blob/main/bitnami/redis/Chart.yaml)) + +### Dependency Versioning + +Updates of sub-charts will be incorporated into the Gitea chart as they are released. +The reasoning behind this is that new users of the chart will start with the most recent sub-chart dependency versions. + +**Note** If you want to stay on an older appVersion of a sub-chart dependency (e.g. PostgreSQL), you need to override the image tag in your `values.yaml` file. +In fact, we recommend to do so right from the start to be independent of major sub-chart dependency changes as they are released. +There is no need to update to every new PostgreSQL major version - you can happily skip some and do larger updates when you are ready for them. + +We recommend to use a rolling tag like `:-debian-` to incorporate minor and patch updates for the respective major version as they are released. +Alternatively you can also use a versioning helper tool like [renovate](https://github.com/renovatebot/renovate). + +Please double-check the image repository and available tags in the sub-chart: + +- [PostgreSQL-HA](https://hub.docker.com/r/bitnami/postgresql-repmgr/tags) +- [PostgreSQL](https://hub.docker.com/r/bitnami/postgresql/tags) +- [Redis Cluster](https://hub.docker.com/r/bitnami/redis-cluster/tags) +- [Redis](https://hub.docker.com/r/bitnami/redis/tags) + +and look up the image tag which fits your needs on Dockerhub. ## Installing ```sh -helm install oci://codeberg.org/forgejo-contrib/forgejo +helm install forgejo oci://code.forgejo.org/forgejo-helm/forgejo ``` -When upgrading, please refer to the [Upgrading](#upgrading) section at the bottom -of this document for major and breaking changes. +In case you want to supply values, you can reference a `values.yaml` file: -## Prerequisites +```sh +helm install forgejo -f values.yaml oci://code.forgejo.org/forgejo-helm/forgejo +``` -- Kubernetes 1.12+ -- Helm 3.0+ -- PV provisioner for persistent data support +When upgrading, please refer to the [Upgrading](#upgrading) section at the bottom of this document for major and breaking changes. -## Examples +## High Availability -### Forgejo Configuration +This chart supports running Forgejo and it's dependencies in HA mode. +Care must be taken for production use as not all implementation details of Forgejo core are officially HA-ready yet. -Forgejo offers lots of configuration options. This is fully described in the -[Gitea Cheat Sheet](https://docs.gitea.io/en-us/config-cheat-sheet/). +Deploying a HA-ready Forgejo instance requires some effort including using HA-ready dependencies. +See the [HA Setup](docs/ha-setup.md) document for more details. + +## Configuration + +Forgejo offers lots of configuration options. +Every value described in the [Cheat Sheet](https://forgejo.org/docs/latest/admin/config-cheat-sheet/) can be set as a Helm value. +Configuration sections map to (lowercased) YAML blocks, while the keys themselves remain in all caps. ```yaml gitea: config: - APP_NAME: 'Forgejo: With a cup of tea.' + # values in the DEFAULT section + # (https://forgejo.org/docs/latest/admin/config-cheat-sheet/#overall-default) + # are un-namespaced + # + APP_NAME: 'Forgejo: Git with a cup of tea' + # + # https://forgejo.org/docs/latest/admin/config-cheat-sheet/#repository-repository repository: ROOT: '~/gitea-repositories' + # + # https://forgejo.org/docs/latest/admin/config-cheat-sheet/#repository---pull-request-repositorypull-request repository.pull-request: WORK_IN_PROGRESS_PREFIXES: 'WIP:,[WIP]:' ``` ### Default Configuration -This chart will set a few defaults in the Forgejo configuration based on the -service and ingress settings. All defaults can be overwritten in `gitea.config`. +This chart will set a few defaults in the Forgejo configuration based on the service and ingress settings. +All defaults can be overwritten in `gitea.config`. -INSTALL_LOCK is always set to true, since we want to configure Forgejo with this -helm chart and everything is taken care of. +INSTALL_LOCK is always set to true because the configuration in this helm chart makes any configuration via installer superfluous. -_All default settings are made directly in the generated app.ini, not in the Values._ +_All default settings are made directly in the generated `app.ini`, not in the Values._ #### Database defaults -If a builtIn database is enabled the database configuration is set -automatically. For example, PostgreSQL builtIn will appear in the app.ini as: +If a database subchart is enabled, the database configuration is set automatically. +For example, PostgreSQL will appear in the `app.ini` as: ```ini [database] @@ -78,23 +194,11 @@ PASSWD = gitea USER = gitea ``` -#### Memcached defaults - -Memcached is handled the exact same way as database builtIn. Once Memcached -builtIn is enabled, this chart will generate the following part in the `app.ini`: - -```ini -[cache] -ADAPTER = memcache -ENABLED = true -HOST = RELEASE-NAME-memcached.default.svc.cluster.local:11211 -``` - #### Server defaults -The server defaults are a bit more complex. If ingress is `enabled`, the -`ROOT_URL`, `DOMAIN` and `SSH_DOMAIN` will be set accordingly. `HTTP_PORT` -always defaults to `3000` as well as `SSH_PORT` to `22`. +The server defaults are a bit more complex. +If ingress is `enabled`, the `ROOT_URL`, `DOMAIN` and `SSH_DOMAIN` will be set accordingly. +`HTTP_PORT` always defaults to `3000` as well as `SSH_PORT` to `22`. ```ini [server] @@ -118,19 +222,116 @@ The Prometheus `/metrics` endpoint is disabled by default. ENABLED = false ``` +#### Rootless Defaults + +If `.Values.image.rootless: true`, then the following will occur. In case you use `.Values.image.fullOverride`, check that this works in your image: + +- `$HOME` becomes `/data/gitea/git` + + [see deployment.yaml](./templates/gitea/deployment.yaml) template inside (init-)container "env" declarations + +- `START_SSH_SERVER: true` (Unless explicity overwritten by `gitea.config.server.START_SSH_SERVER`) + + [see \_helpers.tpl](./templates/_helpers.tpl) in `gitea.inline_configuration.defaults.server` definition + +- `SSH_LISTEN_PORT: 2222` (Unless explicity overwritten by `gitea.config.server.SSH_LISTEN_PORT`) + + [see \_helpers.tpl](./templates/_helpers.tpl) in `gitea.inline_configuration.defaults.server` definition + +- `SSH_LOG_LEVEL` environment variable is not injected into the container + + [see deployment.yaml](./templates/gitea/deployment.yaml) template inside container "env" declarations + +#### Session, Cache and Queue + +The session, cache and queue settings are set to use the built-in Redis Cluster sub-chart dependency. +If Redis Cluster is disabled, the chart will fall back to the Gitea defaults which use "memory" for `session` and `cache` and "level" for `queue`. + +While these will work and even not cause immediate issues after startup, **they are not recommended for production use**. +Reasons being that a single pod will take on all the work for `session` and `cache` tasks in its available memory. +It is likely that the pod will run out of memory or will face substantial memory spikes, depending on the workload. +External tools such as `redis-cluster` or `memcached` handle these workloads much better. + +### Single-Pod Configurations + +If HA is not needed/desired, the following configurations can be used to deploy a single-pod Forgejo instance. + +1. For a production-ready single-pod Forgejo instance without external dependencies (using the chart dependency `postgresql` and `redis`): + +
+ + values.yml + + ```yaml + redis-cluster: + enabled: false + redis: + enabled: true + postgresql: + enabled: true + postgresql-ha: + enabled: false + + persistence: + enabled: true + + gitea: + config: + database: + DB_TYPE: postgres + indexer: + ISSUE_INDEXER_TYPE: bleve + REPO_INDEXER_ENABLED: true + ``` + +
+ +2. For a minimal DEV installation (using the built-in sqlite DB instead of Postgres): + + This will result in a single-pod Forgejo instance _without any dependencies and persistence_. + **Do not use this configuration for production use**. + +
+ + values.yml + + ```yaml + redis-cluster: + enabled: false + redis: + enabled: false + postgresql: + enabled: false + postgresql-ha: + enabled: false + + persistence: + enabled: false + + gitea: + config: + database: + DB_TYPE: sqlite3 + session: + PROVIDER: memory + cache: + ADAPTER: memory + queue: + TYPE: level + ``` + +
+ ### Additional _app.ini_ settings -> **The [generic](https://docs.gitea.io/en-us/config-cheat-sheet/#overall-default) +> **The [generic](https://forgejo.org/docs/latest/admin/config-cheat-sheet/#overall-default) > section cannot be defined that way.** -Some settings inside _app.ini_ (like passwords or whole authentication configurations) -must be considered sensitive and therefore should not be passed via plain text -inside the _values.yaml_ file. In times of _GitOps_ the values.yaml could be stored -in a Git repository where sensitive data should never be accessible. +Some settings inside _app.ini_ (like passwords or whole authentication configurations) must be considered sensitive and therefore should not be passed via plain text inside the _values.yaml_ file. +In times of _GitOps_ the values.yaml could be stored in a Git repository where sensitive data should never be accessible. The Helm Chart supports this approach and let the user define custom sources like -Kubernetes Secrets to be loaded as environment variables during _app.ini_ creation -or update. +Kubernetes Secrets to be loaded as environment variables during _app.ini_ creation or update. ```yaml gitea: @@ -141,10 +342,8 @@ gitea: name: gitea-app-ini-plaintext ``` -This would mount the two additional volumes (`oauth` and `some-additionals`) -from different sources to the init containerwhere the _app.ini_ gets updated. -All files mounted that way will be read and converted to environment variables -and then added to the _app.ini_ using [environment-to-ini](https://github.com/go-gitea/gitea/tree/main/contrib/environment-to-ini). +This would mount the two additional volumes (`oauth` and `some-additionals`) from different sources to the init container where the _app.ini_ gets updated. +All files mounted that way will be read and converted to environment variables and then added to the _app.ini_ using [environment-to-ini](https://github.com/go-gitea/gitea/tree/main/contrib/environment-to-ini). The key of such additional source represents the section inside the _app.ini_. The value for each key can be multiline ini-like definitions. @@ -181,26 +380,23 @@ stringData: #### User defined environment variables in app.ini -Users are able to define their own environment variables, -which are loaded into the containers. We also support to -directly interact with the generated _app.ini_. +Users are able to define their own environment variables, which are loaded into the containers. +We also support interacting directly with the generated _app.ini_. -To inject self defined variables into the _app.ini_ a -certain format needs to be honored. This is -described in detail on the [env-to-ini](https://github.com/go-gitea/gitea/tree/main/contrib/environment-to-ini) -page. +To inject self defined variables into the _app.ini_ a certain format needs to be honored. +This is described in detail on the [env-to-ini](https://github.com/go-gitea/gitea/tree/main/contrib/environment-to-ini) page. -Note that the Prefix on this helm chart is `ENV_TO_INI`. +Environment variables need to be prefixed with `FORGEJO`. -For example a database setting needs to have the following -format: +For example a database setting needs to have the following format: ```yaml gitea: + config: + database: + HOST: my.own.host additionalConfigFromEnvs: - - name: ENV_TO_INI__DATABASE__HOST - value: my.own.host - - name: ENV_TO_INI__DATABASE__PASSWD + - name: FORGEJO__DATABASE__PASSWD valueFrom: secretKeyRef: name: postgres-secret @@ -209,20 +405,24 @@ gitea: Priority (highest to lowest) for defining app.ini variables: -1. Environment variables prefixed with `ENV_TO_INI` -2. Additional config sources -3. Values defined in `gitea.config` +1. Environment variables prefixed with `FORGEJO` + +1. Additional config sources +1. Values defined in `gitea.config` ### External Database -An external Database can be used instead of builtIn PostgreSQL or MySQL. +A [supported external database](https://forgejo.org/docs/latest/admin/config-cheat-sheet/#database-database/)can be used instead of the built-in PostgreSQL. +In fact, it is **highly recommended** to use an external database to ensure a stable Forgejo installation longterm. + +If an external database is used, no matter which type, make sure to set `postgresql.enabled` to `false` to disable the use of the built-in PostgreSQL. ```yaml gitea: config: database: - DB_TYPE: mysql - HOST: 127.0.0.1:3306 + DB_TYPE: mysql # supported values are mysql, postgres, mssql, sqlite3 + HOST: NAME: gitea USER: root PASSWD: gitea @@ -234,7 +434,8 @@ postgresql: ### Ports and external url -By default port `3000` is used for web traffic and `22` for ssh. Those can be changed: +By default port `3000` is used for web traffic and `22` for ssh. +Those can be changed: ```yaml service: @@ -244,45 +445,26 @@ service: port: 22 ``` -This helm chart automatically configures the clone urls to use the correct -ports. You can change these ports by hand using the `gitea.config` dict. However -you should know what you're doing. - -### ClusterIP - -By default the clusterIP will be set to None, which is the default for headless -services. However if you want to omit the clusterIP field in the service, use -the following values: - -```yaml -service: - http: - type: ClusterIP - port: 3000 - clusterIP: - ssh: - type: ClusterIP - port: 22 - clusterIP: -``` +This helm chart automatically configures the clone urls to use the correct ports. +You can change these ports by hand using the `gitea.config` dict. +However you should know what you're doing. ### SSH and Ingress -If you're using ingress and want to use SSH, keep in mind, that ingress is not -able to forward SSH Ports. You will need a LoadBalancer like `metallb` and a -setting in your ssh service annotations. +If you're using ingress and want to use SSH, keep in mind, that ingress is not able to forward SSH Ports. +You will need a LoadBalancer like `metallb` and a setting in your ssh service annotations. ```yaml service: ssh: annotations: - metallb.universe.tf/allow-shared-ip: test + metallb.io/allow-shared-ip: test ``` ### SSH on crio based kubernetes cluster -If you use crio as container runtime it is not possible to read from a remote -repository. You should get an error message like this: +If you use `crio` as container runtime it is not possible to read from a remote repository. +You should get an error message like this: ```bash $ git clone git@k8s-demo.internal:admin/test.git @@ -299,37 +481,25 @@ More about this issue [here](https://gitea.com/gitea/helm-chart/issues/161). ### Cache -This helm chart can use a built in cache. The default is Memcached from bitnami. +The cache handling is done via `redis-cluster` (via the `bitnami` chart) by default. +This deployment is HA-ready but can also be used for single-pod deployments. +By default, 6 replicas are deployed for a working `redis-cluster` deployment. +Many cloud providers offer a managed redis service, which can be used instead of the built-in `redis-cluster`. ```yaml -memcached: +redis-cluster: enabled: true ``` -If the built in cache should not be used simply configure the cache in -`gitea.config`. - -```yaml -gitea: - config: - cache: - ENABLED: true - ADAPTER: memory - INTERVAL: 60 - HOST: 127.0.0.1:9090 -``` - ### Persistence -Forgejo will be deployed as a statefulset. By simply enabling the persistence and -setting the storage class according to your cluster everything else will be -taken care of. The following example will create a PVC as a part of the -statefulset. This PVC will not be deleted even if you uninstall the chart. +Forgejo will be deployed as a deployment. +By simply enabling the persistence and setting the storage class according to your cluster everything else will be taken care of. +The following example will create a PVC as a part of the deployment. -Please note, that an empty storageClass in the persistence will result in -kubernetes using your default storage class. +Please note, that an empty `storageClass` in the persistence will result in kubernetes using your default storage class. -If you want to use your own storageClass define it as followed: +If you want to use your own storage class define it as follows: ```yaml persistence: @@ -337,47 +507,31 @@ persistence: storageClass: myOwnStorageClass ``` -When using PostgreSQL as dependency, this will also be deployed as a statefulset -by default. - If you want to manage your own PVC you can simply pass the PVC name to the chart. ```yaml persistence: enabled: true - existingClaim: MyAwesomeGiteaClaim + claimName: MyAwesomeGiteaClaim ``` -In case that peristence has been disabled it will simply use an empty dir volume. +In case that persistence has been disabled it will simply use an empty dir volume. PostgreSQL handles the persistence in the exact same way. You can interact with the postgres settings as displayed in the following example: ```yaml postgresql: - primary: - persistence: - enabled: true - existingClaim: MyAwesomeGiteaPostgresClaim -``` - -MySQL also handles persistence the same, even though it is not deployed as a statefulset. -You can interact with the postgres settings as displayed in the following example: - -```yaml -mysql: - primary: - persistence: - enabled: true - existingClaim: MyAwesomeGiteaMysqlClaim + persistence: + enabled: true + claimName: MyAwesomeGiteaPostgresClaim ``` ### Admin User -This chart enables you to create a default admin user. It is also possible to -update the password for this user by upgrading or redeloying the chart. It is -not possible to delete an admin user after it has been created. This has to be -done in the ui. You cannot use `admin` as username. +This chart enables you to create a default admin user. +It is also possible to update the password for this user by upgrading or redeploying the chart. +You cannot use `admin` as username. ```yaml gitea: @@ -406,10 +560,26 @@ gitea: existingSecret: gitea-admin-secret ``` +To delete the admin user, set `username` or `password` to an empty value and delete the user in the UI. + +Whether you use the existing Secret or specify a username and password directly, there are three modes for how the admin user password is created or set. + +- `keepUpdated` (the default) will set the admin user password, and reset it to the defined value every time the pod is recreated. +- `initialOnlyNoReset` will set the admin user password when creating it, but never try to update the password. +- `initialOnlyRequireReset` will set the admin user password when creating it, never update it, and require that the password be changed at the initial login. + +These modes can be set like the following: + +```yaml +gitea: + admin: + passwordMode: initialOnlyRequireReset +``` + ### LDAP Settings Like the admin user the LDAP settings can be updated. -All LDAP values from are available. +All LDAP values from are available. Multiple LDAP sources can be configured with additional LDAP list items. @@ -430,7 +600,7 @@ gitea: publicSSHKeyAttribute: publicSSHKey ``` -You can also use an existing secret to set the bindDn and bindPassword: +You can also use an existing secret to set the `bindDn` and `bindPassword`: ```yaml apiVersion: v1 @@ -449,9 +619,9 @@ gitea: - existingSecret: gitea-ldap-secret ``` -⚠️ Some options are just flags and therefore don't have any values. If they -are defined in `gitea.ldap` configuration, they will be passed to the Gitea CLI -without any value. Affected options: +⚠️ Some options are just flags and therefore don't have any values. +If they are defined in `gitea.ldap` configuration, they will be passed to the Forgejo CLI without any value. +Affected options: - notActive - skipTlsVerify @@ -461,10 +631,9 @@ without any value. Affected options: ### OAuth2 Settings -Like the admin user, OAuth2 settings can be updated and disabled but not -deleted. Deleting OAuth2 settings has to be done in the ui. All OAuth2 values, -which are documented [here](https://docs.gitea.io/en-us/command-line/#admin), are -available. +Like the admin user, OAuth2 settings can be updated and disabled but not deleted. +Deleting OAuth2 settings has to be done in the UI. +[All OAuth2 values](https://forgejo.org/docs/latest/admin/command-line/#admin-auth-add-oauth) are available. Multiple OAuth2 sources can be configured with additional OAuth list items. @@ -503,17 +672,29 @@ gitea: existingSecret: gitea-oauth-secret ``` +### Compatibility with OCP (OKD or OpenShift) + +Normally OCP is automatically detected and the compatibility mode set accordingly. To enforce the OCP compatibility mode use the following configuration: + +```yaml +global: + compatibility: + openshift: + adaptSecurityContext: force +``` + +An OCP route to access Forgejo can be enabled with the following config: + +```yaml +route: + enabled: true +``` + ## Configure commit signing -When using the rootless image the gpg key folder is not persistent by -default. If you consider using signed commits for internal Gitea activities -(e.g. initial commit), you'd need to provide a signing key. Prior to -[PR186](https://gitea.com/gitea/helm-chart/pulls/186), imported keys had to be -re-imported once the container got replaced by another. - -The mentioned PR introduced a new configuration object `signing` allowing you to -configure prerequisites for commit signing. By default this section is disabled -to maintain backwards compatibility. +When using the rootless image, the GPG key folder is not persistent by default. +If you want commits by Forgejo (e.g. initial commit) to be signed, +you need to provide a signing key: ```yaml signing: @@ -521,9 +702,10 @@ signing: gpgHome: /data/git/.gnupg ``` -Regardless of the used container image the `signing` object allows to specify a -private gpg key. Either using the `signing.privateKey` to define the key inline, -or refer to an existing secret containing the key data by using `signing.existingKey`. +By default this section is disabled to maintain backwards compatibility. + +Regardless of the used container image the `signing` object allows to specify a private GPG key. +Either using the `signing.privateKey` to define the key inline, or referring to an existing secret containing the key data with `signing.existingSecret`. ```yaml apiVersion: v1 @@ -543,19 +725,15 @@ signing: existingSecret: custom-gitea-gpg-key ``` -To use the gpg key, Gitea needs to be configured accordingly. A detailed description -can be found in the [official Gitea documentation](https://docs.gitea.io/en-us/signing/#general-configuration). +To use the GPG key, Forgejo needs to be configured accordingly. +A detailed description can be found in the [documentation](https://forgejo.org/docs/latest/admin/signing/#general-configuration). -### Metrics and profiling +## Metrics and profiling -A Prometheus `/metrics` endpoint on the `HTTP_PORT` and `pprof` profiling -endpoints on port 6060 can be enabled under `gitea`. Beware that the metrics -endpoint is exposed via the ingress, manage access using ingress annotations for -example. +A Prometheus `/metrics` endpoint on the `HTTP_PORT` and `pprof` profiling endpoints on port 6060 can be enabled under `gitea`. +Beware that the metrics endpoint is exposed via the ingress, manage access using ingress annotations for example. -To deploy the `ServiceMonitor`, you first need to ensure that you have deployed -`prometheus-operator` and its -[CRDs](https://github.com/prometheus-operator/prometheus-operator#customresourcedefinitions). +To deploy the `ServiceMonitor`, you first need to ensure that you have deployed `prometheus-operator` and its [CRDs](https://github.com/prometheus-operator/prometheus-operator#customresourcedefinitions). ```yaml gitea: @@ -569,7 +747,7 @@ gitea: ENABLE_PPROF: true ``` -### Pod Annotations +## Pod annotations Annotations can be added to the Forgejo pod. @@ -578,28 +756,138 @@ gitea: podAnnotations: {} ``` +## Themes + +Custom themes can be added via k8s secrets and referencing them in `values.yaml`. + +The [http provider](https://registry.terraform.io/providers/hashicorp/http/latest/docs/data-sources/http) is useful here. + +```yaml +extraVolumes: + - name: gitea-themes + secret: + secretName: gitea-themes + +extraVolumeMounts: + - name: gitea-themes + readOnly: true + mountPath: '/data/gitea/public/assets/css' +``` + +The secret can be created via `terraform`: + +```hcl +resource "kubernetes_secret" "gitea-themes" { + metadata { + name = "gitea-themes" + namespace = "gitea" + } + + data = { + "my-theme.css" = data.http.gitea-theme-light.body + "my-theme-dark.css" = data.http.gitea-theme-dark.body + "my-theme-auto.css" = data.http.gitea-theme-auto.body + } + + type = "Opaque" +} + + +data "http" "gitea-theme-light" { + url = "" + + request_headers = { + Accept = "application/json" + } +} + +data "http" "gitea-theme-dark" { + url = "" + + request_headers = { + Accept = "application/json" + } +} + +data "http" "gitea-theme-auto" { + url = "" + + request_headers = { + Accept = "application/json" + } +} +``` + +or natively via `kubectl`: + +```bash +kubectl create secret generic gitea-themes --from-file={{FULL-PATH-TO-CSS}} --namespace gitea +``` + +## Renovate + +To be able to use a digest value which is automatically updated by `Renovate` a [customManager](https://docs.renovatebot.com/modules/manager/regex/) is required. +Here's an examplary `values.yml` definition which makes use of a digest: + +```yaml +image: + registry: code.forgejo.org + repository: forgejo/forgejo + tag: 1.20.2-0 + digest: sha256:f597c14a403c2fdee9a62dae8bae29d6442f7b2cc85872cc9bb535a24cb1630e +``` + +By default Renovate adds digest after the `tag`. +To comply with the Forgejo helm chart definition of the digest parameter, a "customManagers" definition is required: + +```json +"customManagers": [ + { + "customType": "regex", + "description": "Apply an explicit gitea digest field match", + "fileMatch": ["values\\.ya?ml"], + "matchStrings": ["(?forgejo\\/forgejo)\\n(?\\s+)tag: (?[^@].*?)\\n\\s+digest: (?sha256:[a-f0-9]+)"], + "datasourceTemplate": "docker", + "packageNameTemplate": "code.forgejo.org/{{depName}}", + "autoReplaceStringTemplate": "{{depName}}\n{{indentation}}tag: {{newValue}}\n{{indentation}}digest: {{#if newDigest}}{{{newDigest}}}{{else}}{{{currentDigest}}}{{/if}}" + } +] +``` + ## Parameters ### Global -| Name | Description | Value | -| ------------------------- | ------------------------------------------------------------------------- | --------------- | -| `global.imageRegistry` | global image registry override | `""` | -| `global.imagePullSecrets` | global image pull secrets override; can be extended by `imagePullSecrets` | `[]` | -| `global.storageClass` | global storage class override | `""` | -| `replicaCount` | number of replicas for the statefulset | `1` | -| `clusterDomain` | cluster domain | `cluster.local` | +| Name | Description | Value | +| ------------------------- | ------------------------------------------------------------------------- | ----- | +| `global.imageRegistry` | global image registry override | `""` | +| `global.imagePullSecrets` | global image pull secrets override; can be extended by `imagePullSecrets` | `[]` | +| `global.storageClass` | global storage class override | `""` | +| `global.hostAliases` | global hostAliases which will be added to the pod's hosts files | `[]` | +| `namespaceOverride` | String to fully override common.names.namespace | `""` | +| `replicaCount` | number of replicas for the deployment | `1` | + +### strategy + +| Name | Description | Value | +| --------------------------------------- | -------------- | --------------- | +| `strategy.type` | strategy type | `RollingUpdate` | +| `strategy.rollingUpdate.maxSurge` | maxSurge | `100%` | +| `strategy.rollingUpdate.maxUnavailable` | maxUnavailable | `0` | +| `clusterDomain` | cluster domain | `cluster.local` | ### Image -| Name | Description | Value | -| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------- | ----------------- | -| `image.registry` | image registry, e.g. gcr.io,docker.io | `codeberg.org` | -| `image.repository` | Image to start for this pod | `forgejo/forgejo` | -| `image.tag` | Visit: [Image tag](https://codeberg.org/forgejo/-/packages/container/forgejo/versions). Defaults to `appVersion` within Chart.yaml. | `""` | -| `image.pullPolicy` | Image pull policy | `Always` | -| `image.rootless` | Wether or not to pull the rootless version of Forgejo, only works on Forgejo 1.14.x or higher | `false` | -| `imagePullSecrets` | Secret to use for pulling the image | `[]` | +| Name | Description | Value | +| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ | +| `image.registry` | image registry, e.g. gcr.io,docker.io | `code.forgejo.org` | +| `image.repository` | Image to start for this pod | `forgejo/forgejo` | +| `image.tag` | Visit: [Image tag](https://code.forgejo.org/forgejo/-/packages/container/forgejo/versions). Defaults to `appVersion` within Chart.yaml. | `""` | +| `image.digest` | Image digest. Allows to pin the given image tag. Useful for having control over mutable tags like `latest` | `""` | +| `image.pullPolicy` | Image pull policy | `IfNotPresent` | +| `image.rootless` | Wether or not to pull the rootless version of Forgejo | `true` | +| `image.fullOverride` | Completely overrides the image registry, path/image, tag and digest. **Adjust `image.rootless` accordingly and review [Rootless defaults](#rootless-defaults).** | `""` | +| `imagePullSecrets` | Secret to use for pulling the image | `[]` | ### Security @@ -608,6 +896,7 @@ gitea: | `podSecurityContext.fsGroup` | Set the shared file system group for all containers in the pod. | `1000` | | `containerSecurityContext` | Security context | `{}` | | `securityContext` | Run init and Forgejo containers as a specific securityContext | `{}` | +| `podDisruptionBudget` | Pod disruption budget | `{}` | ### Service @@ -615,7 +904,7 @@ gitea: | --------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- | | `service.http.type` | Kubernetes service type for web traffic | `ClusterIP` | | `service.http.port` | Port number for web traffic | `3000` | -| `service.http.clusterIP` | ClusterIP setting for http autosetup for statefulset is None | `None` | +| `service.http.clusterIP` | ClusterIP setting for http autosetup for deployment | `nil` | | `service.http.loadBalancerIP` | LoadBalancer IP setting | `nil` | | `service.http.nodePort` | NodePort for http service | `nil` | | `service.http.externalTrafficPolicy` | If `service.http.type` is `NodePort` or `LoadBalancer`, set this to `Local` to enable source IP preservation | `nil` | @@ -624,9 +913,11 @@ gitea: | `service.http.ipFamilies` | HTTP service dual-stack familiy selection,for dual-stack parameters see official kubernetes [dual-stack concept documentation](https://kubernetes.io/docs/concepts/services-networking/dual-stack/). | `nil` | | `service.http.loadBalancerSourceRanges` | Source range filter for http loadbalancer | `[]` | | `service.http.annotations` | HTTP service annotations | `{}` | +| `service.http.labels` | HTTP service additional labels | `{}` | +| `service.http.loadBalancerClass` | Loadbalancer class | `nil` | | `service.ssh.type` | Kubernetes service type for ssh traffic | `ClusterIP` | | `service.ssh.port` | Port number for ssh traffic | `22` | -| `service.ssh.clusterIP` | ClusterIP setting for ssh autosetup for statefulset is None | `None` | +| `service.ssh.clusterIP` | ClusterIP setting for ssh autosetup for deployment | `nil` | | `service.ssh.loadBalancerIP` | LoadBalancer IP setting | `nil` | | `service.ssh.nodePort` | NodePort for ssh service | `nil` | | `service.ssh.externalTrafficPolicy` | If `service.ssh.type` is `NodePort` or `LoadBalancer`, set this to `Local` to enable source IP preservation | `nil` | @@ -636,57 +927,93 @@ gitea: | `service.ssh.hostPort` | HostPort for ssh service | `nil` | | `service.ssh.loadBalancerSourceRanges` | Source range filter for ssh loadbalancer | `[]` | | `service.ssh.annotations` | SSH service annotations | `{}` | +| `service.ssh.labels` | SSH service additional labels | `{}` | +| `service.ssh.loadBalancerClass` | Loadbalancer class | `nil` | ### Ingress -| Name | Description | Value | -| ------------------------------------ | --------------------------------------------------------------------------- | ----------------- | -| `ingress.enabled` | Enable ingress | `false` | -| `ingress.className` | Ingress class name | `nil` | -| `ingress.annotations` | Ingress annotations | `{}` | -| `ingress.hosts[0].host` | Default Ingress host | `git.example.com` | -| `ingress.hosts[0].paths[0].path` | Default Ingress path | `/` | -| `ingress.hosts[0].paths[0].pathType` | Ingress path type | `Prefix` | -| `ingress.tls` | Ingress tls settings | `[]` | -| `ingress.apiVersion` | Specify APIVersion of ingress object. Mostly would only be used for argocd. | | +| Name | Description | Value | +| ------------------------------------ | -------------------- | ----------------- | +| `ingress.enabled` | Enable ingress | `false` | +| `ingress.className` | Ingress class name | `nil` | +| `ingress.annotations` | Ingress annotations | `{}` | +| `ingress.hosts[0].host` | Default Ingress host | `git.example.com` | +| `ingress.hosts[0].paths[0].path` | Default Ingress path | `/` | +| `ingress.hosts[0].paths[0].pathType` | Ingress path type | `Prefix` | +| `ingress.tls` | Ingress tls settings | `[]` | -### StatefulSet +### Route -| Name | Description | Value | -| ------------------------------------------- | ------------------------------------------------------ | ----- | -| `resources` | Kubernetes resources | `{}` | -| `schedulerName` | Use an alternate scheduler, e.g. "stork" | `""` | -| `nodeSelector` | NodeSelector for the statefulset | `{}` | -| `tolerations` | Tolerations for the statefulset | `[]` | -| `affinity` | Affinity for the statefulset | `{}` | -| `dnsConfig` | dnsConfig for the statefulset | `{}` | -| `statefulset.env` | Additional environment variables to pass to containers | `[]` | -| `statefulset.terminationGracePeriodSeconds` | How long to wait until forcefully kill the pod | `60` | -| `statefulset.labels` | Labels for the statefulset | `{}` | -| `statefulset.annotations` | Annotations for the Forgejo StatefulSet to be created | `{}` | +| Name | Description | Value | +| ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- | +| `route.enabled` | Enable route | `false` | +| `route.annotations` | Route annotations | `{}` | +| `route.host` | Host to use for the route (will be assigned automatically by OKD / OpenShift is not defined) | `nil` | +| `route.wildcardPolicy` | Wildcard policy if any for the route, currently only 'Subdomain' or 'None' is allowed. | `nil` | +| `route.tls.termination` | termination type (see [OKD documentation](https://docs.okd.io/latest/rest_api/network_apis/route-route-openshift-io-v1.html#spec-tls)) | `edge` | +| `route.tls.insecureEdgeTerminationPolicy` | the desired behavior for insecure connections to a route (e.g. with http) | `Redirect` | +| `route.tls.existingSecret` | the name of a predefined secret of type kubernetes.io/tls with both key (tls.crt and tls.key) set accordingly (if defined attributes 'certificate', 'caCertificate' and 'privateKey' are ignored) | `nil` | +| `route.tls.certificate` | PEM encoded single certificate | `nil` | +| `route.tls.privateKey` | PEM encoded private key | `nil` | +| `route.tls.caCertificate` | PEM encoded CA certificate or chain that issued the certificate | `nil` | +| `route.tls.destinationCACertificate` | PEM encoded CA certificate used to verify the authenticity of final end point when 'termination' is set to 'passthrough' (ignored otherwise) | `nil` | + +### deployment + +| Name | Description | Value | +| ------------------------------------------ | ------------------------------------------------------ | ----- | +| `resources` | Kubernetes resources | `{}` | +| `schedulerName` | Use an alternate scheduler, e.g. "stork" | `""` | +| `nodeSelector` | NodeSelector for the deployment | `{}` | +| `tolerations` | Tolerations for the deployment | `[]` | +| `affinity` | Affinity for the deployment | `{}` | +| `topologySpreadConstraints` | TopologySpreadConstraints for the deployment | `[]` | +| `dnsConfig` | dnsConfig for the deployment | `{}` | +| `priorityClassName` | priorityClassName for the deployment | `""` | +| `deployment.env` | Additional environment variables to pass to containers | `[]` | +| `deployment.terminationGracePeriodSeconds` | How long to wait until forcefully kill the pod | `60` | +| `deployment.labels` | Labels for the deployment | `{}` | +| `deployment.annotations` | Annotations for the Forgejo deployment to be created | `{}` | + +### ServiceAccount + +| Name | Description | Value | +| --------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | ------- | +| `serviceAccount.create` | Enable the creation of a ServiceAccount | `false` | +| `serviceAccount.name` | Name of the created ServiceAccount, defaults to release name. Can also link to an externally provided ServiceAccount that should be used. | `""` | +| `serviceAccount.automountServiceAccountToken` | Enable/disable auto mounting of the service account token | `false` | +| `serviceAccount.imagePullSecrets` | Image pull secrets, available to the ServiceAccount | `[]` | +| `serviceAccount.annotations` | Custom annotations for the ServiceAccount | `{}` | +| `serviceAccount.labels` | Custom labels for the ServiceAccount | `{}` | ### Persistence -| Name | Description | Value | -| ---------------------------- | ------------------------------------------------------------------------------------------------------- | ------------------- | -| `persistence.enabled` | Enable persistent storage | `true` | -| `persistence.existingClaim` | Use an existing claim to store repository information | `nil` | -| `persistence.size` | Size for persistence to store repo information | `10Gi` | -| `persistence.accessModes` | AccessMode for persistence | `["ReadWriteOnce"]` | -| `persistence.labels` | Labels for the persistence volume claim to be created | `{}` | -| `persistence.annotations` | Annotations for the persistence volume claim to be created | `{}` | -| `persistence.storageClass` | Name of the storage class to use | `nil` | -| `persistence.subPath` | Subdirectory of the volume to mount at | `nil` | -| `extraVolumes` | Additional volumes to mount to the Forgejo statefulset | `[]` | -| `extraContainerVolumeMounts` | Mounts that are only mapped into the Forgejo runtime/main container, to e.g. override custom templates. | `[]` | -| `extraInitVolumeMounts` | Mounts that are only mapped into the init-containers. Can be used for additional preconfiguration. | `[]` | -| `extraVolumeMounts` | **DEPRECATED** Additional volume mounts for init containers and the Forgejo main container | `[]` | +| Name | Description | Value | +| ------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | ---------------------- | +| `persistence.enabled` | Enable persistent storage | `true` | +| `persistence.create` | Whether to create the persistentVolumeClaim for shared storage | `true` | +| `persistence.mount` | Whether the persistentVolumeClaim should be mounted (even if not created) | `true` | +| `persistence.claimName` | Use an existing claim to store repository information | `gitea-shared-storage` | +| `persistence.size` | Size for persistence to store repo information | `10Gi` | +| `persistence.accessModes` | AccessMode for persistence | `["ReadWriteOnce"]` | +| `persistence.labels` | Labels for the persistence volume claim to be created | `{}` | +| `persistence.annotations.helm.sh/resource-policy` | Resource policy for the persistence volume claim | `keep` | +| `persistence.storageClass` | Name of the storage class to use | `nil` | +| `persistence.subPath` | Subdirectory of the volume to mount at | `nil` | +| `persistence.volumeName` | Name of persistent volume in PVC | `""` | +| `extraVolumes` | Additional volumes to mount to the Forgejo deployment | `[]` | +| `extraContainerVolumeMounts` | Mounts that are only mapped into the Forgejo runtime/main container, to e.g. override custom templates. | `[]` | +| `extraInitVolumeMounts` | Mounts that are only mapped into the init-containers. Can be used for additional preconfiguration. | `[]` | +| `extraVolumeMounts` | **DEPRECATED** Additional volume mounts for init containers and the Forgejo main container | `[]` | ### Init -| Name | Description | Value | -| --------------- | --------------------------------------------------------------------- | ----- | -| `initPreScript` | Bash shell script copied verbatim to the start of the init-container. | `""` | +| Name | Description | Value | +| ------------------------------------------ | ------------------------------------------------------------------------------------ | ------- | +| `initPreScript` | Bash shell script copied verbatim to the start of the init-container. | `""` | +| `initContainers.resources.limits` | initContainers.limits Kubernetes resource limits for init containers | `{}` | +| `initContainers.resources.requests.cpu` | initContainers.requests.cpu Kubernetes cpu resource limits for init containers | `100m` | +| `initContainers.resources.requests.memory` | initContainers.requests.memory Kubernetes memory resource limits for init containers | `128Mi` | ### Signing @@ -694,25 +1021,83 @@ gitea: | ------------------------ | ----------------------------------------------------------------- | ------------------ | | `signing.enabled` | Enable commit/action signing | `false` | | `signing.gpgHome` | GPG home directory | `/data/git/.gnupg` | -| `signing.privateKey` | Inline private gpg key for signed Forgejo actions | `""` | +| `signing.privateKey` | Inline private GPG key for signed internal Git activity | `""` | | `signing.existingSecret` | Use an existing secret to store the value of `signing.privateKey` | `""` | ### Gitea -| Name | Description | Value | -| -------------------------------------- | --------------------------------------------------------------------------------------------------------------- | -------------------- | -| `gitea.admin.username` | Username for the Forgejo admin user | `gitea_admin` | -| `gitea.admin.existingSecret` | Use an existing secret to store admin user credentials | `nil` | -| `gitea.admin.password` | Password for the Forgejo admin user | `r8sA8CPHD9!bt6d` | -| `gitea.admin.email` | Email for the Forgejo admin user | `gitea@local.domain` | -| `gitea.metrics.enabled` | Enable Forgejo metrics | `false` | -| `gitea.metrics.serviceMonitor.enabled` | Enable Forgejo metrics service monitor | `false` | -| `gitea.ldap` | LDAP configuration | `[]` | -| `gitea.oauth` | OAuth configuration | `[]` | -| `gitea.config` | Configuration for the Forgejo server,ref: [config-cheat-sheet](https://docs.gitea.io/en-us/config-cheat-sheet/) | `{}` | -| `gitea.additionalConfigSources` | Additional configuration from secret or configmap | `[]` | -| `gitea.additionalConfigFromEnvs` | Additional configuration sources from environment variables | `[]` | -| `gitea.podAnnotations` | Annotations for the Forgejo pod | `{}` | +| Name | Description | Value | +| ---------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | -------------------- | +| `gitea.admin.username` | Username for the Forgejo admin user | `gitea_admin` | +| `gitea.admin.existingSecret` | Use an existing secret to store admin user credentials | `nil` | +| `gitea.admin.password` | Password for the Forgejo admin user | `r8sA8CPHD9!bt6d` | +| `gitea.admin.email` | Email for the Forgejo admin user | `gitea@local.domain` | +| `gitea.admin.passwordMode` | Mode for how to set/update the admin user password. Options are: initialOnlyNoReset, initialOnlyRequireReset, and keepUpdated | `keepUpdated` | +| `gitea.metrics.enabled` | Enable Forgejo metrics | `false` | +| `gitea.metrics.serviceMonitor.enabled` | Enable Forgejo metrics service monitor | `false` | +| `gitea.metrics.serviceMonitor.namespace` | Namespace in which Prometheus is running | `""` | +| `gitea.ldap` | LDAP configuration | `[]` | +| `gitea.oauth` | OAuth configuration | `[]` | +| `gitea.additionalConfigSources` | Additional configuration from secret or configmap | `[]` | +| `gitea.additionalConfigFromEnvs` | Additional configuration sources from environment variables | `[]` | +| `gitea.podAnnotations` | Annotations for the Forgejo pod | `{}` | +| `gitea.ssh.logLevel` | Configure OpenSSH's log level. Only available for root-based Forgejo image. | `INFO` | + +### `app.ini` overrides + +Every value described in the [Cheat +Sheet](https://forgejo.org/docs/latest/admin/config-cheat-sheet/) can be +set as a Helm value. Configuration sections map to (lowercased) YAML +blocks, while the keys themselves remain in all caps. + +| Name | Description | Value | +| ------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------- | +| `gitea.config.APP_NAME` | Application name, used in the page title | `Forgejo: Beyond coding. We forge.` | +| `gitea.config.RUN_MODE` | Application run mode, affects performance and debugging: `dev` or `prod` | `prod` | +| `gitea.config.repository` | General repository settings | `{}` | +| `gitea.config.cors` | Cross-origin resource sharing settings | `{}` | +| `gitea.config.ui` | User interface settings | `{}` | +| `gitea.config.markdown` | Markdown parser settings | `{}` | +| `gitea.config.server` | General server settings | `{}` | +| `gitea.config.database` | Database configuration (only necessary with an [externally managed DB](https://code.forgejo.org/forgejo-helm/forgejo-helm#external-database)). | `{}` | +| `gitea.config.indexer` | Settings for what content is indexed and how | `{}` | +| `gitea.config.queue` | Job queue configuration | `{}` | +| `gitea.config.admin` | Admin user settings | `{}` | +| `gitea.config.security` | Site security settings | `{}` | +| `gitea.config.camo` | Settings for the [camo](https://github.com/cactus/go-camo) media proxy server (disabled by default) | `{}` | +| `gitea.config.openid` | Configuration for authentication with OpenID (disabled by default) | `{}` | +| `gitea.config.oauth2_client` | OAuth2 client settings | `{}` | +| `gitea.config.service` | Configuration for miscellaneous Forgejo services | `{}` | +| `gitea.config.ssh.minimum_key_sizes` | SSH minimum key sizes | `{}` | +| `gitea.config.webhook` | Webhook settings | `{}` | +| `gitea.config.mailer` | Mailer configuration (disabled by default) | `{}` | +| `gitea.config.email.incoming` | Configuration for handling incoming mail (disabled by default) | `{}` | +| `gitea.config.cache` | Cache configuration | `{}` | +| `gitea.config.session` | Session/cookie handling | `{}` | +| `gitea.config.picture` | User avatar settings | `{}` | +| `gitea.config.project` | Project board defaults | `{}` | +| `gitea.config.attachment` | Issue and PR attachment configuration | `{}` | +| `gitea.config.log` | Logging configuration | `{}` | +| `gitea.config.cron` | Cron job configuration | `{}` | +| `gitea.config.git` | Global settings for Git | `{}` | +| `gitea.config.metrics` | Settings for the Prometheus endpoint (disabled by default) | `{}` | +| `gitea.config.api` | Settings for the Swagger API documentation endpoints | `{}` | +| `gitea.config.oauth2` | Settings for the [OAuth2 provider](https://forgejo.org/docs/latest/admin/oauth2-provider/) | `{}` | +| `gitea.config.i18n` | Internationalization settings | `{}` | +| `gitea.config.markup` | Configuration for advanced markup processors | `{}` | +| `gitea.config.highlight.mapping` | File extension to language mapping overrides for syntax highlighting | `{}` | +| `gitea.config.time` | Locale settings | `{}` | +| `gitea.config.migrations` | Settings for Git repository migrations | `{}` | +| `gitea.config.federation` | Federation configuration | `{}` | +| `gitea.config.packages` | Package registry settings | `{}` | +| `gitea.config.mirror` | Configuration for repository mirroring | `{}` | +| `gitea.config.lfs` | Large File Storage configuration | `{}` | +| `gitea.config.repo-avatar` | Repository avatar storage configuration | `{}` | +| `gitea.config.avatar` | User/org avatar storage configuration | `{}` | +| `gitea.config.storage` | General storage settings | `{}` | +| `gitea.config.proxy` | Proxy configuration (disabled by default) | `{}` | +| `gitea.config.actions` | Configuration for [Forgejo Actions](https://forgejo.org/docs/latest/user/actions/) | `{}` | +| `gitea.config.other` | Uncategorized configuration options | `{}` | ### LivenessProbe @@ -728,15 +1113,16 @@ gitea: ### ReadinessProbe -| Name | Description | Value | -| ------------------------------------------ | ------------------------------------------------- | ------ | -| `gitea.readinessProbe.enabled` | Enable readiness probe | `true` | -| `gitea.readinessProbe.tcpSocket.port` | Port to probe for readiness | `http` | -| `gitea.readinessProbe.initialDelaySeconds` | Initial delay before readiness probe is initiated | `5` | -| `gitea.readinessProbe.timeoutSeconds` | Timeout for readiness probe | `1` | -| `gitea.readinessProbe.periodSeconds` | Period for readiness probe | `10` | -| `gitea.readinessProbe.successThreshold` | Success threshold for readiness probe | `1` | -| `gitea.readinessProbe.failureThreshold` | Failure threshold for readiness probe | `3` | +| Name | Description | Value | +| ------------------------------------------ | ------------------------------------------------- | -------------- | +| `gitea.readinessProbe.enabled` | Enable readiness probe | `true` | +| `gitea.readinessProbe.httpGet.path` | Path to probe for readiness | `/api/healthz` | +| `gitea.readinessProbe.httpGet.port` | Port to probe for readiness | `http` | +| `gitea.readinessProbe.initialDelaySeconds` | Initial delay before readiness probe is initiated | `5` | +| `gitea.readinessProbe.timeoutSeconds` | Timeout for readiness probe | `1` | +| `gitea.readinessProbe.periodSeconds` | Period for readiness probe | `10` | +| `gitea.readinessProbe.successThreshold` | Success threshold for readiness probe | `1` | +| `gitea.readinessProbe.failureThreshold` | Failure threshold for readiness probe | `3` | ### StartupProbe @@ -750,62 +1136,73 @@ gitea: | `gitea.startupProbe.successThreshold` | Success threshold for startup probe | `1` | | `gitea.startupProbe.failureThreshold` | Failure threshold for startup probe | `10` | -### Memcached +### Redis® Cluster -Memcached is loaded as a dependency from [Bitnami](https://github.com/bitnami/charts/tree/master/bitnami/memcached) if enabled in the values. Complete Configuration can be taken from their website. +Redis® Cluster is loaded as a dependency from [Bitnami](https://github.com/bitnami/charts/tree/master/bitnami/redis-cluster) if enabled in the values. +Full configuration options are available on their website. +Redis cluster and [Redis](#redis) cannot be enabled at the same time. -| Name | Description | Value | -| ----------------------------------- | ------------------ | ------- | -| `memcached.enabled` | Enable Memcached | `true` | -| `memcached.service.ports.memcached` | Port for Memcached | `11211` | +| Name | Description | Value | +| -------------------------------- | -------------------------------------------- | ------- | +| `redis-cluster.enabled` | Enable redis cluster | `true` | +| `redis-cluster.usePassword` | Whether to use password authentication | `false` | +| `redis-cluster.cluster.nodes` | Number of redis cluster master nodes | `3` | +| `redis-cluster.cluster.replicas` | Number of redis cluster master node replicas | `0` | + +### Redis® + +Redis® is loaded as a dependency from [Bitnami](https://github.com/bitnami/charts/tree/master/bitnami/redis) if enabled in the values. +Full configuration options are available on their website. +Redis and [Redis cluster](#redis-cluster) cannot be enabled at the same time. + +| Name | Description | Value | +| ----------------------------- | ------------------------------------------ | ------------ | +| `redis.enabled` | Enable redis standalone or replicated | `false` | +| `redis.architecture` | Whether to use standalone or replication | `standalone` | +| `redis.global.redis.password` | Required password | `changeme` | +| `redis.master.count` | Number of Redis master instances to deploy | `1` | + +### PostgreSQL HA + +PostgreSQL HA is loaded as a dependency from [Bitnami](https://github.com/bitnami/charts/tree/master/bitnami/postgresql-ha) if enabled in the values. +Full configuration options are available on their website. + +| Name | Description | Value | +| ------------------------------------------- | ---------------------------------------------------------------- | ----------- | +| `postgresql-ha.enabled` | Enable PostgreSQL HA chart | `true` | +| `postgresql-ha.postgresql.password` | Password for the `gitea` user (overrides `auth.password`) | `changeme4` | +| `postgresql-ha.global.postgresql.database` | Name for a custom database to create (overrides `auth.database`) | `gitea` | +| `postgresql-ha.global.postgresql.username` | Name for a custom user to create (overrides `auth.username`) | `gitea` | +| `postgresql-ha.global.postgresql.password` | Name for a custom password to create (overrides `auth.password`) | `gitea` | +| `postgresql-ha.postgresql.repmgrPassword` | Repmgr Password | `changeme2` | +| `postgresql-ha.postgresql.postgresPassword` | postgres Password | `changeme1` | +| `postgresql-ha.pgpool.adminPassword` | pgpool adminPassword | `changeme3` | +| `postgresql-ha.service.ports.postgresql` | PostgreSQL service port (overrides `service.ports.postgresql`) | `5432` | +| `postgresql-ha.primary.persistence.size` | PVC Storage Request for PostgreSQL HA volume | `10Gi` | ### PostgreSQL -PostgreSQL is loaded as a dependency from [Bitnami](https://github.com/bitnami/charts/tree/master/bitnami/postgresql) if enabled in the values. Complete Configuration can be taken from their website. +PostgreSQL is loaded as a dependency from [Bitnami](https://github.com/bitnami/charts/tree/master/bitnami/postgresql) if enabled in the values. +Full configuration options are available on their website. -| Name | Description | Value | -| --------------------------------------------- | ----------------------------------------- | ------- | -| `postgresql.enabled` | Enable PostgreSQL | `true` | -| `postgresql.auth.database` | PostgreSQL database | `gitea` | -| `postgresql.auth.username` | PostgreSQL username | `gitea` | -| `postgresql.auth.password` | PostgreSQL username | `gitea` | -| `postgresql.auth.postgresPassword` | PostgreSQL admin password | `gitea` | -| `postgresql.primary.service.ports.postgresql` | Port to connect to PostgreSQL service | `5432` | -| `postgresql.primary.persistence.size` | PVC Storage Request for PostgreSQL volume | `10Gi` | - -### MySQL - -MySQL is loaded as a dependency from [Bitnami](https://github.com/bitnami/charts/tree/master/bitnami/mysql) if enabled in the values. Complete Configuration can be taken from their website. - -| Name | Description | Value | -| ----------------------------------- | ------------------------------------------------------------------ | ------- | -| `mysql.enabled` | Enable MySQL | `false` | -| `mysql.auth.database` | Name for new database to create. | `gitea` | -| `mysql.auth.username` | Username of new user to create. | `gitea` | -| `mysql.auth.password` | Password for the new user.Ignored if existing secret is provided | `gitea` | -| `mysql.auth.rootPassword` | Password for the root user. Ignored if existing secret is provided | `gitea` | -| `mysql.primary.service.ports.mysql` | Port to connect to MySQL service | `3306` | -| `mysql.primary.persistence.size` | PVC Storage Request for MySQL volume | `10Gi` | - -### MariaDB - -MariaDB is loaded as a dependency from [Bitnami](https://github.com/bitnami/charts/tree/master/bitnami/mariadb) if enabled in the values. Complete Configuration can be taken from their website. - -| Name | Description | Value | -| ------------------------------------- | ----------------------------------------------------------------- | ------- | -| `mariadb.enabled` | Enable MariaDB | `false` | -| `mariadb.auth.database` | Name of the database to create. | `gitea` | -| `mariadb.auth.username` | Username of the new user to create. | `gitea` | -| `mariadb.auth.password` | Password for the new user. Ignored if existing secret is provided | `gitea` | -| `mariadb.auth.rootPassword` | Password for the root user. | `gitea` | -| `mariadb.primary.service.ports.mysql` | Port to connect to MariaDB service | `3306` | -| `mariadb.primary.persistence.size` | Persistence size for MariaDB | `10Gi` | +| Name | Description | Value | +| ------------------------------------------------------- | ---------------------------------------------------------------- | ------- | +| `postgresql.enabled` | Enable PostgreSQL | `false` | +| `postgresql.global.postgresql.auth.password` | Password for the `gitea` user (overrides `auth.password`) | `gitea` | +| `postgresql.global.postgresql.auth.database` | Name for a custom database to create (overrides `auth.database`) | `gitea` | +| `postgresql.global.postgresql.auth.username` | Name for a custom user to create (overrides `auth.username`) | `gitea` | +| `postgresql.global.postgresql.service.ports.postgresql` | PostgreSQL service port (overrides `service.ports.postgresql`) | `5432` | +| `postgresql.primary.persistence.size` | PVC Storage Request for PostgreSQL volume | `10Gi` | ### Advanced -| Name | Description | Value | -| ------------------ | ---------------------------------------------------- | ------ | -| `checkDeprecation` | Set it to false to skip this basic validation check. | `true` | +| Name | Description | Value | +| ------------------ | ------------------------------------------------------------------ | --------- | +| `checkDeprecation` | Whether to run this basic validation check. | `true` | +| `test.enabled` | Whether to use test-connection Pod. | `true` | +| `test.image.name` | Image name for the wget container used in the test-connection Pod. | `busybox` | +| `test.image.tag` | Image tag for the wget container used in the test-connection Pod. | `latest` | +| `extraDeploy` | Array of extra objects to deploy with the release. | `[]` | ## Contributing @@ -813,7 +1210,46 @@ Expected workflow is: Fork -> Patch -> Push -> Pull Request See [CONTRIBUTORS GUIDE](CONTRIBUTING.md) for details. +Hop into [our Matrix room](https://matrix.to/#/#forgejo-helm-chart:matrix.org) if you have any questions or want to get involved. + ## Upgrading This section lists major and breaking changes of each Helm Chart version. -Please read them carefully to upgrade successfully. +Please read them carefully to upgrade successfully, especially the change of the **default database backend**! +If you miss this, blindly upgrading may delete your Postgres instance and you may lose your data! + +### To v11 + +PostgreSQL and PostgreSQL HA are now using PostgreSQL v17. +Please read PostgresSQL upgrade guide before upgrading. + +You need Forgejo v10+ to use this Helm Chart version. +Forgejo v9 is now EOL. + +ClusterIP is now emtpy instead of `None` for http and ssh service. +Unsupported api versions for `Ingress` and `PodDisruptionBudget` are removed. +`Ingress` and `Service` are now using named ports. +The ReadinessProbe is now using the `/api/healthz` endpoint. + +### To v10 + +You need Forgejo v9+ to use this Helm Chart version. +Forgejo v8 is now EOL. + +### To v9 + +Namespaces for all resources are now set to `common.names.namespace` by default. + +### To v8 + +You need Forgejo v8+ to use this Helm Chart version. +Use the v7 Helm Chart for Forgejo v7. + +### To v7 + +The Forgejo docker image is pulled from `code.forgejo.org` instead of `codeberg.org`. + +### To v6 + +You need Forgejo v7+ to use this Helm Chart version. +Use the v5 Helm Chart for Forgejo v1.21. diff --git a/artifacthub-repo.yml b/artifacthub-repo.yml index dca8cd9..7a7ea81 100644 --- a/artifacthub-repo.yml +++ b/artifacthub-repo.yml @@ -2,8 +2,8 @@ # Artifact Hub repository metadata file # https://artifacthub.io/docs/topics/repositories/helm-charts/#oci-support # publish via: -# oras push codeberg.org/forgejo-contrib/forgejo:artifacthub.io --config artifacthub.config.json:application/vnd.cncf.artifacthub.config.v1+yaml artifacthub-repo.yml:application/vnd.cncf.artifacthub.repository-metadata.layer.v1.yaml +# oras push code.forgejo.org/forgejo-helm/forgejo:artifacthub.io --config artifacthub.config.json:application/vnd.cncf.artifacthub.config.v1+yaml artifacthub-repo.yml:application/vnd.cncf.artifacthub.repository-metadata.layer.v1.yaml repositoryID: 'ec84c95a-a288-4aaa-a690-a656b57e3136' owners: # (optional, used to claim repository ownership) - name: viceice - email: michael.kriese@visualon.de \ No newline at end of file + email: michael.kriese@visualon.de diff --git a/artifacthub.config.json b/artifacthub.config.json index 9e26dfe..0967ef4 100644 --- a/artifacthub.config.json +++ b/artifacthub.config.json @@ -1 +1 @@ -{} \ No newline at end of file +{} diff --git a/ci/default-values.yaml b/ci/default-values.yaml new file mode 100644 index 0000000..25fefaa --- /dev/null +++ b/ci/default-values.yaml @@ -0,0 +1,20 @@ +# default values with some modifications + +# Use mirror +# https://code.forgejo.org/forgejo-helm/forgejo-helm/issues/1045 +global: + security: + allowInsecureImages: true +redis-cluster: + image: + registry: public.ecr.aws +postgresql-ha: + postgresql: + image: + registry: public.ecr.aws + pgpool: + image: + registry: public.ecr.aws +test: + image: + name: code.forgejo.org/oci/busybox diff --git a/ci/dev-values.yaml b/ci/dev-values.yaml new file mode 100644 index 0000000..a47f3ba --- /dev/null +++ b/ci/dev-values.yaml @@ -0,0 +1,27 @@ +# Test codeberg.org image +image: + registry: codeberg.org +# Use mirror +# https://code.forgejo.org/forgejo-helm/forgejo-helm/issues/1045 +test: + image: + name: code.forgejo.org/oci/busybox + +redis-cluster: + enabled: false +postgresql-ha: + enabled: false + +persistence: + enabled: false + +gitea: + config: + database: + DB_TYPE: sqlite3 + session: + PROVIDER: memory + cache: + ADAPTER: memory + queue: + TYPE: level diff --git a/ci/single-values.yaml b/ci/single-values.yaml new file mode 100644 index 0000000..6be58e6 --- /dev/null +++ b/ci/single-values.yaml @@ -0,0 +1,37 @@ +redis-cluster: + enabled: false +postgresql-ha: + enabled: false + +postgresql: + enabled: true + # Use mirror + # https://code.forgejo.org/forgejo-helm/forgejo-helm/issues/1045 + image: + registry: public.ecr.aws +global: + security: + allowInsecureImages: true + +# Use mirror +# https://code.forgejo.org/forgejo-helm/forgejo-helm/issues/1045 +test: + image: + name: code.forgejo.org/oci/busybox + +persistence: + enabled: true + +gitea: + config: + database: + DB_TYPE: postgres + session: + PROVIDER: db + cache: + ADAPTER: memory + queue: + TYPE: level + indexer: + ISSUE_INDEXER_TYPE: bleve + REPO_INDEXER_ENABLED: true diff --git a/ci/v10-values.yaml b/ci/v10-values.yaml new file mode 100644 index 0000000..253b35b --- /dev/null +++ b/ci/v10-values.yaml @@ -0,0 +1,29 @@ +image: + registry: codeberg.org + repository: forgejo-experimental/forgejo + tag: 10 # don't pin, manifests can be missing + +# Use mirror +# https://code.forgejo.org/forgejo-helm/forgejo-helm/issues/1045 +test: + image: + name: code.forgejo.org/oci/busybox + +redis-cluster: + enabled: false +postgresql-ha: + enabled: false + +persistence: + enabled: false + +gitea: + config: + database: + DB_TYPE: sqlite3 + session: + PROVIDER: memory + cache: + ADAPTER: memory + queue: + TYPE: level diff --git a/ci/v11-values.yaml b/ci/v11-values.yaml new file mode 100644 index 0000000..6c1a24b --- /dev/null +++ b/ci/v11-values.yaml @@ -0,0 +1,29 @@ +image: + registry: codeberg.org + repository: forgejo-experimental/forgejo + tag: 11 # don't pin, manifests can be missing + +# Use mirror +# https://code.forgejo.org/forgejo-helm/forgejo-helm/issues/1045 +test: + image: + name: code.forgejo.org/oci/busybox + +redis-cluster: + enabled: false +postgresql-ha: + enabled: false + +persistence: + enabled: false + +gitea: + config: + database: + DB_TYPE: sqlite3 + session: + PROVIDER: memory + cache: + ADAPTER: memory + queue: + TYPE: level diff --git a/ci/v12-values.yaml b/ci/v12-values.yaml new file mode 100644 index 0000000..8429086 --- /dev/null +++ b/ci/v12-values.yaml @@ -0,0 +1,29 @@ +image: + registry: codeberg.org + repository: forgejo-experimental/forgejo + tag: 12 # don't pin, manifests can be missing + +# Use mirror +# https://code.forgejo.org/forgejo-helm/forgejo-helm/issues/1045 +test: + image: + name: code.forgejo.org/oci/busybox + +redis-cluster: + enabled: false +postgresql-ha: + enabled: false + +persistence: + enabled: false + +gitea: + config: + database: + DB_TYPE: sqlite3 + session: + PROVIDER: memory + cache: + ADAPTER: memory + queue: + TYPE: level diff --git a/docs/ha-setup.md b/docs/ha-setup.md new file mode 100644 index 0000000..df45ad2 --- /dev/null +++ b/docs/ha-setup.md @@ -0,0 +1,178 @@ +# High Availability + +All components (in-memory DB, volume/asset storage, code indexer) used by Forgejo must be deployed in a HA-ready fashion to achieve a full HA-ready Forgejo deployment. +The following document explains how to achieve this for all individual components. + +The resulting Forgejo deployment will consist of ~ 10 pods (depending on the chosen components and their replicas). +One should evaluate upfront whether a HA-deployment is required as switching between HA/non-HA comes with some effort. +For production instances, HA is always recommended to increase uptime and have a frictionless update process. + +A general comment about chart dependencies and external services: +Instead of relying on chart dependencies, it is often better to rely on an external, (managed) instances (in-memory database, asset storage provider, database, etc.). +Many cloud providers offer such services, at least for databases or in-memory databases. +They might cost a bit more than using a self-hosted k8s variant but are usually easier to maintain and scale, if needed. +Also they can be centrally managed and are not linked to the Forgejo helm chart or namespace. +Please consider using external services before you start with your Forgejo HA setup, it will make your life (and the life of the Forgejo maintainers) easier. + +This helm chart tries to help as much as possible to simplify and assert the provisioning of a HA-ready Forgejo instance by implementing smart conditionals if `replicaCount` is set to a value > 1. +Nevertheless, we cannot guarantee for every possible combination of Forgejo settings to work together perfectly in a HA setup. +As a general advice, we recommend to have a test environment aside on which to test possible changes/upgrades before applying these to a production installation. + +## Requirements for HA + +Storage-wise, the HA-Forgejo setup requires a RWX file-system which can be shared among the deployment-based replica pods. +In addition, the following components are required for full HA-readiness: + +- A HA-ready issue (and optionally code) indexer: `elasticsearch` or `meilisearch` +- A HA-ready external object/asset storage (`minio`) (optional, assets can also be stored on the RWX file-system) +- A HA-ready cache (`redis-cluster`) +- A HA-ready DB + +`postgres.enabled`, which default to `true`, must be set to `false` for a HA setup. +The default `postgres` chart dependency is not HA-ready (there's a dedicated `postgres-ha` chart). + +The following sections discuss each of the components in more detail. +Note that for each component discussed, the shown configurations only provides a (working) starting point, not necessarily the most optimal setup. +We try to optimize this document over time as we have gained more experience with HA setups from users. + +## Indexers (Issues and code/repo) + +The default code indexer `bleve` is not able to allow multiple connections and hence cannot be used in a HA setup. +Alternatives are `elasticsearch` and `meilisearch` (as of >= 1.19.2). +Unless you have an existing `elasticsearch` cluster, we recommend using `meilisearch` as it is faster and requires way less resources. + +Unfortunately, `meilisearch` does only support the `ISSUE_INDEXER` and not the `REPO_INDEXER` yet ([tracking issue](https://github.com/go-gitea/gitea/pull/24149)). +This means that the `REPO_INDEXER` must still be disabled for a HA setup right now. +An alternative to the two options above for the `ISSUE_INDEXER` is `"db"`, however we recommend to just go with `meilisearch` in this case and to not bother the DB with indexing. + +To configure `meilisearch` within Forgejo, do the following: + +```yml +gitea: + config: + indexer: + ISSUE_INDEXER_CONN_STR: .svc.cluster.local:7700> + ISSUE_INDEXER_ENABLED: true + ISSUE_INDEXER_TYPE: meilisearch + REPO_INDEXER_ENABLED: false + # REPO_INDEXER_TYPE: meilisearch # not yet working +``` + +Unfortunately `meilisearch` cannot be deployed in HA as of now. +Nevertheless it allows for multiple Forgejo requests at the same time and is therefore required in a HA setup. + +Exemplary configuration for the [meilisearch-kubernetes](https://github.com/meilisearch/meilisearch-kubernetes/tree/main/charts/meilisearch) chart: + +```yaml +persistence: + enabled: true + accessMode: ReadWriteOnce + size: 5Gi +``` + +## Cache, session and queue + +A `redis` instance is required for the in-memory cache. +Two options exist: + +- `redis` +- `redis-cluster` + +The chart provides `redis-cluster` as a dependency as this one can be used for both HA and non-HA setups. +You're also welcome to go with `redis` if you prefer or already have a running instance. + +It should be noted that `redis-cluster` support is only available starting with Forgejo 1.19.2. +You can also configure an external (managed) `redis` instance to be used. +To do so, you need to set the following configuration values yourself: + +- `gitea.config.queue.TYPE`: redis` +- `gitea.config.queue.CONN_STR`: `` + +- `gitea.config.session.PROVIDER`: `redis` +- `gitea.config.session.PROVIDER_CONFIG`: `` + +- `gitea.config.cache.ENABLED`: `true` +- `gitea.config.cache.ADAPTER`: `redis` +- `gitea.config.cache.HOST`: `` + +By default, the `redis-cluster` chart provisions three standalone master nodes of which each has a single replica. +To reduce the number of pods for a default Forgejo deployment, we opted to omit the replicas (`replicas: 0`) by default. +Only the minimum required number of master pods for a functional `redis-cluster` deployment are provisioned. +For a "proper" `redis-cluster` setup however, we recommend to set `replicas: 1` and `nodes: 6`. + +## Object and asset storage + +Object/asset storage refers to the storage of attachments, avatars, LFS files, etc. +While most of these can be stored on the RWX file-system, it is recommended to use an external S3-compatible object storage for such, mainly for performance reasons. + +By default the chart provisions a single RWO volume to store everything (repos, avatars, packages, etc.). +This volume cannot be mounted by multiple pods. +Hence, a RWX volume is required and (optionally) an external HA-ready object storage. + +> **Note:** Double-check that the file permissions are set correctly on the RWX volume! That is everything should be owned by the `git` user which usually has `uid=1000` and `gid=1000`. + +To use `minio` you need to deploy and configure an external `minio` instance yourself and explicitly define the `STORAGE_TYPE` values as shown below. + +Note that `MINIO_BUCKET` here is just a name and does not refer to a S3 bucket. +It's the root access point for all objects belonging to the respective application, i.e., to Forgejo in this case. + +```yaml +gitea: + config: + attachment: + STORAGE_TYPE: minio + lfs: + STORAGE_TYPE: minio + picture: + AVATAR_STORAGE_TYPE: minio + 'storage.packages': + STORAGE_TYPE: minio + + storage: + MINIO_ENDPOINT: .svc.cluster.local:9000> + MINIO_LOCATION: + MINIO_ACCESS_KEY_ID: + MINIO_SECRET_ACCESS_KEY: + MINIO_BUCKET: + MINIO_USE_SSL: false +``` + +Exemplary configuration for the [bitnami minio](https://github.com/bitnami/charts/blob/main/bitnami/minio) chart: + +```yaml +auth: + rootUser: minio +mode: distributed +replicaCount: 4 +persistence: + enabled: true + size: 20Gi + accessModes: + - ReadWriteOnce +``` + +## Database + +If you do not have an HA-ready DB, using a managed database service in the cloud might be the easiest and most robust solution. +Remember: disable the built-in `postgres` dependency and configure the database connection manually via `gitea.config.database`: + +```yml +gitea: + database: + builtIn: + postgresql: + enabled: false + config: + database: + DB_TYPE: postgres + HOST: + NAME: + USER: +``` + +## Known issues + +- Currently Cron jobs are run on all replicas as no leader election is implemented. + See [https://github.com/go-gitea/gitea/issues/13791](https://github.com/go-gitea/gitea/issues/13791) for a discussion and possible solution. + +- Running with multiple replicas slows down Forgejo a bit, i.e. page loading time increases. diff --git a/e2e/kind.cluster.yml b/e2e/kind.cluster.yml new file mode 100644 index 0000000..c7c4b02 --- /dev/null +++ b/e2e/kind.cluster.yml @@ -0,0 +1,17 @@ +# based on https://github.com/kind-ci/examples +apiVersion: kind.x-k8s.io/v1alpha4 +kind: Cluster +name: chart-testing +networking: + apiServerAddress: '0.0.0.0' + +nodes: + # add to the apiServer certSANs the name of the drone service in order to be able to reach the cluster through it + - role: control-plane + kubeadmConfigPatches: + - | + kind: ClusterConfiguration + apiServer: + certSANs: + - docker + - role: worker diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 51941a5..0000000 --- a/package-lock.json +++ /dev/null @@ -1,3645 +0,0 @@ -{ - "name": "forgejo-helm-chart", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "forgejo-helm-chart", - "license": "MIT", - "devDependencies": { - "@bitnami/readme-generator-for-helm": "^2.4.2", - "conventional-changelog-conventionalcommits": "^5.0.0", - "conventional-changelog-core": "^4.2.4", - "markdownlint-cli": "^0.33.0" - }, - "engines": { - "node": ">=16.0.0", - "npm": ">=8.0.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@bitnami/readme-generator-for-helm": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/@bitnami/readme-generator-for-helm/-/readme-generator-for-helm-2.4.2.tgz", - "integrity": "sha512-2kIXOjRiKJ3PBoBD6EaImp4SNyGM/w67ZPPwbuJi5NeXesupQjFyhIhcKliIledlpuiSrMeH9l80yl6hvmYHUA==", - "dev": true, - "dependencies": { - "commander": "^7.1.0", - "dot-object": "^2.1.4", - "lodash": "^4.17.21", - "markdown-table": "^2.0.0", - "yaml": "^2.0.0-3" - }, - "bin": { - "readme-generator": "bin/index.js" - } - }, - "node_modules/@hutson/parse-repository-url": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz", - "integrity": "sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@types/minimist": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz", - "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", - "dev": true - }, - "node_modules/@types/normalize-package-data": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", - "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", - "dev": true - }, - "node_modules/add-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/add-stream/-/add-stream-1.0.0.tgz", - "integrity": "sha512-qQLMr+8o0WC4FZGQTcJiKBVC59JylcPSrTtk6usvmIDFUOCKegapy1VHQwRbFMOFyb/inzUVqHs+eMYKDM1YeQ==", - "dev": true - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/array-ify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", - "integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==", - "dev": true - }, - "node_modules/arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase-keys": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", - "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", - "dev": true, - "dependencies": { - "camelcase": "^5.3.1", - "map-obj": "^4.0.0", - "quick-lru": "^4.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chalk/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chalk/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/chalk/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/compare-func": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", - "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", - "dev": true, - "dependencies": { - "array-ify": "^1.0.0", - "dot-prop": "^5.1.0" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/conventional-changelog-conventionalcommits": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-5.0.0.tgz", - "integrity": "sha512-lCDbA+ZqVFQGUj7h9QBKoIpLhl8iihkO0nCTyRNzuXtcd7ubODpYB04IFy31JloiJgG0Uovu8ot8oxRzn7Nwtw==", - "dev": true, - "dependencies": { - "compare-func": "^2.0.0", - "lodash": "^4.17.15", - "q": "^1.5.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/conventional-changelog-core": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/conventional-changelog-core/-/conventional-changelog-core-4.2.4.tgz", - "integrity": "sha512-gDVS+zVJHE2v4SLc6B0sLsPiloR0ygU7HaDW14aNJE1v4SlqJPILPl/aJC7YdtRE4CybBf8gDwObBvKha8Xlyg==", - "dev": true, - "dependencies": { - "add-stream": "^1.0.0", - "conventional-changelog-writer": "^5.0.0", - "conventional-commits-parser": "^3.2.0", - "dateformat": "^3.0.0", - "get-pkg-repo": "^4.0.0", - "git-raw-commits": "^2.0.8", - "git-remote-origin-url": "^2.0.0", - "git-semver-tags": "^4.1.1", - "lodash": "^4.17.15", - "normalize-package-data": "^3.0.0", - "q": "^1.5.1", - "read-pkg": "^3.0.0", - "read-pkg-up": "^3.0.0", - "through2": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/conventional-changelog-writer": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-5.0.1.tgz", - "integrity": "sha512-5WsuKUfxW7suLblAbFnxAcrvf6r+0b7GvNaWUwUIk0bXMnENP/PEieGKVUQrjPqwPT4o3EPAASBXiY6iHooLOQ==", - "dev": true, - "dependencies": { - "conventional-commits-filter": "^2.0.7", - "dateformat": "^3.0.0", - "handlebars": "^4.7.7", - "json-stringify-safe": "^5.0.1", - "lodash": "^4.17.15", - "meow": "^8.0.0", - "semver": "^6.0.0", - "split": "^1.0.0", - "through2": "^4.0.0" - }, - "bin": { - "conventional-changelog-writer": "cli.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/conventional-commits-filter": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-2.0.7.tgz", - "integrity": "sha512-ASS9SamOP4TbCClsRHxIHXRfcGCnIoQqkvAzCSbZzTFLfcTqJVugB0agRgsEELsqaeWgsXv513eS116wnlSSPA==", - "dev": true, - "dependencies": { - "lodash.ismatch": "^4.4.0", - "modify-values": "^1.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/conventional-commits-parser": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.2.4.tgz", - "integrity": "sha512-nK7sAtfi+QXbxHCYfhpZsfRtaitZLIA6889kFIouLvz6repszQDgxBu7wf2WbU+Dco7sAnNCJYERCwt54WPC2Q==", - "dev": true, - "dependencies": { - "is-text-path": "^1.0.1", - "JSONStream": "^1.0.4", - "lodash": "^4.17.15", - "meow": "^8.0.0", - "split2": "^3.0.0", - "through2": "^4.0.0" - }, - "bin": { - "conventional-commits-parser": "cli.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true - }, - "node_modules/dargs": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz", - "integrity": "sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/dateformat": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", - "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decamelize-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", - "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", - "dev": true, - "dependencies": { - "decamelize": "^1.1.0", - "map-obj": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/decamelize-keys/node_modules/map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/dot-object": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/dot-object/-/dot-object-2.1.4.tgz", - "integrity": "sha512-7FXnyyCLFawNYJ+NhkqyP9Wd2yzuo+7n9pGiYpkmXCTYa8Ci2U0eUNDVg5OuO5Pm6aFXI2SWN8/N/w7SJWu1WA==", - "dev": true, - "dependencies": { - "commander": "^4.0.0", - "glob": "^7.1.5" - }, - "bin": { - "dot-object": "bin/dot-object" - } - }, - "node_modules/dot-object/node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", - "dev": true, - "dependencies": { - "is-obj": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/entities": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", - "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", - "dev": true, - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", - "dev": true, - "dependencies": { - "locate-path": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-pkg-repo": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/get-pkg-repo/-/get-pkg-repo-4.2.1.tgz", - "integrity": "sha512-2+QbHjFRfGB74v/pYWjd5OhU3TDIC2Gv/YKUTk/tCvAz0pkn/Mz6P3uByuBimLOcPvN2jYdScl3xGFSrx0jEcA==", - "dev": true, - "dependencies": { - "@hutson/parse-repository-url": "^3.0.0", - "hosted-git-info": "^4.0.0", - "through2": "^2.0.0", - "yargs": "^16.2.0" - }, - "bin": { - "get-pkg-repo": "src/cli.js" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-pkg-repo/node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/get-pkg-repo/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/get-pkg-repo/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/get-pkg-repo/node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, - "node_modules/get-stdin": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-9.0.0.tgz", - "integrity": "sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/git-raw-commits": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.11.tgz", - "integrity": "sha512-VnctFhw+xfj8Va1xtfEqCUD2XDrbAPSJx+hSrE5K7fGdjZruW7XV+QOrN7LF/RJyvspRiD2I0asWsxFp0ya26A==", - "dev": true, - "dependencies": { - "dargs": "^7.0.0", - "lodash": "^4.17.15", - "meow": "^8.0.0", - "split2": "^3.0.0", - "through2": "^4.0.0" - }, - "bin": { - "git-raw-commits": "cli.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/git-remote-origin-url": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/git-remote-origin-url/-/git-remote-origin-url-2.0.0.tgz", - "integrity": "sha512-eU+GGrZgccNJcsDH5LkXR3PB9M958hxc7sbA8DFJjrv9j4L2P/eZfKhM+QD6wyzpiv+b1BpK0XrYCxkovtjSLw==", - "dev": true, - "dependencies": { - "gitconfiglocal": "^1.0.0", - "pify": "^2.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/git-semver-tags": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/git-semver-tags/-/git-semver-tags-4.1.1.tgz", - "integrity": "sha512-OWyMt5zBe7xFs8vglMmhM9lRQzCWL3WjHtxNNfJTMngGym7pC1kh8sP6jevfydJ6LP3ZvGxfb6ABYgPUM0mtsA==", - "dev": true, - "dependencies": { - "meow": "^8.0.0", - "semver": "^6.0.0" - }, - "bin": { - "git-semver-tags": "cli.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/gitconfiglocal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/gitconfiglocal/-/gitconfiglocal-1.0.0.tgz", - "integrity": "sha512-spLUXeTAVHxDtKsJc8FkFVgFtMdEN9qPGpL23VfSHx4fP4+Ds097IXLvymbnDH8FnmxX5Nr9bPw3A+AQ6mWEaQ==", - "dev": true, - "dependencies": { - "ini": "^1.3.2" - } - }, - "node_modules/gitconfiglocal/node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true - }, - "node_modules/handlebars": { - "version": "4.7.7", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", - "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.5", - "neo-async": "^2.6.0", - "source-map": "^0.6.1", - "wordwrap": "^1.0.0" - }, - "bin": { - "handlebars": "bin/handlebars" - }, - "engines": { - "node": ">=0.4.7" - }, - "optionalDependencies": { - "uglify-js": "^3.1.4" - } - }, - "node_modules/hard-rejection": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", - "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/hosted-git-info": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/ini": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ini/-/ini-3.0.1.tgz", - "integrity": "sha512-it4HyVAUTKBc6m8e1iXWvXSTdndF7HbdN713+kvLrymxTaU4AUBWrJ4vEooP+V7fexnVD3LKcBshjGGPefSMUQ==", - "dev": true, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true - }, - "node_modules/is-core-module": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", - "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-text-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz", - "integrity": "sha512-xFuJpne9oFz5qDaodwmmG08e3CawH/2ZV8Qqza1Ko7Sk8POWbkRdwIoAWVhqvq0XeUzANEhKo2n0IXUGBm7A/w==", - "dev": true, - "dependencies": { - "text-extensions": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "dev": true - }, - "node_modules/jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true - }, - "node_modules/jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", - "dev": true, - "engines": [ - "node >= 0.2.0" - ] - }, - "node_modules/JSONStream": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", - "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", - "dev": true, - "dependencies": { - "jsonparse": "^1.2.0", - "through": ">=2.2.7 <3" - }, - "bin": { - "JSONStream": "bin.js" - }, - "engines": { - "node": "*" - } - }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true - }, - "node_modules/linkify-it": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-4.0.1.tgz", - "integrity": "sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==", - "dev": true, - "dependencies": { - "uc.micro": "^1.0.1" - } - }, - "node_modules/load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/load-json-file/node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", - "dev": true, - "dependencies": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "node_modules/lodash.ismatch": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz", - "integrity": "sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g==", - "dev": true - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/map-obj": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", - "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/markdown-it": { - "version": "13.0.1", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-13.0.1.tgz", - "integrity": "sha512-lTlxriVoy2criHP0JKRhO2VDG9c2ypWCsT237eDiLqi09rmbKoUetyGHq2uOIRoRS//kfoJckS0eUzzkDR+k2Q==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1", - "entities": "~3.0.1", - "linkify-it": "^4.0.1", - "mdurl": "^1.0.1", - "uc.micro": "^1.0.5" - }, - "bin": { - "markdown-it": "bin/markdown-it.js" - } - }, - "node_modules/markdown-table": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-2.0.0.tgz", - "integrity": "sha512-Ezda85ToJUBhM6WGaG6veasyym+Tbs3cMAw/ZhOPqXiYsr0jgocBV3j3nx+4lk47plLlIqjwuTm/ywVI+zjJ/A==", - "dev": true, - "dependencies": { - "repeat-string": "^1.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/markdownlint": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.27.0.tgz", - "integrity": "sha512-HtfVr/hzJJmE0C198F99JLaeada+646B5SaG2pVoEakLFI6iRGsvMqrnnrflq8hm1zQgwskEgqSnhDW11JBp0w==", - "dev": true, - "dependencies": { - "markdown-it": "13.0.1" - }, - "engines": { - "node": ">=14.18.0" - } - }, - "node_modules/markdownlint-cli": { - "version": "0.33.0", - "resolved": "https://registry.npmjs.org/markdownlint-cli/-/markdownlint-cli-0.33.0.tgz", - "integrity": "sha512-zMK1oHpjYkhjO+94+ngARiBBrRDEUMzooDHBAHtmEIJ9oYddd9l3chCReY2mPlecwH7gflQp1ApilTo+o0zopQ==", - "dev": true, - "dependencies": { - "commander": "~9.4.1", - "get-stdin": "~9.0.0", - "glob": "~8.0.3", - "ignore": "~5.2.4", - "js-yaml": "^4.1.0", - "jsonc-parser": "~3.2.0", - "markdownlint": "~0.27.0", - "minimatch": "~5.1.2", - "run-con": "~1.2.11" - }, - "bin": { - "markdownlint": "markdownlint.js" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/markdownlint-cli/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/markdownlint-cli/node_modules/commander": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-9.4.1.tgz", - "integrity": "sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw==", - "dev": true, - "engines": { - "node": "^12.20.0 || >=14" - } - }, - "node_modules/markdownlint-cli/node_modules/glob": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", - "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/markdownlint-cli/node_modules/minimatch": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.2.tgz", - "integrity": "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", - "dev": true - }, - "node_modules/meow": { - "version": "8.1.2", - "resolved": "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz", - "integrity": "sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==", - "dev": true, - "dependencies": { - "@types/minimist": "^1.2.0", - "camelcase-keys": "^6.2.2", - "decamelize-keys": "^1.1.0", - "hard-rejection": "^2.1.0", - "minimist-options": "4.1.0", - "normalize-package-data": "^3.0.0", - "read-pkg-up": "^7.0.1", - "redent": "^3.0.0", - "trim-newlines": "^3.0.0", - "type-fest": "^0.18.0", - "yargs-parser": "^20.2.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/meow/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/meow/node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, - "node_modules/meow/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/meow/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/meow/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/meow/node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/meow/node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/meow/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/meow/node_modules/read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "dev": true, - "dependencies": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/meow/node_modules/read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", - "dev": true, - "dependencies": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/meow/node_modules/read-pkg-up/node_modules/type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/meow/node_modules/read-pkg/node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/meow/node_modules/read-pkg/node_modules/type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/meow/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/min-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true - }, - "node_modules/minimist-options": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", - "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", - "dev": true, - "dependencies": { - "arrify": "^1.0.1", - "is-plain-obj": "^1.1.0", - "kind-of": "^6.0.3" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/modify-values": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz", - "integrity": "sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true - }, - "node_modules/normalize-package-data": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", - "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^4.0.1", - "is-core-module": "^2.5.0", - "semver": "^7.3.4", - "validate-npm-package-license": "^3.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/normalize-package-data/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "dependencies": { - "p-try": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", - "dev": true, - "dependencies": { - "p-limit": "^1.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", - "dev": true, - "dependencies": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, - "dependencies": { - "pify": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/path-type/node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "node_modules/q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", - "dev": true, - "engines": { - "node": ">=0.6.0", - "teleport": ">=0.2.0" - } - }, - "node_modules/quick-lru": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", - "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==", - "dev": true, - "dependencies": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", - "integrity": "sha512-YFzFrVvpC6frF1sz8psoHDBGF7fLPc+llq/8NB43oagqWkx8ar5zYtsTORtOjw9W2RHLpWP+zTWwBvf1bCmcSw==", - "dev": true, - "dependencies": { - "find-up": "^2.0.0", - "read-pkg": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg/node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, - "node_modules/read-pkg/node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/read-pkg/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/redent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", - "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", - "dev": true, - "dependencies": { - "indent-string": "^4.0.0", - "strip-indent": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", - "dev": true, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", - "dev": true, - "dependencies": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/run-con": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/run-con/-/run-con-1.2.11.tgz", - "integrity": "sha512-NEMGsUT+cglWkzEr4IFK21P4Jca45HqiAbIIZIBdX5+UZTB24Mb/21iNGgz9xZa8tL6vbW7CXmq7MFN42+VjNQ==", - "dev": true, - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~3.0.0", - "minimist": "^1.2.6", - "strip-json-comments": "~3.1.1" - }, - "bin": { - "run-con": "cli.js" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", - "dev": true, - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz", - "integrity": "sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==", - "dev": true - }, - "node_modules/split": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", - "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", - "dev": true, - "dependencies": { - "through": "2" - }, - "engines": { - "node": "*" - } - }, - "node_modules/split2": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", - "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", - "dev": true, - "dependencies": { - "readable-stream": "^3.0.0" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-indent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", - "dev": true, - "dependencies": { - "min-indent": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/text-extensions": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz", - "integrity": "sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==", - "dev": true, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true - }, - "node_modules/through2": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", - "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", - "dev": true, - "dependencies": { - "readable-stream": "3" - } - }, - "node_modules/trim-newlines": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", - "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/type-fest": { - "version": "0.18.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", - "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/uc.micro": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", - "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", - "dev": true - }, - "node_modules/uglify-js": { - "version": "3.17.4", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", - "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", - "dev": true, - "optional": true, - "bin": { - "uglifyjs": "bin/uglifyjs" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true - }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", - "dev": true - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true, - "engines": { - "node": ">=0.4" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/yaml": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.1.3.tgz", - "integrity": "sha512-AacA8nRULjKMX2DvWvOAdBZMOfQlypSFkjcOcu9FalllIDJ1kvlREzcdIZmidQUqqeMv7jorHjq2HlLv/+c2lg==", - "dev": true, - "engines": { - "node": ">= 14" - } - }, - "node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true, - "engines": { - "node": ">=10" - } - } - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", - "dev": true, - "requires": { - "@babel/highlight": "^7.18.6" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "dev": true - }, - "@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "@bitnami/readme-generator-for-helm": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/@bitnami/readme-generator-for-helm/-/readme-generator-for-helm-2.4.2.tgz", - "integrity": "sha512-2kIXOjRiKJ3PBoBD6EaImp4SNyGM/w67ZPPwbuJi5NeXesupQjFyhIhcKliIledlpuiSrMeH9l80yl6hvmYHUA==", - "dev": true, - "requires": { - "commander": "^7.1.0", - "dot-object": "^2.1.4", - "lodash": "^4.17.21", - "markdown-table": "^2.0.0", - "yaml": "^2.0.0-3" - } - }, - "@hutson/parse-repository-url": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz", - "integrity": "sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q==", - "dev": true - }, - "@types/minimist": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz", - "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", - "dev": true - }, - "@types/normalize-package-data": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", - "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", - "dev": true - }, - "add-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/add-stream/-/add-stream-1.0.0.tgz", - "integrity": "sha512-qQLMr+8o0WC4FZGQTcJiKBVC59JylcPSrTtk6usvmIDFUOCKegapy1VHQwRbFMOFyb/inzUVqHs+eMYKDM1YeQ==", - "dev": true - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "array-ify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", - "integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==", - "dev": true - }, - "arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", - "dev": true - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "camelcase-keys": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", - "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", - "dev": true, - "requires": { - "camelcase": "^5.3.1", - "map-obj": "^4.0.0", - "quick-lru": "^4.0.1" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - } - } - }, - "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "dev": true - }, - "compare-func": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", - "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", - "dev": true, - "requires": { - "array-ify": "^1.0.0", - "dot-prop": "^5.1.0" - } - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "conventional-changelog-conventionalcommits": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-5.0.0.tgz", - "integrity": "sha512-lCDbA+ZqVFQGUj7h9QBKoIpLhl8iihkO0nCTyRNzuXtcd7ubODpYB04IFy31JloiJgG0Uovu8ot8oxRzn7Nwtw==", - "dev": true, - "requires": { - "compare-func": "^2.0.0", - "lodash": "^4.17.15", - "q": "^1.5.1" - } - }, - "conventional-changelog-core": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/conventional-changelog-core/-/conventional-changelog-core-4.2.4.tgz", - "integrity": "sha512-gDVS+zVJHE2v4SLc6B0sLsPiloR0ygU7HaDW14aNJE1v4SlqJPILPl/aJC7YdtRE4CybBf8gDwObBvKha8Xlyg==", - "dev": true, - "requires": { - "add-stream": "^1.0.0", - "conventional-changelog-writer": "^5.0.0", - "conventional-commits-parser": "^3.2.0", - "dateformat": "^3.0.0", - "get-pkg-repo": "^4.0.0", - "git-raw-commits": "^2.0.8", - "git-remote-origin-url": "^2.0.0", - "git-semver-tags": "^4.1.1", - "lodash": "^4.17.15", - "normalize-package-data": "^3.0.0", - "q": "^1.5.1", - "read-pkg": "^3.0.0", - "read-pkg-up": "^3.0.0", - "through2": "^4.0.0" - } - }, - "conventional-changelog-writer": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-5.0.1.tgz", - "integrity": "sha512-5WsuKUfxW7suLblAbFnxAcrvf6r+0b7GvNaWUwUIk0bXMnENP/PEieGKVUQrjPqwPT4o3EPAASBXiY6iHooLOQ==", - "dev": true, - "requires": { - "conventional-commits-filter": "^2.0.7", - "dateformat": "^3.0.0", - "handlebars": "^4.7.7", - "json-stringify-safe": "^5.0.1", - "lodash": "^4.17.15", - "meow": "^8.0.0", - "semver": "^6.0.0", - "split": "^1.0.0", - "through2": "^4.0.0" - } - }, - "conventional-commits-filter": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-2.0.7.tgz", - "integrity": "sha512-ASS9SamOP4TbCClsRHxIHXRfcGCnIoQqkvAzCSbZzTFLfcTqJVugB0agRgsEELsqaeWgsXv513eS116wnlSSPA==", - "dev": true, - "requires": { - "lodash.ismatch": "^4.4.0", - "modify-values": "^1.0.0" - } - }, - "conventional-commits-parser": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.2.4.tgz", - "integrity": "sha512-nK7sAtfi+QXbxHCYfhpZsfRtaitZLIA6889kFIouLvz6repszQDgxBu7wf2WbU+Dco7sAnNCJYERCwt54WPC2Q==", - "dev": true, - "requires": { - "is-text-path": "^1.0.1", - "JSONStream": "^1.0.4", - "lodash": "^4.17.15", - "meow": "^8.0.0", - "split2": "^3.0.0", - "through2": "^4.0.0" - } - }, - "core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true - }, - "dargs": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz", - "integrity": "sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==", - "dev": true - }, - "dateformat": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", - "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", - "dev": true - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "dev": true - }, - "decamelize-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", - "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", - "dev": true, - "requires": { - "decamelize": "^1.1.0", - "map-obj": "^1.0.0" - }, - "dependencies": { - "map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", - "dev": true - } - } - }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true - }, - "dot-object": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/dot-object/-/dot-object-2.1.4.tgz", - "integrity": "sha512-7FXnyyCLFawNYJ+NhkqyP9Wd2yzuo+7n9pGiYpkmXCTYa8Ci2U0eUNDVg5OuO5Pm6aFXI2SWN8/N/w7SJWu1WA==", - "dev": true, - "requires": { - "commander": "^4.0.0", - "glob": "^7.1.5" - }, - "dependencies": { - "commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "dev": true - } - } - }, - "dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", - "dev": true, - "requires": { - "is-obj": "^2.0.0" - } - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "entities": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", - "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", - "dev": true - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true - }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "get-pkg-repo": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/get-pkg-repo/-/get-pkg-repo-4.2.1.tgz", - "integrity": "sha512-2+QbHjFRfGB74v/pYWjd5OhU3TDIC2Gv/YKUTk/tCvAz0pkn/Mz6P3uByuBimLOcPvN2jYdScl3xGFSrx0jEcA==", - "dev": true, - "requires": { - "@hutson/parse-repository-url": "^3.0.0", - "hosted-git-info": "^4.0.0", - "through2": "^2.0.0", - "yargs": "^16.2.0" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - } - } - }, - "get-stdin": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-9.0.0.tgz", - "integrity": "sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==", - "dev": true - }, - "git-raw-commits": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.11.tgz", - "integrity": "sha512-VnctFhw+xfj8Va1xtfEqCUD2XDrbAPSJx+hSrE5K7fGdjZruW7XV+QOrN7LF/RJyvspRiD2I0asWsxFp0ya26A==", - "dev": true, - "requires": { - "dargs": "^7.0.0", - "lodash": "^4.17.15", - "meow": "^8.0.0", - "split2": "^3.0.0", - "through2": "^4.0.0" - } - }, - "git-remote-origin-url": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/git-remote-origin-url/-/git-remote-origin-url-2.0.0.tgz", - "integrity": "sha512-eU+GGrZgccNJcsDH5LkXR3PB9M958hxc7sbA8DFJjrv9j4L2P/eZfKhM+QD6wyzpiv+b1BpK0XrYCxkovtjSLw==", - "dev": true, - "requires": { - "gitconfiglocal": "^1.0.0", - "pify": "^2.3.0" - } - }, - "git-semver-tags": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/git-semver-tags/-/git-semver-tags-4.1.1.tgz", - "integrity": "sha512-OWyMt5zBe7xFs8vglMmhM9lRQzCWL3WjHtxNNfJTMngGym7pC1kh8sP6jevfydJ6LP3ZvGxfb6ABYgPUM0mtsA==", - "dev": true, - "requires": { - "meow": "^8.0.0", - "semver": "^6.0.0" - } - }, - "gitconfiglocal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/gitconfiglocal/-/gitconfiglocal-1.0.0.tgz", - "integrity": "sha512-spLUXeTAVHxDtKsJc8FkFVgFtMdEN9qPGpL23VfSHx4fP4+Ds097IXLvymbnDH8FnmxX5Nr9bPw3A+AQ6mWEaQ==", - "dev": true, - "requires": { - "ini": "^1.3.2" - }, - "dependencies": { - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - } - } - }, - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true - }, - "handlebars": { - "version": "4.7.7", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", - "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", - "dev": true, - "requires": { - "minimist": "^1.2.5", - "neo-async": "^2.6.0", - "source-map": "^0.6.1", - "uglify-js": "^3.1.4", - "wordwrap": "^1.0.0" - } - }, - "hard-rejection": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", - "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", - "dev": true - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true - }, - "hosted-git-info": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", - "dev": true - }, - "indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "ini": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ini/-/ini-3.0.1.tgz", - "integrity": "sha512-it4HyVAUTKBc6m8e1iXWvXSTdndF7HbdN713+kvLrymxTaU4AUBWrJ4vEooP+V7fexnVD3LKcBshjGGPefSMUQ==", - "dev": true - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true - }, - "is-core-module": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", - "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", - "dev": true - }, - "is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", - "dev": true - }, - "is-text-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz", - "integrity": "sha512-xFuJpne9oFz5qDaodwmmG08e3CawH/2ZV8Qqza1Ko7Sk8POWbkRdwIoAWVhqvq0XeUzANEhKo2n0IXUGBm7A/w==", - "dev": true, - "requires": { - "text-extensions": "^1.0.0" - } - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, - "json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "dev": true - }, - "jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true - }, - "jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", - "dev": true - }, - "JSONStream": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", - "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", - "dev": true, - "requires": { - "jsonparse": "^1.2.0", - "through": ">=2.2.7 <3" - } - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - }, - "lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true - }, - "linkify-it": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-4.0.1.tgz", - "integrity": "sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==", - "dev": true, - "requires": { - "uc.micro": "^1.0.1" - } - }, - "load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - }, - "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", - "dev": true - } - } - }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", - "dev": true, - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - } - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "lodash.ismatch": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz", - "integrity": "sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g==", - "dev": true - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "map-obj": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", - "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", - "dev": true - }, - "markdown-it": { - "version": "13.0.1", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-13.0.1.tgz", - "integrity": "sha512-lTlxriVoy2criHP0JKRhO2VDG9c2ypWCsT237eDiLqi09rmbKoUetyGHq2uOIRoRS//kfoJckS0eUzzkDR+k2Q==", - "dev": true, - "requires": { - "argparse": "^2.0.1", - "entities": "~3.0.1", - "linkify-it": "^4.0.1", - "mdurl": "^1.0.1", - "uc.micro": "^1.0.5" - } - }, - "markdown-table": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-2.0.0.tgz", - "integrity": "sha512-Ezda85ToJUBhM6WGaG6veasyym+Tbs3cMAw/ZhOPqXiYsr0jgocBV3j3nx+4lk47plLlIqjwuTm/ywVI+zjJ/A==", - "dev": true, - "requires": { - "repeat-string": "^1.0.0" - } - }, - "markdownlint": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.27.0.tgz", - "integrity": "sha512-HtfVr/hzJJmE0C198F99JLaeada+646B5SaG2pVoEakLFI6iRGsvMqrnnrflq8hm1zQgwskEgqSnhDW11JBp0w==", - "dev": true, - "requires": { - "markdown-it": "13.0.1" - } - }, - "markdownlint-cli": { - "version": "0.33.0", - "resolved": "https://registry.npmjs.org/markdownlint-cli/-/markdownlint-cli-0.33.0.tgz", - "integrity": "sha512-zMK1oHpjYkhjO+94+ngARiBBrRDEUMzooDHBAHtmEIJ9oYddd9l3chCReY2mPlecwH7gflQp1ApilTo+o0zopQ==", - "dev": true, - "requires": { - "commander": "~9.4.1", - "get-stdin": "~9.0.0", - "glob": "~8.0.3", - "ignore": "~5.2.4", - "js-yaml": "^4.1.0", - "jsonc-parser": "~3.2.0", - "markdownlint": "~0.27.0", - "minimatch": "~5.1.2", - "run-con": "~1.2.11" - }, - "dependencies": { - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, - "commander": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-9.4.1.tgz", - "integrity": "sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw==", - "dev": true - }, - "glob": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", - "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - } - }, - "minimatch": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.2.tgz", - "integrity": "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==", - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - } - } - } - }, - "mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", - "dev": true - }, - "meow": { - "version": "8.1.2", - "resolved": "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz", - "integrity": "sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==", - "dev": true, - "requires": { - "@types/minimist": "^1.2.0", - "camelcase-keys": "^6.2.2", - "decamelize-keys": "^1.1.0", - "hard-rejection": "^2.1.0", - "minimist-options": "4.1.0", - "normalize-package-data": "^3.0.0", - "read-pkg-up": "^7.0.1", - "redent": "^3.0.0", - "trim-newlines": "^3.0.0", - "type-fest": "^0.18.0", - "yargs-parser": "^20.2.3" - }, - "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "dev": true, - "requires": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" - }, - "dependencies": { - "normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true - } - } - }, - "read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", - "dev": true, - "requires": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" - }, - "dependencies": { - "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true - } - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "min-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", - "dev": true - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true - }, - "minimist-options": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", - "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", - "dev": true, - "requires": { - "arrify": "^1.0.1", - "is-plain-obj": "^1.1.0", - "kind-of": "^6.0.3" - } - }, - "modify-values": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz", - "integrity": "sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==", - "dev": true - }, - "neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true - }, - "normalize-package-data": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", - "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", - "dev": true, - "requires": { - "hosted-git-info": "^4.0.1", - "is-core-module": "^2.5.0", - "semver": "^7.3.4", - "validate-npm-package-license": "^3.0.1" - }, - "dependencies": { - "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "requires": { - "p-try": "^1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", - "dev": true, - "requires": { - "p-limit": "^1.1.0" - } - }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", - "dev": true - }, - "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", - "dev": true, - "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, - "requires": { - "pify": "^3.0.0" - }, - "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", - "dev": true - } - } - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true - }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", - "dev": true - }, - "quick-lru": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", - "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", - "dev": true - }, - "read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==", - "dev": true, - "requires": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - }, - "dependencies": { - "hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, - "normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "read-pkg-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", - "integrity": "sha512-YFzFrVvpC6frF1sz8psoHDBGF7fLPc+llq/8NB43oagqWkx8ar5zYtsTORtOjw9W2RHLpWP+zTWwBvf1bCmcSw==", - "dev": true, - "requires": { - "find-up": "^2.0.0", - "read-pkg": "^3.0.0" - } - }, - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "redent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", - "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", - "dev": true, - "requires": { - "indent-string": "^4.0.0", - "strip-indent": "^3.0.0" - } - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", - "dev": true - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true - }, - "resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", - "dev": true, - "requires": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "run-con": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/run-con/-/run-con-1.2.11.tgz", - "integrity": "sha512-NEMGsUT+cglWkzEr4IFK21P4Jca45HqiAbIIZIBdX5+UZTB24Mb/21iNGgz9xZa8tL6vbW7CXmq7MFN42+VjNQ==", - "dev": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~3.0.0", - "minimist": "^1.2.6", - "strip-json-comments": "~3.1.1" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", - "dev": true, - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true - }, - "spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz", - "integrity": "sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==", - "dev": true - }, - "split": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", - "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", - "dev": true, - "requires": { - "through": "2" - } - }, - "split2": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", - "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", - "dev": true, - "requires": { - "readable-stream": "^3.0.0" - } - }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "requires": { - "safe-buffer": "~5.2.0" - } - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true - }, - "strip-indent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", - "dev": true, - "requires": { - "min-indent": "^1.0.0" - } - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true - }, - "text-extensions": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz", - "integrity": "sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==", - "dev": true - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true - }, - "through2": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", - "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", - "dev": true, - "requires": { - "readable-stream": "3" - } - }, - "trim-newlines": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", - "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", - "dev": true - }, - "type-fest": { - "version": "0.18.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", - "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", - "dev": true - }, - "uc.micro": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", - "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", - "dev": true - }, - "uglify-js": { - "version": "3.17.4", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", - "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", - "dev": true, - "optional": true - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true - }, - "validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", - "dev": true - }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true - }, - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "yaml": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.1.3.tgz", - "integrity": "sha512-AacA8nRULjKMX2DvWvOAdBZMOfQlypSFkjcOcu9FalllIDJ1kvlREzcdIZmidQUqqeMv7jorHjq2HlLv/+c2lg==", - "dev": true - }, - "yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "requires": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - } - }, - "yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true - } - } -} diff --git a/package.json b/package.json index f2406f2..d4cccfc 100644 --- a/package.json +++ b/package.json @@ -1,22 +1,31 @@ { "name": "forgejo-helm-chart", - "homepage": "https://codeberg.org/forgejo-contrib/forgejo-helm.git", + "homepage": "https://code.forgejo.org/forgejo-helm/forgejo-helm", "license": "MIT", "private": true, - "engineStrict": true, - "engines": { - "node": ">=16.0.0", - "npm": ">=8.0.0" - }, "scripts": { "changelog": "node tools/changelog.mjs", + "forgejo:release": "node tools/forgejo-release.js", + "prepare": "husky", + "prettier": "prettier --check --ignore-unknown --cache '**/*.*'", + "prettier-fix": "prettier --write --ignore-unknown --cache '**/*.*'", "readme:lint": "markdownlint *.md -f", - "readme:parameters": "readme-generator -v values.yaml -r README.md" + "readme:parameters": "readme-generator -v values.yaml -r README.md", + "test": "helm unittest --strict -f 'unittests/**/*.yaml' ./" }, "devDependencies": { - "@bitnami/readme-generator-for-helm": "^2.4.2", - "conventional-changelog-conventionalcommits": "^5.0.0", - "conventional-changelog-core": "^4.2.4", - "markdownlint-cli": "^0.33.0" + "@bitnami/readme-generator-for-helm": "2.7.0", + "clipanion": "3.2.1", + "conventional-changelog-conventionalcommits": "8.0.0", + "conventional-changelog-core": "9.0.0", + "husky": "9.1.7", + "lint-staged": "15.5.0", + "markdownlint-cli": "0.44.0", + "prettier": "3.5.3" + }, + "packageManager": "pnpm@10.7.0", + "engines": { + "node": "^22.0.0", + "pnpm": "^10.0.0" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..387c3dc --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,1578 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + devDependencies: + '@bitnami/readme-generator-for-helm': + specifier: 2.7.0 + version: 2.7.0 + clipanion: + specifier: 3.2.1 + version: 3.2.1(typanion@3.14.0) + conventional-changelog-conventionalcommits: + specifier: 8.0.0 + version: 8.0.0 + conventional-changelog-core: + specifier: 9.0.0 + version: 9.0.0(conventional-commits-filter@4.0.0) + husky: + specifier: 9.1.7 + version: 9.1.7 + lint-staged: + specifier: 15.5.0 + version: 15.5.0 + markdownlint-cli: + specifier: 0.44.0 + version: 0.44.0 + prettier: + specifier: 3.5.3 + version: 3.5.3 + +packages: + + '@bitnami/readme-generator-for-helm@2.7.0': + resolution: {integrity: sha512-fVxExmcuJ9NZb9ZE9OW3+lG8pUlXJAJdaO8UukV3A7WzYu4qOTr03MXPH9Gt5e/6mo3x4WYI/cXBksKfS0qn3w==} + hasBin: true + + '@conventional-changelog/git-client@1.0.0': + resolution: {integrity: sha512-PkUIv8bcY8/mIJig+3CGneb1hfXvjUotuBcroBHyVO4obIz5WGJpBWTuo17XV4p1sTmbGa8TxAmdMzhlPU+tLA==} + engines: {node: '>=18'} + peerDependencies: + conventional-commits-filter: ^4.0.0 + conventional-commits-parser: ^5.0.0 + peerDependenciesMeta: + conventional-commits-filter: + optional: true + conventional-commits-parser: + optional: true + + '@hutson/parse-repository-url@5.0.0': + resolution: {integrity: sha512-e5+YUKENATs1JgYHMzTr2MW/NDcXGfYFAuOQU8gJgF/kEh4EqKgfGrfLI67bMD4tbhZVlkigz/9YYwWcbOFthg==} + engines: {node: '>=10.13.0'} + + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + + '@types/debug@4.1.12': + resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} + + '@types/katex@0.16.7': + resolution: {integrity: sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ==} + + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + + '@types/semver@7.5.8': + resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} + + '@types/unist@2.0.11': + resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} + + add-stream@1.0.0: + resolution: {integrity: sha512-qQLMr+8o0WC4FZGQTcJiKBVC59JylcPSrTtk6usvmIDFUOCKegapy1VHQwRbFMOFyb/inzUVqHs+eMYKDM1YeQ==} + + ansi-escapes@7.0.0: + resolution: {integrity: sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==} + engines: {node: '>=18'} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-regex@6.0.1: + resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} + engines: {node: '>=12'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + array-ify@1.0.0: + resolution: {integrity: sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + + brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + chalk@5.4.1: + resolution: {integrity: sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + + character-entities-legacy@3.0.0: + resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} + + character-entities@2.0.2: + resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + + character-reference-invalid@2.0.1: + resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} + + cli-cursor@5.0.0: + resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} + engines: {node: '>=18'} + + cli-truncate@4.0.0: + resolution: {integrity: sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==} + engines: {node: '>=18'} + + clipanion@3.2.1: + resolution: {integrity: sha512-dYFdjLb7y1ajfxQopN05mylEpK9ZX0sO1/RfMXdfmwjlIsPkbh4p7A682x++zFPLDCo1x3p82dtljHf5cW2LKA==} + peerDependencies: + typanion: '*' + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + colorette@2.0.20: + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + + commander@13.1.0: + resolution: {integrity: sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==} + engines: {node: '>=18'} + + commander@6.2.1: + resolution: {integrity: sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==} + engines: {node: '>= 6'} + + commander@8.3.0: + resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} + engines: {node: '>= 12'} + + compare-func@2.0.0: + resolution: {integrity: sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + conventional-changelog-conventionalcommits@8.0.0: + resolution: {integrity: sha512-eOvlTO6OcySPyyyk8pKz2dP4jjElYunj9hn9/s0OB+gapTO8zwS9UQWrZ1pmF2hFs3vw1xhonOLGcGjy/zgsuA==} + engines: {node: '>=18'} + + conventional-changelog-core@9.0.0: + resolution: {integrity: sha512-/XS1hE0axsZ+IwJAoXw1faEdbo5+A975pL6FeLHs5Iz8lgROZ9iAhEFmIFhjHW1/BOhGq7RJU9udzWbeumAfDQ==} + engines: {node: '>=18'} + + conventional-changelog-writer@8.0.1: + resolution: {integrity: sha512-hlqcy3xHred2gyYg/zXSMXraY2mjAYYo0msUCpK+BGyaVJMFCKWVXPIHiaacGO2GGp13kvHWXFhYmxT4QQqW3Q==} + engines: {node: '>=18'} + hasBin: true + + conventional-commits-filter@4.0.0: + resolution: {integrity: sha512-rnpnibcSOdFcdclpFwWa+pPlZJhXE7l+XK04zxhbWrhgpR96h33QLz8hITTXbcYICxVr3HZFtbtUAQ+4LdBo9A==} + engines: {node: '>=16'} + + conventional-commits-filter@5.0.0: + resolution: {integrity: sha512-tQMagCOC59EVgNZcC5zl7XqO30Wki9i9J3acbUvkaosCT6JX3EeFwJD7Qqp4MCikRnzS18WXV3BLIQ66ytu6+Q==} + engines: {node: '>=18'} + + conventional-commits-parser@6.1.0: + resolution: {integrity: sha512-5nxDo7TwKB5InYBl4ZC//1g9GRwB/F3TXOGR9hgUjMGfvSP4Vu5NkpNro2+1+TIEy1vwxApl5ircECr2ri5JIw==} + engines: {node: '>=18'} + hasBin: true + + cross-spawn@7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + engines: {node: '>= 8'} + + debug@4.4.0: + resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decode-named-character-reference@1.0.2: + resolution: {integrity: sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==} + + deep-extend@0.6.0: + resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} + engines: {node: '>=4.0.0'} + + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + + devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + + dot-object@2.1.5: + resolution: {integrity: sha512-xHF8EP4XH/Ba9fvAF2LDd5O3IITVolerVV6xvkxoM8zlGEiCUrggpAnHyOoKJKCrhvPcGATFAUwIujj7bRG5UA==} + hasBin: true + + dot-prop@5.3.0: + resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==} + engines: {node: '>=8'} + + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + + emoji-regex@10.3.0: + resolution: {integrity: sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + + environment@1.1.0: + resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} + engines: {node: '>=18'} + + eventemitter3@5.0.1: + resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + + execa@8.0.1: + resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} + engines: {node: '>=16.17'} + + fd-package-json@1.2.0: + resolution: {integrity: sha512-45LSPmWf+gC5tdCQMNH4s9Sr00bIkiD9aN7dc5hqkrEw1geRYyDQS1v1oMHAW3ysfxfndqGsrDREHHjNNbKUfA==} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + foreground-child@3.1.1: + resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==} + engines: {node: '>=14'} + + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + + get-east-asian-width@1.2.0: + resolution: {integrity: sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==} + engines: {node: '>=18'} + + get-stream@8.0.1: + resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} + engines: {node: '>=16'} + + git-raw-commits@5.0.0: + resolution: {integrity: sha512-I2ZXrXeOc0KrCvC7swqtIFXFN+rbjnC7b2T943tvemIOVNl+XP8YnA9UVwqFhzzLClnSA60KR/qEjLpXzs73Qg==} + engines: {node: '>=18'} + hasBin: true + + git-semver-tags@8.0.0: + resolution: {integrity: sha512-N7YRIklvPH3wYWAR2vysaqGLPRcpwQ0GKdlqTiVN5w1UmCdaeY3K8s6DMKRCh54DDdzyt/OAB6C8jgVtb7Y2Fg==} + engines: {node: '>=18'} + hasBin: true + + glob@10.4.5: + resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + hasBin: true + + glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Glob versions prior to v9 are no longer supported + + handlebars@4.7.8: + resolution: {integrity: sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==} + engines: {node: '>=0.4.7'} + hasBin: true + + hosted-git-info@8.0.2: + resolution: {integrity: sha512-sYKnA7eGln5ov8T8gnYlkSOxFJvywzEx9BueN6xo/GKO8PGiI6uK6xx+DIGe45T3bdVjLAQDQW1aicT8z8JwQg==} + engines: {node: ^18.17.0 || >=20.5.0} + + human-signals@5.0.0: + resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} + engines: {node: '>=16.17.0'} + + husky@9.1.7: + resolution: {integrity: sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==} + engines: {node: '>=18'} + hasBin: true + + ignore@7.0.3: + resolution: {integrity: sha512-bAH5jbK/F3T3Jls4I0SO1hmPR0dKU0a7+SY6n1yzRtG54FLO8d6w/nxLFX2Nb7dBu6cCWXPaAME6cYqFUMmuCA==} + engines: {node: '>= 4'} + + inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + ini@4.1.1: + resolution: {integrity: sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + + is-alphabetical@2.0.1: + resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} + + is-alphanumerical@2.0.1: + resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} + + is-decimal@2.0.1: + resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-fullwidth-code-point@4.0.0: + resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} + engines: {node: '>=12'} + + is-fullwidth-code-point@5.0.0: + resolution: {integrity: sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==} + engines: {node: '>=18'} + + is-hexadecimal@2.0.1: + resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-obj@2.0.0: + resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==} + engines: {node: '>=8'} + + is-stream@3.0.0: + resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + + js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + + jsonc-parser@3.3.1: + resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==} + + jsonpointer@5.0.1: + resolution: {integrity: sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==} + engines: {node: '>=0.10.0'} + + katex@0.16.21: + resolution: {integrity: sha512-XvqR7FgOHtWupfMiigNzmh+MgUVmDGU2kXZm899ZkPfcuoPuFxyHmXsgATDpFZDAXCI8tvinaVcDo8PIIJSo4A==} + hasBin: true + + lilconfig@3.1.3: + resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} + engines: {node: '>=14'} + + linkify-it@5.0.0: + resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} + + lint-staged@15.5.0: + resolution: {integrity: sha512-WyCzSbfYGhK7cU+UuDDkzUiytbfbi0ZdPy2orwtM75P3WTtQBzmG40cCxIa8Ii2+XjfxzLH6Be46tUfWS85Xfg==} + engines: {node: '>=18.12.0'} + hasBin: true + + listr2@8.2.5: + resolution: {integrity: sha512-iyAZCeyD+c1gPyE9qpFu8af0Y+MRtmKOncdGoA2S5EY8iFq99dmmvkNnHiWo+pj0s7yH7l3KPIgee77tKpXPWQ==} + engines: {node: '>=18.0.0'} + + lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + + log-update@6.1.0: + resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==} + engines: {node: '>=18'} + + lru-cache@10.2.0: + resolution: {integrity: sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==} + engines: {node: 14 || >=16.14} + + lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + + markdown-it@14.1.0: + resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==} + hasBin: true + + markdown-table@2.0.0: + resolution: {integrity: sha512-Ezda85ToJUBhM6WGaG6veasyym+Tbs3cMAw/ZhOPqXiYsr0jgocBV3j3nx+4lk47plLlIqjwuTm/ywVI+zjJ/A==} + + markdownlint-cli@0.44.0: + resolution: {integrity: sha512-ZJTAONlvF9NkrIBltCdW15DxN9UTbPiKMEqAh2EU2gwIFlrCMavyCEPPO121cqfYOrLUJWW8/XKWongstmmTeQ==} + engines: {node: '>=18'} + hasBin: true + + markdownlint@0.37.4: + resolution: {integrity: sha512-u00joA/syf3VhWh6/ybVFkib5Zpj2e5KB/cfCei8fkSRuums6nyisTWGqjTWIOFoFwuXoTBQQiqlB4qFKp8ncQ==} + engines: {node: '>=18'} + + mdurl@2.0.0: + resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} + + meow@13.2.0: + resolution: {integrity: sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==} + engines: {node: '>=18'} + + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + + micromark-core-commonmark@2.0.2: + resolution: {integrity: sha512-FKjQKbxd1cibWMM1P9N+H8TwlgGgSkWZMmfuVucLCHaYqeSvJ0hFeHsIa65pA2nYbes0f8LDHPMrd9X7Ujxg9w==} + + micromark-extension-directive@3.0.2: + resolution: {integrity: sha512-wjcXHgk+PPdmvR58Le9d7zQYWy+vKEU9Se44p2CrCDPiLr2FMyiT4Fyb5UFKFC66wGB3kPlgD7q3TnoqPS7SZA==} + + micromark-extension-gfm-autolink-literal@2.1.0: + resolution: {integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==} + + micromark-extension-gfm-footnote@2.1.0: + resolution: {integrity: sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==} + + micromark-extension-gfm-table@2.1.0: + resolution: {integrity: sha512-Ub2ncQv+fwD70/l4ou27b4YzfNaCJOvyX4HxXU15m7mpYY+rjuWzsLIPZHJL253Z643RpbcP1oeIJlQ/SKW67g==} + + micromark-extension-math@3.1.0: + resolution: {integrity: sha512-lvEqd+fHjATVs+2v/8kg9i5Q0AP2k85H0WUOwpIVvUML8BapsMvh1XAogmQjOCsLpoKRCVQqEkQBB3NhVBcsOg==} + + micromark-factory-destination@2.0.1: + resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} + + micromark-factory-label@2.0.1: + resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} + + micromark-factory-space@2.0.1: + resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==} + + micromark-factory-title@2.0.1: + resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} + + micromark-factory-whitespace@2.0.1: + resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} + + micromark-util-character@2.1.1: + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} + + micromark-util-chunked@2.0.1: + resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} + + micromark-util-classify-character@2.0.1: + resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} + + micromark-util-combine-extensions@2.0.1: + resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} + + micromark-util-decode-numeric-character-reference@2.0.2: + resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} + + micromark-util-encode@2.0.1: + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} + + micromark-util-html-tag-name@2.0.1: + resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} + + micromark-util-normalize-identifier@2.0.1: + resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} + + micromark-util-resolve-all@2.0.1: + resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} + + micromark-util-sanitize-uri@2.0.1: + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} + + micromark-util-subtokenize@2.0.4: + resolution: {integrity: sha512-N6hXjrin2GTJDe3MVjf5FuXpm12PGm80BrUAeub9XFXca8JZbP+oIwY4LJSVwFUCL1IPm/WwSVUN7goFHmSGGQ==} + + micromark-util-symbol@2.0.1: + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} + + micromark-util-types@2.0.1: + resolution: {integrity: sha512-534m2WhVTddrcKVepwmVEVnUAmtrx9bfIjNoQHRqfnvdaHQiFytEhJoTgpWJvDEXCO5gLTQh3wYC1PgOJA4NSQ==} + + micromark@4.0.1: + resolution: {integrity: sha512-eBPdkcoCNvYcxQOAKAlceo5SNdzZWfF+FcSupREAzdAh9rRmE239CEQAiTwIgblwnoM8zzj35sZ5ZwvSEOF6Kw==} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + mimic-fn@4.0.0: + resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} + engines: {node: '>=12'} + + mimic-function@5.0.1: + resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} + engines: {node: '>=18'} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + neo-async@2.6.2: + resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + + normalize-package-data@7.0.0: + resolution: {integrity: sha512-k6U0gKRIuNCTkwHGZqblCfLfBRh+w1vI6tBo+IeJwq2M8FUiOqhX7GH+GArQGScA7azd1WfyRCvxoXDO3hQDIA==} + engines: {node: ^18.17.0 || >=20.5.0} + + npm-run-path@5.2.0: + resolution: {integrity: sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + onetime@6.0.0: + resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} + engines: {node: '>=12'} + + onetime@7.0.0: + resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} + engines: {node: '>=18'} + + package-json-from-dist@1.0.0: + resolution: {integrity: sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==} + + parse-entities@4.0.2: + resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==} + + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-key@4.0.0: + resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} + engines: {node: '>=12'} + + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + pidtree@0.6.0: + resolution: {integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==} + engines: {node: '>=0.10'} + hasBin: true + + prettier@3.5.3: + resolution: {integrity: sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==} + engines: {node: '>=14'} + hasBin: true + + punycode.js@2.3.1: + resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} + engines: {node: '>=6'} + + repeat-string@1.6.1: + resolution: {integrity: sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==} + engines: {node: '>=0.10'} + + restore-cursor@5.1.0: + resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} + engines: {node: '>=18'} + + rfdc@1.4.1: + resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} + + run-con@1.3.2: + resolution: {integrity: sha512-CcfE+mYiTcKEzg0IqS08+efdnH0oJ3zV0wSUFBNrMHMuxCtXvBCLzCJHatwuXDcu/RlhjTziTo/a1ruQik6/Yg==} + hasBin: true + + semver@7.6.0: + resolution: {integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==} + engines: {node: '>=10'} + hasBin: true + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + slice-ansi@5.0.0: + resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} + engines: {node: '>=12'} + + slice-ansi@7.1.0: + resolution: {integrity: sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==} + engines: {node: '>=18'} + + smol-toml@1.3.1: + resolution: {integrity: sha512-tEYNll18pPKHroYSmLLrksq233j021G0giwW7P3D24jC54pQ5W5BXMsQ/Mvw1OJCmEYDgY+lrzT+3nNUtoNfXQ==} + engines: {node: '>= 18'} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + spdx-correct@3.2.0: + resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} + + spdx-exceptions@2.4.0: + resolution: {integrity: sha512-hcjppoJ68fhxA/cjbN4T8N6uCUejN8yFw69ttpqtBeCbF3u13n7mb31NB9jKwGTTWWnt9IbRA/mf1FprYS8wfw==} + + spdx-expression-parse@3.0.1: + resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} + + spdx-license-ids@3.0.16: + resolution: {integrity: sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==} + + string-argv@0.3.2: + resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} + engines: {node: '>=0.6.19'} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + + string-width@7.1.0: + resolution: {integrity: sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==} + engines: {node: '>=18'} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-ansi@7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} + + strip-final-newline@3.0.0: + resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} + engines: {node: '>=12'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + typanion@3.14.0: + resolution: {integrity: sha512-ZW/lVMRabETuYCd9O9ZvMhAh8GslSqaUjxmK/JLPCh6l73CvLBiuXswj/+7LdnWOgYsQ130FqLzFz5aGT4I3Ug==} + + uc.micro@2.1.0: + resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} + + uglify-js@3.17.4: + resolution: {integrity: sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==} + engines: {node: '>=0.8.0'} + hasBin: true + + validate-npm-package-license@3.0.4: + resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} + + walk-up-path@3.0.1: + resolution: {integrity: sha512-9YlCL/ynK3CTlrSRrDxZvUauLzAswPCrsaCgilqFevUYpeEW0/3ScEjaa3kbW/T0ghhkEr7mv+fpjqn1Y1YuTA==} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + wordwrap@1.0.0: + resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + + wrap-ansi@9.0.0: + resolution: {integrity: sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==} + engines: {node: '>=18'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + + yaml@2.7.0: + resolution: {integrity: sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==} + engines: {node: '>= 14'} + hasBin: true + +snapshots: + + '@bitnami/readme-generator-for-helm@2.7.0': + dependencies: + commander: 13.1.0 + dot-object: 2.1.5 + lodash: 4.17.21 + markdown-table: 2.0.0 + yaml: 2.7.0 + + '@conventional-changelog/git-client@1.0.0(conventional-commits-filter@4.0.0)(conventional-commits-parser@6.1.0)': + dependencies: + '@types/semver': 7.5.8 + semver: 7.6.0 + optionalDependencies: + conventional-commits-filter: 4.0.0 + conventional-commits-parser: 6.1.0 + + '@hutson/parse-repository-url@5.0.0': {} + + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.1.0 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + + '@pkgjs/parseargs@0.11.0': + optional: true + + '@types/debug@4.1.12': + dependencies: + '@types/ms': 2.1.0 + + '@types/katex@0.16.7': {} + + '@types/ms@2.1.0': {} + + '@types/semver@7.5.8': {} + + '@types/unist@2.0.11': {} + + add-stream@1.0.0: {} + + ansi-escapes@7.0.0: + dependencies: + environment: 1.1.0 + + ansi-regex@5.0.1: {} + + ansi-regex@6.0.1: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@6.2.1: {} + + argparse@2.0.1: {} + + array-ify@1.0.0: {} + + balanced-match@1.0.2: {} + + brace-expansion@1.1.11: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.1: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + chalk@5.4.1: {} + + character-entities-legacy@3.0.0: {} + + character-entities@2.0.2: {} + + character-reference-invalid@2.0.1: {} + + cli-cursor@5.0.0: + dependencies: + restore-cursor: 5.1.0 + + cli-truncate@4.0.0: + dependencies: + slice-ansi: 5.0.0 + string-width: 7.1.0 + + clipanion@3.2.1(typanion@3.14.0): + dependencies: + typanion: 3.14.0 + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + colorette@2.0.20: {} + + commander@13.1.0: {} + + commander@6.2.1: {} + + commander@8.3.0: {} + + compare-func@2.0.0: + dependencies: + array-ify: 1.0.0 + dot-prop: 5.3.0 + + concat-map@0.0.1: {} + + conventional-changelog-conventionalcommits@8.0.0: + dependencies: + compare-func: 2.0.0 + + conventional-changelog-core@9.0.0(conventional-commits-filter@4.0.0): + dependencies: + '@hutson/parse-repository-url': 5.0.0 + add-stream: 1.0.0 + conventional-changelog-writer: 8.0.1 + conventional-commits-parser: 6.1.0 + fd-package-json: 1.2.0 + git-raw-commits: 5.0.0(conventional-commits-filter@4.0.0)(conventional-commits-parser@6.1.0) + git-semver-tags: 8.0.0(conventional-commits-filter@4.0.0)(conventional-commits-parser@6.1.0) + hosted-git-info: 8.0.2 + normalize-package-data: 7.0.0 + transitivePeerDependencies: + - conventional-commits-filter + + conventional-changelog-writer@8.0.1: + dependencies: + conventional-commits-filter: 5.0.0 + handlebars: 4.7.8 + meow: 13.2.0 + semver: 7.6.0 + + conventional-commits-filter@4.0.0: + optional: true + + conventional-commits-filter@5.0.0: {} + + conventional-commits-parser@6.1.0: + dependencies: + meow: 13.2.0 + + cross-spawn@7.0.3: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + debug@4.4.0: + dependencies: + ms: 2.1.3 + + decode-named-character-reference@1.0.2: + dependencies: + character-entities: 2.0.2 + + deep-extend@0.6.0: {} + + dequal@2.0.3: {} + + devlop@1.1.0: + dependencies: + dequal: 2.0.3 + + dot-object@2.1.5: + dependencies: + commander: 6.2.1 + glob: 7.2.3 + + dot-prop@5.3.0: + dependencies: + is-obj: 2.0.0 + + eastasianwidth@0.2.0: {} + + emoji-regex@10.3.0: {} + + emoji-regex@8.0.0: {} + + emoji-regex@9.2.2: {} + + entities@4.5.0: {} + + environment@1.1.0: {} + + eventemitter3@5.0.1: {} + + execa@8.0.1: + dependencies: + cross-spawn: 7.0.3 + get-stream: 8.0.1 + human-signals: 5.0.0 + is-stream: 3.0.0 + merge-stream: 2.0.0 + npm-run-path: 5.2.0 + onetime: 6.0.0 + signal-exit: 4.1.0 + strip-final-newline: 3.0.0 + + fd-package-json@1.2.0: + dependencies: + walk-up-path: 3.0.1 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + foreground-child@3.1.1: + dependencies: + cross-spawn: 7.0.3 + signal-exit: 4.1.0 + + fs.realpath@1.0.0: {} + + get-east-asian-width@1.2.0: {} + + get-stream@8.0.1: {} + + git-raw-commits@5.0.0(conventional-commits-filter@4.0.0)(conventional-commits-parser@6.1.0): + dependencies: + '@conventional-changelog/git-client': 1.0.0(conventional-commits-filter@4.0.0)(conventional-commits-parser@6.1.0) + meow: 13.2.0 + transitivePeerDependencies: + - conventional-commits-filter + - conventional-commits-parser + + git-semver-tags@8.0.0(conventional-commits-filter@4.0.0)(conventional-commits-parser@6.1.0): + dependencies: + '@conventional-changelog/git-client': 1.0.0(conventional-commits-filter@4.0.0)(conventional-commits-parser@6.1.0) + meow: 13.2.0 + transitivePeerDependencies: + - conventional-commits-filter + - conventional-commits-parser + + glob@10.4.5: + dependencies: + foreground-child: 3.1.1 + jackspeak: 3.4.3 + minimatch: 9.0.5 + minipass: 7.1.2 + package-json-from-dist: 1.0.0 + path-scurry: 1.11.1 + + glob@7.2.3: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + + handlebars@4.7.8: + dependencies: + minimist: 1.2.8 + neo-async: 2.6.2 + source-map: 0.6.1 + wordwrap: 1.0.0 + optionalDependencies: + uglify-js: 3.17.4 + + hosted-git-info@8.0.2: + dependencies: + lru-cache: 10.2.0 + + human-signals@5.0.0: {} + + husky@9.1.7: {} + + ignore@7.0.3: {} + + inflight@1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + inherits@2.0.4: {} + + ini@4.1.1: {} + + is-alphabetical@2.0.1: {} + + is-alphanumerical@2.0.1: + dependencies: + is-alphabetical: 2.0.1 + is-decimal: 2.0.1 + + is-decimal@2.0.1: {} + + is-fullwidth-code-point@3.0.0: {} + + is-fullwidth-code-point@4.0.0: {} + + is-fullwidth-code-point@5.0.0: + dependencies: + get-east-asian-width: 1.2.0 + + is-hexadecimal@2.0.1: {} + + is-number@7.0.0: {} + + is-obj@2.0.0: {} + + is-stream@3.0.0: {} + + isexe@2.0.0: {} + + jackspeak@3.4.3: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + + js-yaml@4.1.0: + dependencies: + argparse: 2.0.1 + + jsonc-parser@3.3.1: {} + + jsonpointer@5.0.1: {} + + katex@0.16.21: + dependencies: + commander: 8.3.0 + + lilconfig@3.1.3: {} + + linkify-it@5.0.0: + dependencies: + uc.micro: 2.1.0 + + lint-staged@15.5.0: + dependencies: + chalk: 5.4.1 + commander: 13.1.0 + debug: 4.4.0 + execa: 8.0.1 + lilconfig: 3.1.3 + listr2: 8.2.5 + micromatch: 4.0.8 + pidtree: 0.6.0 + string-argv: 0.3.2 + yaml: 2.7.0 + transitivePeerDependencies: + - supports-color + + listr2@8.2.5: + dependencies: + cli-truncate: 4.0.0 + colorette: 2.0.20 + eventemitter3: 5.0.1 + log-update: 6.1.0 + rfdc: 1.4.1 + wrap-ansi: 9.0.0 + + lodash@4.17.21: {} + + log-update@6.1.0: + dependencies: + ansi-escapes: 7.0.0 + cli-cursor: 5.0.0 + slice-ansi: 7.1.0 + strip-ansi: 7.1.0 + wrap-ansi: 9.0.0 + + lru-cache@10.2.0: {} + + lru-cache@6.0.0: + dependencies: + yallist: 4.0.0 + + markdown-it@14.1.0: + dependencies: + argparse: 2.0.1 + entities: 4.5.0 + linkify-it: 5.0.0 + mdurl: 2.0.0 + punycode.js: 2.3.1 + uc.micro: 2.1.0 + + markdown-table@2.0.0: + dependencies: + repeat-string: 1.6.1 + + markdownlint-cli@0.44.0: + dependencies: + commander: 13.1.0 + glob: 10.4.5 + ignore: 7.0.3 + js-yaml: 4.1.0 + jsonc-parser: 3.3.1 + jsonpointer: 5.0.1 + markdownlint: 0.37.4 + minimatch: 9.0.5 + run-con: 1.3.2 + smol-toml: 1.3.1 + transitivePeerDependencies: + - supports-color + + markdownlint@0.37.4: + dependencies: + markdown-it: 14.1.0 + micromark: 4.0.1 + micromark-core-commonmark: 2.0.2 + micromark-extension-directive: 3.0.2 + micromark-extension-gfm-autolink-literal: 2.1.0 + micromark-extension-gfm-footnote: 2.1.0 + micromark-extension-gfm-table: 2.1.0 + micromark-extension-math: 3.1.0 + micromark-util-types: 2.0.1 + transitivePeerDependencies: + - supports-color + + mdurl@2.0.0: {} + + meow@13.2.0: {} + + merge-stream@2.0.0: {} + + micromark-core-commonmark@2.0.2: + dependencies: + decode-named-character-reference: 1.0.2 + devlop: 1.1.0 + micromark-factory-destination: 2.0.1 + micromark-factory-label: 2.0.1 + micromark-factory-space: 2.0.1 + micromark-factory-title: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-html-tag-name: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-subtokenize: 2.0.4 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.1 + + micromark-extension-directive@3.0.2: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.1 + parse-entities: 4.0.2 + + micromark-extension-gfm-autolink-literal@2.1.0: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.1 + + micromark-extension-gfm-footnote@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-core-commonmark: 2.0.2 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.1 + + micromark-extension-gfm-table@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.1 + + micromark-extension-math@3.1.0: + dependencies: + '@types/katex': 0.16.7 + devlop: 1.1.0 + katex: 0.16.21 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.1 + + micromark-factory-destination@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.1 + + micromark-factory-label@2.0.1: + dependencies: + devlop: 1.1.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.1 + + micromark-factory-space@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-types: 2.0.1 + + micromark-factory-title@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.1 + + micromark-factory-whitespace@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.1 + + micromark-util-character@2.1.1: + dependencies: + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.1 + + micromark-util-chunked@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-classify-character@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.1 + + micromark-util-combine-extensions@2.0.1: + dependencies: + micromark-util-chunked: 2.0.1 + micromark-util-types: 2.0.1 + + micromark-util-decode-numeric-character-reference@2.0.2: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-encode@2.0.1: {} + + micromark-util-html-tag-name@2.0.1: {} + + micromark-util-normalize-identifier@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-resolve-all@2.0.1: + dependencies: + micromark-util-types: 2.0.1 + + micromark-util-sanitize-uri@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-encode: 2.0.1 + micromark-util-symbol: 2.0.1 + + micromark-util-subtokenize@2.0.4: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.1 + + micromark-util-symbol@2.0.1: {} + + micromark-util-types@2.0.1: {} + + micromark@4.0.1: + dependencies: + '@types/debug': 4.1.12 + debug: 4.4.0 + decode-named-character-reference: 1.0.2 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.2 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-combine-extensions: 2.0.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-encode: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-subtokenize: 2.0.4 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.1 + transitivePeerDependencies: + - supports-color + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + mimic-fn@4.0.0: {} + + mimic-function@5.0.1: {} + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.11 + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.1 + + minimist@1.2.8: {} + + minipass@7.1.2: {} + + ms@2.1.3: {} + + neo-async@2.6.2: {} + + normalize-package-data@7.0.0: + dependencies: + hosted-git-info: 8.0.2 + semver: 7.6.0 + validate-npm-package-license: 3.0.4 + + npm-run-path@5.2.0: + dependencies: + path-key: 4.0.0 + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + onetime@6.0.0: + dependencies: + mimic-fn: 4.0.0 + + onetime@7.0.0: + dependencies: + mimic-function: 5.0.1 + + package-json-from-dist@1.0.0: {} + + parse-entities@4.0.2: + dependencies: + '@types/unist': 2.0.11 + character-entities-legacy: 3.0.0 + character-reference-invalid: 2.0.1 + decode-named-character-reference: 1.0.2 + is-alphanumerical: 2.0.1 + is-decimal: 2.0.1 + is-hexadecimal: 2.0.1 + + path-is-absolute@1.0.1: {} + + path-key@3.1.1: {} + + path-key@4.0.0: {} + + path-scurry@1.11.1: + dependencies: + lru-cache: 10.2.0 + minipass: 7.1.2 + + picomatch@2.3.1: {} + + pidtree@0.6.0: {} + + prettier@3.5.3: {} + + punycode.js@2.3.1: {} + + repeat-string@1.6.1: {} + + restore-cursor@5.1.0: + dependencies: + onetime: 7.0.0 + signal-exit: 4.1.0 + + rfdc@1.4.1: {} + + run-con@1.3.2: + dependencies: + deep-extend: 0.6.0 + ini: 4.1.1 + minimist: 1.2.8 + strip-json-comments: 3.1.1 + + semver@7.6.0: + dependencies: + lru-cache: 6.0.0 + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + signal-exit@4.1.0: {} + + slice-ansi@5.0.0: + dependencies: + ansi-styles: 6.2.1 + is-fullwidth-code-point: 4.0.0 + + slice-ansi@7.1.0: + dependencies: + ansi-styles: 6.2.1 + is-fullwidth-code-point: 5.0.0 + + smol-toml@1.3.1: {} + + source-map@0.6.1: {} + + spdx-correct@3.2.0: + dependencies: + spdx-expression-parse: 3.0.1 + spdx-license-ids: 3.0.16 + + spdx-exceptions@2.4.0: {} + + spdx-expression-parse@3.0.1: + dependencies: + spdx-exceptions: 2.4.0 + spdx-license-ids: 3.0.16 + + spdx-license-ids@3.0.16: {} + + string-argv@0.3.2: {} + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.0 + + string-width@7.1.0: + dependencies: + emoji-regex: 10.3.0 + get-east-asian-width: 1.2.0 + strip-ansi: 7.1.0 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-ansi@7.1.0: + dependencies: + ansi-regex: 6.0.1 + + strip-final-newline@3.0.0: {} + + strip-json-comments@3.1.1: {} + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + typanion@3.14.0: {} + + uc.micro@2.1.0: {} + + uglify-js@3.17.4: + optional: true + + validate-npm-package-license@3.0.4: + dependencies: + spdx-correct: 3.2.0 + spdx-expression-parse: 3.0.1 + + walk-up-path@3.0.1: {} + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + wordwrap@1.0.0: {} + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.1.0 + + wrap-ansi@9.0.0: + dependencies: + ansi-styles: 6.2.1 + string-width: 7.1.0 + strip-ansi: 7.1.0 + + wrappy@1.0.2: {} + + yallist@4.0.0: {} + + yaml@2.7.0: {} diff --git a/renovate.json b/renovate.json index 45b9953..9e09aef 100644 --- a/renovate.json +++ b/renovate.json @@ -1,11 +1,24 @@ { "$schema": "https://docs.renovatebot.com/renovate-schema.json", - "extends": "config:base", + "extends": [ + "forgejo-contrib/forgejo-renovate//base.json", + "forgejo-helm/forgejo-helm//.forgejo/renovate/k3s.json" + ], "assignees": ["viceice"], - "semanticCommits": "enabled", - "automergeStrategy": "fast-forward", - "enabledManagers": ["helmv3", "npm", "regex", "woodpecker"], + "baseBranches": ["main", "/^maint\\/.+/"], "packageRules": [ + { + "description": "Separate multiple major sub chart updates", + "matchFileNames": ["Chart.yaml"], + "separateMultipleMajor": true + }, + { + "description": "Require approval for major sub chart updates for maintenance branches", + "matchBaseBranches": ["/^maint\\/.+/"], + "matchUpdateTypes": ["major"], + "matchFileNames": ["Chart.yaml"], + "dependencyDashboardApproval": true + }, { "matchManagers": ["helmv3"], "matchUpdateTypes": ["minor", "patch"], @@ -17,45 +30,108 @@ "semanticCommitType": "feat" }, { - "description": "Fix forgejo docker image versioning", - "matchDepNames": ["forgejo"], - "matchDatasources": ["docker"], - "versioning": "regex:^(?\\d+)\\.(?\\d+)\\.(?\\d+)-(?\\d+)(?:-(?.+))?$" - }, - { - "matchManagers": ["regex"], + "matchManagers": ["custom.regex"], "matchDepNames": ["forgejo"], "matchUpdateTypes": ["patch"], "semanticCommitType": "fix" }, { - "matchManagers": ["regex"], + "matchManagers": ["custom.regex"], "matchDepNames": ["forgejo"], "matchUpdateTypes": ["major", "minor"], "semanticCommitType": "feat" }, { - "description": "Automerge renovate updates", - "matchPackageNames": ["ghcr.io/visualon/renovate"], + "description": "Automerge and group helm subchart updates weekly (minor & patch)", + "matchManagers": ["helmv3"], + "matchFileNames": ["Chart.yaml"], + "matchUpdateTypes": ["minor", "patch"], "automerge": true, - "platformAutomerge": true + "groupName": "subcharts", + "extends": ["schedule:weekly"] }, { - "description": "Automerge patch deps updates", - "matchManagers": ["helmv3"], - "matchFiles": ["Chart.yaml"], - "matchUpdateTypes": ["patch"], - "automerge": true, - "platformAutomerge": true + "description": "Automerge dev deps updates", + "matchManagers": ["npm"], + "matchDepTypes": ["devDependencies"], + "matchUpdateTypes": ["minor", "patch"], + "automerge": true + }, + { + "description": "Automerge node updates", + "matchManagers": ["nodenv"], + "matchUpdateTypes": ["minor", "patch"], + "automerge": true + }, + { + "description": "Automerge some updates", + "matchDepNames": ["pnpm", "helm-unittest"], + "matchUpdateTypes": ["minor", "patch"], + "automerge": true + }, + { + "description": "Automerge digest updates", + "matchUpdateTypes": ["digest"], + "automerge": true + }, + { + "description": "Use test scope for forgejo ci tests", + "matchFileNames": ["ci/*.yaml"], + "additionalBranchPrefix": "ci-forgejo-", + "semanticCommitType": "ci", + "semanticCommitScope": "forgejo", + "groupName": "experimental docker digests", + "extends": ["schedule:daily"] + }, + { + "description": "Disable updates for forgejo ci tests", + "matchFileNames": ["ci/*.yaml"], + "matchUpdateTypes": ["major", "minor", "patch"], + "enabled": false + }, + { + "description": "Don't pin digests for forgejo ci tests, not supported", + "matchFileNames": ["ci/*.yaml"], + "pinDigests": false + }, + { + "description": "branch automerge not possible", + "automergeType": "pr", + "matchPackageNames": ["/.+/"] } ], - "regexManagers": [ + "customManagers": [ { + "description": "Update forgeo version in chart", + "customType": "regex", "fileMatch": ["^Chart\\.yaml$"], "matchStrings": ["appVersion: (?.+?)\\s"], "depNameTemplate": "forgejo", - "packageNameTemplate": "codeberg.org/forgejo/forgejo", + "packageNameTemplate": "code.forgejo.org/forgejo/forgejo", "datasourceTemplate": "docker" + }, + { + "description": "Detect helm-unittest yaml schema file", + "customType": "regex", + "fileMatch": [".vscode/settings\\.json$"], + "matchStrings": [ + "https://raw\\.githubusercontent\\.com/helm-unittest/helm-unittest/(?v[0-9.]+?)/schema/helm-testsuite\\.json" + ], + "depNameTemplate": "helm-unittest", + "packageNameTemplate": "helm-unittest/helm-unittest", + "datasourceTemplate": "github-releases" + }, + { + "customType": "regex", + "description": "Update k3s kubernetes references", + "fileMatch": ["^\\.forgejo/workflows/[^/]+\\.ya?ml$"], + "matchStrings": [" +- (?.+?) # renovate: k3s\\n"], + "depNameTemplate": "k3s", + "packageNameTemplate": "k3s-io/k3s", + "datasourceTemplate": "github-releases" } - ] + ], + "helm-values": { + "fileMatch": ["^ci/.+\\.yaml$"] + } } diff --git a/templates/NOTES.txt b/templates/NOTES.txt index 25b35e7..a1ccb23 100644 --- a/templates/NOTES.txt +++ b/templates/NOTES.txt @@ -18,3 +18,19 @@ echo "Visit http://127.0.0.1:{{ .Values.service.http.port }} to use your application" kubectl --namespace {{ .Release.Namespace }} port-forward svc/{{ .Release.Name }}-http {{ .Values.service.http.port }}:{{ .Values.service.http.port }} {{- end }} +{{- $warnings := list -}} +{{- if eq (get .Values.gitea.config.cache "ADAPTER") "memory" -}} + {{- $warnings = append $warnings "Forgejo uses 'memory' for caching which is not recommended for production use. See https://forgejo.org/docs/latest/admin/config-cheat-sheet/#cache-cache for available options." -}} +{{- end }} +{{- if eq (get .Values.gitea.config.queue "TYPE") "level" -}} + {{- $warnings = append $warnings "Forgejo uses 'leveldb' for queue actions which is not recommended for production use. See https://forgejo.org/docs/latest/admin/config-cheat-sheet/#queue-queue-and-queue for available options." -}} +{{- end }} +{{- if eq (get .Values.gitea.config.session "PROVIDER") "memory" -}} + {{- $warnings = append $warnings "Forgejo uses 'memory' for sessions which is not recommended for production use. See https://forgejo.org/docs/latest/admin/config-cheat-sheet/#session-session for available options." -}} +{{- end }} +{{- if gt (len $warnings) 0 }} +2. Review these warnings: +{{- range $warnings }} + - {{ . }} +{{- end }} +{{- end }} diff --git a/templates/_helpers.tpl b/templates/_helpers.tpl index 7fd7372..234c839 100644 --- a/templates/_helpers.tpl +++ b/templates/_helpers.tpl @@ -2,6 +2,7 @@ {{/* Expand the name of the chart. */}} + {{- define "gitea.name" -}} {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} {{- end -}} @@ -31,18 +32,34 @@ Create chart name and version as used by the chart label. {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} {{- end -}} +{{/* +Get version from .Values.image.tag or Chart.AppVersion. +Trim optional docker digest. +*/}} +{{- define "gitea.version" -}} +{{- regexReplaceAll "@.+" (.Values.image.tag | default .Chart.AppVersion | toString) "" -}} +{{- end -}} + {{/* Create image name and tag used by the deployment. */}} {{- define "gitea.image" -}} +{{- $fullOverride := .Values.image.fullOverride | default "" -}} {{- $registry := .Values.global.imageRegistry | default .Values.image.registry -}} -{{- $name := .Values.image.repository -}} -{{- $tag := .Values.image.tag | default .Chart.AppVersion -}} +{{- $repository := .Values.image.repository -}} +{{- $separator := ":" -}} +{{- $tag := .Values.image.tag | default .Chart.AppVersion | toString -}} {{- $rootless := ternary "-rootless" "" (.Values.image.rootless) -}} -{{- if $registry -}} - {{- printf "%s/%s:%s%s" $registry $name $tag $rootless -}} +{{- $digest := "" -}} +{{- if .Values.image.digest }} + {{- $digest = (printf "@%s" (.Values.image.digest | toString)) -}} +{{- end -}} +{{- if $fullOverride }} + {{- printf "%s" $fullOverride -}} +{{- else if $registry }} + {{- printf "%s/%s%s%s%s%s" $registry $repository $separator $tag $rootless $digest -}} {{- else -}} - {{- printf "%s:%s%s" $name $tag $rootless -}} + {{- printf "%s%s%s%s%s" $repository $separator $tag $rootless $digest -}} {{- end -}} {{- end -}} @@ -65,7 +82,7 @@ imagePullSecrets: Storage Class */}} {{- define "gitea.persistence.storageClass" -}} -{{- $storageClass := .Values.global.storageClass | default .Values.persistence.storageClass }} +{{- $storageClass := (tpl ( default "" .Values.persistence.storageClass) .) | default (tpl ( default "" .Values.global.storageClass) .) }} {{- if $storageClass }} storageClassName: {{ $storageClass | quote }} {{- end }} @@ -78,8 +95,8 @@ Common labels helm.sh/chart: {{ include "gitea.chart" . }} app: {{ include "gitea.name" . }} {{ include "gitea.selectorLabels" . }} -app.kubernetes.io/version: {{ .Values.image.tag | default .Chart.AppVersion | quote }} -version: {{ .Values.image.tag | default .Chart.AppVersion | quote }} +app.kubernetes.io/version: {{ include "gitea.version" . | quote }} +version: {{ include "gitea.version" . | quote }} app.kubernetes.io/managed-by: {{ .Release.Service }} {{- end -}} @@ -91,24 +108,46 @@ app.kubernetes.io/name: {{ include "gitea.name" . }} app.kubernetes.io/instance: {{ .Release.Name }} {{- end -}} +{{- define "postgresql-ha.dns" -}} +{{- if (index .Values "postgresql-ha").enabled -}} +{{- printf "%s-postgresql-ha-pgpool.%s.svc.%s:%g" .Release.Name .Release.Namespace .Values.clusterDomain (index .Values "postgresql-ha" "service" "ports" "postgresql") -}} +{{- end -}} +{{- end -}} + {{- define "postgresql.dns" -}} -{{- printf "%s-postgresql.%s.svc.%s:%g" .Release.Name .Release.Namespace .Values.clusterDomain .Values.postgresql.primary.service.ports.postgresql -}} +{{- if (index .Values "postgresql").enabled -}} +{{- printf "%s-postgresql.%s.svc.%s:%g" .Release.Name .Release.Namespace .Values.clusterDomain .Values.postgresql.global.postgresql.service.ports.postgresql -}} +{{- end -}} {{- end -}} -{{- define "mysql.dns" -}} -{{- printf "%s-mysql.%s.svc.%s:%g" .Release.Name .Release.Namespace .Values.clusterDomain .Values.mysql.primary.service.ports.mysql | trunc 63 | trimSuffix "-" -}} +{{- define "redis.dns" -}} +{{- if and ((index .Values "redis-cluster").enabled) ((index .Values "redis").enabled) -}} +{{- fail "redis and redis-cluster cannot be enabled at the same time. Please only choose one." -}} +{{- else if (index .Values "redis-cluster").enabled -}} +{{- printf "redis+cluster://:%s@%s-redis-cluster-headless.%s.svc.%s:%g/0?pool_size=100&idle_timeout=180s&" (index .Values "redis-cluster").global.redis.password .Release.Name .Release.Namespace .Values.clusterDomain (index .Values "redis-cluster").service.ports.redis -}} +{{- else if (index .Values "redis").enabled -}} +{{- printf "redis://:%s@%s-redis-headless.%s.svc.%s:%g/0?pool_size=100&idle_timeout=180s&" (index .Values "redis").global.redis.password .Release.Name .Release.Namespace .Values.clusterDomain (index .Values "redis").master.service.ports.redis -}} +{{- end -}} {{- end -}} -{{- define "mariadb.dns" -}} -{{- printf "%s-mariadb.%s.svc.%s:%g" .Release.Name .Release.Namespace .Values.clusterDomain .Values.mariadb.primary.service.ports.mysql | trunc 63 | trimSuffix "-" -}} +{{- define "redis.port" -}} +{{- if (index .Values "redis-cluster").enabled -}} +{{ (index .Values "redis-cluster").service.ports.redis }} +{{- else if (index .Values "redis").enabled -}} +{{ (index .Values "redis").master.service.ports.redis }} +{{- end -}} {{- end -}} -{{- define "memcached.dns" -}} -{{- printf "%s-memcached.%s.svc.%s:%g" .Release.Name .Release.Namespace .Values.clusterDomain .Values.memcached.service.ports.memcached | trunc 63 | trimSuffix "-" -}} +{{- define "redis.servicename" -}} +{{- if (index .Values "redis-cluster").enabled -}} +{{- printf "%s-redis-cluster-headless.%s.svc.%s" .Release.Name .Release.Namespace .Values.clusterDomain -}} +{{- else if (index .Values "redis").enabled -}} +{{- printf "%s-redis-headless.%s.svc.%s" .Release.Name .Release.Namespace .Values.clusterDomain -}} +{{- end -}} {{- end -}} {{- define "gitea.default_domain" -}} -{{- printf "%s-gitea.%s.svc.%s" (include "gitea.fullname" .) .Release.Namespace .Values.clusterDomain | trunc 63 | trimSuffix "-" -}} +{{- printf "%s-http.%s.svc.%s" (include "gitea.fullname" .) .Release.Namespace .Values.clusterDomain -}} {{- end -}} {{- define "gitea.ldap_settings" -}} @@ -185,11 +224,12 @@ https {{- $_ := set $inlines $key (join "\n" $section) -}} {{- end -}} {{- else }} - {{- if or (eq $key "APP_NAME") (eq $key "RUN_USER") (eq $key "RUN_MODE") -}} + {{- if or (eq $key "APP_NAME") (eq $key "RUN_USER") (eq $key "RUN_MODE") (eq $key "APP_SLOGAN") (eq $key "APP_DISPLAY_NAME_FORMAT") -}} {{- $generals = append $generals (printf "%s=%s" $key $value) -}} {{- else -}} {{- (printf "Key %s cannot be on top level of configuration" $key) | fail -}} {{- end -}} + {{- end }} {{- end }} @@ -219,6 +259,18 @@ https {{- if not (hasKey .Values.gitea.config "oauth2") -}} {{- $_ := set .Values.gitea.config "oauth2" dict -}} {{- end -}} + {{- if not (hasKey .Values.gitea.config "session") -}} + {{- $_ := set .Values.gitea.config "session" dict -}} + {{- end -}} + {{- if not (hasKey .Values.gitea.config "queue") -}} + {{- $_ := set .Values.gitea.config "queue" dict -}} + {{- end -}} + {{- if not (hasKey .Values.gitea.config "queue.issue_indexer") -}} + {{- $_ := set .Values.gitea.config "queue.issue_indexer" dict -}} + {{- end -}} + {{- if not (hasKey .Values.gitea.config "indexer") -}} + {{- $_ := set .Values.gitea.config "indexer" dict -}} + {{- end -}} {{- end -}} {{- define "gitea.inline_configuration.defaults" -}} @@ -234,12 +286,36 @@ https {{- if not (hasKey .Values.gitea.config.metrics "ENABLED") -}} {{- $_ := set .Values.gitea.config.metrics "ENABLED" .Values.gitea.metrics.enabled -}} {{- end -}} - {{- if .Values.memcached.enabled -}} - {{- $_ := set .Values.gitea.config.cache "ENABLED" "true" -}} - {{- $_ := set .Values.gitea.config.cache "ADAPTER" "memcache" -}} - {{- if not (.Values.gitea.config.cache.HOST) -}} - {{- $_ := set .Values.gitea.config.cache "HOST" (include "memcached.dns" .) -}} + {{- /* redis queue */ -}} + {{- if or ((index .Values "redis-cluster").enabled) ((index .Values "redis").enabled) -}} + {{- $_ := set .Values.gitea.config.queue "TYPE" "redis" -}} + {{- $_ := set .Values.gitea.config.queue "CONN_STR" (include "redis.dns" .) -}} + {{- $_ := set .Values.gitea.config.session "PROVIDER" "redis" -}} + {{- $_ := set .Values.gitea.config.session "PROVIDER_CONFIG" (include "redis.dns" .) -}} + {{- $_ := set .Values.gitea.config.cache "ADAPTER" "redis" -}} + {{- $_ := set .Values.gitea.config.cache "HOST" (include "redis.dns" .) -}} + {{- else -}} + {{- if not (get .Values.gitea.config.session "PROVIDER") -}} + {{- $_ := set .Values.gitea.config.session "PROVIDER" "memory" -}} {{- end -}} + {{- if not (get .Values.gitea.config.session "PROVIDER_CONFIG") -}} + {{- $_ := set .Values.gitea.config.session "PROVIDER_CONFIG" "" -}} + {{- end -}} + {{- if not (get .Values.gitea.config.queue "TYPE") -}} + {{- $_ := set .Values.gitea.config.queue "TYPE" "level" -}} + {{- end -}} + {{- if not (get .Values.gitea.config.queue "CONN_STR") -}} + {{- $_ := set .Values.gitea.config.queue "CONN_STR" "" -}} + {{- end -}} + {{- if not (get .Values.gitea.config.cache "ADAPTER") -}} + {{- $_ := set .Values.gitea.config.cache "ADAPTER" "memory" -}} + {{- end -}} + {{- if not (get .Values.gitea.config.cache "HOST") -}} + {{- $_ := set .Values.gitea.config.cache "HOST" "" -}} + {{- end -}} + {{- end -}} + {{- if not .Values.gitea.config.indexer.ISSUE_INDEXER_TYPE -}} + {{- $_ := set .Values.gitea.config.indexer "ISSUE_INDEXER_TYPE" "db" -}} {{- end -}} {{- end -}} @@ -252,7 +328,7 @@ https {{- end -}} {{- if not (.Values.gitea.config.server.DOMAIN) -}} {{- if gt (len .Values.ingress.hosts) 0 -}} - {{- $_ := set .Values.gitea.config.server "DOMAIN" (index .Values.ingress.hosts 0).host -}} + {{- $_ := set .Values.gitea.config.server "DOMAIN" ( tpl (index .Values.ingress.hosts 0).host $) -}} {{- else -}} {{- $_ := set .Values.gitea.config.server "DOMAIN" (include "gitea.default_domain" .) -}} {{- end -}} @@ -287,30 +363,23 @@ https {{- end -}} {{- define "gitea.inline_configuration.defaults.database" -}} - {{- if .Values.postgresql.enabled -}} + {{- if (index .Values "postgresql-ha" "enabled") -}} + {{- $_ := set .Values.gitea.config.database "DB_TYPE" "postgres" -}} + {{- if not (.Values.gitea.config.database.HOST) -}} + {{- $_ := set .Values.gitea.config.database "HOST" (include "postgresql-ha.dns" .) -}} + {{- end -}} + {{- $_ := set .Values.gitea.config.database "NAME" (index .Values "postgresql-ha" "global" "postgresql" "database") -}} + {{- $_ := set .Values.gitea.config.database "USER" (index .Values "postgresql-ha" "global" "postgresql" "username") -}} + {{- $_ := set .Values.gitea.config.database "PASSWD" (index .Values "postgresql-ha" "global" "postgresql" "password") -}} + {{- end -}} + {{- if (index .Values "postgresql" "enabled") -}} {{- $_ := set .Values.gitea.config.database "DB_TYPE" "postgres" -}} {{- if not (.Values.gitea.config.database.HOST) -}} {{- $_ := set .Values.gitea.config.database "HOST" (include "postgresql.dns" .) -}} {{- end -}} - {{- $_ := set .Values.gitea.config.database "NAME" .Values.postgresql.auth.database -}} - {{- $_ := set .Values.gitea.config.database "USER" .Values.postgresql.auth.username -}} - {{- $_ := set .Values.gitea.config.database "PASSWD" .Values.postgresql.auth.password -}} - {{- else if .Values.mysql.enabled -}} - {{- $_ := set .Values.gitea.config.database "DB_TYPE" "mysql" -}} - {{- if not (.Values.gitea.config.database.HOST) -}} - {{- $_ := set .Values.gitea.config.database "HOST" (include "mysql.dns" .) -}} - {{- end -}} - {{- $_ := set .Values.gitea.config.database "NAME" .Values.mysql.auth.database -}} - {{- $_ := set .Values.gitea.config.database "USER" .Values.mysql.auth.username -}} - {{- $_ := set .Values.gitea.config.database "PASSWD" .Values.mysql.auth.password -}} - {{- else if .Values.mariadb.enabled -}} - {{- $_ := set .Values.gitea.config.database "DB_TYPE" "mysql" -}} - {{- if not (.Values.gitea.config.database.HOST) -}} - {{- $_ := set .Values.gitea.config.database "HOST" (include "mariadb.dns" .) -}} - {{- end -}} - {{- $_ := set .Values.gitea.config.database "NAME" .Values.mariadb.auth.database -}} - {{- $_ := set .Values.gitea.config.database "USER" .Values.mariadb.auth.username -}} - {{- $_ := set .Values.gitea.config.database "PASSWD" .Values.mariadb.auth.password -}} + {{- $_ := set .Values.gitea.config.database "NAME" .Values.postgresql.global.postgresql.auth.database -}} + {{- $_ := set .Values.gitea.config.database "USER" .Values.postgresql.global.postgresql.auth.username -}} + {{- $_ := set .Values.gitea.config.database "PASSWD" .Values.postgresql.global.postgresql.auth.password -}} {{- end -}} {{- end -}} @@ -335,3 +404,15 @@ https {{- define "gitea.gpg-key-secret-name" -}} {{ default (printf "%s-gpg-key" (include "gitea.fullname" .)) .Values.signing.existingSecret }} {{- end -}} + +{{- define "gitea.serviceAccountName" -}} +{{ .Values.serviceAccount.name | default (include "gitea.fullname" .) }} +{{- end -}} + +{{- define "gitea.admin.passwordMode" -}} +{{- if has .Values.gitea.admin.passwordMode (tuple "keepUpdated" "initialOnlyNoReset" "initialOnlyRequireReset") -}} +{{ .Values.gitea.admin.passwordMode }} +{{- else -}} +{{ printf "gitea.admin.passwordMode must be set to one of 'keepUpdated', 'initialOnlyNoReset', or 'initialOnlyRequireReset'. Received: '%s'" .Values.gitea.admin.passwordMode | fail }} +{{- end -}} +{{- end -}} diff --git a/templates/gitea/config.yaml b/templates/gitea/config.yaml index bcc7c4d..c551c96 100644 --- a/templates/gitea/config.yaml +++ b/templates/gitea/config.yaml @@ -2,6 +2,7 @@ apiVersion: v1 kind: Secret metadata: name: {{ include "gitea.fullname" . }}-inline-config + namespace: {{ include "common.names.namespace" . | quote }} labels: {{- include "gitea.labels" . | nindent 4 }} type: Opaque @@ -16,6 +17,42 @@ metadata: {{- include "gitea.labels" . | nindent 4 }} type: Opaque stringData: + assertions: | + + {{- /*assert that only one PG dep is enabled */ -}} + {{- if and (.Values.postgresql.enabled) (index .Values "postgresql-ha" "enabled") -}} + {{- fail "Only one of postgresql or postgresql-ha can be enabled at the same time." -}} + {{- end }} + + {{- /* multiple replicas assertions */ -}} + {{- if gt .Values.replicaCount 1.0 -}} + {{- if .Values.gitea.config.cron -}} + {{- if .Values.gitea.config.cron.GIT_GC_REPOS -}} + {{- if eq .Values.gitea.config.cron.GIT_GC_REPOS.ENABLED true -}} + {{ fail "Invoking the garbage collector via CRON is not yet supported when running with multiple replicas. Please set 'cron.GIT_GC_REPOS.enabled = false'." }} + {{- end }} + {{- end }} + {{- end }} + + {{- if eq (first .Values.persistence.accessModes) "ReadWriteOnce" -}} + {{- fail "When using multiple replicas, a RWX file system is required and gitea.persistence.accessModes[0] must be set to ReadWriteMany." -}} + {{- end }} + {{- if .Values.gitea.config.indexer -}} + {{- if eq .Values.gitea.config.indexer.ISSUE_INDEXER_TYPE "bleve" -}} + {{- fail "When using multiple replicas, the issue indexer (gitea.config.indexer.ISSUE_INDEXER_TYPE) must be set to a HA-ready provider such as 'meilisearch', 'elasticsearch' or 'db' (if the DB is HA-ready)." -}} + {{- end }} + {{- if .Values.gitea.config.indexer.REPO_INDEXER_TYPE -}} + {{- if eq .Values.gitea.config.indexer.REPO_INDEXER_TYPE "bleve" -}} + {{- if .Values.gitea.config.indexer.REPO_INDEXER_ENABLED -}} + {{- if eq .Values.gitea.config.indexer.REPO_INDEXER_ENABLED true -}} + {{- fail "When using multiple replicas, the repo indexer (gitea.config.indexer.REPO_INDEXER_TYPE) must be set to 'meilisearch' or 'elasticsearch' or disabled." -}} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + + {{- end }} config_environment.sh: |- #!/usr/bin/env bash set -euo pipefail @@ -32,7 +69,7 @@ stringData: # skip empty line return fi - + # 'xargs echo -n' trims all leading/trailing whitespaces and a trailing new line local setting="$(awk -F '=' '{print $1}' <<< "${line}" | xargs echo -n)" @@ -52,15 +89,18 @@ stringData: env2ini::log " + '${setting}'" + local masked_setting="${setting//./_0X2E_}" # '//' instructs to replace all matches + masked_setting="${masked_setting//-/_0X2D_}" + if [[ -z "${section}" ]]; then - export "ENV_TO_INI____${setting^^}=${value}" # '^^' makes the variable content uppercase + export "FORGEJO____${masked_setting^^}=${value}" # '^^' makes the variable content uppercase return fi - local masked_section="${section//./_0X2E_}" # '//' instructs to replace all matches + local masked_section="${section//./_0X2E_}" # '//' instructs to replace all matches masked_section="${masked_section//-/_0X2D_}" - export "ENV_TO_INI__${masked_section^^}__${setting^^}=${value}" # '^^' makes the variable content uppercase + export "FORGEJO__${masked_section^^}__${masked_setting^^}=${value}" # '^^' makes the variable content uppercase } function env2ini::reload_preset_envs() { @@ -131,19 +171,21 @@ stringData: function env2ini::generate_initial_secrets() { # These environment variables will either be # - overwritten with user defined values, - # - initially used to set up Gitea + # - initially used to set up Forgejo # Anyway, they won't harm existing app.ini files - export ENV_TO_INI__SECURITY__INTERNAL_TOKEN=$(gitea generate secret INTERNAL_TOKEN) - export ENV_TO_INI__SECURITY__SECRET_KEY=$(gitea generate secret SECRET_KEY) - export ENV_TO_INI__OAUTH2__JWT_SECRET=$(gitea generate secret JWT_SECRET) - export ENV_TO_INI__SERVER__LFS_JWT_SECRET=$(gitea generate secret LFS_JWT_SECRET) + export FORGEJO__SECURITY__INTERNAL_TOKEN=$(gitea generate secret INTERNAL_TOKEN) + export FORGEJO__SECURITY__SECRET_KEY=$(gitea generate secret SECRET_KEY) + export FORGEJO__OAUTH2__JWT_SECRET=$(gitea generate secret JWT_SECRET) + export FORGEJO__SERVER__LFS_JWT_SECRET=$(gitea generate secret LFS_JWT_SECRET) env2ini::log "...Initial secrets generated\n" } - env | (grep ENV_TO_INI || [[ $? == 1 ]]) > /tmp/existing-envs - + # save existing envs prior to script execution. Necessary to keep order of + # preexisting and custom envs + env | (grep -e '^FORGEJO__' || [[ $? == 1 ]]) > /tmp/existing-envs + # MUST BE CALLED BEFORE OTHER CONFIGURATION env2ini::generate_initial_secrets @@ -163,10 +205,10 @@ stringData: env2ini::log ' - oauth2.JWT_SECRET' env2ini::log ' - server.LFS_JWT_SECRET' - unset ENV_TO_INI__SECURITY__INTERNAL_TOKEN - unset ENV_TO_INI__SECURITY__SECRET_KEY - unset ENV_TO_INI__OAUTH2__JWT_SECRET - unset ENV_TO_INI__SERVER__LFS_JWT_SECRET + unset FORGEJO__SECURITY__INTERNAL_TOKEN + unset FORGEJO__SECURITY__SECRET_KEY + unset FORGEJO__OAUTH2__JWT_SECRET + unset FORGEJO__SERVER__LFS_JWT_SECRET fi - environment-to-ini -o $GITEA_APP_INI -p ENV_TO_INI + environment-to-ini -o $GITEA_APP_INI diff --git a/templates/gitea/statefulset.yaml b/templates/gitea/deployment.yaml similarity index 76% rename from templates/gitea/statefulset.yaml rename to templates/gitea/deployment.yaml index ce6f550..f82c407 100644 --- a/templates/gitea/statefulset.yaml +++ b/templates/gitea/deployment.yaml @@ -1,22 +1,32 @@ apiVersion: apps/v1 -kind: StatefulSet +kind: Deployment metadata: name: {{ include "gitea.fullname" . }} + namespace: {{ include "common.names.namespace" . | quote }} annotations: - {{- if .Values.statefulset.annotations }} - {{- toYaml .Values.statefulset.annotations | nindent 4 }} + {{- if .Values.deployment.annotations }} + {{- toYaml .Values.deployment.annotations | nindent 4 }} {{- end }} labels: {{- include "gitea.labels" . | nindent 4 }} + {{- if .Values.deployment.labels }} + {{- toYaml .Values.deployment.labels | nindent 4 }} + {{- end }} spec: replicas: {{ .Values.replicaCount }} + strategy: + type: {{ .Values.strategy.type }} + {{- if eq .Values.strategy.type "RollingUpdate" }} + rollingUpdate: + maxUnavailable: {{ .Values.strategy.rollingUpdate.maxUnavailable }} + maxSurge: {{ .Values.strategy.rollingUpdate.maxSurge }} + {{- end }} selector: matchLabels: {{- include "gitea.selectorLabels" . | nindent 6 }} - {{- if .Values.statefulset.labels }} - {{- toYaml .Values.statefulset.labels | nindent 6 }} + {{- if .Values.deployment.labels }} + {{- toYaml .Values.deployment.labels | nindent 6 }} {{- end }} - serviceName: {{ include "gitea.fullname" . }} template: metadata: annotations: @@ -32,16 +42,22 @@ spec: {{- end }} labels: {{- include "gitea.labels" . | nindent 8 }} - {{- if .Values.statefulset.labels }} - {{- toYaml .Values.statefulset.labels | nindent 8 }} + {{- if .Values.deployment.labels }} + {{- toYaml .Values.deployment.labels | nindent 8 }} {{- end }} spec: {{- if .Values.schedulerName }} schedulerName: "{{ .Values.schedulerName }}" {{- end }} + {{- if (or .Values.serviceAccount.create .Values.serviceAccount.name) }} + serviceAccountName: {{ include "gitea.serviceAccountName" . }} + {{- end }} + {{- if .Values.priorityClassName }} + priorityClassName: "{{ .Values.priorityClassName }}" + {{- end }} {{- include "gitea.images.pullSecrets" . | nindent 6 }} securityContext: - {{- toYaml .Values.podSecurityContext | nindent 8 }} + {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.podSecurityContext "context" $) | nindent 8 }} initContainers: - name: init-directories image: "{{ include "gitea.image" . }}" @@ -56,8 +72,8 @@ spec: value: /data - name: GITEA_TEMP value: /tmp/gitea - {{- if .Values.statefulset.env }} - {{- toYaml .Values.statefulset.env | nindent 12 }} + {{- if .Values.deployment.env }} + {{- toYaml .Values.deployment.env | nindent 12 }} {{- end }} {{- if .Values.signing.enabled }} - name: GNUPGHOME @@ -75,7 +91,9 @@ spec: {{- end }} {{- include "gitea.init-additional-mounts" . | nindent 12 }} securityContext: - {{- toYaml .Values.containerSecurityContext | nindent 12 }} + {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.containerSecurityContext "context" $) | nindent 12 }} + resources: + {{- toYaml .Values.initContainers.resources | nindent 12 }} - name: init-app-ini image: "{{ include "gitea.image" . }}" imagePullPolicy: {{ .Values.image.pullPolicy }} @@ -89,8 +107,8 @@ spec: value: /data - name: GITEA_TEMP value: /tmp/gitea - {{- if .Values.statefulset.env }} - {{- toYaml .Values.statefulset.env | nindent 12 }} + {{- if .Values.deployment.env }} + {{- toYaml .Values.deployment.env | nindent 12 }} {{- end }} {{- if .Values.gitea.additionalConfigFromEnvs }} {{- toYaml .Values.gitea.additionalConfigFromEnvs | nindent 12 }} @@ -113,7 +131,9 @@ spec: {{- end }} {{- include "gitea.init-additional-mounts" . | nindent 12 }} securityContext: - {{- toYaml .Values.containerSecurityContext | nindent 12 }} + {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.containerSecurityContext "context" $) | nindent 12 }} + resources: + {{- toYaml .Values.initContainers.resources | nindent 12 }} {{- if .Values.signing.enabled }} - name: configure-gpg image: "{{ include "gitea.image" . }}" @@ -125,7 +145,7 @@ spec: {{- if not (hasKey $csc "runAsUser") -}} {{- $_ := set $csc "runAsUser" 1000 -}} {{- end -}} - {{- toYaml $csc | nindent 12 }} + {{- include "common.compatibility.renderSecurityContext" (dict "secContext" $csc "context" $) | nindent 12 }} env: - name: GNUPGHOME value: {{ .Values.signing.gpgHome }} @@ -143,6 +163,8 @@ spec: {{- if .Values.extraVolumeMounts }} {{- toYaml .Values.extraVolumeMounts | nindent 12 }} {{- end }} + resources: + {{- toYaml .Values.initContainers.resources | nindent 12 }} {{- end }} - name: configure-gitea image: "{{ include "gitea.image" . }}" @@ -154,7 +176,7 @@ spec: {{- if not (hasKey $csc "runAsUser") -}} {{- $_ := set $csc "runAsUser" 1000 -}} {{- end -}} - {{- toYaml $csc | nindent 12 }} + {{- include "common.compatibility.renderSecurityContext" (dict "secContext" $csc "context" $) | nindent 12 }} env: - name: GITEA_APP_INI value: /data/gitea/conf/app.ini @@ -164,6 +186,10 @@ spec: value: /data - name: GITEA_TEMP value: /tmp/gitea + {{- if .Values.image.rootless }} + - name: HOME + value: /data/gitea/git + {{- end }} {{- if .Values.gitea.ldap }} {{- range $idx, $value := .Values.gitea.ldap }} {{- if $value.existingSecret }} @@ -218,8 +244,10 @@ spec: - name: GITEA_ADMIN_PASSWORD value: {{ .Values.gitea.admin.password | quote }} {{- end }} - {{- if .Values.statefulset.env }} - {{- toYaml .Values.statefulset.env | nindent 12 }} + - name: GITEA_ADMIN_PASSWORD_MODE + value: {{ include "gitea.admin.passwordMode" $ }} + {{- if .Values.deployment.env }} + {{- toYaml .Values.deployment.env | nindent 12 }} {{- end }} volumeMounts: - name: init @@ -232,7 +260,9 @@ spec: subPath: {{ .Values.persistence.subPath }} {{- end }} {{- include "gitea.init-additional-mounts" . | nindent 12 }} - terminationGracePeriodSeconds: {{ .Values.statefulset.terminationGracePeriodSeconds }} + resources: + {{- toYaml .Values.initContainers.resources | nindent 12 }} + terminationGracePeriodSeconds: {{ .Values.deployment.terminationGracePeriodSeconds }} containers: - name: {{ .Chart.Name }} image: "{{ include "gitea.image" . }}" @@ -243,6 +273,10 @@ spec: value: {{ .Values.gitea.config.server.SSH_LISTEN_PORT | quote }} - name: SSH_PORT value: {{ .Values.gitea.config.server.SSH_PORT | quote }} + {{- if not .Values.image.rootless }} + - name: SSH_LOG_LEVEL + value: {{ .Values.gitea.ssh.logLevel | quote }} + {{- end }} - name: GITEA_APP_INI value: /data/gitea/conf/app.ini - name: GITEA_CUSTOM @@ -253,12 +287,16 @@ spec: value: /tmp/gitea - name: TMPDIR value: /tmp/gitea + {{- if .Values.image.rootless }} + - name: HOME + value: /data/gitea/git + {{- end }} {{- if .Values.signing.enabled }} - name: GNUPGHOME value: {{ .Values.signing.gpgHome }} {{- end }} - {{- if .Values.statefulset.env }} - {{- toYaml .Values.statefulset.env | nindent 12 }} + {{- if .Values.deployment.env }} + {{- toYaml .Values.deployment.env | nindent 12 }} {{- end }} ports: - name: ssh @@ -289,9 +327,9 @@ spec: securityContext: {{- /* Honor the deprecated securityContext variable when defined */ -}} {{- if .Values.containerSecurityContext -}} - {{ toYaml .Values.containerSecurityContext | nindent 12 -}} + {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.containerSecurityContext "context" $) | nindent 12 }} {{- else -}} - {{ toYaml .Values.securityContext | nindent 12 -}} + {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.securityContext "context" $) | nindent 12 }} {{- end }} volumeMounts: - name: temp @@ -302,6 +340,10 @@ spec: subPath: {{ .Values.persistence.subPath }} {{- end }} {{- include "gitea.container-additional-mounts" . | nindent 12 }} + {{- with .Values.global.hostAliases }} + hostAliases: + {{- toYaml . | nindent 8 }} + {{- end }} {{- with .Values.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }} @@ -310,6 +352,10 @@ spec: affinity: {{- toYaml . | nindent 8 }} {{- end }} + {{- with .Values.topologySpreadConstraints }} + topologySpreadConstraints: + {{- toYaml . | nindent 8 }} + {{- end }} {{- with .Values.tolerations }} tolerations: {{- toYaml . | nindent 8 }} @@ -348,38 +394,13 @@ spec: path: private.asc defaultMode: 0100 {{- end }} - {{- if and .Values.persistence.enabled .Values.persistence.existingClaim }} + {{- if .Values.persistence.enabled }} + {{- if .Values.persistence.mount }} - name: data persistentVolumeClaim: - {{- with .Values.persistence.existingClaim }} - claimName: {{ tpl . $ }} - {{- end }} + claimName: {{ .Values.persistence.claimName }} + {{- end }} {{- else if not .Values.persistence.enabled }} - name: data emptyDir: {} - {{- else if and .Values.persistence.enabled (not .Values.persistence.existingClaim) }} - volumeClaimTemplates: - - metadata: - name: data - {{- with .Values.persistence.annotations }} - annotations: - {{- range $key, $value := . }} - {{ $key }}: {{ $value }} - {{- end }} - {{- end }} - {{- with .Values.persistence.labels }} - labels: - {{- range $key, $value := . }} - {{ $key }}: {{ $value }} - {{- end }} - {{- end }} - spec: - accessModes: - {{- range .Values.persistence.accessModes }} - - {{ . | quote }} - {{- end }} - {{- include "gitea.persistence.storageClass" . | indent 8 }} - resources: - requests: - storage: {{ .Values.persistence.size | quote }} {{- end }} diff --git a/templates/gitea/extra-list.yaml b/templates/gitea/extra-list.yaml new file mode 100644 index 0000000..62c0aca --- /dev/null +++ b/templates/gitea/extra-list.yaml @@ -0,0 +1,8 @@ +{{- range .Values.extraDeploy }} +--- +{{- if typeIs "string" . }} + {{- tpl . $ }} +{{- else }} + {{- tpl (. | toYaml) $ }} +{{- end }} +{{- end }} diff --git a/templates/gitea/gpg-secret.yaml b/templates/gitea/gpg-secret.yaml index 29b6d4f..0b7716a 100644 --- a/templates/gitea/gpg-secret.yaml +++ b/templates/gitea/gpg-secret.yaml @@ -1,12 +1,13 @@ {{- if .Values.signing.enabled -}} {{- if and (empty .Values.signing.privateKey) (empty .Values.signing.existingSecret) -}} - {{- fail "Either specify `signing.privateKey` or `signing.existingKey`" -}} + {{- fail "Either specify `signing.privateKey` or `signing.existingSecret`" -}} {{- end }} {{- if and (not (empty .Values.signing.privateKey)) (empty .Values.signing.existingSecret) -}} apiVersion: v1 kind: Secret metadata: name: {{ include "gitea.gpg-key-secret-name" . }} + namespace: {{ include "common.names.namespace" . | quote }} labels: {{- include "gitea.labels" . | nindent 4 }} type: Opaque diff --git a/templates/gitea/http-svc.yaml b/templates/gitea/http-svc.yaml index 659724c..6962930 100644 --- a/templates/gitea/http-svc.yaml +++ b/templates/gitea/http-svc.yaml @@ -2,13 +2,21 @@ apiVersion: v1 kind: Service metadata: name: {{ include "gitea.fullname" . }}-http + namespace: {{ include "common.names.namespace" . | quote }} labels: {{- include "gitea.labels" . | nindent 4 }} + {{- if .Values.service.http.labels }} + {{- toYaml .Values.service.http.labels | nindent 4 }} + {{- end }} annotations: {{- toYaml .Values.service.http.annotations | nindent 4 }} spec: type: {{ .Values.service.http.type }} - {{- if and .Values.service.http.loadBalancerIP (eq .Values.service.http.type "LoadBalancer") }} + {{- if eq .Values.service.http.type "LoadBalancer" }} + {{- if .Values.service.http.loadBalancerClass }} + loadBalancerClass: {{ .Values.service.http.loadBalancerClass }} + {{- end }} + {{- if and .Values.service.http.loadBalancerIP }} loadBalancerIP: {{ .Values.service.http.loadBalancerIP }} {{- end }} {{- if .Values.service.http.loadBalancerSourceRanges }} @@ -17,6 +25,7 @@ spec: - {{ . }} {{- end }} {{- end }} + {{- end }} {{- if .Values.service.http.externalIPs }} externalIPs: {{- toYaml .Values.service.http.externalIPs | nindent 4 }} @@ -40,6 +49,6 @@ spec: {{- if .Values.service.http.nodePort }} nodePort: {{ .Values.service.http.nodePort }} {{- end }} - targetPort: {{ .Values.gitea.config.server.HTTP_PORT }} + targetPort: http selector: {{- include "gitea.selectorLabels" . | nindent 4 }} diff --git a/templates/gitea/ingress.yaml b/templates/gitea/ingress.yaml index 224e777..d764bb6 100644 --- a/templates/gitea/ingress.yaml +++ b/templates/gitea/ingress.yaml @@ -1,58 +1,45 @@ {{- if .Values.ingress.enabled -}} {{- $fullName := include "gitea.fullname" . -}} -{{- $httpPort := .Values.service.http.port -}} -{{- $apiVersion := "extensions/v1beta1" -}} -{{- if .Values.ingress.apiVersion -}} -{{- $apiVersion = .Values.ingress.apiVersion -}} -{{- else if .Capabilities.APIVersions.Has "networking.k8s.io/v1/Ingress" -}} -{{- $apiVersion = "networking.k8s.io/v1" }} -{{- else if .Capabilities.APIVersions.Has "networking.k8s.io/v1beta1/Ingress" -}} -{{- $apiVersion = "networking.k8s.io/v1beta1" }} -{{- end }} -apiVersion: {{ $apiVersion }} +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: {{ $fullName }} + namespace: {{ include "common.names.namespace" . | quote }} labels: {{- include "gitea.labels" . | nindent 4 }} - {{- with .Values.ingress.annotations }} annotations: - {{- toYaml . | nindent 4 }} - {{- end }} + {{- range $key, $value := .Values.ingress.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} spec: {{- if .Values.ingress.className }} - ingressClassName: {{ .Values.ingress.className }} + ingressClassName: {{ tpl .Values.ingress.className . }} {{- end }} {{- if .Values.ingress.tls }} tls: {{- range .Values.ingress.tls }} - hosts: {{- range .hosts }} - - {{ . | quote }} + - {{ tpl . $ | quote }} {{- end }} secretName: {{ .secretName }} {{- end }} {{- end }} rules: {{- range .Values.ingress.hosts }} - - host: {{ .host | quote }} + - host: {{ tpl .host $ | quote }} http: paths: {{- range .paths }} - path: {{ .path }} - {{- if and .pathType (eq $apiVersion "networking.k8s.io/v1") }} + {{- if .pathType }} pathType: {{ .pathType }} {{- end }} backend: - {{- if eq $apiVersion "networking.k8s.io/v1" }} service: name: {{ $fullName }}-http port: - number: {{ $httpPort }} - {{- else }} - serviceName: {{ $fullName }}-http - servicePort: {{ $httpPort }} - {{- end }} + name: http {{- end }} {{- end }} {{- end }} diff --git a/templates/gitea/init.yaml b/templates/gitea/init.yaml index 838460b..546f4c4 100644 --- a/templates/gitea/init.yaml +++ b/templates/gitea/init.yaml @@ -2,6 +2,7 @@ apiVersion: v1 kind: Secret metadata: name: {{ include "gitea.fullname" . }}-init + namespace: {{ include "common.names.namespace" . | quote }} labels: {{- include "gitea.labels" . | nindent 4 }} type: Opaque @@ -58,22 +59,77 @@ stringData: { # try gitea migrate } || { # catch - echo "Gitea migrate might fail due to database connection...This init-container will try again in a few seconds" + echo "Forgejo migrate might fail due to database connection...This init-container will try again in a few seconds" exit 1 } + + {{- if include "redis.servicename" . }} + function test_redis_connection() { + local RETRY=0 + local MAX=30 + + echo 'Wait for redis to become avialable...' + until [ "${RETRY}" -ge "${MAX}" ]; do + nc -vz -w2 {{ include "redis.servicename" . }} {{ include "redis.port" . }} && break + RETRY=$[${RETRY}+1] + echo "...not ready yet (${RETRY}/${MAX})" + done + + if [ "${RETRY}" -ge "${MAX}" ]; then + echo "Redis not reachable after '${MAX}' attempts!" + exit 1 + fi + } + + test_redis_connection + {{- end }} {{- if or .Values.gitea.admin.existingSecret (and .Values.gitea.admin.username .Values.gitea.admin.password) }} function configure_admin_user() { - local ACCOUNT_ID=$(gitea admin user list --admin | grep -e "\s\+${GITEA_ADMIN_USERNAME}\s\+" | awk -F " " "{printf \$1}") + local full_admin_list=$(gitea admin user list --admin) + local actual_user_table='' + + # We might have distorted output due to warning logs, so we have to detect the actual user table by its headline and trim output above that line + local regex="(.*)(ID\s+Username\s+Email\s+IsActive.*)" + if [[ "${full_admin_list}" =~ $regex ]]; then + actual_user_table=$(echo "${BASH_REMATCH[2]}" | tail -n+2) # tail'ing to drop the table headline + else + # This code block should never be reached, as long as the output table header remains the same. + # If this code block is reached, the regex doesn't match anymore and we probably have to adjust this script. + + echo "ERROR: 'configure_admin_user' was not able to determine the current list of admin users." + echo " Please review the output of 'gitea admin user list --admin' shown below." + echo " If you think it is an issue with the Helm Chart provisioning, file an issue at https://gitea.com/gitea/helm-chart/issues." + echo "DEBUG: Output of 'gitea admin user list --admin'" + echo "--" + echo "${full_admin_list}" + echo "--" + exit 1 + fi + + local ACCOUNT_ID=$(echo "${actual_user_table}" | grep -E "\s+${GITEA_ADMIN_USERNAME}\s+" | awk -F " " "{printf \$1}") if [[ -z "${ACCOUNT_ID}" ]]; then + local -a create_args + create_args=(--admin --username "${GITEA_ADMIN_USERNAME}" --password "${GITEA_ADMIN_PASSWORD}" --email {{ .Values.gitea.admin.email | quote }}) + if [[ "${GITEA_ADMIN_PASSWORD_MODE}" = initialOnlyRequireReset ]]; then + create_args+=(--must-change-password=true) + else + create_args+=(--must-change-password=false) + fi echo "No admin user '${GITEA_ADMIN_USERNAME}' found. Creating now..." - gitea admin user create --admin --username "${GITEA_ADMIN_USERNAME}" --password "${GITEA_ADMIN_PASSWORD}" --email {{ .Values.gitea.admin.email | quote }} --must-change-password=false + gitea admin user create "${create_args[@]}" echo '...created.' else - echo "Admin account '${GITEA_ADMIN_USERNAME}' already exist. Running update to sync password..." - gitea admin user change-password --username "${GITEA_ADMIN_USERNAME}" --password "${GITEA_ADMIN_PASSWORD}" - echo '...password sync done.' + if [[ "${GITEA_ADMIN_PASSWORD_MODE}" = keepUpdated ]]; then + echo "Admin account '${GITEA_ADMIN_USERNAME}' already exist. Running update to sync password..." + local -a change_args + change_args=(--username "${GITEA_ADMIN_USERNAME}" --password "${GITEA_ADMIN_PASSWORD}" --must-change-password=false) + gitea admin user change-password "${change_args[@]}" + echo '...password sync done.' + else + echo "Admin account '${GITEA_ADMIN_USERNAME}' already exist, but update mode is set to '${GITEA_ADMIN_PASSWORD_MODE}'. Skipping." + fi fi } @@ -84,7 +140,28 @@ stringData: {{- if .Values.gitea.ldap }} {{- range $idx, $value := .Values.gitea.ldap }} local LDAP_NAME={{ (printf "%s" $value.name) | squote }} - local GITEA_AUTH_ID=$(gitea admin auth list --vertical-bars | grep -E "\|${LDAP_NAME}\s+\|" | grep -iE '\|LDAP \(via BindDN\)\s+\|' | awk -F " " "{print \$1}") + local full_auth_list=$(gitea admin auth list --vertical-bars) + local actual_auth_table='' + + # We might have distorted output due to warning logs, so we have to detect the actual user table by its headline and trim output above that line + local regex="(.*)(ID\s+\|Name\s+\|Type\s+\|Enabled.*)" + if [[ "${full_auth_list}" =~ $regex ]]; then + actual_auth_table=$(echo "${BASH_REMATCH[2]}" | tail -n+2) # tail'ing to drop the table headline + else + # This code block should never be reached, as long as the output table header remains the same. + # If this code block is reached, the regex doesn't match anymore and we probably have to adjust this script. + + echo "ERROR: 'configure_ldap' was not able to determine the current list of authentication sources." + echo " Please review the output of 'gitea admin auth list --vertical-bars' shown below." + echo " If you think it is an issue with the Helm Chart provisioning, file an issue at https://gitea.com/gitea/helm-chart/issues." + echo "DEBUG: Output of 'gitea admin auth list --vertical-bars'" + echo "--" + echo "${full_auth_list}" + echo "--" + exit 1 + fi + + local GITEA_AUTH_ID=$(echo "${actual_auth_table}" | grep -E "\|${LDAP_NAME}\s+\|" | grep -iE '\|LDAP \(via BindDN\)\s+\|' | awk -F " " "{print \$1}") if [[ -z "${GITEA_AUTH_ID}" ]]; then echo "No ldap configuration found with name '${LDAP_NAME}'. Installing it now..." @@ -107,7 +184,28 @@ stringData: {{- if .Values.gitea.oauth }} {{- range $idx, $value := .Values.gitea.oauth }} local OAUTH_NAME={{ (printf "%s" $value.name) | squote }} - local AUTH_ID=$(gitea admin auth list --vertical-bars | grep -E "\|${OAUTH_NAME}\s+\|" | grep -iE '\|OAuth2\s+\|' | awk -F " " "{print \$1}") + local full_auth_list=$(gitea admin auth list --vertical-bars) + local actual_auth_table='' + + # We might have distorted output due to warning logs, so we have to detect the actual user table by its headline and trim output above that line + local regex="(.*)(ID\s+\|Name\s+\|Type\s+\|Enabled.*)" + if [[ "${full_auth_list}" =~ $regex ]]; then + actual_auth_table=$(echo "${BASH_REMATCH[2]}" | tail -n+2) # tail'ing to drop the table headline + else + # This code block should never be reached, as long as the output table header remains the same. + # If this code block is reached, the regex doesn't match anymore and we probably have to adjust this script. + + echo "ERROR: 'configure_oauth' was not able to determine the current list of authentication sources." + echo " Please review the output of 'gitea admin auth list --vertical-bars' shown below." + echo " If you think it is an issue with the Helm Chart provisioning, file an issue at https://gitea.com/gitea/helm-chart/issues." + echo "DEBUG: Output of 'gitea admin auth list --vertical-bars'" + echo "--" + echo "${full_auth_list}" + echo "--" + exit 1 + fi + + local AUTH_ID=$(echo "${actual_auth_table}" | grep -E "\|${OAUTH_NAME}\s+\|" | grep -iE '\|OAuth2\s+\|' | awk -F " " "{print \$1}") if [[ -z "${AUTH_ID}" ]]; then echo "No oauth configuration found with name '${OAUTH_NAME}'. Installing it now..." diff --git a/templates/gitea/poddisruptionbudget.yaml b/templates/gitea/poddisruptionbudget.yaml new file mode 100644 index 0000000..d40a166 --- /dev/null +++ b/templates/gitea/poddisruptionbudget.yaml @@ -0,0 +1,14 @@ +{{- if .Values.podDisruptionBudget -}} +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: {{ include "gitea.fullname" . }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: + {{- include "gitea.labels" . | nindent 4 }} +spec: + selector: + matchLabels: + {{- include "gitea.selectorLabels" . | nindent 6 }} + {{- toYaml .Values.podDisruptionBudget | nindent 2 }} +{{- end -}} diff --git a/templates/gitea/pvc.yaml b/templates/gitea/pvc.yaml new file mode 100644 index 0000000..2c82cb0 --- /dev/null +++ b/templates/gitea/pvc.yaml @@ -0,0 +1,28 @@ +{{- if and .Values.persistence.enabled .Values.persistence.create }} +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: {{ .Values.persistence.claimName }} + namespace: {{ include "common.names.namespace" . | quote }} + annotations: +{{ .Values.persistence.annotations | toYaml | indent 4}} +{{- if .Values.persistence.labels }} + labels: +{{ .Values.persistence.labels | toYaml | indent 4}} +{{- end }} +spec: + accessModes: + {{- if gt .Values.replicaCount 1.0 }} + - ReadWriteMany + {{- else }} + {{- .Values.persistence.accessModes | toYaml | nindent 4 }} + {{- end }} + volumeMode: Filesystem + {{- include "gitea.persistence.storageClass" . | nindent 2 }} + {{- with .Values.persistence.volumeName }} + volumeName: {{ . }} + {{- end }} + resources: + requests: + storage: {{ .Values.persistence.size }} +{{- end }} diff --git a/templates/gitea/route.yaml b/templates/gitea/route.yaml new file mode 100644 index 0000000..740721f --- /dev/null +++ b/templates/gitea/route.yaml @@ -0,0 +1,43 @@ +{{- if .Values.route.enabled -}} +apiVersion: route.openshift.io/v1 +kind: Route +metadata: + name: {{ include "gitea.fullname" . }}-http + namespace: {{ include "common.names.namespace" . | quote }} + labels: + {{- include "gitea.labels" . | nindent 4 }} + annotations: + {{- toYaml .Values.route.annotations | nindent 4 }} +spec: + {{- if .Values.route.host }} + host: {{ tpl .Values.route.host $ | quote }} + {{- end }} + {{- if .Values.route.wildcardPolicy }} + wildcardPolicy: {{ .Values.route.wildcardPolicy }} + {{- end }} + to: + kind: Service + name: {{ include "gitea.fullname" . }}-http + weight: 100 + port: + targetPort: http + tls: + termination: edge + insecureEdgeTerminationPolicy: Redirect + {{- if .Values.route.tls.existingSecret }} + externalCertificate: {{ .Values.route.tls.existingSecret }} + {{- else if and .Values.route.tls.certificate + .Values.route.tls.privateKey + .Values.route.tls.caCertificate }} + certificate: | +{{ .Values.route.tls.certificate | indent 6 }} + key: | +{{ .Values.route.tls.privateKey | indent 6 }} + caCertificate: | +{{ .Values.route.tls.caCertificate | indent 6 }} + {{- else if or .Values.route.tls.certificate + .Values.route.tls.privateKey + .Values.route.tls.caCertificate }} + {{- fail "certificate, privateKey and caCertificate must be specified together" }} + {{- end }} +{{- end }} diff --git a/templates/gitea/serviceaccount.yaml b/templates/gitea/serviceaccount.yaml new file mode 100644 index 0000000..e97608b --- /dev/null +++ b/templates/gitea/serviceaccount.yaml @@ -0,0 +1,21 @@ +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "gitea.serviceAccountName" . }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: + {{- include "gitea.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.labels }} + {{- . | toYaml | nindent 4 }} + {{- end }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- . | toYaml | nindent 4 }} + {{- end }} +automountServiceAccountToken: {{ .Values.serviceAccount.automountServiceAccountToken }} +{{- with .Values.serviceAccount.imagePullSecrets }} +imagePullSecrets: + {{- . | toYaml | nindent 2 }} +{{- end }} +{{- end }} diff --git a/templates/gitea/servicemonitor.yaml b/templates/gitea/servicemonitor.yaml index 02750d0..c740ec8 100644 --- a/templates/gitea/servicemonitor.yaml +++ b/templates/gitea/servicemonitor.yaml @@ -3,6 +3,7 @@ apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: name: {{ include "gitea.fullname" . }} + namespace: {{ default (include "common.names.namespace" .) .Values.gitea.metrics.serviceMonitor.namespace | quote }} labels: {{- include "gitea.labels" . | nindent 4 }} {{- if .Values.gitea.metrics.serviceMonitor.additionalLabels }} @@ -14,4 +15,4 @@ spec: {{- include "gitea.selectorLabels" . | nindent 6 }} endpoints: - port: http -{{- end -}} \ No newline at end of file +{{- end -}} diff --git a/templates/gitea/ssh-svc.yaml b/templates/gitea/ssh-svc.yaml index 620f624..c1576da 100644 --- a/templates/gitea/ssh-svc.yaml +++ b/templates/gitea/ssh-svc.yaml @@ -2,13 +2,20 @@ apiVersion: v1 kind: Service metadata: name: {{ include "gitea.fullname" . }}-ssh + namespace: {{ include "common.names.namespace" . | quote }} labels: {{- include "gitea.labels" . | nindent 4 }} + {{- if .Values.service.ssh.labels }} + {{- toYaml .Values.service.ssh.labels | nindent 4 }} + {{- end }} annotations: {{- toYaml .Values.service.ssh.annotations | nindent 4 }} spec: type: {{ .Values.service.ssh.type }} {{- if eq .Values.service.ssh.type "LoadBalancer" }} + {{- if .Values.service.ssh.loadBalancerClass }} + loadBalancerClass: {{ .Values.service.ssh.loadBalancerClass }} + {{- end }} {{- if .Values.service.ssh.loadBalancerIP }} loadBalancerIP: {{ .Values.service.ssh.loadBalancerIP }} {{- end -}} @@ -39,7 +46,9 @@ spec: ports: - name: ssh port: {{ .Values.service.ssh.port }} - targetPort: {{ .Values.gitea.config.server.SSH_LISTEN_PORT }} + {{- if .Values.gitea.config.server.SSH_LISTEN_PORT }} + targetPort: ssh + {{- end }} protocol: TCP {{- if .Values.service.ssh.nodePort }} nodePort: {{ .Values.service.ssh.nodePort }} diff --git a/templates/tests/test-http-connection.yaml b/templates/tests/test-http-connection.yaml index 7fab1b7..1a2e13f 100644 --- a/templates/tests/test-http-connection.yaml +++ b/templates/tests/test-http-connection.yaml @@ -1,3 +1,4 @@ +{{- if .Values.test.enabled }} apiVersion: v1 kind: Pod metadata: @@ -5,11 +6,12 @@ metadata: labels: {{ include "gitea.labels" . | nindent 4 }} annotations: - "helm.sh/hook": test-success + "helm.sh/hook": test spec: containers: - name: wget - image: busybox + image: "{{ .Values.test.image.name }}:{{ .Values.test.image.tag }}" command: ['wget'] args: ['{{ include "gitea.fullname" . }}-http:{{ .Values.service.http.port }}'] restartPolicy: Never +{{- end }} diff --git a/tools/changelog.mjs b/tools/changelog.mjs index 313a4a4..0fe6c09 100644 --- a/tools/changelog.mjs +++ b/tools/changelog.mjs @@ -1,71 +1,12 @@ -import conventionalChangelogCore from 'conventional-changelog-core'; -import conventionalChangelogPreset from 'conventional-changelog-conventionalcommits'; -import fs from 'node:fs'; +import { getChangelog } from './changelog/util.js'; -const config = conventionalChangelogPreset({ - types: [ - { - type: 'feat', - section: 'Features', - }, - { - type: 'feature', - section: 'Features', - }, - { - type: 'fix', - section: 'Bug Fixes', - }, - { - type: 'perf', - section: 'Performance Improvements', - }, - { - type: 'revert', - section: 'Reverts', - }, - { - type: 'docs', - section: 'Documentation', - }, - { - type: 'style', - section: 'Styles', - }, - { - type: 'chore', - section: 'Miscellaneous Chores', - }, - { - type: 'refactor', - section: 'Code Refactoring', - }, - { - type: 'test', - section: 'Tests', - }, - { - type: 'build', - section: 'Build System', - }, - { - type: 'ci', - section: 'Continuous Integration', - }, - ], -}); +const stream = getChangelog(!!process.argv[2]).setEncoding('utf8'); -const file = process.argv[3] - ? fs.createWriteStream(process.argv[3]) - : process.stdout; +const changes = (await stream.toArray()).join(''); -conventionalChangelogCore( - { - config, - releaseCount: 2, - }, - { version: process.argv[2], linkCompare: false }, - undefined, - undefined, - { headerPartial: '' } -).pipe(file); +if (!changes.length) { + console.error('No changelog found'); + process.exit(1); +} + +process.stdout.write(changes); diff --git a/tools/changelog/util.js b/tools/changelog/util.js new file mode 100644 index 0000000..bbbe366 --- /dev/null +++ b/tools/changelog/util.js @@ -0,0 +1,73 @@ +import conventionalChangelogPreset from 'conventional-changelog-conventionalcommits'; +import conventionalChangelogCore from 'conventional-changelog-core'; + +/** + * @type {import('conventional-changelog-core').Options} + */ +// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call +export const config = conventionalChangelogPreset({ + types: [ + { + type: 'feat', + section: 'Features', + }, + { + type: 'fix', + section: 'Bug Fixes', + }, + { + type: 'perf', + section: 'Performance Improvements', + }, + { + type: 'revert', + section: 'Reverts', + }, + { + type: 'docs', + section: 'Documentation', + }, + { + type: 'style', + section: 'Styles', + }, + { + type: 'refactor', + section: 'Code Refactoring', + }, + { + type: 'test', + section: 'Tests', + }, + { + type: 'build', + section: 'Build System', + }, + { + type: 'ci', + section: 'Continuous Integration', + }, + { + type: 'chore', + section: 'Miscellaneous Chores', + }, + ], +}); + +/** + * + * @param {boolean|undefined} onTag + * @returns + */ +export function getChangelog(onTag = false) { + return conventionalChangelogCore( + { + config, + releaseCount: onTag ? 2 : 1, + }, + undefined, + undefined, + undefined, + { headerPartial: '' }, + ); +} diff --git a/tools/ct.yml b/tools/ct.yml new file mode 100644 index 0000000..3d241fc --- /dev/null +++ b/tools/ct.yml @@ -0,0 +1,7 @@ +# https://github.com/helm/chart-testing/blob/main/doc/ct_install.md +helm-extra-args: --timeout 3m +check-version-increment: false +debug: true +target-branch: main +lint-conf: .yamllint +validate-maintainers: false # does not work with gitea diff --git a/tools/forgejo-release.js b/tools/forgejo-release.js new file mode 100644 index 0000000..bdbe8e2 --- /dev/null +++ b/tools/forgejo-release.js @@ -0,0 +1,100 @@ +import { Command, runExit } from 'clipanion'; +import { getChangelog } from './changelog/util.js'; + +class GiteaReleaseCommand extends Command { + async execute() { + const api = process.env.GITHUB_API_URL; + const repo = process.env.GITHUB_REPOSITORY; + const token = process.env.GITHUB_TOKEN; + const tag = process.env.GITHUB_REF_NAME; + + if (!api) { + this.context.stdout.write( + 'GITHUB_API_URL environment variable not set.\n', + ); + return 1; + } else { + this.context.stdout.write(`Using api: ${api}.\n`); + } + + if (!token) { + this.context.stdout.write('GITHUB_TOKEN environment variable not set.\n'); + return 1; + } + + if (!repo) { + this.context.stdout.write( + 'GITHUB_REPOSITORY environment variable not set.\n', + ); + return 1; + } else { + this.context.stdout.write(`Using repository: ${repo}.\n`); + } + + if (!tag) { + this.context.stdout.write( + 'GITHUB_REF_NAME environment variable not set.', + ); + return 1; + } else { + this.context.stdout.write(`Using tag: ${tag}.\n`); + } + + this.context.stdout.write(`Checking remote tag ${tag}.\n`); + let resp = await fetch(`${api}/repos/${repo}/tags/${tag}`, { + headers: { + Authorization: `Bearer ${token}`, + }, + }); + + if (!resp.ok) { + this.context.stdout.write(`Tag ${tag} not found on remote.\n`); + return 1; + } + + this.context.stdout.write(`Checking remote release ${tag}.\n`); + resp = await fetch(`${api}/repos/${repo}/releases/tags/${tag}`, { + headers: { + Authorization: `Bearer ${token}`, + }, + }); + if (resp.ok) { + this.context.stdout.write(`Release ${tag} already exists.\n`); + return 1; + } else if (resp.status !== 404) { + this.context.stdout.write( + `Error checking for release ${tag}.\n${resp.status}: ${resp.statusText}\n`, + ); + return 1; + } + + const stream = getChangelog(true).setEncoding('utf8'); + const changes = (await stream.toArray()).join(''); + + this.context.stdout.write(`Creating release ${tag}.\n`); + resp = await fetch(`${api}/repos/${repo}/releases`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + }, + body: JSON.stringify({ + draft: false, + prerelease: tag.includes('-'), + tag_name: tag, + name: tag.replace(/^v/, ''), + body: changes, + target_commitish: 'main', + }), + }); + + if (!resp.ok) { + this.context.stdout.write( + `Error creating release ${tag}.\n${resp.status}: ${resp.statusText}\n`, + ); + return 1; + } + } +} + +void runExit(GiteaReleaseCommand); diff --git a/tools/package.json b/tools/package.json new file mode 100644 index 0000000..3dbc1ca --- /dev/null +++ b/tools/package.json @@ -0,0 +1,3 @@ +{ + "type": "module" +} diff --git a/unittests/config/cache-config.yaml b/unittests/config/cache-config.yaml new file mode 100644 index 0000000..b935fd1 --- /dev/null +++ b/unittests/config/cache-config.yaml @@ -0,0 +1,66 @@ +suite: config template | cache config +release: + name: gitea-unittests + namespace: testing +tests: + - it: 'cache is configured correctly for redis-cluster' + template: templates/gitea/config.yaml + set: + redis-cluster: + enabled: true + redis: + enabled: false + asserts: + - documentIndex: 0 + equal: + path: stringData.cache + value: |- + ADAPTER=redis + HOST=redis+cluster://:@gitea-unittests-redis-cluster-headless.testing.svc.cluster.local:6379/0?pool_size=100&idle_timeout=180s& + + - it: 'cache is configured correctly for redis' + template: templates/gitea/config.yaml + set: + redis-cluster: + enabled: false + redis: + enabled: true + asserts: + - documentIndex: 0 + equal: + path: stringData.cache + value: |- + ADAPTER=redis + HOST=redis://:changeme@gitea-unittests-redis-headless.testing.svc.cluster.local:6379/0?pool_size=100&idle_timeout=180s& + + - it: "cache is configured correctly for 'memory' when redis (or redis-cluster) is disabled" + template: templates/gitea/config.yaml + set: + redis-cluster: + enabled: false + redis: + enabled: false + asserts: + - documentIndex: 0 + equal: + path: stringData.cache + value: |- + ADAPTER=memory + HOST= + + - it: 'cache can be customized when redis (or redis-cluster) is disabled' + template: templates/gitea/config.yaml + set: + redis-cluster: + enabled: false + redis: + enabled: false + gitea.config.cache.ADAPTER: custom-adapter + gitea.config.cache.HOST: custom-host + asserts: + - documentIndex: 0 + equal: + path: stringData.cache + value: |- + ADAPTER=custom-adapter + HOST=custom-host diff --git a/unittests/config/database-section_postgresql-ha.yaml b/unittests/config/database-section_postgresql-ha.yaml new file mode 100644 index 0000000..f416d79 --- /dev/null +++ b/unittests/config/database-section_postgresql-ha.yaml @@ -0,0 +1,30 @@ +suite: config template | database section (postgresql-ha) +release: + name: gitea-unittests + namespace: testing +tests: + - it: connects to pgpool service + template: templates/gitea/config.yaml + set: + postgresql: + enabled: false + postgresql-ha: + enabled: true + asserts: + - documentIndex: 0 + matchRegex: + path: stringData.database + pattern: HOST=gitea-unittests-postgresql-ha-pgpool.testing.svc.cluster.local:5432 + - it: renders the referenced service + template: charts/postgresql-ha/templates/pgpool/service.yaml + set: + postgresql: + enabled: false + postgresql-ha: + enabled: true + asserts: + - containsDocument: + kind: Service + apiVersion: v1 + name: gitea-unittests-postgresql-ha-pgpool + namespace: testing diff --git a/unittests/config/database-section_postgresql.yaml b/unittests/config/database-section_postgresql.yaml new file mode 100644 index 0000000..8c1f3c2 --- /dev/null +++ b/unittests/config/database-section_postgresql.yaml @@ -0,0 +1,30 @@ +suite: config template | database section (postgresql) +release: + name: gitea-unittests + namespace: testing +tests: + - it: 'connects to postgresql service' + template: templates/gitea/config.yaml + set: + postgresql: + enabled: true + postgresql-ha: + enabled: false + asserts: + - documentIndex: 0 + matchRegex: + path: stringData.database + pattern: HOST=gitea-unittests-postgresql.testing.svc.cluster.local:5432 + - it: 'renders the referenced service' + template: charts/postgresql/templates/primary/svc.yaml + set: + postgresql: + enabled: true + postgresql-ha: + enabled: false + asserts: + - containsDocument: + kind: Service + apiVersion: v1 + name: gitea-unittests-postgresql + namespace: testing diff --git a/unittests/config/queue-config.yaml b/unittests/config/queue-config.yaml new file mode 100644 index 0000000..cdb2678 --- /dev/null +++ b/unittests/config/queue-config.yaml @@ -0,0 +1,66 @@ +suite: config template | queue config +release: + name: gitea-unittests + namespace: testing +tests: + - it: 'queue is configured correctly for redis-cluster' + template: templates/gitea/config.yaml + set: + redis-cluster: + enabled: true + redis: + enabled: false + asserts: + - documentIndex: 0 + equal: + path: stringData.queue + value: |- + CONN_STR=redis+cluster://:@gitea-unittests-redis-cluster-headless.testing.svc.cluster.local:6379/0?pool_size=100&idle_timeout=180s& + TYPE=redis + + - it: 'queue is configured correctly for redis' + template: templates/gitea/config.yaml + set: + redis-cluster: + enabled: false + redis: + enabled: true + asserts: + - documentIndex: 0 + equal: + path: stringData.queue + value: |- + CONN_STR=redis://:changeme@gitea-unittests-redis-headless.testing.svc.cluster.local:6379/0?pool_size=100&idle_timeout=180s& + TYPE=redis + + - it: "queue is configured correctly for 'levelDB' when redis (and redis-cluster) is disabled" + template: templates/gitea/config.yaml + set: + redis-cluster: + enabled: false + redis: + enabled: false + asserts: + - documentIndex: 0 + equal: + path: stringData.queue + value: |- + CONN_STR= + TYPE=level + + - it: 'queue can be customized when redis (and redis-cluster) are disabled' + template: templates/gitea/config.yaml + set: + redis-cluster: + enabled: false + redis: + enabled: false + gitea.config.queue.TYPE: custom-type + gitea.config.queue.CONN_STR: custom-connection-string + asserts: + - documentIndex: 0 + equal: + path: stringData.queue + value: |- + CONN_STR=custom-connection-string + TYPE=custom-type diff --git a/unittests/config/server-section_domain.yaml b/unittests/config/server-section_domain.yaml new file mode 100644 index 0000000..ea52b8a --- /dev/null +++ b/unittests/config/server-section_domain.yaml @@ -0,0 +1,67 @@ +suite: config template | server section (domain related) +release: + name: gitea-unittests + namespace: testing +tests: + - it: '[default values] uses ingress host for DOMAIN|SSH_DOMAIN|ROOT_URL' + template: templates/gitea/config.yaml + asserts: + - documentIndex: 0 + matchRegex: + path: stringData.server + pattern: \nDOMAIN=git.example.com + - documentIndex: 0 + matchRegex: + path: stringData.server + pattern: \nSSH_DOMAIN=git.example.com + - documentIndex: 0 + matchRegex: + path: stringData.server + pattern: \nROOT_URL=http://git.example.com + + ################################################ + + - it: '[no ingress hosts] uses gitea http service for DOMAIN|SSH_DOMAIN|ROOT_URL' + template: templates/gitea/config.yaml + set: + ingress: + hosts: [] + asserts: + - documentIndex: 0 + matchRegex: + path: stringData.server + pattern: \nDOMAIN=gitea-unittests-forgejo-http.testing.svc.cluster.local + - documentIndex: 0 + matchRegex: + path: stringData.server + pattern: \nSSH_DOMAIN=gitea-unittests-forgejo-http.testing.svc.cluster.local + - documentIndex: 0 + matchRegex: + path: stringData.server + pattern: \nROOT_URL=http://gitea-unittests-forgejo-http.testing.svc.cluster.local + + ################################################ + + - it: '[provided via values] uses that for DOMAIN|SSH_DOMAIN|ROOT_URL' + template: templates/gitea/config.yaml + set: + gitea.config.server.DOMAIN: provided.example.com + ingress: + hosts: + - host: non-used.example.com + paths: + - path: / + pathType: Prefix + asserts: + - documentIndex: 0 + matchRegex: + path: stringData.server + pattern: \nDOMAIN=provided.example.com + - documentIndex: 0 + matchRegex: + path: stringData.server + pattern: \nSSH_DOMAIN=provided.example.com + - documentIndex: 0 + matchRegex: + path: stringData.server + pattern: \nROOT_URL=http://provided.example.com diff --git a/unittests/config/session-config.yaml b/unittests/config/session-config.yaml new file mode 100644 index 0000000..2a49baa --- /dev/null +++ b/unittests/config/session-config.yaml @@ -0,0 +1,66 @@ +suite: config template | session config +release: + name: gitea-unittests + namespace: testing +tests: + - it: 'session is configured correctly for redis-cluster' + template: templates/gitea/config.yaml + set: + redis-cluster: + enabled: true + redis: + enabled: false + asserts: + - documentIndex: 0 + equal: + path: stringData.session + value: |- + PROVIDER=redis + PROVIDER_CONFIG=redis+cluster://:@gitea-unittests-redis-cluster-headless.testing.svc.cluster.local:6379/0?pool_size=100&idle_timeout=180s& + + - it: 'session is configured correctly for redis' + template: templates/gitea/config.yaml + set: + redis-cluster: + enabled: false + redis: + enabled: true + asserts: + - documentIndex: 0 + equal: + path: stringData.session + value: |- + PROVIDER=redis + PROVIDER_CONFIG=redis://:changeme@gitea-unittests-redis-headless.testing.svc.cluster.local:6379/0?pool_size=100&idle_timeout=180s& + + - it: "session is configured correctly for 'memory' when redis (and redis-cluster) is disabled" + template: templates/gitea/config.yaml + set: + redis-cluster: + enabled: false + redis: + enabled: false + asserts: + - documentIndex: 0 + equal: + path: stringData.session + value: |- + PROVIDER=memory + PROVIDER_CONFIG= + + - it: 'session can be customized when redis (and redis-cluster) is disabled' + template: templates/gitea/config.yaml + set: + redis-cluster: + enabled: false + redis: + enabled: false + gitea.config.session.PROVIDER: custom-provider + gitea.config.session.PROVIDER_CONFIG: custom-provider-config + asserts: + - documentIndex: 0 + equal: + path: stringData.session + value: |- + PROVIDER=custom-provider + PROVIDER_CONFIG=custom-provider-config diff --git a/unittests/dependency-major-image-check.yaml b/unittests/dependency-major-image-check.yaml new file mode 100644 index 0000000..1ff65cc --- /dev/null +++ b/unittests/dependency-major-image-check.yaml @@ -0,0 +1,57 @@ +suite: Dependency update consistency +release: + name: gitea-unittests + namespace: testing +tests: + - it: '[postgresql-ha] ensures we detect major image version upgrades' + template: charts/postgresql-ha/templates/postgresql/statefulset.yaml + set: + postgresql: + enabled: false + postgresql-ha: + enabled: true + asserts: + - documentIndex: 0 + matchRegex: + path: spec.template.spec.containers[0].image + # IN CASE OF AN INTENTIONAL MAJOR BUMP, ADJUST THIS TEST + pattern: ^docker.io/bitnami/postgresql-repmgr:17.+$ + - it: '[postgresql] ensures we detect major image version upgrades' + template: charts/postgresql/templates/primary/statefulset.yaml + set: + postgresql: + enabled: true + postgresql-ha: + enabled: false + asserts: + - documentIndex: 0 + matchRegex: + path: spec.template.spec.containers[0].image + # IN CASE OF AN INTENTIONAL MAJOR BUMP, ADJUST THIS TEST + pattern: ^docker.io/bitnami/postgresql:17.+$ + - it: '[redis-cluster] ensures we detect major image version upgrades' + template: charts/redis-cluster/templates/redis-statefulset.yaml + set: + redis-cluster: + enabled: true + redis: + enabled: false + asserts: + - documentIndex: 0 + matchRegex: + path: spec.template.spec.containers[0].image + # IN CASE OF AN INTENTIONAL MAJOR BUMP, ADJUST THIS TEST + pattern: bitnami/redis-cluster:7.+$ + - it: '[redis] ensures we detect major image version upgrades' + template: charts/redis/templates/master/application.yaml + set: + redis-cluster: + enabled: false + redis: + enabled: true + asserts: + - documentIndex: 0 + matchRegex: + path: spec.template.spec.containers[0].image + # IN CASE OF AN INTENTIONAL MAJOR BUMP, ADJUST THIS TEST + pattern: bitnami/redis:7.+$ diff --git a/unittests/deployment/HA.yaml b/unittests/deployment/HA.yaml new file mode 100644 index 0000000..aeecad6 --- /dev/null +++ b/unittests/deployment/HA.yaml @@ -0,0 +1,59 @@ +suite: deployment template (HA) +release: + name: gitea-unittests + namespace: testing +templates: + - templates/gitea/deployment.yaml + - templates/gitea/config.yaml +tests: + - it: fails with multiple replicas and "GIT_GC_REPOS" enabled + template: templates/gitea/deployment.yaml + set: + replicaCount: 2 + persistence: + accessModes: + - ReadWriteMany + gitea: + config: + cron: + GIT_GC_REPOS: + ENABLED: true + asserts: + - failedTemplate: + errorMessage: "Invoking the garbage collector via CRON is not yet supported when running with multiple replicas. Please set 'cron.GIT_GC_REPOS.enabled = false'." + - it: fails with multiple replicas and RWX file system not set + template: templates/gitea/deployment.yaml + set: + replicaCount: 2 + asserts: + - failedTemplate: + errorMessage: 'When using multiple replicas, a RWX file system is required and gitea.persistence.accessModes[0] must be set to ReadWriteMany.' + - it: fails with multiple replicas and bleve issue indexer + template: templates/gitea/deployment.yaml + set: + replicaCount: 2 + persistence: + accessModes: + - ReadWriteMany + gitea: + config: + indexer: + ISSUE_INDEXER_TYPE: bleve + asserts: + - failedTemplate: + errorMessage: "When using multiple replicas, the issue indexer (gitea.config.indexer.ISSUE_INDEXER_TYPE) must be set to a HA-ready provider such as 'meilisearch', 'elasticsearch' or 'db' (if the DB is HA-ready)." + - it: fails with multiple replicas and bleve repo indexer + template: templates/gitea/deployment.yaml + set: + replicaCount: 2 + persistence: + accessModes: + - ReadWriteMany + gitea: + config: + indexer: + REPO_INDEXER_TYPE: bleve + REPO_INDEXER_ENABLED: true + asserts: + - failedTemplate: + errorMessage: "When using multiple replicas, the repo indexer (gitea.config.indexer.REPO_INDEXER_TYPE) must be set to 'meilisearch' or 'elasticsearch' or disabled." diff --git a/unittests/deployment/basic.yaml b/unittests/deployment/basic.yaml new file mode 100644 index 0000000..133a7c2 --- /dev/null +++ b/unittests/deployment/basic.yaml @@ -0,0 +1,31 @@ +suite: deployment template (basic) +release: + name: forgejo-unittests + namespace: testing +templates: + - templates/gitea/deployment.yaml + - templates/gitea/config.yaml +tests: + - it: renders a deployment + template: templates/gitea/deployment.yaml + asserts: + - hasDocuments: + count: 1 + - containsDocument: + kind: Deployment + apiVersion: apps/v1 + name: forgejo-unittests + - it: deployment labels are set + template: templates/gitea/deployment.yaml + set: + deployment.labels: + hello: world + asserts: + - isSubset: + path: metadata.labels + content: + hello: world + - isSubset: + path: spec.template.metadata.labels + content: + hello: world diff --git a/unittests/deployment/image-configuration.yaml b/unittests/deployment/image-configuration.yaml new file mode 100644 index 0000000..9370b88 --- /dev/null +++ b/unittests/deployment/image-configuration.yaml @@ -0,0 +1,110 @@ +suite: deployment template (image configuration) +release: + name: gitea-unittests + namespace: testing +chart: + # Override appVersion to be consistent with used digest :) + appVersion: 1.19.3 +templates: + - templates/gitea/deployment.yaml + - templates/gitea/config.yaml +tests: + - it: default values + template: templates/gitea/deployment.yaml + asserts: + - equal: + path: spec.template.spec.containers[0].image + value: 'code.forgejo.org/forgejo/forgejo:1.19.3-rootless' + - it: tag override + template: templates/gitea/deployment.yaml + set: + image.tag: '1.19.4' + asserts: + - equal: + path: spec.template.spec.containers[0].image + value: 'code.forgejo.org/forgejo/forgejo:1.19.4-rootless' + - it: root-based image + template: templates/gitea/deployment.yaml + set: + image.rootless: false + asserts: + - equal: + path: spec.template.spec.containers[0].image + value: 'code.forgejo.org/forgejo/forgejo:1.19.3' + - it: scoped registry + template: templates/gitea/deployment.yaml + set: + image.registry: 'example.com' + asserts: + - equal: + path: spec.template.spec.containers[0].image + value: 'example.com/forgejo/forgejo:1.19.3-rootless' + - it: global registry + template: templates/gitea/deployment.yaml + set: + global.imageRegistry: 'global.example.com' + asserts: + - equal: + path: spec.template.spec.containers[0].image + value: 'global.example.com/forgejo/forgejo:1.19.3-rootless' + - it: digest for rootless image + template: templates/gitea/deployment.yaml + set: + image: + rootless: true + digest: sha256:b28e8f3089b52ebe6693295df142f8c12eff354e9a4a5bfbb5c10f296c3a537a + asserts: + - equal: + path: spec.template.spec.containers[0].image + value: 'code.forgejo.org/forgejo/forgejo:1.19.3-rootless@sha256:b28e8f3089b52ebe6693295df142f8c12eff354e9a4a5bfbb5c10f296c3a537a' + - it: image fullOverride (does not append rootless) + template: templates/gitea/deployment.yaml + set: + image: + fullOverride: gitea/gitea:1.19.3 + # setting rootless, registry, repository, tag, and digest to prove that override works + rootless: true + registry: example.com + repository: example/image + tag: '1.0.0' + digest: sha256:b28e8f3089b52ebe6693295df142f8c12eff354e9a4a5bfbb5c10f296c3a537a + asserts: + - equal: + path: spec.template.spec.containers[0].image + value: 'gitea/gitea:1.19.3' + - it: digest for root-based image + template: templates/gitea/deployment.yaml + set: + image: + rootless: false + digest: sha256:b28e8f3089b52ebe6693295df142f8c12eff354e9a4a5bfbb5c10f296c3a537a + asserts: + - equal: + path: spec.template.spec.containers[0].image + value: 'code.forgejo.org/forgejo/forgejo:1.19.3@sha256:b28e8f3089b52ebe6693295df142f8c12eff354e9a4a5bfbb5c10f296c3a537a' + - it: digest and global registry + template: templates/gitea/deployment.yaml + set: + global.imageRegistry: 'global.example.com' + image.digest: 'sha256:b28e8f3089b52ebe6693295df142f8c12eff354e9a4a5bfbb5c10f296c3a537a' + asserts: + - equal: + path: spec.template.spec.containers[0].image + value: 'global.example.com/forgejo/forgejo:1.19.3-rootless@sha256:b28e8f3089b52ebe6693295df142f8c12eff354e9a4a5bfbb5c10f296c3a537a' + - it: correctly renders floating tag references + template: templates/gitea/deployment.yaml + set: + image.tag: 1.21 # use non-quoted value on purpose. See: https://gitea.com/gitea/helm-chart/issues/631 + asserts: + - equal: + path: spec.template.spec.initContainers[0].image + value: 'code.forgejo.org/forgejo/forgejo:1.21-rootless' + - equal: + path: spec.template.spec.initContainers[1].image + value: 'code.forgejo.org/forgejo/forgejo:1.21-rootless' + - equal: + path: spec.template.spec.initContainers[2].image + value: 'code.forgejo.org/forgejo/forgejo:1.21-rootless' + - equal: + path: spec.template.spec.containers[0].image + value: 'code.forgejo.org/forgejo/forgejo:1.21-rootless' diff --git a/unittests/deployment/ingress-configuration.yaml b/unittests/deployment/ingress-configuration.yaml new file mode 100644 index 0000000..4dfda51 --- /dev/null +++ b/unittests/deployment/ingress-configuration.yaml @@ -0,0 +1,47 @@ +suite: ingress template +release: + name: gitea-unittests + namespace: testing +templates: + - templates/gitea/ingress.yaml +tests: + - it: hostname using TPL + set: + global.giteaHostName: 'gitea.example.com' + ingress.enabled: true + ingress.hosts[0].host: '{{ .Values.global.giteaHostName }}' + ingress.tls: + - secretName: gitea-tls + hosts: + - '{{ .Values.global.giteaHostName }}' + asserts: + - isKind: + of: Ingress + - equal: + path: spec.tls[0].hosts[0] + value: 'gitea.example.com' + - equal: + path: spec.rules[0].host + value: 'gitea.example.com' + - it: Ingress Class using TPL + set: + global.ingress.className: 'ingress-class' + ingress.className: '{{ .Values.global.ingress.className }}' + ingress.enabled: true + ingress.hosts[0].host: 'some-host' + ingress.tls: + - secretName: gitea-tls + hosts: + - 'some-host' + asserts: + - isKind: + of: Ingress + - equal: + path: spec.tls[0].hosts[0] + value: 'some-host' + - equal: + path: spec.rules[0].host + value: 'some-host' + - equal: + path: spec.ingressClassName + value: 'ingress-class' diff --git a/unittests/deployment/inline-config.yaml b/unittests/deployment/inline-config.yaml new file mode 100644 index 0000000..3b30a69 --- /dev/null +++ b/unittests/deployment/inline-config.yaml @@ -0,0 +1,33 @@ +suite: config template +release: + name: gitea-unittests + namespace: testing +templates: + - templates/gitea/config.yaml +tests: + - it: inline config stringData.server using TPL + set: + global.giteaHostName: 'gitea.example.com' + ingress.enabled: true + ingress.hosts[0].host: '{{ .Values.global.giteaHostName }}' + ingress.tls: + - secretName: gitea-tls + hosts: + - '{{ .Values.global.giteaHostName }}' + asserts: + - documentIndex: 0 + matchRegex: + path: metadata.name + pattern: .*-inline-config$ + - documentIndex: 0 + matchRegex: + path: stringData.server + pattern: DOMAIN=gitea\.example\.com + - documentIndex: 0 + matchRegex: + path: stringData.server + pattern: ROOT_URL=https://gitea\.example\.com + - documentIndex: 0 + matchRegex: + path: stringData.server + pattern: SSH_DOMAIN=gitea\.example\.com diff --git a/unittests/deployment/route-configuration.yaml b/unittests/deployment/route-configuration.yaml new file mode 100644 index 0000000..b4da640 --- /dev/null +++ b/unittests/deployment/route-configuration.yaml @@ -0,0 +1,155 @@ +# $schema: https://raw.githubusercontent.com/helm-unittest/helm-unittest/main/schema/helm-testsuite.json +suite: route template +release: + name: gitea-unittests + namespace: testing +templates: + - templates/gitea/route.yaml +tests: + - it: hostname using TPL + set: + global.giteaHostName: 'gitea.example.com' + route.enabled: true + route.host: '{{ .Values.global.giteaHostName }}' + asserts: + - isKind: + of: Route + - equal: + path: spec.host + value: 'gitea.example.com' + - notExists: + path: spec.wildcardPolicy + - it: wildcard policy + set: + global.giteaHostName: 'gitea.example.com' + route.enabled: true + route.wildcardPolicy: 'Subdomain' + asserts: + - isKind: + of: Route + - equal: + path: spec.wildcardPolicy + value: 'Subdomain' + - it: existing certificate + set: + route.enabled: true + route.tls.existingSecret: certificate-secret + route.tls.certificate: | + -----BEGIN CERTIFICATE----- + ... + -----END CERTIFICATE----- + route.tls.privateKey: | + -----BEGIN PRIVATE KEY----- + ... + -----END PRIVATE KEY----- + route.tls.caCertificate: | + -----BEGIN CERTIFICATE----- + ... + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + ... + -----END CERTIFICATE----- + asserts: + - isKind: + of: Route + - equal: + path: spec.tls.externalCertificate + value: certificate-secret + - notExists: + path: spec.tls.certificate + - notExists: + path: spec.tls.key + - notExists: + path: spec.tls.caCertificate + - it: valid certificate values + set: + route.enabled: true + route.tls.certificate: | + -----BEGIN CERTIFICATE----- + ... + -----END CERTIFICATE----- + route.tls.privateKey: | + -----BEGIN PRIVATE KEY----- + ... + -----END PRIVATE KEY----- + route.tls.caCertificate: | + -----BEGIN CERTIFICATE----- + ... + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + ... + -----END CERTIFICATE----- + asserts: + - isKind: + of: Route + - notExists: + path: spec.tls.externalCertificate + - equal: + path: spec.tls.certificate + value: | + -----BEGIN CERTIFICATE----- + ... + -----END CERTIFICATE----- + - equal: + path: spec.tls.key + value: | + -----BEGIN PRIVATE KEY----- + ... + -----END PRIVATE KEY----- + - equal: + path: spec.tls.caCertificate + value: | + -----BEGIN CERTIFICATE----- + ... + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + ... + -----END CERTIFICATE----- + - it: missing certificate values + set: + route.enabled: true + route.tls.privateKey: | + -----BEGIN PRIVATE KEY----- + ... + -----END PRIVATE KEY----- + route.tls.caCertificate: | + -----BEGIN CERTIFICATE----- + ... + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + ... + -----END CERTIFICATE----- + asserts: + - failedTemplate: + errorMessage: certificate, privateKey and caCertificate must be specified together + - it: missing privateKey values + set: + route.enabled: true + route.tls.certificate: | + -----BEGIN CERTIFICATE----- + ... + -----END CERTIFICATE----- + route.tls.caCertificate: | + -----BEGIN CERTIFICATE----- + ... + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + ... + -----END CERTIFICATE----- + asserts: + - failedTemplate: + errorMessage: certificate, privateKey and caCertificate must be specified together + - it: missing caCertificate values + set: + route.enabled: true + route.tls.certificate: | + -----BEGIN CERTIFICATE----- + ... + -----END CERTIFICATE----- + route.tls.privateKey: | + -----BEGIN PRIVATE KEY----- + ... + -----END PRIVATE KEY----- + asserts: + - failedTemplate: + errorMessage: certificate, privateKey and caCertificate must be specified together diff --git a/unittests/deployment/security-context-normal.yaml b/unittests/deployment/security-context-normal.yaml new file mode 100644 index 0000000..2418371 --- /dev/null +++ b/unittests/deployment/security-context-normal.yaml @@ -0,0 +1,25 @@ +# $schema: https://raw.githubusercontent.com/helm-unittest/helm-unittest/main/schema/helm-testsuite.json +suite: deployment template (security context) +release: + name: gitea-unittests + namespace: testing +templates: + - templates/gitea/deployment.yaml + - templates/gitea/config.yaml +tests: + - it: FS group set to 1000 + template: templates/gitea/deployment.yaml + set: + image.rootless: false + asserts: + - equal: + path: spec.template.spec.securityContext.fsGroup + value: 1000 + - it: run configure-gitea with UID 1000 + template: templates/gitea/deployment.yaml + set: + image.rootless: false + asserts: + - equal: + path: spec.template.spec.initContainers[?(@.name == 'configure-gitea')].securityContext.runAsUser + value: 1000 diff --git a/unittests/deployment/security-context-ocp.yaml b/unittests/deployment/security-context-ocp.yaml new file mode 100644 index 0000000..5f7127a --- /dev/null +++ b/unittests/deployment/security-context-ocp.yaml @@ -0,0 +1,25 @@ +# $schema: https://raw.githubusercontent.com/helm-unittest/helm-unittest/main/schema/helm-testsuite.json +suite: deployment template (security context) +release: + name: gitea-unittests + namespace: testing +templates: + - templates/gitea/deployment.yaml + - templates/gitea/config.yaml +tests: + - it: FS group not set + template: templates/gitea/deployment.yaml + set: + image.rootless: false + global.compatibility.openshift.adaptSecurityContext: force + asserts: + - notExists: + path: spec.template.spec.securityContext.fsGroup + - it: configure-gitea without runaAsUser + template: templates/gitea/deployment.yaml + set: + image.rootless: false + global.compatibility.openshift.adaptSecurityContext: force + asserts: + - notExists: + path: spec.template.spec.initContainers[?(@.name == 'configure-gitea')].securityContext.runAsUser diff --git a/unittests/statefulset/signing-disabled.yaml b/unittests/deployment/signing-disabled.yaml similarity index 72% rename from unittests/statefulset/signing-disabled.yaml rename to unittests/deployment/signing-disabled.yaml index dc6b1b8..7dd5b0e 100644 --- a/unittests/statefulset/signing-disabled.yaml +++ b/unittests/deployment/signing-disabled.yaml @@ -1,13 +1,13 @@ -suite: Statefulset template (signing disabled) +suite: deployment template (signing disabled) release: name: forgejo-unittests namespace: testing templates: - - templates/gitea/statefulset.yaml + - templates/gitea/deployment.yaml - templates/gitea/config.yaml tests: - it: skips gpg init container - template: templates/gitea/statefulset.yaml + template: templates/gitea/deployment.yaml asserts: - notContains: path: spec.template.spec.initContainers @@ -15,24 +15,24 @@ tests: content: name: configure-gpg - it: skips gpg env in `init-directories` init container - template: templates/gitea/statefulset.yaml + template: templates/gitea/deployment.yaml set: - signing.enabled: true + signing.enabled: false asserts: - - contains: + - notContains: path: spec.template.spec.initContainers[0].env content: name: GNUPGHOME value: /data/git/.gnupg - it: skips gpg env in runtime container - template: templates/gitea/statefulset.yaml + template: templates/gitea/deployment.yaml asserts: - notContains: path: spec.template.spec.containers[0].env content: name: GNUPGHOME - it: skips gpg volume spec - template: templates/gitea/statefulset.yaml + template: templates/gitea/deployment.yaml asserts: - notContains: path: spec.template.spec.volumes diff --git a/unittests/statefulset/signing-enabled.yaml b/unittests/deployment/signing-enabled.yaml similarity index 80% rename from unittests/statefulset/signing-enabled.yaml rename to unittests/deployment/signing-enabled.yaml index 25e8cd7..5628603 100644 --- a/unittests/statefulset/signing-enabled.yaml +++ b/unittests/deployment/signing-enabled.yaml @@ -1,24 +1,24 @@ -suite: Statefulset template (signing enabled) +suite: deployment template (signing enabled) release: name: forgejo-unittests namespace: testing templates: - - templates/gitea/statefulset.yaml + - templates/gitea/deployment.yaml - templates/gitea/config.yaml tests: - it: adds gpg init container - template: templates/gitea/statefulset.yaml + template: templates/gitea/deployment.yaml set: signing: enabled: true - existingSecret: "custom-gpg-secret" + existingSecret: 'custom-gpg-secret' asserts: - equal: path: spec.template.spec.initContainers[2].name value: configure-gpg - equal: path: spec.template.spec.initContainers[2].command - value: ["/usr/sbin/configure_gpg_environment.sh"] + value: ['/usr/sbin/configure_gpg_environment.sh'] - equal: path: spec.template.spec.initContainers[2].securityContext value: @@ -39,9 +39,10 @@ tests: mountPath: /raw readOnly: true - it: adds gpg env in `init-directories` init container - template: templates/gitea/statefulset.yaml + template: templates/gitea/deployment.yaml set: signing.enabled: true + signing.existingSecret: 'custom-gpg-secret' asserts: - contains: path: spec.template.spec.initContainers[0].env @@ -49,9 +50,10 @@ tests: name: GNUPGHOME value: /data/git/.gnupg - it: adds gpg env in runtime container - template: templates/gitea/statefulset.yaml + template: templates/gitea/deployment.yaml set: signing.enabled: true + signing.existingSecret: 'custom-gpg-secret' asserts: - contains: path: spec.template.spec.containers[0].env @@ -59,10 +61,11 @@ tests: name: GNUPGHOME value: /data/git/.gnupg - it: adds gpg volume spec - template: templates/gitea/statefulset.yaml + template: templates/gitea/deployment.yaml set: signing: enabled: true + existingSecret: 'forgejo-unittests-gpg-key' asserts: - contains: path: spec.template.spec.volumes @@ -75,7 +78,7 @@ tests: path: private.asc defaultMode: 0100 - it: supports gpg volume spec with external reference - template: templates/gitea/statefulset.yaml + template: templates/gitea/deployment.yaml set: signing: enabled: true diff --git a/unittests/deployment/ssh-configuration.yaml b/unittests/deployment/ssh-configuration.yaml new file mode 100644 index 0000000..95e312d --- /dev/null +++ b/unittests/deployment/ssh-configuration.yaml @@ -0,0 +1,64 @@ +suite: deployment template (SSH configuration) +release: + name: gitea-unittests + namespace: testing +templates: + - templates/gitea/deployment.yaml + - templates/gitea/config.yaml +tests: + - it: supports defining SSH log level for root based image + template: templates/gitea/deployment.yaml + set: + image.rootless: false + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: SSH_LOG_LEVEL + value: 'INFO' + - it: supports overriding SSH log level + template: templates/gitea/deployment.yaml + set: + image.rootless: false + gitea.ssh.logLevel: 'DEBUG' + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: SSH_LOG_LEVEL + value: 'DEBUG' + - it: supports overriding SSH log level (even when image.fullOverride set) + template: templates/gitea/deployment.yaml + set: + image.fullOverride: gitea/gitea:1.19.3 + image.rootless: false + gitea.ssh.logLevel: 'DEBUG' + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: SSH_LOG_LEVEL + value: 'DEBUG' + - it: skips SSH_LOG_LEVEL for rootless image + template: templates/gitea/deployment.yaml + set: + image.rootless: true + gitea.ssh.logLevel: 'DEBUG' # explicitly defining a non-standard level here + asserts: + - notContains: + path: spec.template.spec.containers[0].env + any: true + content: + name: SSH_LOG_LEVEL + - it: skips SSH_LOG_LEVEL for rootless image (even when image.fullOverride set) + template: templates/gitea/deployment.yaml + set: + image.fullOverride: gitea/gitea:1.19.3 + image.rootless: true + gitea.ssh.logLevel: 'DEBUG' # explicitly defining a non-standard level here + asserts: + - notContains: + path: spec.template.spec.containers[0].env + any: true + content: + name: SSH_LOG_LEVEL diff --git a/unittests/deployment/storage-class-configuration.yaml b/unittests/deployment/storage-class-configuration.yaml new file mode 100644 index 0000000..525197f --- /dev/null +++ b/unittests/deployment/storage-class-configuration.yaml @@ -0,0 +1,39 @@ +# File: tests/gitea-storageclass-tests.yaml + +suite: storage class configuration tests + +release: + name: gitea-storageclass-tests + namespace: testing + +templates: + - templates/gitea/pvc.yaml + +tests: + - it: should set storageClassName when persistence.storageClass is defined + template: templates/gitea/pvc.yaml + set: + persistence.storageClass: 'my-storage-class' + asserts: + - equal: + path: 'spec.storageClassName' + value: 'my-storage-class' + + - it: should set global.storageClass when persistence.storageClass is not defined + template: templates/gitea/pvc.yaml + set: + global.storageClass: 'default-storage-class' + asserts: + - equal: + path: spec.storageClassName + value: 'default-storage-class' + + - it: should set storageClassName when persistence.storageClass is defined and global.storageClass is defined + template: templates/gitea/pvc.yaml + set: + global.storageClass: 'default-storage-class' + persistence.storageClass: 'my-storage-class' + asserts: + - equal: + path: spec.storageClassName + value: 'my-storage-class' diff --git a/unittests/deployment/svc-configuration.yaml b/unittests/deployment/svc-configuration.yaml new file mode 100644 index 0000000..f39bb1b --- /dev/null +++ b/unittests/deployment/svc-configuration.yaml @@ -0,0 +1,128 @@ +suite: ssh-svc / http-svc template (Services configuration) +release: + name: gitea-unittests + namespace: testing +templates: + - templates/gitea/ssh-svc.yaml + - templates/gitea/http-svc.yaml +tests: + - it: supports adding custom labels to ssh-svc + template: templates/gitea/ssh-svc.yaml + set: + service: + ssh: + labels: + gitea/testkey: testvalue + asserts: + - equal: + path: metadata.labels["gitea/testkey"] + value: 'testvalue' + + - it: keeps existing labels (ssh) + template: templates/gitea/ssh-svc.yaml + set: + service: + ssh: + labels: {} + asserts: + - exists: + path: metadata.labels["app"] + + - it: supports adding custom labels to http-svc + template: templates/gitea/http-svc.yaml + set: + service: + http: + labels: + gitea/testkey: testvalue + asserts: + - equal: + path: metadata.labels["gitea/testkey"] + value: 'testvalue' + + - it: keeps existing labels (http) + template: templates/gitea/http-svc.yaml + set: + service: + http: + labels: {} + asserts: + - exists: + path: metadata.labels["app"] + + - it: uses default ports to ssh-svc + template: templates/gitea/ssh-svc.yaml + asserts: + - equal: + path: spec.ports[0].port + value: 22 + - equal: + path: spec.ports[0].targetPort + value: ssh + + - it: render service.ssh.loadBalancerClass if set and type is LoadBalancer + template: templates/gitea/ssh-svc.yaml + set: + service: + ssh: + loadBalancerClass: 'example.com/class' + type: LoadBalancer + loadBalancerIP: '1.2.3.4' + loadBalancerSourceRanges: + - '1.2.3.4/32' + - '5.6.7.8/32' + asserts: + - equal: + path: spec.loadBalancerClass + value: 'example.com/class' + - equal: + path: spec.loadBalancerIP + value: '1.2.3.4' + - equal: + path: spec.loadBalancerSourceRanges + value: ['1.2.3.4/32', '5.6.7.8/32'] + + - it: does not render when loadbalancer properties are set but type is not loadBalancerClass + template: templates/gitea/http-svc.yaml + set: + service: + http: + type: ClusterIP + loadBalancerClass: 'example.com/class' + loadBalancerIP: '1.2.3.4' + loadBalancerSourceRanges: + - '1.2.3.4/32' + - '5.6.7.8/32' + asserts: + - notExists: + path: spec.loadBalancerClass + - notExists: + path: spec.loadBalancerIP + - notExists: + path: spec.loadBalancerSourceRanges + + - it: does not render loadBalancerClass by default even when type is LoadBalancer + template: templates/gitea/http-svc.yaml + set: + service: + http: + type: LoadBalancer + loadBalancerIP: '1.2.3.4' + asserts: + - notExists: + path: spec.loadBalancerClass + - equal: + path: spec.loadBalancerIP + value: '1.2.3.4' + + - it: both ssh and http services exist + templates: + - templates/gitea/ssh-svc.yaml + - templates/gitea/http-svc.yaml + asserts: + - matchRegex: + path: metadata.name + pattern: '^gitea-unittests-forgejo-(?:ssh|http)$' + - matchRegex: + path: spec.ports[0].name + pattern: '^(?:ssh|http)$' diff --git a/unittests/gpg-secret/signing-enabled.yaml b/unittests/gpg-secret/signing-enabled.yaml index 84cdc3f..ad38d45 100644 --- a/unittests/gpg-secret/signing-enabled.yaml +++ b/unittests/gpg-secret/signing-enabled.yaml @@ -11,12 +11,12 @@ tests: enabled: true asserts: - failedTemplate: - errorMessage: Either specify `signing.privateKey` or `signing.existingKey` + errorMessage: Either specify `signing.privateKey` or `signing.existingSecret` - it: skips rendering using external secret reference set: signing: enabled: true - existingSecret: "external-secret-reference" + existingSecret: 'external-secret-reference' asserts: - hasDocuments: count: 0 @@ -24,7 +24,7 @@ tests: set: signing: enabled: true - privateKey: "gpg-key-placeholder" + privateKey: 'gpg-key-placeholder' asserts: - hasDocuments: count: 1 @@ -33,8 +33,8 @@ tests: kind: Secret apiVersion: v1 name: forgejo-unittests-gpg-key - - isNotEmpty: + - isNotNullOrEmpty: path: metadata.labels - equal: path: data.privateKey - value: "Z3BnLWtleS1wbGFjZWhvbGRlcg==" + value: 'Z3BnLWtleS1wbGFjZWhvbGRlcg==' diff --git a/unittests/init/basic.yaml b/unittests/init/basic.yaml index cfa8a17..292a92d 100644 --- a/unittests/init/basic.yaml +++ b/unittests/init/basic.yaml @@ -10,6 +10,6 @@ tests: - hasDocuments: count: 1 - containsDocument: - kind: Secret + kind: Secret apiVersion: v1 name: forgejo-unittests-init diff --git a/unittests/init/init_directory_structure.sh-rootless.yaml b/unittests/init/init_directory_structure.sh-rootless.yaml new file mode 100644 index 0000000..ea5f3cf --- /dev/null +++ b/unittests/init/init_directory_structure.sh-rootless.yaml @@ -0,0 +1,87 @@ +suite: Init template (rootless) +release: + name: forgejo-unittests + namespace: testing +templates: + - templates/gitea/init.yaml +tests: + - it: runs gpg in batch mode + set: + signing.enabled: true + signing.privateKey: |- + -----BEGIN PGP PRIVATE KEY BLOCK----- + {placeholder} + -----END PGP PRIVATE KEY BLOCK----- + asserts: + - equal: + path: stringData["configure_gpg_environment.sh"] + value: |- + #!/usr/bin/env bash + set -eu + + gpg --batch --import /raw/private.asc + - it: skips gpg script block for disabled signing + asserts: + - equal: + path: stringData["init_directory_structure.sh"] + value: |- + #!/usr/bin/env bash + + set -euo pipefail + + set -x + mkdir -p /data/git/.ssh + chmod -R 700 /data/git/.ssh + [ ! -d /data/gitea/conf ] && mkdir -p /data/gitea/conf + + # prepare temp directory structure + mkdir -p "${GITEA_TEMP}" + chmod ug+rwx "${GITEA_TEMP}" + - it: adds gpg script block for enabled signing + set: + signing.enabled: true + signing.privateKey: |- + -----BEGIN PGP PRIVATE KEY BLOCK----- + {placeholder} + -----END PGP PRIVATE KEY BLOCK----- + asserts: + - equal: + path: stringData["init_directory_structure.sh"] + value: |- + #!/usr/bin/env bash + + set -euo pipefail + + set -x + mkdir -p /data/git/.ssh + chmod -R 700 /data/git/.ssh + [ ! -d /data/gitea/conf ] && mkdir -p /data/gitea/conf + + # prepare temp directory structure + mkdir -p "${GITEA_TEMP}" + chmod ug+rwx "${GITEA_TEMP}" + + if [ ! -d "${GNUPGHOME}" ]; then + mkdir -p "${GNUPGHOME}" + chmod 700 "${GNUPGHOME}" + chown 1000:1000 "${GNUPGHOME}" + fi + - it: it does not chown /data even when image.fullOverride is set + set: + image.fullOverride: gitea/gitea:1.20.5 + asserts: + - equal: + path: stringData["init_directory_structure.sh"] + value: |- + #!/usr/bin/env bash + + set -euo pipefail + + set -x + mkdir -p /data/git/.ssh + chmod -R 700 /data/git/.ssh + [ ! -d /data/gitea/conf ] && mkdir -p /data/gitea/conf + + # prepare temp directory structure + mkdir -p "${GITEA_TEMP}" + chmod ug+rwx "${GITEA_TEMP}" diff --git a/unittests/init/init_directory_structure.sh.yaml b/unittests/init/init_directory_structure.sh.yaml index 2372be6..fa1e969 100644 --- a/unittests/init/init_directory_structure.sh.yaml +++ b/unittests/init/init_directory_structure.sh.yaml @@ -7,19 +7,26 @@ templates: tests: - it: runs gpg in batch mode set: + image.rootless: false signing.enabled: true + signing.privateKey: |- + -----BEGIN PGP PRIVATE KEY BLOCK----- + {placeholder} + -----END PGP PRIVATE KEY BLOCK----- asserts: - equal: - path: stringData.[configure_gpg_environment.sh] + path: stringData["configure_gpg_environment.sh"] value: |- #!/usr/bin/env bash set -eu gpg --batch --import /raw/private.asc - it: skips gpg script block for disabled signing + set: + image.rootless: false asserts: - equal: - path: stringData.[init_directory_structure.sh] + path: stringData["init_directory_structure.sh"] value: |- #!/usr/bin/env bash @@ -37,10 +44,15 @@ tests: chmod ug+rwx "${GITEA_TEMP}" - it: adds gpg script block for enabled signing set: + image.rootless: false signing.enabled: true + signing.privateKey: |- + -----BEGIN PGP PRIVATE KEY BLOCK----- + {placeholder} + -----END PGP PRIVATE KEY BLOCK----- asserts: - equal: - path: stringData.[init_directory_structure.sh] + path: stringData["init_directory_structure.sh"] value: |- #!/usr/bin/env bash diff --git a/unittests/pvc/pvc-configuration.yaml b/unittests/pvc/pvc-configuration.yaml new file mode 100644 index 0000000..c3afaaf --- /dev/null +++ b/unittests/pvc/pvc-configuration.yaml @@ -0,0 +1,19 @@ +suite: PVC template +release: + name: gitea-unittests + namespace: testing +templates: + - templates/gitea/pvc.yaml +tests: + - it: Storage Class using TPL + set: + global.persistence.storageClass: 'storage-class' + persistence.enabled: true + persistence.create: true + persistence.storageClass: '{{ .Values.global.persistence.storageClass }}' + asserts: + - isKind: + of: PersistentVolumeClaim + - equal: + path: spec.storageClassName + value: 'storage-class' diff --git a/unittests/serviceaccount/basic.yaml b/unittests/serviceaccount/basic.yaml new file mode 100644 index 0000000..94b4413 --- /dev/null +++ b/unittests/serviceaccount/basic.yaml @@ -0,0 +1,82 @@ +suite: ServiceAccount template (basic) +release: + name: gitea-unittests + namespace: testing +templates: + - templates/gitea/serviceaccount.yaml +tests: + - it: skips rendering by default + asserts: + - hasDocuments: + count: 0 + - it: renders default ServiceAccount object with serviceAccount.create=true + set: + serviceAccount.create: true + asserts: + - hasDocuments: + count: 1 + - containsDocument: + kind: ServiceAccount + apiVersion: v1 + name: gitea-unittests-forgejo + - equal: + path: automountServiceAccountToken + value: false + - notExists: + path: imagePullSecrets + - notExists: + path: metadata.annotations + - it: allows for adding custom labels + set: + serviceAccount: + create: true + labels: + custom: label + asserts: + - equal: + path: metadata.labels.custom + value: label + - it: allows for adding custom annotations + set: + serviceAccount: + create: true + annotations: + myCustom: annotation + asserts: + - equal: + path: metadata.annotations.myCustom + value: annotation + - it: allows to override the generated name + set: + serviceAccount: + create: true + name: provided-serviceaccount-name + asserts: + - equal: + path: metadata.name + value: provided-serviceaccount-name + - it: allows to mount the token + set: + serviceAccount: + create: true + automountServiceAccountToken: true + asserts: + - equal: + path: automountServiceAccountToken + value: true + - it: allows to reference image pull secrets + set: + serviceAccount: + create: true + imagePullSecrets: + - name: testing-image-pull-secret + - name: another-pull-secret + asserts: + - contains: + path: imagePullSecrets + content: + name: testing-image-pull-secret + - contains: + path: imagePullSecrets + content: + name: another-pull-secret diff --git a/unittests/serviceaccount/reference.yaml b/unittests/serviceaccount/reference.yaml new file mode 100644 index 0000000..3a40688 --- /dev/null +++ b/unittests/serviceaccount/reference.yaml @@ -0,0 +1,32 @@ +suite: ServiceAccount template (reference) +release: + name: gitea-unittests + namespace: testing +templates: + - templates/gitea/serviceaccount.yaml + - templates/gitea/deployment.yaml + - templates/gitea/config.yaml +tests: + - it: does not modify the deployment by default + template: templates/gitea/deployment.yaml + asserts: + - notExists: + path: spec.serviceAccountName + - it: adds the reference to the deployment with serviceAccount.create=true + template: templates/gitea/deployment.yaml + set: + serviceAccount.create: true + asserts: + - equal: + path: spec.template.spec.serviceAccountName + value: gitea-unittests-forgejo + - it: allows referencing an externally created ServiceAccount to the deployment + template: templates/gitea/deployment.yaml + set: + serviceAccount: + create: false # explicitly set to define rendering behavior + name: 'externally-existing-serviceaccount' + asserts: + - equal: + path: spec.template.spec.serviceAccountName + value: externally-existing-serviceaccount diff --git a/unittests/statefulset/basic.yaml b/unittests/statefulset/basic.yaml deleted file mode 100644 index b487ba1..0000000 --- a/unittests/statefulset/basic.yaml +++ /dev/null @@ -1,17 +0,0 @@ -suite: Statefulset template (basic) -release: - name: forgejo-unittests - namespace: testing -templates: - - templates/gitea/statefulset.yaml - - templates/gitea/config.yaml -tests: - - it: renders a statefulset - template: templates/gitea/statefulset.yaml - asserts: - - hasDocuments: - count: 1 - - containsDocument: - kind: StatefulSet - apiVersion: apps/v1 - name: forgejo-unittests diff --git a/unittests/values-conflicting-checks.yaml b/unittests/values-conflicting-checks.yaml new file mode 100644 index 0000000..a257690 --- /dev/null +++ b/unittests/values-conflicting-checks.yaml @@ -0,0 +1,14 @@ +suite: Values conflicting checks +release: + name: gitea-unittests + namespace: testing +tests: + - it: fails when trying to configure redis and redis-cluster the same time + set: + redis-cluster: + enabled: true + redis: + enabled: true + asserts: + - failedTemplate: + errorMessage: redis and redis-cluster cannot be enabled at the same time. Please only choose one. diff --git a/values.yaml b/values.yaml index a7f0450..4af2e9f 100644 --- a/values.yaml +++ b/values.yaml @@ -6,34 +6,57 @@ ## @param global.imageRegistry global image registry override ## @param global.imagePullSecrets global image pull secrets override; can be extended by `imagePullSecrets` ## @param global.storageClass global storage class override +## @param global.hostAliases global hostAliases which will be added to the pod's hosts files global: - imageRegistry: "" + imageRegistry: '' ## E.g. ## imagePullSecrets: ## - myRegistryKeySecretName ## imagePullSecrets: [] - storageClass: "" + storageClass: '' + hostAliases: [] + # - ip: 192.168.137.2 + # hostnames: + # - example.com -## @param replicaCount number of replicas for the statefulset +## @param namespaceOverride String to fully override common.names.namespace +## +namespaceOverride: '' + +## @param replicaCount number of replicas for the deployment replicaCount: 1 +## @section strategy +## @param strategy.type strategy type +## @param strategy.rollingUpdate.maxSurge maxSurge +## @param strategy.rollingUpdate.maxUnavailable maxUnavailable +strategy: + type: 'RollingUpdate' + rollingUpdate: + maxSurge: '100%' + maxUnavailable: 0 + ## @param clusterDomain cluster domain clusterDomain: cluster.local ## @section Image ## @param image.registry image registry, e.g. gcr.io,docker.io ## @param image.repository Image to start for this pod -## @param image.tag Visit: [Image tag](https://codeberg.org/forgejo/-/packages/container/forgejo/versions). Defaults to `appVersion` within Chart.yaml. +## @param image.tag Visit: [Image tag](https://code.forgejo.org/forgejo/-/packages/container/forgejo/versions). Defaults to `appVersion` within Chart.yaml. +## @param image.digest Image digest. Allows to pin the given image tag. Useful for having control over mutable tags like `latest` ## @param image.pullPolicy Image pull policy -## @param image.rootless Wether or not to pull the rootless version of Forgejo, only works on Forgejo 1.14.x or higher +## @param image.rootless Wether or not to pull the rootless version of Forgejo +## @param image.fullOverride Completely overrides the image registry, path/image, tag and digest. **Adjust `image.rootless` accordingly and review [Rootless defaults](#rootless-defaults).** image: - registry: "codeberg.org" + registry: code.forgejo.org repository: forgejo/forgejo # Overrides the image tag whose default is the chart appVersion. - tag: "" - pullPolicy: Always - rootless: false # only possible when running 1.14 or later + tag: '' + digest: '' + pullPolicy: IfNotPresent + rootless: true + fullOverride: '' ## @param imagePullSecrets Secret to use for pulling the image imagePullSecrets: [] @@ -69,11 +92,16 @@ containerSecurityContext: {} ## @param securityContext Run init and Forgejo containers as a specific securityContext securityContext: {} +## @param podDisruptionBudget Pod disruption budget +podDisruptionBudget: {} +# maxUnavailable: 1 +# minAvailable: 1 + ## @section Service service: ## @param service.http.type Kubernetes service type for web traffic ## @param service.http.port Port number for web traffic - ## @param service.http.clusterIP ClusterIP setting for http autosetup for statefulset is None + ## @param service.http.clusterIP ClusterIP setting for http autosetup for deployment ## @param service.http.loadBalancerIP LoadBalancer IP setting ## @param service.http.nodePort NodePort for http service ## @param service.http.externalTrafficPolicy If `service.http.type` is `NodePort` or `LoadBalancer`, set this to `Local` to enable source IP preservation @@ -82,10 +110,12 @@ service: ## @param service.http.ipFamilies HTTP service dual-stack familiy selection,for dual-stack parameters see official kubernetes [dual-stack concept documentation](https://kubernetes.io/docs/concepts/services-networking/dual-stack/). ## @param service.http.loadBalancerSourceRanges Source range filter for http loadbalancer ## @param service.http.annotations HTTP service annotations + ## @param service.http.labels HTTP service additional labels + ## @param service.http.loadBalancerClass Loadbalancer class http: type: ClusterIP port: 3000 - clusterIP: None + clusterIP: loadBalancerIP: nodePort: externalTrafficPolicy: @@ -94,9 +124,11 @@ service: ipFamilies: loadBalancerSourceRanges: [] annotations: {} + labels: {} + loadBalancerClass: ## @param service.ssh.type Kubernetes service type for ssh traffic ## @param service.ssh.port Port number for ssh traffic - ## @param service.ssh.clusterIP ClusterIP setting for ssh autosetup for statefulset is None + ## @param service.ssh.clusterIP ClusterIP setting for ssh autosetup for deployment ## @param service.ssh.loadBalancerIP LoadBalancer IP setting ## @param service.ssh.nodePort NodePort for ssh service ## @param service.ssh.externalTrafficPolicy If `service.ssh.type` is `NodePort` or `LoadBalancer`, set this to `Local` to enable source IP preservation @@ -106,10 +138,12 @@ service: ## @param service.ssh.hostPort HostPort for ssh service ## @param service.ssh.loadBalancerSourceRanges Source range filter for ssh loadbalancer ## @param service.ssh.annotations SSH service annotations + ## @param service.ssh.labels SSH service additional labels + ## @param service.ssh.loadBalancerClass Loadbalancer class ssh: type: ClusterIP port: 22 - clusterIP: None + clusterIP: loadBalancerIP: nodePort: externalTrafficPolicy: @@ -119,7 +153,8 @@ service: hostPort: loadBalancerSourceRanges: [] annotations: {} - + labels: {} + loadBalancerClass: ## @section Ingress ## @param ingress.enabled Enable ingress @@ -129,12 +164,12 @@ service: ## @param ingress.hosts[0].paths[0].path Default Ingress path ## @param ingress.hosts[0].paths[0].pathType Ingress path type ## @param ingress.tls Ingress tls settings -## @extra ingress.apiVersion Specify APIVersion of ingress object. Mostly would only be used for argocd. ingress: enabled: false # className: nginx className: - annotations: {} + annotations: + {} # kubernetes.io/ingress.class: nginx # kubernetes.io/tls-acme: "true" hosts: @@ -146,14 +181,54 @@ ingress: # - secretName: chart-example-tls # hosts: # - git.example.com - # Mostly for argocd or any other CI that uses `helm template | kubectl apply` or similar - # If helm doesn't correctly detect your ingress API version you can set it here. - # apiVersion: networking.k8s.io/v1 -## @section StatefulSet +## @section Route +## @param route.enabled Enable route +## @param route.annotations Route annotations +## @param route.host Host to use for the route (will be assigned automatically by OKD / OpenShift is not defined) +## @param route.wildcardPolicy Wildcard policy if any for the route, currently only 'Subdomain' or 'None' is allowed. +## @param route.tls.termination termination type (see [OKD documentation](https://docs.okd.io/latest/rest_api/network_apis/route-route-openshift-io-v1.html#spec-tls)) +## @param route.tls.insecureEdgeTerminationPolicy the desired behavior for insecure connections to a route (e.g. with http) +## @param route.tls.existingSecret the name of a predefined secret of type kubernetes.io/tls with both key (tls.crt and tls.key) set accordingly (if defined attributes 'certificate', 'caCertificate' and 'privateKey' are ignored) +## @param route.tls.certificate PEM encoded single certificate +## @param route.tls.privateKey PEM encoded private key +## @param route.tls.caCertificate PEM encoded CA certificate or chain that issued the certificate +## @param route.tls.destinationCACertificate PEM encoded CA certificate used to verify the authenticity of final end point when 'termination' is set to 'passthrough' (ignored otherwise) +route: + enabled: false + annotations: {} + host: + wildcardPolicy: + tls: + termination: edge + insecureEdgeTerminationPolicy: Redirect + existingSecret: + certificate: + # certificate: |- + # -----BEGIN CERTIFICATE----- + # ... + # -----END CERTIFICATE----- + privateKey: + # privateKey: |- + # -----BEGIN PRIVATE KEY----- + # ... + # -----END PRIVATE KEY----- + caCertificate: + # caCertificate: |- + # -----BEGIN CERTIFICATE----- + # ... + # -----END CERTIFICATE----- + destinationCACertificate: + # destinationCACertificate: |- + # -----BEGIN CERTIFICATE----- + # ... + # -----END CERTIFICATE----- + +## @section deployment # ## @param resources Kubernetes resources -resources: {} +resources: + {} # We usually recommend not to specify default resources and to leave this as a conscious # choice for the user. This also increases chances charts run on environments with little # resources, such as Minikube. If you do want to specify resources, uncomment the following @@ -169,54 +244,85 @@ resources: {} ## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/ ## ## @param schedulerName Use an alternate scheduler, e.g. "stork" -schedulerName: "" +schedulerName: '' -## @param nodeSelector NodeSelector for the statefulset +## @param nodeSelector NodeSelector for the deployment nodeSelector: {} -## @param tolerations Tolerations for the statefulset +## @param tolerations Tolerations for the deployment tolerations: [] -## @param affinity Affinity for the statefulset +## @param affinity Affinity for the deployment affinity: {} -## @param dnsConfig dnsConfig for the statefulset +## @param topologySpreadConstraints TopologySpreadConstraints for the deployment +topologySpreadConstraints: [] + +## @param dnsConfig dnsConfig for the deployment dnsConfig: {} -## @param statefulset.env Additional environment variables to pass to containers -## @param statefulset.terminationGracePeriodSeconds How long to wait until forcefully kill the pod -## @param statefulset.labels Labels for the statefulset -## @param statefulset.annotations Annotations for the Forgejo StatefulSet to be created -statefulset: - env: [] +## @param priorityClassName priorityClassName for the deployment +priorityClassName: '' + +## @param deployment.env Additional environment variables to pass to containers +## @param deployment.terminationGracePeriodSeconds How long to wait until forcefully kill the pod +## @param deployment.labels Labels for the deployment +## @param deployment.annotations Annotations for the Forgejo deployment to be created +deployment: + env: + [] # - name: VARIABLE # value: my-value terminationGracePeriodSeconds: 60 labels: {} annotations: {} +## @section ServiceAccount + +## @param serviceAccount.create Enable the creation of a ServiceAccount +## @param serviceAccount.name Name of the created ServiceAccount, defaults to release name. Can also link to an externally provided ServiceAccount that should be used. +## @param serviceAccount.automountServiceAccountToken Enable/disable auto mounting of the service account token +## @param serviceAccount.imagePullSecrets Image pull secrets, available to the ServiceAccount +## @param serviceAccount.annotations Custom annotations for the ServiceAccount +## @param serviceAccount.labels Custom labels for the ServiceAccount +serviceAccount: + create: false + name: '' + automountServiceAccountToken: false + imagePullSecrets: [] + # - name: private-registry-access + annotations: {} + labels: {} + ## @section Persistence # ## @param persistence.enabled Enable persistent storage -## @param persistence.existingClaim Use an existing claim to store repository information +## @param persistence.create Whether to create the persistentVolumeClaim for shared storage +## @param persistence.mount Whether the persistentVolumeClaim should be mounted (even if not created) +## @param persistence.claimName Use an existing claim to store repository information ## @param persistence.size Size for persistence to store repo information ## @param persistence.accessModes AccessMode for persistence ## @param persistence.labels Labels for the persistence volume claim to be created -## @param persistence.annotations Annotations for the persistence volume claim to be created +## @param persistence.annotations.helm.sh/resource-policy Resource policy for the persistence volume claim ## @param persistence.storageClass Name of the storage class to use ## @param persistence.subPath Subdirectory of the volume to mount at +## @param persistence.volumeName Name of persistent volume in PVC persistence: enabled: true - existingClaim: + create: true + mount: true + claimName: gitea-shared-storage size: 10Gi accessModes: - ReadWriteOnce labels: {} - annotations: {} storageClass: subPath: + volumeName: '' + annotations: + helm.sh/resource-policy: keep -## @param extraVolumes Additional volumes to mount to the Forgejo statefulset +## @param extraVolumes Additional volumes to mount to the Forgejo deployment extraVolumes: [] # - name: postgres-ssl-vol # secret: @@ -240,7 +346,7 @@ extraVolumeMounts: [] ## @section Init ## @param initPreScript Bash shell script copied verbatim to the start of the init-container. -initPreScript: "" +initPreScript: '' # # initPreScript: | # mkdir -p /data/git/.postgresql @@ -248,22 +354,32 @@ initPreScript: "" # chown -R git:git /data/git/.postgresql/ # chmod 400 /data/git/.postgresql/postgresql.key +## @param initContainers.resources.limits initContainers.limits Kubernetes resource limits for init containers +## @param initContainers.resources.requests.cpu initContainers.requests.cpu Kubernetes cpu resource limits for init containers +## @param initContainers.resources.requests.memory initContainers.requests.memory Kubernetes memory resource limits for init containers +initContainers: + resources: + limits: {} + requests: + cpu: 100m + memory: 128Mi + # Configure commit/action signing prerequisites ## @section Signing # ## @param signing.enabled Enable commit/action signing ## @param signing.gpgHome GPG home directory -## @param signing.privateKey Inline private gpg key for signed Forgejo actions +## @param signing.privateKey Inline private GPG key for signed internal Git activity ## @param signing.existingSecret Use an existing secret to store the value of `signing.privateKey` signing: enabled: false gpgHome: /data/git/.gnupg - privateKey: "" + privateKey: '' # privateKey: |- # -----BEGIN PGP PRIVATE KEY BLOCK----- # ... # -----END PGP PRIVATE KEY BLOCK----- - existingSecret: "" + existingSecret: '' ## @section Gitea # @@ -272,24 +388,29 @@ gitea: ## @param gitea.admin.existingSecret Use an existing secret to store admin user credentials ## @param gitea.admin.password Password for the Forgejo admin user ## @param gitea.admin.email Email for the Forgejo admin user + ## @param gitea.admin.passwordMode Mode for how to set/update the admin user password. Options are: initialOnlyNoReset, initialOnlyRequireReset, and keepUpdated admin: - #existingSecret: gitea-admin-secret + # existingSecret: gitea-admin-secret existingSecret: username: gitea_admin password: r8sA8CPHD9!bt6d - email: "gitea@local.domain" + email: 'gitea@local.domain' + passwordMode: keepUpdated ## @param gitea.metrics.enabled Enable Forgejo metrics ## @param gitea.metrics.serviceMonitor.enabled Enable Forgejo metrics service monitor + ## @param gitea.metrics.serviceMonitor.namespace Namespace in which Prometheus is running metrics: enabled: false serviceMonitor: enabled: false + namespace: '' # additionalLabels: # prometheus-release: prom1 ## @param gitea.ldap LDAP configuration - ldap: [] + ldap: + [] # - name: "LDAP 1" # existingSecret: # securityProtocol: @@ -306,7 +427,8 @@ gitea: # Either specify inline `key` and `secret` or refer to them via `existingSecret` ## @param gitea.oauth OAuth configuration - oauth: [] + oauth: + [] # - name: 'OAuth 1' # provider: # key: @@ -319,17 +441,6 @@ gitea: # customProfileUrl: # customEmailUrl: - ## @param gitea.config Configuration for the Forgejo server,ref: [config-cheat-sheet](https://docs.gitea.io/en-us/config-cheat-sheet/) - config: {} - # APP_NAME: "Forgejo: Git with a cup of tea" - # RUN_MODE: dev - # - # server: - # SSH_PORT: 22 - # - # security: - # PASSWORD_COMPLEXITY: spec - ## @param gitea.additionalConfigSources Additional configuration from secret or configmap additionalConfigSources: [] # - secret: @@ -343,6 +454,162 @@ gitea: ## @param gitea.podAnnotations Annotations for the Forgejo pod podAnnotations: {} + ## @param gitea.ssh.logLevel Configure OpenSSH's log level. Only available for root-based Forgejo image. + ssh: + logLevel: 'INFO' + + ## @section `app.ini` overrides + ## @descriptionStart + ## Every value described in the [Cheat + ## Sheet](https://forgejo.org/docs/latest/admin/config-cheat-sheet/) can be + ## set as a Helm value. Configuration sections map to (lowercased) YAML + ## blocks, while the keys themselves remain in all caps. + ## @descriptionEnd + config: + # values in the DEFAULT section + # (https://forgejo.org/docs/latest/admin/config-cheat-sheet/#overall-default) + # are un-namespaced + + ## @param gitea.config.APP_NAME Application name, used in the page title + APP_NAME: 'Forgejo: Beyond coding. We forge.' + + ## @param gitea.config.RUN_MODE Application run mode, affects performance and debugging: `dev` or `prod` + RUN_MODE: prod + + ## @param gitea.config.repository General repository settings + repository: {} + + ## @param gitea.config.cors Cross-origin resource sharing settings + cors: {} + + ## @param gitea.config.ui User interface settings + ui: {} + + ## @param gitea.config.markdown Markdown parser settings + markdown: {} + + ## @param gitea.config.server [object] General server settings + server: + SSH_PORT: 22 # rootful image + SSH_LISTEN_PORT: 2222 # rootless image + + ## @param gitea.config.database Database configuration (only necessary with an [externally managed DB](https://code.forgejo.org/forgejo-helm/forgejo-helm#external-database)). + database: {} + + ## @param gitea.config.indexer Settings for what content is indexed and how + indexer: {} + + ## @param gitea.config.queue Job queue configuration + queue: {} + + ## @param gitea.config.admin Admin user settings + admin: {} + + ## @param gitea.config.security Site security settings + security: {} + + ## @param gitea.config.camo Settings for the [camo](https://github.com/cactus/go-camo) media proxy server (disabled by default) + camo: {} + + ## @param gitea.config.openid Configuration for authentication with OpenID (disabled by default) + openid: {} + + ## @param gitea.config.oauth2_client OAuth2 client settings + oauth2_client: {} + + ## @param gitea.config.service Configuration for miscellaneous Forgejo services + service: {} + + ## @param gitea.config.ssh.minimum_key_sizes SSH minimum key sizes + ssh.minimum_key_sizes: {} + + ## @param gitea.config.webhook Webhook settings + webhook: {} + + ## @param gitea.config.mailer Mailer configuration (disabled by default) + mailer: {} + + ## @param gitea.config.email.incoming Configuration for handling incoming mail (disabled by default) + email.incoming: {} + + ## @param gitea.config.cache Cache configuration + cache: {} + + ## @param gitea.config.session Session/cookie handling + session: {} + + ## @param gitea.config.picture User avatar settings + picture: {} + + ## @param gitea.config.project Project board defaults + project: {} + + ## @param gitea.config.attachment Issue and PR attachment configuration + attachment: {} + + ## @param gitea.config.log Logging configuration + log: {} + + ## @param gitea.config.cron Cron job configuration + cron: {} + + ## @param gitea.config.git Global settings for Git + git: {} + + ## @param gitea.config.metrics Settings for the Prometheus endpoint (disabled by default) + metrics: {} + + ## @param gitea.config.api Settings for the Swagger API documentation endpoints + api: {} + + ## @param gitea.config.oauth2 Settings for the [OAuth2 provider](https://forgejo.org/docs/latest/admin/oauth2-provider/) + oauth2: {} + + ## @param gitea.config.i18n Internationalization settings + i18n: {} + + ## @param gitea.config.markup Configuration for advanced markup processors + markup: {} + + ## @param gitea.config.highlight.mapping File extension to language mapping overrides for syntax highlighting + highlight.mapping: {} + + ## @param gitea.config.time Locale settings + time: {} + + ## @param gitea.config.migrations Settings for Git repository migrations + migrations: {} + + ## @param gitea.config.federation Federation configuration + federation: {} + + ## @param gitea.config.packages Package registry settings + packages: {} + + ## @param gitea.config.mirror Configuration for repository mirroring + mirror: {} + + ## @param gitea.config.lfs Large File Storage configuration + lfs: {} + + ## @param gitea.config.repo-avatar Repository avatar storage configuration + repo-avatar: {} + + ## @param gitea.config.avatar User/org avatar storage configuration + avatar: {} + + ## @param gitea.config.storage General storage settings + storage: {} + + ## @param gitea.config.proxy Proxy configuration (disabled by default) + proxy: {} + + ## @param gitea.config.actions Configuration for [Forgejo Actions](https://forgejo.org/docs/latest/user/actions/) + actions: {} + + ## @param gitea.config.other Uncategorized configuration options + other: {} + ## @section LivenessProbe # ## @param gitea.livenessProbe.enabled Enable liveness probe @@ -366,7 +633,8 @@ gitea: ## @section ReadinessProbe # ## @param gitea.readinessProbe.enabled Enable readiness probe - ## @param gitea.readinessProbe.tcpSocket.port Port to probe for readiness + ## @param gitea.readinessProbe.httpGet.path Path to probe for readiness + ## @param gitea.readinessProbe.httpGet.port Port to probe for readiness ## @param gitea.readinessProbe.initialDelaySeconds Initial delay before readiness probe is initiated ## @param gitea.readinessProbe.timeoutSeconds Timeout for readiness probe ## @param gitea.readinessProbe.periodSeconds Period for readiness probe @@ -375,7 +643,8 @@ gitea: # Modify the readiness probe for your needs or completely disable it by commenting out. readinessProbe: enabled: true - tcpSocket: + httpGet: + path: /api/healthz port: http initialDelaySeconds: 5 timeoutSeconds: 1 @@ -403,101 +672,121 @@ gitea: successThreshold: 1 failureThreshold: 10 -## @section Memcached +## @section Redis® Cluster ## @descriptionStart -## Memcached is loaded as a dependency from [Bitnami](https://github.com/bitnami/charts/tree/master/bitnami/memcached) if enabled in the values. Complete Configuration can be taken from their website. +## Redis® Cluster is loaded as a dependency from [Bitnami](https://github.com/bitnami/charts/tree/master/bitnami/redis-cluster) if enabled in the values. +## Full configuration options are available on their website. +## Redis cluster and [Redis](#redis) cannot be enabled at the same time. ## @descriptionEnd # -## @param memcached.enabled Enable Memcached -## @param memcached.service.ports.memcached Port for Memcached -memcached: +## @param redis-cluster.enabled Enable redis cluster +## @param redis-cluster.usePassword Whether to use password authentication +## @param redis-cluster.cluster.nodes Number of redis cluster master nodes +## @param redis-cluster.cluster.replicas Number of redis cluster master node replicas +redis-cluster: enabled: true + usePassword: false + cluster: + nodes: 3 # default: 6 + replicas: 0 # default: 1 + +## @section Redis® +## @descriptionStart +## Redis® is loaded as a dependency from [Bitnami](https://github.com/bitnami/charts/tree/master/bitnami/redis) if enabled in the values. +## Full configuration options are available on their website. +## Redis and [Redis cluster](#redis-cluster) cannot be enabled at the same time. +## @descriptionEnd +# +## @param redis.enabled Enable redis standalone or replicated +## @param redis.architecture Whether to use standalone or replication +## @param redis.global.redis.password Required password +## @param redis.master.count Number of Redis master instances to deploy +redis: + enabled: false + architecture: standalone + global: + redis: + password: changeme + master: + count: 1 + +## @section PostgreSQL HA +## @descriptionStart +## PostgreSQL HA is loaded as a dependency from [Bitnami](https://github.com/bitnami/charts/tree/master/bitnami/postgresql-ha) if enabled in the values. +## Full configuration options are available on their website. +## @descriptionEnd +# +## @param postgresql-ha.enabled Enable PostgreSQL HA chart +## @param postgresql-ha.postgresql.password Password for the `gitea` user (overrides `auth.password`) +## @param postgresql-ha.global.postgresql.database Name for a custom database to create (overrides `auth.database`) +## @param postgresql-ha.global.postgresql.username Name for a custom user to create (overrides `auth.username`) +## @param postgresql-ha.global.postgresql.password Name for a custom password to create (overrides `auth.password`) +## @param postgresql-ha.postgresql.repmgrPassword Repmgr Password +## @param postgresql-ha.postgresql.postgresPassword postgres Password +## @param postgresql-ha.pgpool.adminPassword pgpool adminPassword +## @param postgresql-ha.service.ports.postgresql PostgreSQL service port (overrides `service.ports.postgresql`) +## @param postgresql-ha.primary.persistence.size PVC Storage Request for PostgreSQL HA volume +postgresql-ha: + global: + postgresql: + database: gitea + password: gitea + username: gitea + enabled: true + postgresql: + repmgrPassword: changeme2 + postgresPassword: changeme1 + password: changeme4 + pgpool: + adminPassword: changeme3 service: ports: - memcached: 11211 + postgresql: 5432 + primary: + persistence: + size: 10Gi ## @section PostgreSQL ## @descriptionStart -## PostgreSQL is loaded as a dependency from [Bitnami](https://github.com/bitnami/charts/tree/master/bitnami/postgresql) if enabled in the values. Complete Configuration can be taken from their website. +## PostgreSQL is loaded as a dependency from [Bitnami](https://github.com/bitnami/charts/tree/master/bitnami/postgresql) if enabled in the values. +## Full configuration options are available on their website. ## @descriptionEnd # ## @param postgresql.enabled Enable PostgreSQL -## @param postgresql.auth.database PostgreSQL database -## @param postgresql.auth.username PostgreSQL username -## @param postgresql.auth.password PostgreSQL username -## @param postgresql.auth.postgresPassword PostgreSQL admin password -## @param postgresql.primary.service.ports.postgresql Port to connect to PostgreSQL service +## @param postgresql.global.postgresql.auth.password Password for the `gitea` user (overrides `auth.password`) +## @param postgresql.global.postgresql.auth.database Name for a custom database to create (overrides `auth.database`) +## @param postgresql.global.postgresql.auth.username Name for a custom user to create (overrides `auth.username`) +## @param postgresql.global.postgresql.service.ports.postgresql PostgreSQL service port (overrides `service.ports.postgresql`) ## @param postgresql.primary.persistence.size PVC Storage Request for PostgreSQL volume postgresql: - enabled: true - auth: - database: gitea - username: gitea - password: gitea - postgresPassword: gitea - primary: - service: - ports: - postgresql: 5432 - persistence: - size: 10Gi - -## @section MySQL -## @descriptionStart -## MySQL is loaded as a dependency from [Bitnami](https://github.com/bitnami/charts/tree/master/bitnami/mysql) if enabled in the values. Complete Configuration can be taken from their website. -## @descriptionEnd -# -# -## @param mysql.enabled Enable MySQL -## @param mysql.auth.database Name for new database to create. -## @param mysql.auth.username Username of new user to create. -## @param mysql.auth.password Password for the new user.Ignored if existing secret is provided -## @param mysql.auth.rootPassword Password for the root user. Ignored if existing secret is provided -## @param mysql.primary.service.ports.mysql Port to connect to MySQL service -## @param mysql.primary.persistence.size PVC Storage Request for MySQL volume -mysql: enabled: false - auth: - database: gitea - username: gitea - password: gitea - rootPassword: gitea + global: + postgresql: + auth: + password: gitea + database: gitea + username: gitea + service: + ports: + postgresql: 5432 primary: - service: - ports: - mysql: 3306 - persistence: - size: 10Gi - -## @section MariaDB -## @descriptionStart -## MariaDB is loaded as a dependency from [Bitnami](https://github.com/bitnami/charts/tree/master/bitnami/mariadb) if enabled in the values. Complete Configuration can be taken from their website. -## @descriptionEnd -# -# -## @param mariadb.enabled Enable MariaDB -## @param mariadb.auth.database Name of the database to create. -## @param mariadb.auth.username Username of the new user to create. -## @param mariadb.auth.password Password for the new user. Ignored if existing secret is provided -## @param mariadb.auth.rootPassword Password for the root user. -## @param mariadb.primary.service.ports.mysql Port to connect to MariaDB service -## @param mariadb.primary.persistence.size Persistence size for MariaDB -mariadb: - enabled: false - auth: - database: gitea - username: gitea - password: gitea - rootPassword: gitea - primary: - service: - ports: - mysql: 3306 persistence: size: 10Gi # By default, removed or moved settings that still remain in a user defined values.yaml will cause Helm to fail running the install/update. # Set it to false to skip this basic validation check. ## @section Advanced -## @param checkDeprecation Set it to false to skip this basic validation check. +## @param checkDeprecation Whether to run this basic validation check. +## @param test.enabled Whether to use test-connection Pod. +## @param test.image.name Image name for the wget container used in the test-connection Pod. +## @param test.image.tag Image tag for the wget container used in the test-connection Pod. checkDeprecation: true +test: + enabled: true + image: + name: busybox + tag: latest + +## @param extraDeploy Array of extra objects to deploy with the release. +## +extraDeploy: []