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-node/action.yml b/.forgejo/actions/setup-node/action.yml new file mode 100644 index 0000000..ad112e3 --- /dev/null +++ b/.forgejo/actions/setup-node/action.yml @@ -0,0 +1,13 @@ +# action.yml +name: setup-node +description: 'setup node' + +runs: + using: 'composite' + steps: + - uses: actions/setup-node@v4 + with: + node-version-file: .node-version + cache: 'npm' + - shell: bash + run: npm ci diff --git a/.forgejo/actions/setup/action.yml b/.forgejo/actions/setup/action.yml new file mode 100644 index 0000000..01afeaf --- /dev/null +++ b/.forgejo/actions/setup/action.yml @@ -0,0 +1,26 @@ +# 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 \ + ; diff --git a/.forgejo/workflows/build.yml b/.forgejo/workflows/build.yml new file mode 100644 index 0000000..23b44a4 --- /dev/null +++ b/.forgejo/workflows/build.yml @@ -0,0 +1,178 @@ +name: build + +on: + pull_request: + push: + branches: + - main + - release/** + tags: + - v* + +permissions: + contents: read + +env: + HELM_VERSION: v3.11.2 # renovate: datasource=github-releases depName=helm packageName=helm/helm + HELM_UNITTEST_VERSION: v0.3.6 # renovate: datasource=github-releases depName=helm-unittest packageName=helm-unittest/helm-unittest + HELM_CHART_TESTING_VERSION: v3.10.1 # renovate: datasource=github-releases depName=chart-testing packageName=helm/chart-testing + KIND_VERSION: v0.20.0 # renovate: datasource=github-releases depName=kind packageName=kubernetes-sigs/kind + KUBECTL_VERSION: v1.28.0 # renovate: datasource=github-releases depName=kubectl packageName=kubernetes/kubernetes + +jobs: + lint-node: + runs-on: docker + steps: + - run: cat /etc/os-release + + - uses: actions/checkout@v4 + with: + show-progress: false + + - uses: ./.forgejo/actions/setup + - uses: ./.forgejo/actions/setup-node + + - run: npm run prettier + - run: npx markdownlint-cli . + - run: make readme + - run: git diff --exit-code --name-only README.md + + lint-helm: + runs-on: docker + steps: + - run: cat /etc/os-release + + - run: ps axf + + - uses: actions/checkout@v4 + with: + show-progress: false + fetch-depth: 0 + + - uses: ./.forgejo/actions/setup + + - name: install chart-testing + uses: helm/chart-testing-action@e6669bcd63d7cb57cb4380c33043eebe5d111992 # v2.6.1 + with: + version: ${{ env.HELM_CHART_TESTING_VERSION }} + + - name: install helm + uses: azure/setup-helm@5119fcb9089d432beecbf79bb2c7915207344b78 # v3.5 + 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: + runs-on: k8s + + strategy: + matrix: + k8s: + # from https://hub.docker.com/r/kindest/node/tags + # - v1.25.3 # renovate: kindest + - v1.28.0 # renovate: kindest + + steps: + - run: cat /etc/os-release + + - uses: actions/checkout@v4 + with: + show-progress: false + fetch-depth: 0 + + - uses: ./.forgejo/actions/setup + + - name: install helm + uses: azure/setup-helm@5119fcb9089d432beecbf79bb2c7915207344b78 # v3.5 + with: + version: ${{ env.HELM_VERSION }} + + - name: Install chart-testing + # TODO: pin to version when this is released: https://github.com/helm/chart-testing-action/pull/137 + uses: helm/chart-testing-action@86b540ddcecb3cc009fa2bc0f44fa5b33e9751a2 # main + with: + version: ${{ env.HELM_CHART_TESTING_VERSION }} + + - uses: ./.forgejo/actions/setup-docker + + - name: Create kind cluster + uses: helm/kind-action@dda0770415bac9fc20092cacbc54aa298604d140 # v1.8.0 + with: + node_image: kindest/node:${{ matrix.k8s }} + kubectl_version: ${{ env.KUBECTL_VERSION }} + version: ${{ env.KIND_VERSION }} + + - run: kubectl get no -o wide + + - name: install chart + run: 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@v4 + with: + show-progress: false + + - uses: ./.forgejo/actions/setup + - uses: ./.forgejo/actions/setup-node + + - name: install helm + uses: https://github.com/azure/setup-helm@5119fcb9089d432beecbf79bb2c7915207344b78 # v3.5 + with: + version: v3.13.2 # renovate: datasource=github-releases depName=helm packageName=helm/helm + + - run: helm dependency build + - run: helm package --version "${GITHUB_REF_NAME#v}" -d tmp/ ./ + + - name: login to codeberg packages + run: echo ${TOKEN} | helm registry login -u viceice --password-stdin codeberg.org/forgejo-contrib + env: + TOKEN: ${{secrets.token}} + + - name: publish forgejo helm chart + run: helm push tmp/forgejo-${GITHUB_REF_NAME#v}.tgz oci://codeberg.org/forgejo-contrib + + - name: publish forgejo release + run: npm run forgejo:release diff --git a/.node-version b/.node-version new file mode 100644 index 0000000..d5a1596 --- /dev/null +++ b/.node-version @@ -0,0 +1 @@ +20.10.0 diff --git a/.vscode/settings.json b/.vscode/settings.json index 93bb0e3..2133edb 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,9 @@ { "yaml.schemas": { + "https://json.schemastore.org/github-workflow.json": [ + ".github/workflows/*", + ".forgejo/workflows/*" + ], "https://raw.githubusercontent.com/helm-unittest/helm-unittest/v0.3.6/schema/helm-testsuite.json": [ "/unittests/**/*.yaml" ] diff --git a/.woodpecker/e2e.yml b/.woodpecker/e2e.yml deleted file mode 100644 index 36dcfc1..0000000 --- a/.woodpecker/e2e.yml +++ /dev/null @@ -1,49 +0,0 @@ -platform: linux/amd64 - -when: - event: - - pull_request - - push - - tag - branch: - - main - - release/** - -services: - docker: - image: docker:24.0.7-dind - pull: true - environment: - DOCKER_TLS_CERTDIR: '' - -matrix: - k8s: - # from https://hub.docker.com/r/kindest/node/tags - # - v1.25.3 # renovate: kindest - - v1.28.0 # renovate: kindest - -pipeline: - create-cluster: - image: alpine:3.18.5 - pull: true - environment: - DOCKER_HOST: tcp://docker:2375 - commands: - - apk add docker-cli kind - - export KUBECONFIG=$${CI_WORKSPACE}/kube.config - - sleep 15s - - docker info - - kind create cluster --config e2e/kind.cluster.yml --image kindest/node:${k8s} --wait 1m - - kind get clusters - - docker ps - # replace localhost or 0.0.0.0 in the kubeconfig file with "docker", in order to be able to reach the cluster through the docker service - - sed -i -E -e 's/localhost|0\.0\.0\.0/docker/g' $${KUBECONFIG} - - ct-install: - image: quay.io/helmpack/chart-testing:v3.10.1 - pull: true - commands: - - git fetch --no-tags --filter=blob:none origin - - export KUBECONFIG=$${CI_WORKSPACE}/kube.config - - kubectl get no -o wide - - ct install --config tools/ct.yml --charts . diff --git a/.woodpecker/lint.yml b/.woodpecker/lint.yml deleted file mode 100644 index 85af536..0000000 --- a/.woodpecker/lint.yml +++ /dev/null @@ -1,71 +0,0 @@ -platform: linux/amd64 - -when: - event: - - pull_request - - tag - - push - branch: - - main - - release/** - -pipeline: - prettier: - image: alpine:3.18.5 - pull: true - commands: - - apk add nodejs npm - - npm ci - - npm run prettier - - npx markdownlint-cli . - - deps: - image: alpine:3.18.5 - pull: true - commands: - - apk add helm - - helm dependency build - - helm-lint: - image: alpine:3.18.5 - pull: true - commands: - - apk add helm - - helm lint - - helm-template: - image: alpine:3.18.5 - pull: true - commands: - - apk add helm - - helm template --debug gitea-helm . - - helm-unittests: - image: alpine:3.18.5 - pull: true - commands: - - apk add make helm git bash - - helm plugin install --version v0.3.6 https://github.com/helm-unittest/helm-unittest - - helm dependency update - - make unittests - - verify-readme: - image: alpine:3.18.5 - pull: true - commands: - - apk add make nodejs npm git - - make readme - - git diff --exit-code --name-only README.md - - yaml-lint: - image: quay.io/helmpack/chart-testing:v3.10.1 - pull: true - commands: - - yamllint -f colored . - - ct-lint: - image: quay.io/helmpack/chart-testing:v3.10.1 - pull: true - commands: - - git fetch --no-tags --filter=blob:none origin - - ct lint --config tools/ct.yml --charts . diff --git a/.woodpecker/release-version.yml b/.woodpecker/release-version.yml deleted file mode 100644 index 382808e..0000000 --- a/.woodpecker/release-version.yml +++ /dev/null @@ -1,47 +0,0 @@ -platform: linux/amd64 - -depends_on: - - lint - - e2e - -when: - event: - - tag - tag: v* - -pipeline: - generate-chart: - image: alpine:3.18.5 - pull: true - commands: - - apk add git nodejs npm helm - - 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: codeberg.org/woodpecker-plugins/gitea-release:0.3.1 - 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 - target: main - - publish-chart: - image: alpine:3.18.5 - pull: true - commands: - - apk add 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/package-lock.json b/package-lock.json index ddb04ba..f6e49c1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "license": "MIT", "devDependencies": { "@bitnami/readme-generator-for-helm": "^2.4.2", + "clipanion": "^3.2.1", "conventional-changelog-conventionalcommits": "^7.0.0", "conventional-changelog-core": "^7.0.0", "husky": "^8.0.3", @@ -279,6 +280,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/clipanion": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/clipanion/-/clipanion-3.2.1.tgz", + "integrity": "sha512-dYFdjLb7y1ajfxQopN05mylEpK9ZX0sO1/RfMXdfmwjlIsPkbh4p7A682x++zFPLDCo1x3p82dtljHf5cW2LKA==", + "dev": true, + "dependencies": { + "typanion": "^3.8.0" + }, + "peerDependencies": { + "typanion": "*" + } + }, "node_modules/color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -2116,6 +2129,12 @@ "node": ">=8.0" } }, + "node_modules/typanion": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/typanion/-/typanion-3.14.0.tgz", + "integrity": "sha512-ZW/lVMRabETuYCd9O9ZvMhAh8GslSqaUjxmK/JLPCh6l73CvLBiuXswj/+7LdnWOgYsQ130FqLzFz5aGT4I3Ug==", + "dev": true + }, "node_modules/type-fest": { "version": "4.8.3", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.8.3.tgz", diff --git a/package.json b/package.json index 2d4e648..6b78d64 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ }, "scripts": { "changelog": "node tools/changelog.mjs", + "forgejo:release": "node tools/gitea-release.js", "prepare": "husky install", "prettier": "prettier --check --ignore-unknown --cache \"**/*.*\"", "prettier-fix": "prettier --write --ignore-unknown --cache \"**/*.*\"", @@ -18,6 +19,7 @@ }, "devDependencies": { "@bitnami/readme-generator-for-helm": "^2.4.2", + "clipanion": "^3.2.1", "conventional-changelog-conventionalcommits": "^7.0.0", "conventional-changelog-core": "^7.0.0", "husky": "^8.0.3", diff --git a/renovate.json b/renovate.json index a2ed136..2fae018 100644 --- a/renovate.json +++ b/renovate.json @@ -38,6 +38,18 @@ "matchManagers": ["npm"], "matchDepTypes": ["devDependencies"], "automerge": true + }, + { + "description": "Separate minor and patch updates for kindest", + "matchPackageNames": ["kindest/node"], + "separateMinorPatch": true + }, + { + "description": "Require approval and no automerge for kindest major and minor updates", + "matchPackageNames": ["kindest/node"], + "matchUpdateTypes": ["major", "minor"], + "dependencyDashboardApproval": true, + "automerge": false } ], "customManagers": [ @@ -69,6 +81,16 @@ "https:\\/\\/raw\\.githubusercontent\\.com\\/(?[^\\s]+?)\\/(?v[0-9.]+?)\\/schema\\/helm-testsuite\\.json" ], "datasourceTemplate": "github-releases" + }, + { + "customType": "regex", + "description": "Update kindest kubernetes references", + "fileMatch": ["^\\.forgejo\\/workflows\\/[^/]+\\.ya?ml$"], + "matchStrings": [ + " +- (?v\\d+\\.\\d+\\.\\d+) # renovate: kindest\\n" + ], + "depNameTemplate": "kindest/node", + "datasourceTemplate": "docker" } ] } diff --git a/tools/changelog/util.js b/tools/changelog/util.js new file mode 100644 index 0000000..987b87f --- /dev/null +++ b/tools/changelog/util.js @@ -0,0 +1,78 @@ +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: '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', + }, + ], +}); + +/** + * + * @param {string} version + * @param {boolean} onTag + * @returns + */ +export function getChangelog(version, onTag) { + return conventionalChangelogCore( + { + config, + releaseCount: onTag ? 2 : 1, + }, + { version, linkCompare: false }, + undefined, + undefined, + { headerPartial: '' }, + ); +} diff --git a/tools/ct.yml b/tools/ct.yml index 044539c..66fa900 100644 --- a/tools/ct.yml +++ b/tools/ct.yml @@ -1,4 +1,4 @@ -# helm-extra-args: --timeout 600s +helm-extra-args: --timeout 600s check-version-increment: false debug: true target-branch: main diff --git a/tools/forgejo-release.js b/tools/forgejo-release.js new file mode 100644 index 0000000..a9cb6ab --- /dev/null +++ b/tools/forgejo-release.js @@ -0,0 +1,83 @@ +import { Command, runExit } from 'clipanion'; +import { getChangelog } from './changelog/util.js'; + +const api = 'https://https://codeberg.org/api/v1'; +const repo = 'forgejo-contrib/forgejo-helm'; + +class GiteaReleaseCommand extends Command { + async execute() { + const token = process.env.GITHUB_TOKEN; + + if (!token) { + this.context.stdout.write('GITHUB_TOKEN environment variable not set.\n'); + return 1; + } + + this.context.stdout.write(`Getting tag.\n`); + const tag = process.env.GITHUB_REF_NAME; + + if (!tag) { + this.context.stdout.write( + 'No tag found for this commit. Please tag the commit and try again.\n', + ); + return 1; + } + + 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(tag, 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" +}