diff --git a/.gitea/PULL_REQUEST_TEMPLATE.md b/.gitea/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..3f1a225 --- /dev/null +++ b/.gitea/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,44 @@ + + +### 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` +- [ ] Helm templating unittests are added (required when changing anything in `templates` folder) +- [ ] Bash unittests are added (required when changing anything in `scripts` folder) +- [ ] All added template resources MUST render a namespace in metadata diff --git a/.gitea/workflows/changelog.yml b/.gitea/workflows/changelog.yml new file mode 100644 index 0000000..585c117 --- /dev/null +++ b/.gitea/workflows/changelog.yml @@ -0,0 +1,32 @@ +name: changelog + +on: + push: + branches: + - main + +jobs: + changelog: + runs-on: ubuntu-latest + container: docker.io/thegeeklab/git-sv:1.0.12 + steps: + - name: install tools + run: | + apk add -q --update --no-cache nodejs curl jq sed + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Generate upcoming changelog + run: | + git sv rn -o changelog.md + export RELEASE_NOTES=$(cat changelog.md) + export ISSUE_NUMBER=$(curl -s "https://gitea.com/api/v1/repos/gitea/helm-actions/issues?state=open&q=Changelog%20for%20upcoming%20version" | jq '.[].number') + + echo $RELEASE_NOTES + JSON_DATA=$(echo "" | jq -Rs --arg title 'Changelog for upcoming version' --arg body "$(cat changelog.md)" '{title: $title, body: $body}') + + if [ -z "$ISSUE_NUMBER" ]; then + curl -s -X POST "https://gitea.com/api/v1/repos/gitea/helm-actions/issues" -H "Authorization: token ${{ secrets.ISSUE_RW_TOKEN }}" -H "Content-Type: application/json" -d "$JSON_DATA" + else + curl -s -X PATCH "https://gitea.com/api/v1/repos/gitea/helm-actions/issues/$ISSUE_NUMBER" -H "Authorization: token ${{ secrets.ISSUE_RW_TOKEN }}" -H "Content-Type: application/json" -d "$JSON_DATA" + fi diff --git a/.gitea/workflows/commitlint.yml b/.gitea/workflows/commitlint.yml new file mode 100644 index 0000000..b52cc38 --- /dev/null +++ b/.gitea/workflows/commitlint.yml @@ -0,0 +1,19 @@ +name: commitlint + +on: + pull_request: + branches: + - "*" + types: + - opened + - edited + +jobs: + check-and-test: + runs-on: ubuntu-latest + container: commitlint/commitlint:19.7.1 + steps: + - uses: actions/checkout@v4 + - name: check PR title + run: | + echo "${{ gitea.event.pull_request.title }}" | commitlint --config .commitlintrc.json diff --git a/.gitea/workflows/release-version.yml b/.gitea/workflows/release-version.yml new file mode 100644 index 0000000..974c5c0 --- /dev/null +++ b/.gitea/workflows/release-version.yml @@ -0,0 +1,70 @@ +name: generate-chart + +on: + push: + tags: + - "*" + +env: + # renovate: datasource=docker depName=alpine/helm + HELM_VERSION: "3.17.1" + +jobs: + generate-chart-publish: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: install tools + run: | + apt update -y + apt install -y curl ca-certificates curl gnupg + # helm + curl -O https://get.helm.sh/helm-v${{ env.HELM_VERSION }}-linux-amd64.tar.gz + tar -xzf helm-v${{ env.HELM_VERSION }}-linux-amd64.tar.gz + mv linux-amd64/helm /usr/local/bin/ + rm -rf linux-amd64 helm-v${{ env.HELM_VERSION }}-linux-amd64.tar.gz + helm version + # docker + install -m 0755 -d /etc/apt/keyrings + curl -fsSL https://download.docker.com/linux/ubuntu/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/ubuntu "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null + apt update -y + apt install -y python3 python3-pip apt-transport-https docker-ce-cli + pip install awscli --break-system-packages + + - name: Import GPG key + id: import_gpg + uses: https://github.com/crazy-max/ghaction-import-gpg@v6 + with: + gpg_private_key: ${{ secrets.GPGSIGN_KEY }} + passphrase: ${{ secrets.GPGSIGN_PASSPHRASE }} + fingerprint: CC64B1DB67ABBEECAB24B6455FC346329753F4B0 + + # Using helm gpg plugin as 'helm package --sign' has issues with gpg2: https://github.com/helm/helm/issues/2843 + - name: package chart + run: | + echo ${{ secrets.DOCKER_CHARTS_PASSWORD }} | docker login -u ${{ secrets.DOCKER_CHARTS_USERNAME }} --password-stdin + # FIXME: use upstream after https://github.com/technosophos/helm-gpg/issues/1 is solved + helm plugin install https://github.com/pat-s/helm-gpg + helm dependency build + helm package --version "${GITHUB_REF#refs/tags/v}" ./ + mkdir actions + mv actions*.tgz actions/ + curl -s -L -o actions/index.yaml https://dl.gitea.com/charts/index.yaml + helm repo index actions/ --url https://dl.gitea.com/charts --merge actions/index.yaml + # push to dockerhub + echo ${{ secrets.DOCKER_CHARTS_PASSWORD }} | helm registry login -u ${{ secrets.DOCKER_CHARTS_USERNAME }} registry-1.docker.io --password-stdin + helm push actions/actions-${GITHUB_REF#refs/tags/v}.tgz oci://registry-1.docker.io/giteacharts + helm registry logout registry-1.docker.io + + - name: aws credential configure + uses: https://github.com/aws-actions/configure-aws-credentials@v4 + with: + aws-access-key-id: ${{ secrets.AWS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ secrets.AWS_REGION }} + + - name: Copy files to S3 and clear cache + run: | + aws s3 sync actions/ s3://${{ secrets.AWS_S3_BUCKET}}/charts/ diff --git a/.gitea/workflows/test-pr.yml b/.gitea/workflows/test-pr.yml new file mode 100644 index 0000000..af88695 --- /dev/null +++ b/.gitea/workflows/test-pr.yml @@ -0,0 +1,45 @@ +name: check-and-test + +on: + pull_request: + branches: + - "*" + push: + branches: + - main + +env: + # renovate: datasource=github-releases depName=helm-unittest/helm-unittest + HELM_UNITTEST_VERSION: "v0.7.2" + +jobs: + check-and-test: + runs-on: ubuntu-latest + container: alpine/helm:3.17.1 + steps: + - name: install tools + run: | + apk update + apk add --update bash make nodejs npm yamllint ncurses + - uses: actions/checkout@v4 + - name: install chart dependencies + run: helm dependency build + - name: lint + run: helm lint + - name: template + run: helm template --debug gitea-actions . + - name: prepare unit test environment + run: | + helm plugin install --version ${{ env.HELM_UNITTEST_VERSION }} https://github.com/helm-unittest/helm-unittest + git submodule update --init --recursive + - name: unit tests + env: + TERM: xterm + run: | + make unittests + - name: verify readme + run: | + make readme + git diff --exit-code --name-only README.md + - name: yaml lint + uses: https://github.com/ibiqlik/action-yamllint@v3 diff --git a/Chart.yaml b/Chart.yaml index e8f14fe..2b47a38 100644 --- a/Chart.yaml +++ b/Chart.yaml @@ -1,36 +1,20 @@ apiVersion: v2 -name: gitea -description: Gitea Helm chart for Kubernetes +name: actions +description: Gitea Actions chart for Kubernetes type: application version: 0.0.0 -# renovate datasource=github-releases depName=go-gitea/gitea extractVersion=^v(?.*)$ -appVersion: 1.23.5 -icon: https://gitea.com/assets/img/logo.svg +# renovate datasource=github-releases depName=go-gitea/act extractVersion=^v(?.*)$ +appVersion: 0.261.3 keywords: - - git - - issue tracker - - code review - - wiki - - gitea - - gogs + - cicd + - runner + - actions sources: - - https://gitea.com/gitea/helm-chart - - https://github.com/go-gitea/gitea - - https://hub.docker.com/r/gitea/gitea/ -maintainers: - - name: Charlie Drage - email: charlie@charliedrage.com - - name: Gitea Authors - email: maintainers@gitea.io - - name: Konrad Lother - email: konrad.lother@novum-rgi.de - - name: Lucas Hahn - email: lucas.hahn@novum-rgi.de - - name: Steven Kriegler - email: sk.bunsenbrenner@gmail.com - - name: Patrick Schratz - email: patrick.schratz@gmail.com + - https://gitea.com/gitea/helm-actions + - https://gitea.com/gitea/act +# FIXME: +# maintainers: dependencies: # https://github.com/bitnami/charts/blob/main/bitnami/postgresql diff --git a/templates/01-consistency-checks.yaml b/templates/01-consistency-checks.yaml new file mode 100644 index 0000000..25ae556 --- /dev/null +++ b/templates/01-consistency-checks.yaml @@ -0,0 +1,15 @@ +{{- if .Values.actions.enabled -}} + {{- if .Values.actions.provisioning.enabled -}} + {{- if not (and .Values.persistence.enabled .Values.persistence.mount) -}} + {{- fail "persistence.enabled and persistence.mount are required when provisioning is enabled" -}} + {{- end -}} + {{- if and .Values.persistence.enabled .Values.persistence.mount -}} + {{- if .Values.actions.existingSecret -}} + {{- fail "Can't specify both actions.provisioning.enabled and actions.existingSecret" -}} + {{- end -}} + {{- end -}} + {{- end -}} + {{- if and (not .Values.actions.provisioning.enabled) (or (empty .Values.actions.existingSecret) (empty .Values.actions.existingSecretKey)) -}} + {{- fail "actions.existingSecret and actions.existingSecretKey are required when provisioning is disabled" -}} + {{- end -}} +{{- end -}} diff --git a/templates/config-act-runner.yaml b/templates/config-act-runner.yaml new file mode 100644 index 0000000..433fb69 --- /dev/null +++ b/templates/config-act-runner.yaml @@ -0,0 +1,15 @@ +{{- if .Values.actions.enabled }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "gitea.fullname" . }}-act-runner-config + namespace: {{ .Values.namespace | default .Release.Namespace }} + labels: + {{- include "gitea.labels" . | nindent 4 }} +data: + config.yaml: | + {{- with .Values.actions.statefulset.actRunner.config -}} + {{ . | nindent 4}} + {{- end -}} +{{- end }} diff --git a/templates/config-scripts.yaml b/templates/config-scripts.yaml new file mode 100644 index 0000000..5c47763 --- /dev/null +++ b/templates/config-scripts.yaml @@ -0,0 +1,14 @@ +{{- if .Values.actions.enabled }} +{{- if and (and .Values.actions.provisioning.enabled .Values.persistence.enabled) .Values.persistence.mount }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "gitea.fullname" . }}-scripts + namespace: {{ .Values.namespace | default .Release.Namespace }} + labels: + {{- include "gitea.labels" . | nindent 4 }} +data: +{{ (.Files.Glob "scripts/act_runner/*.sh").AsConfig | indent 2 }} +{{- end }} +{{- end }} diff --git a/templates/job.yaml b/templates/job.yaml new file mode 100644 index 0000000..777eb77 --- /dev/null +++ b/templates/job.yaml @@ -0,0 +1,115 @@ +{{- if .Values.actions.enabled }} +{{- if and (and .Values.actions.provisioning.enabled .Values.persistence.enabled) .Values.persistence.mount }} +{{- $name := include "gitea.workername" (dict "global" . "worker" "actions-token-job") }} +{{- $secretName := include "gitea.workername" (dict "global" . "worker" "actions-token") }} +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ $name }} + namespace: {{ .Values.namespace | default .Release.Namespace }} + labels: + {{- include "gitea.labels" . | nindent 4 }} + {{- with .Values.actions.provisioning.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + app.kubernetes.io/component: token-job + annotations: + {{- with .Values.actions.provisioning.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + ttlSecondsAfterFinished: {{ .Values.actions.provisioning.ttlSecondsAfterFinished }} + template: + metadata: + labels: + {{- include "gitea.labels" . | nindent 8 }} + {{- with .Values.actions.provisioning.labels }} + {{- toYaml . | nindent 8 }} + {{- end }} + app.kubernetes.io/component: token-job + spec: + initContainers: + - name: init-gitea + image: "{{ .Values.actions.init.image.repository }}:{{ .Values.actions.init.image.tag }}" + command: + - sh + - -c + - | + while ! nc -z {{ include "gitea.fullname" . }}-http {{ .Values.service.http.port }}; do + sleep 5 + done + containers: + - name: actions-token-create + image: "{{ include "gitea.image" . }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + env: + - name: GITEA_APP_INI + value: /data/gitea/conf/app.ini + command: + - sh + - -c + - | + echo "Generating act_runner token via 'gitea actions generate-runner-token'..." + mkdir -p /data/actions/ + gitea actions generate-runner-token | grep -E '^.{40}$' | tr -d '\n' > /data/actions/token + resources: + {{- toYaml .Values.actions.provisioning.resources | nindent 12 }} + volumeMounts: + - name: data + mountPath: /data + {{- if .Values.persistence.subPath }} + subPath: {{ .Values.persistence.subPath }} + {{- end }} + - name: actions-token-upload + image: "{{ .Values.actions.provisioning.publish.repository }}:{{ .Values.actions.provisioning.publish.tag }}" + imagePullPolicy: {{ .Values.actions.provisioning.publish.pullPolicy }} + env: + - name: SECRET_NAME + value: {{ $secretName }} + command: + - sh + - -c + - | + printf "Checking rights to update kubernetes act_runner secret..." + kubectl auth can-i update secret/${SECRET_NAME} + /scripts/token.sh + resources: + {{- toYaml .Values.actions.provisioning.resources | nindent 12 }} + volumeMounts: + - mountPath: /scripts + name: scripts + readOnly: true + - mountPath: /data + name: data + readOnly: true + {{- if .Values.persistence.subPath }} + subPath: {{ .Values.persistence.subPath }} + {{- end }} + {{- range $key, $value := .Values.actions.provisioning.nodeSelector }} + nodeSelector: + {{ $key }}: {{ $value | quote }} + {{- end }} + {{- with .Values.actions.provisioning.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.actions.provisioning.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + restartPolicy: Never + serviceAccount: {{ $name }} + volumes: + - name: scripts + configMap: + name: {{ include "gitea.fullname" . }}-scripts + defaultMode: 0755 + - name: data + persistentVolumeClaim: + claimName: {{ .Values.persistence.claimName }} + parallelism: 1 + completions: 1 + backoffLimit: 1 +{{- end }} +{{- end }} diff --git a/templates/role-job.yaml b/templates/role-job.yaml new file mode 100644 index 0000000..c2afa57 --- /dev/null +++ b/templates/role-job.yaml @@ -0,0 +1,26 @@ +{{- if .Values.actions.enabled }} +{{- if and (and .Values.actions.provisioning.enabled .Values.persistence.enabled) .Values.persistence.mount }} +{{- $name := include "gitea.workername" (dict "global" . "worker" "actions-token-job") }} +{{- $secretName := include "gitea.workername" (dict "global" . "worker" "actions-token") }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ $name }} + namespace: {{ .Values.namespace | default .Release.Namespace }} + labels: + {{- include "gitea.labels" . | nindent 4 }} + app.kubernetes.io/component: token-job +rules: + - apiGroups: + - "" + resources: + - secrets + resourceNames: + - {{ $secretName }} + verbs: + - get + - update + - patch +{{- end }} +{{- end }} diff --git a/templates/rolebinding-job.yaml b/templates/rolebinding-job.yaml new file mode 100644 index 0000000..1c67e84 --- /dev/null +++ b/templates/rolebinding-job.yaml @@ -0,0 +1,23 @@ +{{- if .Values.actions.enabled }} +{{- if and (and .Values.actions.provisioning.enabled .Values.persistence.enabled) .Values.persistence.mount }} +{{- $name := include "gitea.workername" (dict "global" . "worker" "actions-token-job") }} +{{- $secretName := include "gitea.workername" (dict "global" . "worker" "actions-token") }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ $name }} + namespace: {{ .Values.namespace | default .Release.Namespace }} + labels: + {{- include "gitea.labels" . | nindent 4 }} + app.kubernetes.io/component: token-job +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ $name }} +subjects: + - kind: ServiceAccount + name: {{ $name }} + namespace: {{ .Release.Namespace }} +{{- end }} +{{- end }} diff --git a/templates/secret-token.yaml b/templates/secret-token.yaml new file mode 100644 index 0000000..bc3416b --- /dev/null +++ b/templates/secret-token.yaml @@ -0,0 +1,20 @@ +{{- if .Values.actions.enabled }} +{{- if and (and .Values.actions.provisioning.enabled .Values.persistence.enabled) .Values.persistence.mount }} +{{- $name := include "gitea.workername" (dict "global" . "worker" "actions-token-job") }} +{{- $secretName := include "gitea.workername" (dict "global" . "worker" "actions-token") }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ $secretName }} + namespace: {{ .Values.namespace | default .Release.Namespace }} + labels: + {{- include "gitea.labels" . | nindent 4 }} + app.kubernetes.io/component: token-job +{{ $secret := (lookup "v1" "Secret" .Release.Namespace $secretName) -}} +{{ if $secret -}} +data: + token: {{ (b64dec (index $secret.data "token")) | b64enc }} +{{ end -}} +{{- end }} +{{- end }} diff --git a/templates/serviceaccount-job.yaml b/templates/serviceaccount-job.yaml new file mode 100644 index 0000000..dd39752 --- /dev/null +++ b/templates/serviceaccount-job.yaml @@ -0,0 +1,14 @@ +{{- if .Values.actions.enabled }} +{{- if and (and .Values.actions.provisioning.enabled .Values.persistence.enabled) .Values.persistence.mount }} +{{- $name := include "gitea.workername" (dict "global" . "worker" "actions-token-job") }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ $name }} + namespace: {{ .Values.namespace | default .Release.Namespace }} + labels: + {{- include "gitea.labels" . | nindent 4 }} + app.kubernetes.io/component: token-job +{{- end }} +{{- end }} diff --git a/templates/statefulset.yaml b/templates/statefulset.yaml new file mode 100644 index 0000000..72b4e19 --- /dev/null +++ b/templates/statefulset.yaml @@ -0,0 +1,129 @@ +{{- if .Values.actions.enabled }} +{{- $secretName := include "gitea.workername" (dict "global" . "worker" "actions-token") }} +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + labels: + {{- include "gitea.labels.actRunner" . | nindent 4 }} + {{- with .Values.actions.statefulset.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + annotations: + {{- with .Values.actions.statefulset.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + name: {{ include "gitea.fullname" . }}-act-runner + namespace: {{ .Values.namespace | default .Release.Namespace }} +spec: + selector: + matchLabels: + {{- include "gitea.selectorLabels.actRunner" . | nindent 6 }} + template: + metadata: + annotations: + checksum/config: {{ include (print $.Template.BasePath "/gitea/act_runner/config-act-runner.yaml") . | sha256sum }} + labels: + {{- include "gitea.labels.actRunner" . | nindent 8 }} + {{- with .Values.actions.statefulset.labels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + initContainers: + - name: init-gitea + image: "{{ .Values.actions.init.image.repository }}:{{ .Values.actions.init.image.tag }}" + command: + - sh + - -c + - | + while ! nc -z {{ include "gitea.fullname" . }}-http {{ .Values.service.http.port }}; do + sleep 5 + done + containers: + - name: act-runner + image: "{{ .Values.actions.statefulset.actRunner.repository }}:{{ .Values.actions.statefulset.actRunner.tag }}" + imagePullPolicy: {{ .Values.actions.statefulset.actRunner.pullPolicy }} + workingDir: /data + env: + - name: DOCKER_HOST + value: tcp://127.0.0.1:2376 + - name: DOCKER_TLS_VERIFY + value: "1" + - name: DOCKER_CERT_PATH + value: /certs/server + - name: GITEA_RUNNER_REGISTRATION_TOKEN + valueFrom: + secretKeyRef: + name: "{{ .Values.actions.existingSecret | default $secretName }}" + key: "{{ .Values.actions.existingSecretKey | default "token" }}" + - name: GITEA_INSTANCE_URL + value: {{ include "gitea.act_runner.local_root_url" . }} + - name: CONFIG_FILE + value: /actrunner/config.yaml + resources: + {{- toYaml .Values.actions.statefulset.resources | nindent 12 }} + volumeMounts: + - mountPath: /actrunner/config.yaml + name: act-runner-config + subPath: config.yaml + - mountPath: /certs/server + name: docker-certs + - mountPath: /data + name: data-act-runner + {{- with .Values.actions.statefulset.actRunner.extraVolumeMounts }} + {{- toYaml . | nindent 12 }} + {{- end }} + - name: dind + image: "{{ .Values.actions.statefulset.dind.repository }}:{{ .Values.actions.statefulset.dind.tag }}" + imagePullPolicy: {{ .Values.actions.statefulset.dind.pullPolicy }} + env: + - name: DOCKER_HOST + value: tcp://127.0.0.1:2376 + - name: DOCKER_TLS_VERIFY + value: "1" + - name: DOCKER_CERT_PATH + value: /certs/server + {{- if .Values.actions.statefulset.dind.extraEnvs }} + {{- toYaml .Values.actions.statefulset.dind.extraEnvs | nindent 12 }} + {{- end }} + securityContext: + privileged: true + resources: + {{- toYaml .Values.actions.statefulset.resources | nindent 12 }} + volumeMounts: + - mountPath: /certs/server + name: docker-certs + {{- with .Values.actions.statefulset.dind.extraVolumeMounts }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- range $key, $value := .Values.actions.statefulset.nodeSelector }} + nodeSelector: + {{ $key }}: {{ $value | quote }} + {{- end }} + {{- with .Values.actions.statefulset.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.actions.statefulset.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + volumes: + - name: act-runner-config + configMap: + name: {{ include "gitea.fullname" . }}-act-runner-config + - name: docker-certs + emptyDir: {} + {{- with .Values.actions.statefulset.extraVolumes }} + {{- toYaml . | nindent 8 }} + {{- end }} + volumeClaimTemplates: + - metadata: + name: data-act-runner + spec: + accessModes: [ "ReadWriteOnce" ] + {{- include "gitea.persistence.storageClass" . | nindent 8 }} + resources: + requests: + storage: 1Mi +{{- end }} diff --git a/unittests/01-consistency-checks.yaml b/unittests/01-consistency-checks.yaml new file mode 100644 index 0000000..1c30924 --- /dev/null +++ b/unittests/01-consistency-checks.yaml @@ -0,0 +1,69 @@ +suite: actions template | consistency checks +release: + name: gitea-unittests + namespace: testing +templates: + - templates/gitea/act_runner/01-consistency-checks.yaml +tests: + - it: fails when provisioning is enabled BUT persistence is completely disabled + set: + persistence: + enabled: false + actions: + enabled: true + provisioning: + enabled: true + asserts: + - failedTemplate: + errorMessage: "persistence.enabled and persistence.mount are required when provisioning is enabled" + - it: fails when provisioning is enabled BUT mount is disabled, although persistence is enabled + set: + persistence: + enabled: true + mount: false + actions: + enabled: true + provisioning: + enabled: true + asserts: + - failedTemplate: + errorMessage: "persistence.enabled and persistence.mount are required when provisioning is enabled" + - it: fails when provisioning is enabled AND existingSecret is given + set: + actions: + enabled: true + provisioning: + enabled: true + existingSecret: "secret-reference" + asserts: + - failedTemplate: + errorMessage: "Can't specify both actions.provisioning.enabled and actions.existingSecret" + - it: fails when provisioning is disabled BUT existingSecret and existingSecretKey are missing + set: + actions: + enabled: true + provisioning: + enabled: false + asserts: + - failedTemplate: + errorMessage: "actions.existingSecret and actions.existingSecretKey are required when provisioning is disabled" + - it: fails when provisioning is disabled BUT existingSecretKey is missing + set: + actions: + enabled: true + provisioning: + enabled: false + existingSecret: "my-secret" + asserts: + - failedTemplate: + errorMessage: "actions.existingSecret and actions.existingSecretKey are required when provisioning is disabled" + - it: fails when provisioning is disabled BUT existingSecret is missing + set: + actions: + enabled: true + provisioning: + enabled: false + existingSecretKey: "my-secret-key" + asserts: + - failedTemplate: + errorMessage: "actions.existingSecret and actions.existingSecretKey are required when provisioning is disabled" diff --git a/unittests/config-act-runner.yaml b/unittests/config-act-runner.yaml new file mode 100644 index 0000000..2cba6bc --- /dev/null +++ b/unittests/config-act-runner.yaml @@ -0,0 +1,45 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/helm-unittest/helm-unittest/main/schema/helm-testsuite.json +suite: actions template | config-act-runner +release: + name: gitea-unittests + namespace: testing +templates: + - templates/gitea/act_runner/config-act-runner.yaml +tests: + - it: doesn't renders a ConfigMap by default + template: templates/gitea/act_runner/config-act-runner.yaml + asserts: + - hasDocuments: + count: 0 + - it: renders a ConfigMap + template: templates/gitea/act_runner/config-act-runner.yaml + set: + actions: + enabled: true + statefulset: + actRunner: + config: | + log: + level: info + cache: + enabled: false + runner: + labels: + - "ubuntu-latest" + asserts: + - hasDocuments: + count: 1 + - containsDocument: + kind: ConfigMap + apiVersion: v1 + name: gitea-unittests-act-runner-config + - equal: + path: data["config.yaml"] + value: | + log: + level: info + cache: + enabled: false + runner: + labels: + - "ubuntu-latest" diff --git a/unittests/config-scripts.yaml b/unittests/config-scripts.yaml new file mode 100644 index 0000000..da6d9aa --- /dev/null +++ b/unittests/config-scripts.yaml @@ -0,0 +1,49 @@ +suite: actions template | config-scripts +release: + name: gitea-unittests + namespace: testing +templates: + - templates/gitea/act_runner/config-scripts.yaml +tests: + - it: renders a ConfigMap when all criteria are met + template: templates/gitea/act_runner/config-scripts.yaml + set: + actions: + enabled: true + provisioning: + enabled: true + persistence: + enabled: true + mount: true + asserts: + - hasDocuments: + count: 1 + - containsDocument: + kind: ConfigMap + apiVersion: v1 + name: gitea-unittests-scripts + - isNotNullOrEmpty: + path: data["token.sh"] + - it: doesn't renders a ConfigMap by default + template: templates/gitea/act_runner/config-scripts.yaml + asserts: + - hasDocuments: + count: 0 + - it: doesn't renders a ConfigMap with disabled actions but enabled provisioning + template: templates/gitea/act_runner/config-scripts.yaml + asserts: + - hasDocuments: + count: 0 + - it: doesn't renders a ConfigMap with disabled actions but otherwise met criteria + template: templates/gitea/act_runner/config-scripts.yaml + set: + actions: + enabled: false + provisioning: + enabled: true + persistence: + enabled: true + mount: true + asserts: + - hasDocuments: + count: 0 diff --git a/unittests/helm/actions-config.yaml b/unittests/helm/actions-config.yaml new file mode 100644 index 0000000..e244aa8 --- /dev/null +++ b/unittests/helm/actions-config.yaml @@ -0,0 +1,53 @@ +suite: config template | actions config +release: + name: gitea-unittests + namespace: testing +templates: + - templates/config.yaml +tests: + + - it: "actions can be enabled via inline config" + template: templates/config.yaml + set: + gitea.config.actions.ENABLED: true + asserts: + - documentIndex: 0 + equal: + path: stringData.actions + value: |- + ENABLED=true + + - it: "actions can be enabled via dedicated values object" + template: templates/config.yaml + set: + actions: + enabled: true + asserts: + - documentIndex: 0 + equal: + path: stringData.actions + value: |- + ENABLED=true + + - it: "defines LOCAL_ROOT_URL when actions are enabled" + template: templates/config.yaml + set: + actions: + enabled: true + asserts: + - documentIndex: 0 + matchRegex: + path: stringData.server + pattern: \nLOCAL_ROOT_URL=http://gitea-unittests-http:3000 + + - it: "respects custom LOCAL_ROOT_URL, even when actions are enabled" + template: templates/config.yaml + set: + actions: + enabled: true + gitea.config.server.LOCAL_ROOT_URL: "http://git.example.com" + asserts: + - documentIndex: 0 + matchRegex: + path: stringData.server + pattern: \nLOCAL_ROOT_URL=http://git.example.com diff --git a/unittests/job.yaml b/unittests/job.yaml new file mode 100644 index 0000000..a16d40d --- /dev/null +++ b/unittests/job.yaml @@ -0,0 +1,65 @@ +suite: actions template | job +release: + name: gitea-unittests + namespace: testing +chart: + # Override appVersion to have a pinned version for comparison + appVersion: 1.19.3 +templates: + - templates/gitea/act_runner/job.yaml +tests: + - it: renders a Job + template: templates/gitea/act_runner/job.yaml + set: + actions: + enabled: true + provisioning: + enabled: true + persistence: + enabled: true + mount: true + asserts: + - hasDocuments: + count: 1 + - containsDocument: + kind: Job + apiVersion: batch/v1 + name: gitea-unittests-actions-token-job + - equal: + path: spec.template.spec.containers[0].image + value: "docker.gitea.com/gitea:1.19.3-rootless" + - it: tag override + template: templates/gitea/act_runner/job.yaml + set: + image.tag: "1.19.4" + actions: + enabled: true + provisioning: + enabled: true + publish: + tag: "1.29.0" + persistence: + enabled: true + mount: true + asserts: + - equal: + path: spec.template.spec.containers[0].image + value: "docker.gitea.com/gitea:1.19.4-rootless" + - equal: + path: spec.template.spec.containers[1].image + value: "bitnami/kubectl:1.29.0" + - it: doesn't renders a Job by default + template: templates/gitea/act_runner/job.yaml + asserts: + - hasDocuments: + count: 0 + - it: doesn't renders a Job when provisioning is enabled BUT actions are not enabled + template: templates/gitea/act_runner/job.yaml + set: + actions: + enabled: false + provisioning: + enabled: true + asserts: + - hasDocuments: + count: 0 diff --git a/unittests/role-job.yaml b/unittests/role-job.yaml new file mode 100644 index 0000000..8c511d8 --- /dev/null +++ b/unittests/role-job.yaml @@ -0,0 +1,42 @@ +suite: actions template | role-job +release: + name: gitea-unittests + namespace: testing +templates: + - templates/gitea/act_runner/role-job.yaml +tests: + - it: doesn't renders a Role by default + template: templates/gitea/act_runner/role-job.yaml + asserts: + - hasDocuments: + count: 0 + - it: renders a Role + template: templates/gitea/act_runner/role-job.yaml + set: + actions: + enabled: true + provisioning: + enabled: true + persistence: + enabled: true + mount: true + asserts: + - hasDocuments: + count: 1 + - containsDocument: + kind: Role + apiVersion: rbac.authorization.k8s.io/v1 + name: gitea-unittests-actions-token-job + - it: doesn't renders a Role when criteria met BUT actions are not enabled + template: templates/gitea/act_runner/role-job.yaml + set: + actions: + enabled: false + provisioning: + enabled: true + persistence: + enabled: true + mount: true + asserts: + - hasDocuments: + count: 0 diff --git a/unittests/rolebinding-job.yaml b/unittests/rolebinding-job.yaml new file mode 100644 index 0000000..2073bfc --- /dev/null +++ b/unittests/rolebinding-job.yaml @@ -0,0 +1,42 @@ +suite: actions template | rolebinding-job +release: + name: gitea-unittests + namespace: testing +templates: + - templates/gitea/act_runner/rolebinding-job.yaml +tests: + - it: doesn't renders a RoleBinding by default + template: templates/gitea/act_runner/rolebinding-job.yaml + asserts: + - hasDocuments: + count: 0 + - it: renders a RoleBinding + template: templates/gitea/act_runner/rolebinding-job.yaml + set: + actions: + enabled: true + provisioning: + enabled: true + persistence: + enabled: true + mount: true + asserts: + - hasDocuments: + count: 1 + - containsDocument: + kind: RoleBinding + apiVersion: rbac.authorization.k8s.io/v1 + name: gitea-unittests-actions-token-job + - it: doesn't renders a RoleBinding when criteria met BUT actions are not enabled + template: templates/gitea/act_runner/rolebinding-job.yaml + set: + actions: + enabled: false + provisioning: + enabled: true + persistence: + enabled: true + mount: true + asserts: + - hasDocuments: + count: 0 diff --git a/unittests/secret-token.yaml b/unittests/secret-token.yaml new file mode 100644 index 0000000..b5054f3 --- /dev/null +++ b/unittests/secret-token.yaml @@ -0,0 +1,42 @@ +suite: actions template | secret-token +release: + name: gitea-unittests + namespace: testing +templates: + - templates/gitea/act_runner/secret-token.yaml +tests: + - it: doesn't renders a Secret by default + template: templates/gitea/act_runner/secret-token.yaml + asserts: + - hasDocuments: + count: 0 + - it: renders a Secret + template: templates/gitea/act_runner/secret-token.yaml + set: + actions: + enabled: true + provisioning: + enabled: true + persistence: + enabled: true + mount: true + asserts: + - hasDocuments: + count: 1 + - containsDocument: + kind: Secret + apiVersion: v1 + name: gitea-unittests-actions-token + - it: doesn't renders a Secret when criteria met BUT actions are not enabled + template: templates/gitea/act_runner/secret-token.yaml + set: + actions: + enabled: false + provisioning: + enabled: true + persistence: + enabled: true + mount: true + asserts: + - hasDocuments: + count: 0 diff --git a/unittests/serviceaccount-job.yaml b/unittests/serviceaccount-job.yaml new file mode 100644 index 0000000..bf8f0c8 --- /dev/null +++ b/unittests/serviceaccount-job.yaml @@ -0,0 +1,42 @@ +suite: actions template | serviceaccount-job +release: + name: gitea-unittests + namespace: testing +templates: + - templates/gitea/act_runner/serviceaccount-job.yaml +tests: + - it: doesn't renders a ServiceAccount by default + template: templates/gitea/act_runner/serviceaccount-job.yaml + asserts: + - hasDocuments: + count: 0 + - it: renders a ServiceAccount + template: templates/gitea/act_runner/serviceaccount-job.yaml + set: + actions: + enabled: true + provisioning: + enabled: true + persistence: + enabled: true + mount: true + asserts: + - hasDocuments: + count: 1 + - containsDocument: + kind: ServiceAccount + apiVersion: v1 + name: gitea-unittests-actions-token-job + - it: doesn't renders a ServiceAccount when criteria met BUT actions are not enabled + template: templates/gitea/act_runner/serviceaccount-job.yaml + set: + actions: + enabled: false + provisioning: + enabled: true + persistence: + enabled: true + mount: true + asserts: + - hasDocuments: + count: 0 diff --git a/unittests/statefulset.yaml b/unittests/statefulset.yaml new file mode 100644 index 0000000..323fef6 --- /dev/null +++ b/unittests/statefulset.yaml @@ -0,0 +1,182 @@ +suite: actions template | statefulset +release: + name: gitea-unittests + namespace: testing +templates: + - templates/gitea/act_runner/statefulset.yaml + - templates/gitea/act_runner/config-act-runner.yaml +tests: + - it: doesn't renders a StatefulSet by default + template: templates/gitea/act_runner/statefulset.yaml + asserts: + - hasDocuments: + count: 0 + - it: renders a StatefulSet (with given existingSecret/existingSecretKey) + template: templates/gitea/act_runner/statefulset.yaml + set: + actions: + enabled: true + existingSecret: "my-secret" + existingSecretKey: "my-secret-key" + asserts: + - hasDocuments: + count: 1 + - containsDocument: + kind: StatefulSet + apiVersion: apps/v1 + name: gitea-unittests-act-runner + - equal: + path: spec.template.spec.containers[0].env[3] + value: + name: GITEA_RUNNER_REGISTRATION_TOKEN + valueFrom: + secretKeyRef: + name: "my-secret" + key: "my-secret-key" + - it: renders a StatefulSet (with secret reference defaults for enabled provisioning) + template: templates/gitea/act_runner/statefulset.yaml + set: + actions: + enabled: true + provisioning: + enabled: true + asserts: + - hasDocuments: + count: 1 + - containsDocument: + kind: StatefulSet + apiVersion: apps/v1 + name: gitea-unittests-act-runner + - equal: + path: spec.template.spec.containers[0].env[3] + value: + name: GITEA_RUNNER_REGISTRATION_TOKEN + valueFrom: + secretKeyRef: + name: "gitea-unittests-actions-token" + key: "token" + - it: renders a StatefulSet (that tracks changes of the runner configuration as annotation) + template: templates/gitea/act_runner/statefulset.yaml + set: + image.tag: "1.22.3" # lock image tag to prevent test failures on future Gitea upgrades + actions: + enabled: true + existingSecret: "my-secret" + existingSecretKey: "my-secret-key" + asserts: + - hasDocuments: + count: 1 + - containsDocument: + kind: StatefulSet + apiVersion: apps/v1 + name: gitea-unittests-act-runner + - equal: + path: spec.template.metadata.annotations["checksum/config"] + value: "2a2200e80fc29111d18b675789c265cd3d5f917754850f946f1ce3c55dcd65f8" + - it: renders a StatefulSet (with correct GITEA_INSTANCE_URL env with default act-runner specific LOCAL_ROOT_URL) + template: templates/gitea/act_runner/statefulset.yaml + set: + actions: + enabled: true + existingSecret: "my-secret" + existingSecretKey: "my-secret-key" + asserts: + - hasDocuments: + count: 1 + - containsDocument: + kind: StatefulSet + apiVersion: apps/v1 + name: gitea-unittests-act-runner + - equal: + path: spec.template.spec.containers[0].env[4] + value: + name: GITEA_INSTANCE_URL + value: "http://gitea-unittests-http:3000" + - it: renders a StatefulSet (with correct GITEA_INSTANCE_URL env from customized LOCAL_ROOT_URL) + template: templates/gitea/act_runner/statefulset.yaml + set: + gitea.config.server.LOCAL_ROOT_URL: "http://git.example.com" + actions: + enabled: true + existingSecret: "my-secret" + existingSecretKey: "my-secret-key" + asserts: + - hasDocuments: + count: 1 + - containsDocument: + kind: StatefulSet + apiVersion: apps/v1 + name: gitea-unittests-act-runner + - equal: + path: spec.template.spec.containers[0].env[4] + value: + name: GITEA_INSTANCE_URL + value: "http://git.example.com" + - it: allows adding custom environment variables to the docker-in-docker container + template: templates/gitea/act_runner/statefulset.yaml + set: + actions: + enabled: true + statefulset: + dind: + extraEnvs: + - name: "CUSTOM_ENV_NAME" + value: "custom env value" + asserts: + - equal: + path: spec.template.spec.containers[1].env[3] + value: + name: "CUSTOM_ENV_NAME" + value: "custom env value" + - it: should mount an extra volume in the act runner container + template: templates/gitea/act_runner/statefulset.yaml + set: + actions: + enabled: true + statefulset: + extraVolumes: + - name: my-act-runner-volume + emptyDir: {} + actRunner: + extraVolumeMounts: + - mountPath: /mnt + name: my-act-runner-volume + asserts: + - hasDocuments: + count: 1 + - containsDocument: + kind: StatefulSet + apiVersion: apps/v1 + name: gitea-unittests-act-runner + - contains: + any: true + path: spec.template.spec.containers[0].volumeMounts + content: + mountPath: /mnt + name: my-act-runner-volume + - it: should mount an extra volume in the docker-in-docker container + template: templates/gitea/act_runner/statefulset.yaml + set: + actions: + enabled: true + statefulset: + extraVolumes: + - name: my-dind-volume + emptyDir: {} + dind: + extraVolumeMounts: + - mountPath: /mnt + name: my-dind-volume + asserts: + - hasDocuments: + count: 1 + - containsDocument: + kind: StatefulSet + apiVersion: apps/v1 + name: gitea-unittests-act-runner + - contains: + any: true + path: spec.template.spec.containers[1].volumeMounts + content: + mountPath: /mnt + name: my-dind-volume diff --git a/values.yaml b/values.yaml new file mode 100644 index 0000000..fc8ddec --- /dev/null +++ b/values.yaml @@ -0,0 +1,99 @@ +# Configure Gitea Actions +# - must enable persistence if the job is enabled +## @section Gitea Actions +# +## @param init.image.repository The image used for the init containers +## @param init.image.tag The image tag used for the init containers +## @param statefulset.annotations Act runner annotations +## @param statefulset.labels Act runner labels +## @param statefulset.resources Act runner resources +## @param statefulset.nodeSelector NodeSelector for the statefulset +## @param statefulset.tolerations Tolerations for the statefulset +## @param statefulset.affinity Affinity for the statefulset +## @param statefulset.extraVolumes Extra volumes for the statefulset +## @param statefulset.actRunner.repository The Gitea act runner image +## @param statefulset.actRunner.tag The Gitea act runner tag +## @param statefulset.actRunner.pullPolicy The Gitea act runner pullPolicy +## @param statefulset.actRunner.extraVolumeMounts Allows mounting extra volumes in the act runner container +## @param statefulset.actRunner.config [default: Too complex. See values.yaml] Act runner custom configuration. See [Act Runner documentation](https://docs.gitea.com/usage/actions/act-runner#configuration) for details. +## @param statefulset.dind.repository The Docker-in-Docker image +## @param statefulset.dind.tag The Docker-in-Docker image tag +## @param statefulset.dind.pullPolicy The Docker-in-Docker pullPolicy +## @param statefulset.dind.extraVolumeMounts Allows mounting extra volumes in the Docker-in-Docker container +## @param statefulset.dind.extraEnvs Allows adding custom environment variables, such as `DOCKER_IPTABLES_LEGACY` +## @param provisioning.enabled Create a job that will create and save the token in a Kubernetes Secret +## @param provisioning.annotations Job's annotations +## @param provisioning.labels Job's labels +## @param provisioning.resources Job's resources +## @param provisioning.nodeSelector NodeSelector for the job +## @param provisioning.tolerations Tolerations for the job +## @param provisioning.affinity Affinity for the job +## @param provisioning.ttlSecondsAfterFinished ttl for the job after finished in order to allow helm to properly recognize that the job completed +## @param provisioning.publish.repository The image that can create the secret via kubectl +## @param provisioning.publish.tag The publish image tag that can create the secret +## @param provisioning.publish.pullPolicy The publish image pullPolicy that can create the secret +## @param existingSecret Secret that contains the token +## @param existingSecretKey Secret key +enabled: false +statefulset: + annotations: {} + labels: {} + resources: {} + nodeSelector: {} + tolerations: [] + affinity: {} + extraVolumes: [] + + actRunner: + repository: gitea/act_runner + tag: 0.2.11 + pullPolicy: IfNotPresent + extraVolumeMounts: [] + + # See full example here: https://gitea.com/gitea/act_runner/src/branch/main/internal/pkg/config/config.example.yaml + config: | + log: + level: debug + cache: + enabled: false + + dind: + repository: docker + tag: 25.0.2-dind + pullPolicy: IfNotPresent + extraVolumeMounts: [] + + # If the container keeps crashing in your environment, you might have to add the `DOCKER_IPTABLES_LEGACY` environment variable. + # See https://github.com/docker-library/docker/issues/463#issuecomment-1881909456 + extraEnvs: + [] + # - name: "DOCKER_IPTABLES_LEGACY" + # value: "1" + +init: + image: + repository: busybox + # Overrides the image tag whose default is the chart appVersion. + tag: "1.37.0" + +provisioning: + enabled: false + + annotations: {} + labels: {} + resources: {} + nodeSelector: {} + tolerations: [] + affinity: {} + + publish: + repository: bitnami/kubectl + tag: 1.29.0 + pullPolicy: IfNotPresent + + ttlSecondsAfterFinished: 300 + +## Specify an existing token secret +## +existingSecret: "" +existingSecretKey: ""