46 Commits

Author SHA1 Message Date
Tom Alexander
3b9f07f4fd Update the build pipelines.
Some checks failed
semver Build semver has succeeded
rust-test Build rust-test has failed
clippy Build clippy has failed
format Build format has failed
build Build build has failed
2026-05-02 22:18:30 -04:00
Tom Alexander
9e92c5c49f Add better logging.
Some checks failed
format Build format has failed
rust-test Build rust-test has failed
build Build build has failed
semver Build semver has succeeded
clippy Build clippy has failed
2026-05-02 21:54:24 -04:00
Tom Alexander
cedf2eef54 Update to the latest catalog. 2026-05-02 21:14:51 -04:00
Tom Alexander
e5aff59cd2 Build using nix. 2026-05-02 21:14:51 -04:00
Tom Alexander
6e209bdcef Update for the latest gitea. 2026-05-02 16:35:31 -04:00
Tom Alexander
5fb1982930 Mark internal_tracker as optional.
Some checks failed
semver Build semver has succeeded
format Build format has succeeded
clippy Build clippy has failed
build Build build has succeeded
rust-test Build rust-test has succeeded
2025-09-23 21:09:24 -04:00
Tom Alexander
ac3c23e65a Switch to local-path-provisioner.
Some checks failed
format Build format has succeeded
clippy Build clippy has failed
rust-test Build rust-test has succeeded
semver Build semver has succeeded
build Build build has succeeded
2025-08-31 18:35:48 -04:00
Tom Alexander
3f2bdda8cb Add support for new fields in payload.
All checks were successful
semver Build semver has succeeded
format Build format has succeeded
clippy Build clippy has succeeded
rust-test Build rust-test has succeeded
build Build build has succeeded
2025-02-08 21:11:23 -05:00
Tom Alexander
e7eeeefa53 Add back in docker targets.
All checks were successful
semver Build semver has succeeded
format Build format has succeeded
build Build build has succeeded
clippy Build clippy has succeeded
rust-test Build rust-test has succeeded
2024-10-20 23:12:52 -04:00
Tom Alexander
a17f6502c0 Use linked copy. 2024-10-20 23:03:40 -04:00
Tom Alexander
16a39809e4 Merge branch 'buildkit'
All checks were successful
semver Build semver has succeeded
format Build format has succeeded
clippy Build clippy has succeeded
rust-test Build rust-test has succeeded
build Build build has succeeded
2024-10-20 22:42:36 -04:00
Tom Alexander
7dd0a9d0ad Update dockerfiles to take advantage of BuildKit.
All checks were successful
format Build format has succeeded
rust-test Build rust-test has succeeded
clippy Build clippy has succeeded
2024-10-20 22:35:16 -04:00
Tom Alexander
9d682cbe83 Switch to using BuiltKit instead of Kaniko to build docker images.
All checks were successful
format Build format has succeeded
rust-test Build rust-test has succeeded
clippy Build clippy has succeeded
2024-10-20 22:28:04 -04:00
Tom Alexander
3ca037411a Add more new fields for webhook payload.
All checks were successful
semver Build semver has succeeded
format Build format has succeeded
clippy Build clippy has succeeded
rust-test Build rust-test has succeeded
2024-10-18 20:27:57 -04:00
Tom Alexander
e991b259f2 Add source_id to HookUser.
This must be a new field that gitea added in an update.
2024-10-18 19:41:56 -04:00
Tom Alexander
f3b00c46ea Test: Remove the clients from AppState entirely.
Some checks failed
semver Build semver has succeeded
format Build format has succeeded
clippy Build clippy has succeeded
rust-test Build rust-test has failed
build Build build has succeeded
2024-09-30 00:38:32 -04:00
Tom Alexander
e4463fe79d Remove redundant runAfter directives from workflows.
Some checks failed
semver Build semver has failed
format Build format has succeeded
clippy Build clippy has failed
rust-test Build rust-test has succeeded
2024-09-30 00:29:07 -04:00
Tom Alexander
f18c1fe421 Fix typo in pipelines.
Some checks failed
semver Build semver has succeeded
format Build format has succeeded
rust-test Build rust-test has succeeded
build Build build has succeeded
clippy Build clippy has failed
2024-09-30 00:03:10 -04:00
Tom Alexander
3c58d19a88 Add support for dockerfile targets to workflows.
Some checks failed
semver Build semver has succeeded
format Build format has succeeded
rust-test Build rust-test has succeeded
build Build build has succeeded
clippy Build clippy has failed
2024-09-29 23:23:22 -04:00
Tom Alexander
f07c0dc971 Rename pipeline-build to pipeline-build-semver to distinguish it from pipeline-build-hash used in poudboot. 2024-09-29 22:21:37 -04:00
Tom Alexander
fd7b22c5ce Remove cranelift.
Some checks failed
semver Build semver has succeeded
format Build format has succeeded
clippy Build clippy has failed
rust-test Build rust-test has succeeded
build Build build has succeeded
I should be configuring cranelift globally in my per-machine configs, not spreading my build preferences in the project's Cargo.toml.
2024-09-29 22:17:35 -04:00
Tom Alexander
1c082a5e24 Test: instantiate new clients for every request.
Some checks failed
semver Build semver has succeeded
format Build format has succeeded
build Build build has succeeded
clippy Build clippy has failed
rust-test Build rust-test has succeeded
Trying to figure out why I am getting the below error occasionally in gitea:

Delivery: Post "https://webhookbridge.fizz.buzz/hook": context deadline exceeded (Client.Timeout exceeded while awaiting headers)
2024-09-29 21:58:05 -04:00
Tom Alexander
9ed8905a5c Always return status code ok.
All checks were successful
semver Build semver has succeeded
format Build format has succeeded
clippy Build clippy has succeeded
build Build build has succeeded
rust-test Build rust-test has succeeded
2024-09-29 18:37:23 -04:00
Tom Alexander
8cb28459a0 Fix clippy lint. 2024-09-29 18:31:47 -04:00
Tom Alexander
753ad6dd05 Handle errors in push events.
Some checks failed
semver Build semver has succeeded
format Build format has succeeded
rust-test Build rust-test has failed
clippy Build clippy has failed
build Build build has succeeded
2024-09-29 18:24:50 -04:00
Tom Alexander
dd4c20f0a7 Remove log of secret.
All checks were successful
semver Build semver has succeeded
format Build format has succeeded
build Build build has succeeded
clippy Build clippy has succeeded
rust-test Build rust-test has succeeded
2024-09-29 18:14:36 -04:00
Tom Alexander
c04b4e8da5 Fix bug that prevented actions from triggering.
All checks were successful
semver Build semver has succeeded
format Build format has succeeded
build Build build has succeeded
clippy Build clippy has succeeded
rust-test Build rust-test has succeeded
2024-09-29 18:09:07 -04:00
Tom Alexander
69dd1ba156 Remove support for http2.
Nginx does not support http2 for upstream proxies because there is not much point for low-latency connections.
2024-09-29 18:00:34 -04:00
Tom Alexander
65c964b329 Fix clippy lint. 2024-09-29 17:42:08 -04:00
Tom Alexander
613026b326 Adding repo whitelist.
Some checks failed
semver Build semver has succeeded
format Build format has succeeded
clippy Build clippy has failed
build Build build has succeeded
rust-test Build rust-test has succeeded
2024-09-29 16:54:58 -04:00
Tom Alexander
cd56bb2fe1 Fix debug build in docker container by adding cranelift.
All checks were successful
semver Build semver has succeeded
format Build format has succeeded
clippy Build clippy has succeeded
build Build build has succeeded
rust-test Build rust-test has succeeded
2024-09-29 15:31:24 -04:00
Tom Alexander
4bcf8b9ddc Merge branch 'lint'
Some checks failed
semver Build semver has succeeded
format Build format has succeeded
rust-test Build rust-test has failed
clippy Build clippy has failed
build Build build has succeeded
2024-09-29 15:03:19 -04:00
Tom Alexander
14b38b7fcd Add rustfmt config. 2024-09-29 15:03:07 -04:00
Tom Alexander
0602f8472b Separate out to two binaries.
Some checks failed
format Build format has succeeded
clippy Build clippy has failed
rust-test Build rust-test has failed
2024-09-29 14:59:39 -04:00
Tom Alexander
cdac8224c6 Fix clippy lints. 2024-09-29 14:08:05 -04:00
Tom Alexander
ef195cd4df Update to alpine 3.20.
Some checks failed
semver Build semver has succeeded
build Build build has succeeded
format Build format has succeeded
rust-test Build rust-test has succeeded
clippy Build clippy has failed
2024-09-29 04:48:25 -04:00
Tom Alexander
a95339539b Use default namespace kubernetes client.
Some checks failed
semver Build semver has succeeded
format Build format has succeeded
rust-test Build rust-test has succeeded
clippy Build clippy has failed
build Build build has succeeded
2024-09-29 02:44:58 -04:00
Tom Alexander
07797b9906 Move the logic into the server.
Some checks failed
semver Build semver has succeeded
clippy Build clippy has failed
format Build format has succeeded
rust-test Build rust-test has succeeded
build Build build has succeeded
2024-09-29 01:27:00 -04:00
Tom Alexander
0548571b6b Add a pipeline to build the server image. 2024-09-29 00:36:51 -04:00
Tom Alexander
a2aca6d2f1 Add support for tags. 2024-09-29 00:13:56 -04:00
Tom Alexander
1efd7b1d73 Add a semver job to assign an automatically-incrementing version tag to commits to main.
Some checks failed
semver Build semver has succeeded
rust-test Build rust-test has succeeded
format Build format has succeeded
clippy Build clippy has failed
This automatically increments the patch (3rd) digit, so to update the major or minor version, manually push a tag.
2024-09-28 23:59:32 -04:00
Tom Alexander
b122e6ee99 Create a docker image for running the server. 2024-09-28 23:50:03 -04:00
Tom Alexander
c20927b726 Add Makefile for running CI jobs locally. 2024-09-28 23:20:35 -04:00
Tom Alexander
efe37f020a Generate names for pipeline runs.
Some checks failed
format Build format has succeeded
clippy Build clippy has failed
rust-test Build rust-test has succeeded
2024-09-28 22:50:35 -04:00
Tom Alexander
470031251c Remove prettier.
Some checks failed
rust-test Build rust-test has started
format Build format has started
clippy Build clippy has failed
2024-09-28 21:46:25 -04:00
Tom Alexander
ed1e1c08d0 Create PipelineRun in response to webhook triggers. 2024-09-28 21:40:00 -04:00
38 changed files with 1760 additions and 555 deletions

5
.dockerignore Normal file
View File

@@ -0,0 +1,5 @@
**/.git
target/
docker/
.dockerignore
*.bash

1
.gitignore vendored
View File

@@ -1 +1,2 @@
/target
TODO.org

View File

@@ -0,0 +1,256 @@
apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
name: build
spec:
timeouts:
pipeline: "2h0m0s"
tasks: "1h0m0s"
finally: "0h30m0s"
taskRunTemplate:
serviceAccountName: build-bot
pipelineSpec:
params:
- name: image-name
description: The name for the built image
type: string
- name: target-name
description: The dockerfile target to build
type: string
- name: path-to-image-context
description: The path to the build context
type: string
- name: path-to-dockerfile
description: The path to the Dockerfile
type: string
tasks:
- name: detect-tag
taskSpec:
metadata: {}
stepTemplate:
image: alpine:3.20
computeResources:
requests:
cpu: 10m
memory: 600Mi
workingDir: "$(workspaces.repo.path)"
results:
- name: tag
description: The tag to use for the docker container.
steps:
- image: alpine/git:v2.34.2
name: detect-tag-step
script: |
#!/usr/bin/env sh
set -euo pipefail
git fetch --tags
current_tag=$(git tag --points-at HEAD --list 'v*.*.*')
if [ -z "$current_tag" ]; then
echo "No tag at current commit"
exit 1
else
echo -n "${current_tag}" | tee $(results.tag.path)
fi
workspaces:
- name: repo
workspace: git-source
runAfter:
- fetch-repository
- name: report-pending
taskRef:
resolver: git
params:
- name: url
value: https://code.fizz.buzz/mirror/catalog.git # mirror of https://github.com/tektoncd/catalog.git
- name: revision
value: f914437a46978b95f325f68d791dcf1a35738f60
- name: pathInRepo
value: task/gitea-set-status/0.1/gitea-set-status.yaml
params:
- name: CONTEXT
value: "$(params.JOB_NAME)"
- name: REPO_FULL_NAME
value: "$(params.REPO_OWNER)/$(params.REPO_NAME)"
- name: GITEA_HOST_URL
value: code.fizz.buzz
- name: SHA
value: "$(tasks.fetch-repository.results.commit)"
- name: DESCRIPTION
value: "Build $(params.JOB_NAME) has started"
- name: STATE
value: pending
- name: TARGET_URL
value: "https://tekton.fizz.buzz/#/namespaces/$(context.pipelineRun.namespace)/pipelineruns/$(context.pipelineRun.name)"
- name: fetch-repository
taskRef:
resolver: git
params:
- name: url
value: https://code.fizz.buzz/mirror/catalog.git # mirror of https://github.com/tektoncd/catalog.git
- name: revision
value: f914437a46978b95f325f68d791dcf1a35738f60
- name: pathInRepo
value: task/git-clone/0.9/git-clone.yaml
workspaces:
- name: output
workspace: git-source
params:
- name: url
value: $(params.REPO_URL)
- name: revision
value: $(params.PULL_BASE_SHA)
- name: deleteExisting
value: "true"
- name: get-git-commit-time
taskSpec:
metadata: {}
stepTemplate:
image: alpine:3.20
computeResources:
requests:
cpu: 10m
memory: 600Mi
workingDir: "$(workspaces.repo.path)"
results:
- name: unix-time
description: The time of the git commit in unix timestamp format.
steps:
- image: alpine/git:v2.34.2
name: detect-tag-step
script: |
#!/usr/bin/env sh
set -euo pipefail
echo -n "$(git log -1 --pretty=%ct)" | tee $(results.unix-time.path)
workspaces:
- name: repo
workspace: git-source
runAfter:
- fetch-repository
- name: build-image
taskRef:
resolver: git
params:
- name: url
value: https://code.fizz.buzz/talexander/personal_tekton_catalog.git
- name: revision
value: af22c87d0db59dece97d03e6b6a796d84010158f
- name: pathInRepo
value: task/buildkit-rootless-daemonless/0.1/buildkit-rootless-daemonless.yaml
params:
- name: OUTPUT
value: >-
type=image,"name=$(params.image-name):latest,$(params.image-name):$(tasks.detect-tag.results.tag)",push=true,compression=zstd,compression-level=22,oci-mediatypes=true
- name: CONTEXT
value: $(params.path-to-image-context)
- name: DOCKERFILE
value: $(params.path-to-dockerfile)
- name: EXTRA_ARGS
value:
- "--opt"
- "target=$(params.target-name)"
- --import-cache
- "type=registry,ref=$(params.image-name):buildcache"
- --export-cache
- "type=registry,ref=$(params.image-name):buildcache,mode=max,compression=zstd,compression-level=22,rewrite-timestamp=true,image-manifest=true,oci-mediatypes=true"
- --opt
- build-arg:SOURCE_DATE_EPOCH=$(tasks.get-git-commit-time.results.unix-time)
- name: BUILDKITD_TOML
value: |
debug = true
[registry."docker.io"]
mirrors = ["dockerhub.dockerhub.svc.cluster.local"]
[registry."dockerhub.dockerhub.svc.cluster.local"]
http = true
insecure = true
workspaces:
- name: source
workspace: git-source
- name: dockerconfig
workspace: docker-credentials
runAfter:
- fetch-repository
finally:
- name: report-success
when:
- input: "$(tasks.status)"
operator: in
values: ["Succeeded", "Completed"]
taskRef:
resolver: git
params:
- name: url
value: https://code.fizz.buzz/mirror/catalog.git # mirror of https://github.com/tektoncd/catalog.git
- name: revision
value: f914437a46978b95f325f68d791dcf1a35738f60
- name: pathInRepo
value: task/gitea-set-status/0.1/gitea-set-status.yaml
params:
- name: CONTEXT
value: "$(params.JOB_NAME)"
- name: REPO_FULL_NAME
value: "$(params.REPO_OWNER)/$(params.REPO_NAME)"
- name: GITEA_HOST_URL
value: code.fizz.buzz
- name: SHA
value: "$(tasks.fetch-repository.results.commit)"
- name: DESCRIPTION
value: "Build $(params.JOB_NAME) has succeeded"
- name: STATE
value: success
- name: TARGET_URL
value: "https://tekton.fizz.buzz/#/namespaces/$(context.pipelineRun.namespace)/pipelineruns/$(context.pipelineRun.name)"
- name: report-failure
when:
- input: "$(tasks.status)"
operator: in
values: ["Failed"]
taskRef:
resolver: git
params:
- name: url
value: https://code.fizz.buzz/mirror/catalog.git # mirror of https://github.com/tektoncd/catalog.git
- name: revision
value: f914437a46978b95f325f68d791dcf1a35738f60
- name: pathInRepo
value: task/gitea-set-status/0.1/gitea-set-status.yaml
params:
- name: CONTEXT
value: "$(params.JOB_NAME)"
- name: REPO_FULL_NAME
value: "$(params.REPO_OWNER)/$(params.REPO_NAME)"
- name: GITEA_HOST_URL
value: code.fizz.buzz
- name: SHA
value: "$(tasks.fetch-repository.results.commit)"
- name: DESCRIPTION
value: "Build $(params.JOB_NAME) has failed"
- name: STATE
value: failure
- name: TARGET_URL
value: "https://tekton.fizz.buzz/#/namespaces/$(context.pipelineRun.namespace)/pipelineruns/$(context.pipelineRun.name)"
workspaces:
- name: git-source
- name: docker-credentials
workspaces:
- name: git-source
volumeClaimTemplate:
spec:
storageClassName: "local-path"
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
subPath: rust-source
- name: docker-credentials
secret:
secretName: harbor-plain
params:
- name: image-name
value: "harbor.fizz.buzz/private/webhook-bridge"
- name: target-name
value: ""
- name: path-to-image-context
value: .
- name: path-to-dockerfile
value: docker/webhook_bridge/

View File

@@ -14,6 +14,9 @@ spec:
- name: image-name
description: The name for the built image
type: string
- name: target-name
description: The dockerfile target to build
type: string
- name: path-to-image-context
description: The path to the build context
type: string
@@ -26,13 +29,11 @@ spec:
resolver: git
params:
- name: url
value: https://github.com/tektoncd/catalog.git
value: https://code.fizz.buzz/mirror/catalog.git # mirror of https://github.com/tektoncd/catalog.git
- name: revision
value: df36b3853a5657fd883015cdbf07ad6466918acf
value: f914437a46978b95f325f68d791dcf1a35738f60
- name: pathInRepo
value: task/gitea-set-status/0.1/gitea-set-status.yaml
runAfter:
- fetch-repository
params:
- name: CONTEXT
value: "$(params.JOB_NAME)"
@@ -53,9 +54,9 @@ spec:
resolver: git
params:
- name: url
value: https://github.com/tektoncd/catalog.git
value: https://code.fizz.buzz/mirror/catalog.git # mirror of https://github.com/tektoncd/catalog.git
- name: revision
value: df36b3853a5657fd883015cdbf07ad6466918acf
value: f914437a46978b95f325f68d791dcf1a35738f60
- name: pathInRepo
value: task/git-clone/0.9/git-clone.yaml
workspaces:
@@ -68,35 +69,67 @@ spec:
value: $(params.PULL_BASE_SHA)
- name: deleteExisting
value: "true"
- name: get-git-commit-time
taskSpec:
metadata: {}
stepTemplate:
image: alpine:3.20
computeResources:
requests:
cpu: 10m
memory: 600Mi
workingDir: "$(workspaces.repo.path)"
results:
- name: unix-time
description: The time of the git commit in unix timestamp format.
steps:
- image: alpine/git:v2.34.2
name: detect-tag-step
script: |
#!/usr/bin/env sh
set -euo pipefail
echo -n "$(git log -1 --pretty=%ct)" | tee $(results.unix-time.path)
workspaces:
- name: repo
workspace: git-source
runAfter:
- fetch-repository
- name: build-image
taskRef:
resolver: git
params:
- name: url
value: https://github.com/tektoncd/catalog.git
value: https://code.fizz.buzz/talexander/personal_tekton_catalog.git
- name: revision
value: df36b3853a5657fd883015cdbf07ad6466918acf
value: af22c87d0db59dece97d03e6b6a796d84010158f
- name: pathInRepo
value: task/kaniko/0.6/kaniko.yaml
value: task/buildkit-rootless-daemonless/0.1/buildkit-rootless-daemonless.yaml
params:
- name: IMAGE
value: "$(params.image-name):$(tasks.fetch-repository.results.commit)"
- name: OUTPUT
value: >-
type=image,"name=$(params.image-name):latest,$(params.image-name):$(tasks.fetch-repository.results.commit)",push=true,compression=zstd,compression-level=22,oci-mediatypes=true
- name: CONTEXT
value: $(params.path-to-image-context)
- name: DOCKERFILE
value: $(params.path-to-dockerfile)
- name: BUILDER_IMAGE
value: "gcr.io/kaniko-project/executor:v1.12.1"
- name: EXTRA_ARGS
value:
- --cache=true
- --cache-copy-layers
- --cache-repo=harbor.fizz.buzz/kanikocache/cache
- --use-new-run # Should result in a speed-up
- --reproducible # To remove timestamps so layer caching works.
- --snapshot-mode=redo
- --skip-unused-stages=true
- --registry-mirror=dockerhub.dockerhub.svc.cluster.local
- "--opt"
- "target=$(params.target-name)"
- --import-cache
- "type=registry,ref=$(params.image-name):buildcache"
- --export-cache
- "type=registry,ref=$(params.image-name):buildcache,mode=max,compression=zstd,compression-level=22,rewrite-timestamp=true,image-manifest=true,oci-mediatypes=true"
- --opt
- build-arg:SOURCE_DATE_EPOCH=$(tasks.get-git-commit-time.results.unix-time)
- name: BUILDKITD_TOML
value: |
debug = true
[registry."docker.io"]
mirrors = ["dockerhub.dockerhub.svc.cluster.local"]
[registry."dockerhub.dockerhub.svc.cluster.local"]
http = true
insecure = true
workspaces:
- name: source
workspace: git-source
@@ -111,9 +144,9 @@ spec:
- name: docker-image
type: string
description: Docker image to run.
default: alpine:3.19
default: alpine:3.20
stepTemplate:
image: alpine:3.19
image: alpine:3.20
computeResources:
requests:
cpu: 10m
@@ -143,52 +176,15 @@ spec:
- build-image
params:
- name: docker-image
value: "$(params.image-name):$(tasks.fetch-repository.results.commit)"
- name: run-prettier
taskSpec:
metadata: {}
params:
- name: docker-image
type: string
description: Docker image to run.
default: alpine:3.19
stepTemplate:
image: alpine:3.19
computeResources:
requests:
cpu: 10m
memory: 600Mi
workingDir: /workspace/source
workspaces:
- name: source
mountPath: /source
steps:
- name: run
image: $(params.docker-image)
workingDir: "$(workspaces.source.path)"
command: ["sh", "-c"]
args:
- |
prettier --write --no-error-on-unmatched-pattern "default_environment/**/*.js" "default_environment/**/*.css"
env:
- name: CARGO_TARGET_DIR
value: /target
workspaces:
- name: source
workspace: git-source
runAfter:
- run-cargo-fmt
params:
- name: docker-image
value: "$(params.image-name):$(tasks.fetch-repository.results.commit)"
value: "$(tasks.build-image.results.IMAGE_URL[1])"
- name: commit-changes
taskRef:
resolver: git
params:
- name: url
value: https://github.com/tektoncd/catalog.git
value: https://code.fizz.buzz/mirror/catalog.git # mirror of https://github.com/tektoncd/catalog.git
- name: revision
value: df36b3853a5657fd883015cdbf07ad6466918acf
value: f914437a46978b95f325f68d791dcf1a35738f60
- name: pathInRepo
value: task/git-cli/0.4/git-cli.yaml
params:
@@ -211,7 +207,7 @@ spec:
- name: source
workspace: git-source
runAfter:
- run-prettier
- run-cargo-fmt
finally:
- name: report-success
when:
@@ -222,9 +218,9 @@ spec:
resolver: git
params:
- name: url
value: https://github.com/tektoncd/catalog.git
value: https://code.fizz.buzz/mirror/catalog.git # mirror of https://github.com/tektoncd/catalog.git
- name: revision
value: df36b3853a5657fd883015cdbf07ad6466918acf
value: f914437a46978b95f325f68d791dcf1a35738f60
- name: pathInRepo
value: task/gitea-set-status/0.1/gitea-set-status.yaml
params:
@@ -251,9 +247,9 @@ spec:
resolver: git
params:
- name: url
value: https://github.com/tektoncd/catalog.git
value: https://code.fizz.buzz/mirror/catalog.git # mirror of https://github.com/tektoncd/catalog.git
- name: revision
value: df36b3853a5657fd883015cdbf07ad6466918acf
value: f914437a46978b95f325f68d791dcf1a35738f60
- name: pathInRepo
value: task/gitea-set-status/0.1/gitea-set-status.yaml
params:
@@ -278,9 +274,9 @@ spec:
- name: docker-image
type: string
description: Docker image to run.
default: alpine:3.19
default: alpine:3.20
stepTemplate:
image: alpine:3.19
image: alpine:3.20
computeResources:
requests:
cpu: 10m
@@ -305,7 +301,7 @@ spec:
workspace: cargo-cache
params:
- name: docker-image
value: "$(params.image-name):$(tasks.fetch-repository.results.commit)"
value: "$(tasks.build-image.results.IMAGE_URL[1])"
workspaces:
- name: git-source
- name: docker-credentials
@@ -314,7 +310,7 @@ spec:
- name: git-source
volumeClaimTemplate:
spec:
storageClassName: "nfs-client"
storageClassName: "local-path"
accessModes:
- ReadWriteOnce
resources:
@@ -329,8 +325,10 @@ spec:
secretName: harbor-plain
params:
- name: image-name
value: "harbor.fizz.buzz/private/webhook-bridge-development"
value: "harbor.fizz.buzz/private/webhook-bridge-development-format"
- name: target-name
value: ""
- name: path-to-image-context
value: docker/webhook_bridge_development/
- name: path-to-dockerfile
value: docker/webhook_bridge_development/Dockerfile
value: docker/webhook_bridge_development/

View File

@@ -14,6 +14,9 @@ spec:
- name: image-name
description: The name for the built image
type: string
- name: target-name
description: The dockerfile target to build
type: string
- name: path-to-image-context
description: The path to the build context
type: string
@@ -26,13 +29,11 @@ spec:
resolver: git
params:
- name: url
value: https://github.com/tektoncd/catalog.git
value: https://code.fizz.buzz/mirror/catalog.git # mirror of https://github.com/tektoncd/catalog.git
- name: revision
value: df36b3853a5657fd883015cdbf07ad6466918acf
value: f914437a46978b95f325f68d791dcf1a35738f60
- name: pathInRepo
value: task/gitea-set-status/0.1/gitea-set-status.yaml
runAfter:
- fetch-repository
params:
- name: CONTEXT
value: "$(params.JOB_NAME)"
@@ -53,9 +54,9 @@ spec:
resolver: git
params:
- name: url
value: https://github.com/tektoncd/catalog.git
value: https://code.fizz.buzz/mirror/catalog.git # mirror of https://github.com/tektoncd/catalog.git
- name: revision
value: df36b3853a5657fd883015cdbf07ad6466918acf
value: f914437a46978b95f325f68d791dcf1a35738f60
- name: pathInRepo
value: task/git-clone/0.9/git-clone.yaml
workspaces:
@@ -68,35 +69,67 @@ spec:
value: $(params.PULL_BASE_SHA)
- name: deleteExisting
value: "true"
- name: get-git-commit-time
taskSpec:
metadata: {}
stepTemplate:
image: alpine:3.20
computeResources:
requests:
cpu: 10m
memory: 600Mi
workingDir: "$(workspaces.repo.path)"
results:
- name: unix-time
description: The time of the git commit in unix timestamp format.
steps:
- image: alpine/git:v2.34.2
name: detect-tag-step
script: |
#!/usr/bin/env sh
set -euo pipefail
echo -n "$(git log -1 --pretty=%ct)" | tee $(results.unix-time.path)
workspaces:
- name: repo
workspace: git-source
runAfter:
- fetch-repository
- name: build-image
taskRef:
resolver: git
params:
- name: url
value: https://github.com/tektoncd/catalog.git
value: https://code.fizz.buzz/talexander/personal_tekton_catalog.git
- name: revision
value: df36b3853a5657fd883015cdbf07ad6466918acf
value: af22c87d0db59dece97d03e6b6a796d84010158f
- name: pathInRepo
value: task/kaniko/0.6/kaniko.yaml
value: task/buildkit-rootless-daemonless/0.1/buildkit-rootless-daemonless.yaml
params:
- name: IMAGE
value: "$(params.image-name):$(tasks.fetch-repository.results.commit)"
- name: OUTPUT
value: >-
type=image,"name=$(params.image-name):latest,$(params.image-name):$(tasks.fetch-repository.results.commit)",push=true,compression=zstd,compression-level=22,oci-mediatypes=true
- name: CONTEXT
value: $(params.path-to-image-context)
- name: DOCKERFILE
value: $(params.path-to-dockerfile)
- name: BUILDER_IMAGE
value: "gcr.io/kaniko-project/executor:v1.12.1"
- name: EXTRA_ARGS
value:
- --cache=true
- --cache-copy-layers
- --cache-repo=harbor.fizz.buzz/kanikocache/cache
- --use-new-run # Should result in a speed-up
- --reproducible # To remove timestamps so layer caching works.
- --snapshot-mode=redo
- --skip-unused-stages=true
- --registry-mirror=dockerhub.dockerhub.svc.cluster.local
- "--opt"
- "target=$(params.target-name)"
- --import-cache
- "type=registry,ref=$(params.image-name):buildcache"
- --export-cache
- "type=registry,ref=$(params.image-name):buildcache,mode=max,compression=zstd,compression-level=22,rewrite-timestamp=true,image-manifest=true,oci-mediatypes=true"
- --opt
- build-arg:SOURCE_DATE_EPOCH=$(tasks.get-git-commit-time.results.unix-time)
- name: BUILDKITD_TOML
value: |
debug = true
[registry."docker.io"]
mirrors = ["dockerhub.dockerhub.svc.cluster.local"]
[registry."dockerhub.dockerhub.svc.cluster.local"]
http = true
insecure = true
workspaces:
- name: source
workspace: git-source
@@ -111,9 +144,9 @@ spec:
- name: docker-image
type: string
description: Docker image to run.
default: alpine:3.19
default: alpine:3.20
stepTemplate:
image: alpine:3.19
image: alpine:3.20
computeResources:
requests:
cpu: 10m
@@ -153,7 +186,7 @@ spec:
- build-image
params:
- name: docker-image
value: "$(params.image-name):$(tasks.fetch-repository.results.commit)"
value: "$(tasks.build-image.results.IMAGE_URL[1])"
finally:
- name: report-success
when:
@@ -164,9 +197,9 @@ spec:
resolver: git
params:
- name: url
value: https://github.com/tektoncd/catalog.git
value: https://code.fizz.buzz/mirror/catalog.git # mirror of https://github.com/tektoncd/catalog.git
- name: revision
value: df36b3853a5657fd883015cdbf07ad6466918acf
value: f914437a46978b95f325f68d791dcf1a35738f60
- name: pathInRepo
value: task/gitea-set-status/0.1/gitea-set-status.yaml
params:
@@ -193,9 +226,9 @@ spec:
resolver: git
params:
- name: url
value: https://github.com/tektoncd/catalog.git
value: https://code.fizz.buzz/mirror/catalog.git # mirror of https://github.com/tektoncd/catalog.git
- name: revision
value: df36b3853a5657fd883015cdbf07ad6466918acf
value: f914437a46978b95f325f68d791dcf1a35738f60
- name: pathInRepo
value: task/gitea-set-status/0.1/gitea-set-status.yaml
params:
@@ -220,9 +253,9 @@ spec:
- name: docker-image
type: string
description: Docker image to run.
default: alpine:3.19
default: alpine:3.20
stepTemplate:
image: alpine:3.19
image: alpine:3.20
computeResources:
requests:
cpu: 10m
@@ -247,7 +280,7 @@ spec:
workspace: cargo-cache
params:
- name: docker-image
value: "$(params.image-name):$(tasks.fetch-repository.results.commit)"
value: "$(tasks.build-image.results.IMAGE_URL[1])"
workspaces:
- name: git-source
- name: docker-credentials
@@ -256,7 +289,7 @@ spec:
- name: git-source
volumeClaimTemplate:
spec:
storageClassName: "nfs-client"
storageClassName: "local-path"
accessModes:
- ReadWriteOnce
resources:
@@ -271,8 +304,10 @@ spec:
secretName: harbor-plain
params:
- name: image-name
value: "harbor.fizz.buzz/private/webhook-bridge-development"
value: "harbor.fizz.buzz/private/webhook-bridge-development-clippy"
- name: target-name
value: ""
- name: path-to-image-context
value: docker/webhook_bridge_development/
- name: path-to-dockerfile
value: docker/webhook_bridge_development/Dockerfile
value: docker/webhook_bridge_development/

View File

@@ -14,6 +14,9 @@ spec:
- name: image-name
description: The name for the built image
type: string
- name: target-name
description: The dockerfile target to build
type: string
- name: path-to-image-context
description: The path to the build context
type: string
@@ -26,13 +29,11 @@ spec:
resolver: git
params:
- name: url
value: https://github.com/tektoncd/catalog.git
value: https://code.fizz.buzz/mirror/catalog.git # mirror of https://github.com/tektoncd/catalog.git
- name: revision
value: df36b3853a5657fd883015cdbf07ad6466918acf
value: f914437a46978b95f325f68d791dcf1a35738f60
- name: pathInRepo
value: task/gitea-set-status/0.1/gitea-set-status.yaml
runAfter:
- fetch-repository
params:
- name: CONTEXT
value: "$(params.JOB_NAME)"
@@ -53,9 +54,9 @@ spec:
resolver: git
params:
- name: url
value: https://github.com/tektoncd/catalog.git
value: https://code.fizz.buzz/mirror/catalog.git # mirror of https://github.com/tektoncd/catalog.git
- name: revision
value: df36b3853a5657fd883015cdbf07ad6466918acf
value: f914437a46978b95f325f68d791dcf1a35738f60
- name: pathInRepo
value: task/git-clone/0.9/git-clone.yaml
workspaces:
@@ -68,35 +69,67 @@ spec:
value: $(params.PULL_BASE_SHA)
- name: deleteExisting
value: "true"
- name: get-git-commit-time
taskSpec:
metadata: {}
stepTemplate:
image: alpine:3.20
computeResources:
requests:
cpu: 10m
memory: 600Mi
workingDir: "$(workspaces.repo.path)"
results:
- name: unix-time
description: The time of the git commit in unix timestamp format.
steps:
- image: alpine/git:v2.34.2
name: detect-tag-step
script: |
#!/usr/bin/env sh
set -euo pipefail
echo -n "$(git log -1 --pretty=%ct)" | tee $(results.unix-time.path)
workspaces:
- name: repo
workspace: git-source
runAfter:
- fetch-repository
- name: build-image
taskRef:
resolver: git
params:
- name: url
value: https://github.com/tektoncd/catalog.git
value: https://code.fizz.buzz/talexander/personal_tekton_catalog.git
- name: revision
value: df36b3853a5657fd883015cdbf07ad6466918acf
value: af22c87d0db59dece97d03e6b6a796d84010158f
- name: pathInRepo
value: task/kaniko/0.6//kaniko.yaml
value: task/buildkit-rootless-daemonless/0.1/buildkit-rootless-daemonless.yaml
params:
- name: IMAGE
value: "$(params.image-name):$(tasks.fetch-repository.results.commit)"
- name: OUTPUT
value: >-
type=image,"name=$(params.image-name):latest,$(params.image-name):$(tasks.fetch-repository.results.commit)",push=true,compression=zstd,compression-level=22,oci-mediatypes=true
- name: CONTEXT
value: $(params.path-to-image-context)
- name: DOCKERFILE
value: $(params.path-to-dockerfile)
- name: BUILDER_IMAGE
value: "gcr.io/kaniko-project/executor:v1.12.1"
- name: EXTRA_ARGS
value:
- --cache=true
- --cache-copy-layers
- --cache-repo=harbor.fizz.buzz/kanikocache/cache
- --use-new-run # Should result in a speed-up
- --reproducible # To remove timestamps so layer caching works.
- --snapshot-mode=redo
- --skip-unused-stages=true
- --registry-mirror=dockerhub.dockerhub.svc.cluster.local
- "--opt"
- "target=$(params.target-name)"
- --import-cache
- "type=registry,ref=$(params.image-name):buildcache"
- --export-cache
- "type=registry,ref=$(params.image-name):buildcache,mode=max,compression=zstd,compression-level=22,rewrite-timestamp=true,image-manifest=true,oci-mediatypes=true"
- --opt
- build-arg:SOURCE_DATE_EPOCH=$(tasks.get-git-commit-time.results.unix-time)
- name: BUILDKITD_TOML
value: |
debug = true
[registry."docker.io"]
mirrors = ["dockerhub.dockerhub.svc.cluster.local"]
[registry."dockerhub.dockerhub.svc.cluster.local"]
http = true
insecure = true
workspaces:
- name: source
workspace: git-source
@@ -111,9 +144,9 @@ spec:
- name: docker-image
type: string
description: Docker image to run.
default: alpine:3.19
default: alpine:3.20
stepTemplate:
image: alpine:3.19
image: alpine:3.20
computeResources:
requests:
cpu: 10m
@@ -143,7 +176,7 @@ spec:
- build-image
params:
- name: docker-image
value: "$(params.image-name):$(tasks.fetch-repository.results.commit)"
value: "$(tasks.build-image.results.IMAGE_URL[1])"
finally:
- name: report-success
when:
@@ -154,9 +187,9 @@ spec:
resolver: git
params:
- name: url
value: https://github.com/tektoncd/catalog.git
value: https://code.fizz.buzz/mirror/catalog.git # mirror of https://github.com/tektoncd/catalog.git
- name: revision
value: df36b3853a5657fd883015cdbf07ad6466918acf
value: f914437a46978b95f325f68d791dcf1a35738f60
- name: pathInRepo
value: task/gitea-set-status/0.1/gitea-set-status.yaml
params:
@@ -183,9 +216,9 @@ spec:
resolver: git
params:
- name: url
value: https://github.com/tektoncd/catalog.git
value: https://code.fizz.buzz/mirror/catalog.git # mirror of https://github.com/tektoncd/catalog.git
- name: revision
value: df36b3853a5657fd883015cdbf07ad6466918acf
value: f914437a46978b95f325f68d791dcf1a35738f60
- name: pathInRepo
value: task/gitea-set-status/0.1/gitea-set-status.yaml
params:
@@ -210,9 +243,9 @@ spec:
- name: docker-image
type: string
description: Docker image to run.
default: alpine:3.19
default: alpine:3.20
stepTemplate:
image: alpine:3.19
image: alpine:3.20
computeResources:
requests:
cpu: 10m
@@ -237,7 +270,7 @@ spec:
workspace: cargo-cache
params:
- name: docker-image
value: "$(params.image-name):$(tasks.fetch-repository.results.commit)"
value: "$(tasks.build-image.results.IMAGE_URL[1])"
workspaces:
- name: git-source
- name: docker-credentials
@@ -246,7 +279,7 @@ spec:
- name: git-source
volumeClaimTemplate:
spec:
storageClassName: "nfs-client"
storageClassName: "local-path"
accessModes:
- ReadWriteOnce
resources:
@@ -261,8 +294,10 @@ spec:
secretName: harbor-plain
params:
- name: image-name
value: "harbor.fizz.buzz/private/webhook-bridge-development"
value: "harbor.fizz.buzz/private/webhook-bridge-development-test"
- name: target-name
value: ""
- name: path-to-image-context
value: docker/webhook_bridge_development/
- name: path-to-dockerfile
value: docker/webhook_bridge_development/Dockerfile
value: docker/webhook_bridge_development/

View File

@@ -0,0 +1,187 @@
apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
name: semver
spec:
timeouts:
pipeline: "2h0m0s"
tasks: "1h0m0s"
finally: "0h30m0s"
taskRunTemplate:
serviceAccountName: build-bot
pipelineSpec:
params:
- name: REPO_OWNER
description: Owner of the repo on gitea
type: string
- name: REPO_NAME
description: Name of the repo on gitea
type: string
- name: PULL_BASE_SHA
description: The commit sha
type: string
- name: JOB_NAME
description: The name of the job to report to gitea
type: string
tasks:
- name: calculate-tag
runAfter:
- fetch-repository
workspaces:
- name: source
workspace: git-source
taskSpec:
metadata: {}
stepTemplate:
image: alpine:3.20
computeResources:
requests:
cpu: 10m
memory: 600Mi
workingDir: /workspace/source
results:
- name: tag
description: The tag to use for the docker container
steps:
- image: alpine/git:2.43.0
name: calculate-tag
script: |
#!/usr/bin/env sh
set -euo pipefail
git config --global --add safe.directory $(workspaces.source.path)
git fetch --tags
current_tag=$(git tag --points-at HEAD --list 'v*.*.*')
if [ -z "$current_tag" ]; then
prev_tag=$(git tag --list 'v*.*.*' | sort -V -r | head -n 1)
if [ -n "$prev_tag" ]; then
last_bit=$(echo "$prev_tag" | cut -d '.' -f 3)
incremented=$((last_bit + 1))
prefix=$(echo "$prev_tag" | grep -oE 'v[0-9]*\.[0-9]*\.')
final_tag="${prefix}${incremented}"
else
final_tag="v0.0.1"
fi
echo -n "${final_tag}" | tee $(results.tag.path)
git tag "${final_tag}"
git push origin "${final_tag}"
else
echo -n "${current_tag}" | tee $(results.tag.path)
fi
- name: report-pending
taskRef:
resolver: git
params:
- name: url
value: https://code.fizz.buzz/mirror/catalog.git # mirror of https://github.com/tektoncd/catalog.git
- name: revision
value: f914437a46978b95f325f68d791dcf1a35738f60
- name: pathInRepo
value: task/gitea-set-status/0.1/gitea-set-status.yaml
params:
- name: CONTEXT
value: "$(params.JOB_NAME)"
- name: REPO_FULL_NAME
value: "$(params.REPO_OWNER)/$(params.REPO_NAME)"
- name: GITEA_HOST_URL
value: code.fizz.buzz
- name: SHA
value: "$(tasks.fetch-repository.results.commit)"
- name: DESCRIPTION
value: "Build $(params.JOB_NAME) has started"
- name: STATE
value: pending
- name: TARGET_URL
value: "https://tekton.fizz.buzz/#/namespaces/$(context.pipelineRun.namespace)/pipelineruns/$(context.pipelineRun.name)"
- name: fetch-repository
taskRef:
resolver: git
params:
- name: url
value: https://code.fizz.buzz/mirror/catalog.git # mirror of https://github.com/tektoncd/catalog.git
- name: revision
value: f914437a46978b95f325f68d791dcf1a35738f60
- name: pathInRepo
value: task/git-clone/0.9/git-clone.yaml
workspaces:
- name: output
workspace: git-source
params:
- name: url
value: $(params.REPO_URL)
- name: revision
value: $(params.PULL_BASE_SHA)
- name: deleteExisting
value: "true"
finally:
- name: report-success
when:
- input: "$(tasks.status)"
operator: in
values: ["Succeeded", "Completed"]
taskRef:
resolver: git
params:
- name: url
value: https://code.fizz.buzz/mirror/catalog.git # mirror of https://github.com/tektoncd/catalog.git
- name: revision
value: f914437a46978b95f325f68d791dcf1a35738f60
- name: pathInRepo
value: task/gitea-set-status/0.1/gitea-set-status.yaml
params:
- name: CONTEXT
value: "$(params.JOB_NAME)"
- name: REPO_FULL_NAME
value: "$(params.REPO_OWNER)/$(params.REPO_NAME)"
- name: GITEA_HOST_URL
value: code.fizz.buzz
- name: SHA
value: "$(tasks.fetch-repository.results.commit)"
- name: DESCRIPTION
value: "Build $(params.JOB_NAME) has succeeded"
- name: STATE
value: success
- name: TARGET_URL
value: "https://tekton.fizz.buzz/#/namespaces/$(context.pipelineRun.namespace)/pipelineruns/$(context.pipelineRun.name)"
- name: report-failure
when:
- input: "$(tasks.status)"
operator: in
values: ["Failed"]
taskRef:
resolver: git
params:
- name: url
value: https://code.fizz.buzz/mirror/catalog.git # mirror of https://github.com/tektoncd/catalog.git
- name: revision
value: f914437a46978b95f325f68d791dcf1a35738f60
- name: pathInRepo
value: task/gitea-set-status/0.1/gitea-set-status.yaml
params:
- name: CONTEXT
value: "$(params.JOB_NAME)"
- name: REPO_FULL_NAME
value: "$(params.REPO_OWNER)/$(params.REPO_NAME)"
- name: GITEA_HOST_URL
value: code.fizz.buzz
- name: SHA
value: "$(tasks.fetch-repository.results.commit)"
- name: DESCRIPTION
value: "Build $(params.JOB_NAME) has failed"
- name: STATE
value: failure
- name: TARGET_URL
value: "https://tekton.fizz.buzz/#/namespaces/$(context.pipelineRun.namespace)/pipelineruns/$(context.pipelineRun.name)"
workspaces:
- name: git-source
workspaces:
- name: git-source
volumeClaimTemplate:
spec:
storageClassName: "local-path"
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
subPath: source
params: []

View File

@@ -1,19 +1,31 @@
version = "0.0.1"
[[push]]
name = "rust-test"
source = "pipeline-rust-test.yaml"
clone_uri = "git@code.fizz.buzz:talexander/webhook_bridge.git"
branches = [ "^main$", "^master$" ]
name = "rust-test"
source = "pipeline-rust-test.yaml"
clone_uri = "git@code.fizz.buzz:talexander/webhook_bridge.git"
skip_branches = [ "^v[0-9]+\\.[0-9]+\\.[0-9]+$" ]
[[push]]
name = "clippy"
source = "pipeline-rust-clippy.yaml"
clone_uri = "git@code.fizz.buzz:talexander/webhook_bridge.git"
skip_branches = [ "^v[0-9]+\\.[0-9]+\\.[0-9]+$" ]
name = "clippy"
source = "pipeline-rust-clippy.yaml"
clone_uri = "git@code.fizz.buzz:talexander/webhook_bridge.git"
skip_branches = [ "^v[0-9]+\\.[0-9]+\\.[0-9]+$" ]
[[push]]
name = "format"
source = "pipeline-format.yaml"
clone_uri = "git@code.fizz.buzz:talexander/webhook_bridge.git"
skip_branches = [ "^v[0-9]+\\.[0-9]+\\.[0-9]+$" ]
name = "format"
source = "pipeline-format.yaml"
clone_uri = "git@code.fizz.buzz:talexander/webhook_bridge.git"
skip_branches = [ "^v[0-9]+\\.[0-9]+\\.[0-9]+$" ]
[[push]]
name = "semver"
source = "pipeline-semver.yaml"
clone_uri = "git@code.fizz.buzz:talexander/webhook_bridge.git"
branches = [ "^main$", "^master$" ]
[[push]]
name = "build"
source = "pipeline-build-semver.yaml"
clone_uri = "git@code.fizz.buzz:talexander/webhook_bridge.git"
branches = [ "^v[0-9]+\\.[0-9]+\\.[0-9]+$" ]

106
Cargo.lock generated
View File

@@ -1,6 +1,6 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
version = 4
[[package]]
name = "addr2line"
@@ -1039,11 +1039,11 @@ checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]]
name = "matchers"
version = "0.1.0"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9"
dependencies = [
"regex-automata 0.1.10",
"regex-automata",
]
[[package]]
@@ -1101,16 +1101,6 @@ dependencies = [
"tempfile",
]
[[package]]
name = "nu-ansi-term"
version = "0.46.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
dependencies = [
"overload",
"winapi",
]
[[package]]
name = "num-traits"
version = "0.2.19"
@@ -1198,12 +1188,6 @@ dependencies = [
"num-traits",
]
[[package]]
name = "overload"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
[[package]]
name = "parking"
version = "2.2.0"
@@ -1403,17 +1387,8 @@ checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata 0.4.7",
"regex-syntax 0.8.4",
]
[[package]]
name = "regex-automata"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
dependencies = [
"regex-syntax 0.6.29",
"regex-automata",
"regex-syntax",
]
[[package]]
@@ -1424,15 +1399,9 @@ checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax 0.8.4",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.6.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
[[package]]
name = "regex-syntax"
version = "0.8.4"
@@ -2095,9 +2064,9 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
[[package]]
name = "tracing"
version = "0.1.40"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
dependencies = [
"log",
"pin-project-lite",
@@ -2107,9 +2076,9 @@ dependencies = [
[[package]]
name = "tracing-attributes"
version = "0.1.27"
version = "0.1.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
dependencies = [
"proc-macro2",
"quote",
@@ -2118,41 +2087,26 @@ dependencies = [
[[package]]
name = "tracing-core"
version = "0.1.32"
version = "0.1.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
dependencies = [
"once_cell",
"valuable",
]
[[package]]
name = "tracing-log"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
dependencies = [
"log",
"once_cell",
"tracing-core",
]
[[package]]
name = "tracing-subscriber"
version = "0.3.18"
version = "0.3.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b"
checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319"
dependencies = [
"matchers",
"nu-ansi-term",
"once_cell",
"regex",
"regex-automata",
"sharded-slab",
"smallvec",
"thread_local",
"tracing",
"tracing-core",
"tracing-log",
]
[[package]]
@@ -2217,12 +2171,6 @@ dependencies = [
"percent-encoding",
]
[[package]]
name = "valuable"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
[[package]]
name = "vcpkg"
version = "0.2.15"
@@ -2350,28 +2298,6 @@ dependencies = [
"tracing-subscriber",
]
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
version = "0.48.0"

View File

@@ -7,7 +7,7 @@ description = "Trigger tekton jobs with gitea webhooks."
license = "0BSD"
repository = "https://code.fizz.buzz/talexander/webhook_bridge"
readme = "README.md"
keywords = ["gitea", "webhook"]
keywords = ["tekton", "gitea", "webhook"]
categories = ["development-tools"]
resolver = "2"
include = [
@@ -17,8 +17,26 @@ include = [
"Cargo.lock"
]
[lib]
name = "webhookbridge"
path = "src/lib.rs"
[[bin]]
name = "webhook_bridge"
path = "src/main.rs"
[[bin]]
# This bin exists for development purposes only. The real target of this crate is the webhook_bridge server binary.
name = "local_trigger"
path = "src/bin_local_trigger.rs"
required-features = ["local_trigger"]
[features]
default = ["local_trigger"]
local_trigger = []
[dependencies]
axum = { version = "0.7.5", default-features = false, features = ["tokio", "http1", "http2", "json"] }
axum = { version = "0.7.5", default-features = false, features = ["tokio", "http1", "json"] }
base64 = "0.22.1"
hmac = "0.12.1"
http-body-util = "0.1.2"
@@ -34,8 +52,8 @@ sha2 = "0.10.8"
tokio = { version = "1.38.0", default-features = false, features = ["macros", "process", "rt-multi-thread", "signal"] }
toml = { version = "0.8.19", default-features = false, features = ["display", "parse"] }
tower-http = { version = "0.5.2", default-features = false, features = ["trace", "timeout"] }
tracing = { version = "0.1.40", default-features = false, features = ["attributes", "std", "tracing-attributes", "async-await"] }
tracing-subscriber = { version = "0.3.18", default-features = false, features = ["alloc", "ansi", "fmt", "nu-ansi-term", "registry", "sharded-slab", "smallvec", "std", "thread_local", "tracing-log", "env-filter"] }
tracing = { version = "0.1.44", default-features = false, features = [] }
tracing-subscriber = { version = "0.3.23", default-features = false, features = ["env-filter", "fmt"] }
[profile.release-lto]
inherits = "release"

36
Makefile Normal file
View File

@@ -0,0 +1,36 @@
SHELL := bash
.ONESHELL:
.SHELLFLAGS := -eu -o pipefail -c
.DELETE_ON_ERROR:
MAKEFLAGS += --warn-undefined-variables
MAKEFLAGS += --no-builtin-rules
OS:=$(shell uname -s)
ifeq ($(origin .RECIPEPREFIX), undefined)
$(error This Make does not support .RECIPEPREFIX. Please use GNU Make 4.0 or later)
endif
.RECIPEPREFIX = >
.PHONY: help
help:
> @grep -h "##" $(MAKEFILE_LIST) | grep -v grep | sed -E 's/^([^:]*): *## */\1: /'
.PHONY: test
test: ## Run the rust tests
> $(MAKE) -C docker/webhook_bridge_development build
> docker run --rm -i -t --mount type=tmpfs,destination=/tmp -v "$(shell readlink -f .):/source" --workdir=/source --env CARGO_TARGET_DIR=/target -v "webhook-bridge-cargo-registry:/usr/local/cargo/registry" -v "webhook-bridge-rust-target:/target" webhook-bridge-development cargo test
.PHONY: clippy
clippy: ## Run static analysis of the code.
> $(MAKE) -C docker/webhook_bridge_development build
> docker run --rm -i -t --mount type=tmpfs,destination=/tmp -v "$(shell readlink -f .):/source" --workdir=/source --env CARGO_TARGET_DIR=/target -v "webhook-bridge-cargo-registry:/usr/local/cargo/registry" -v "webhook-bridge-rust-target:/target" webhook-bridge-development cargo clippy --no-deps --all-targets --all-features -- -D warnings
.PHONY: format
format: ## Auto-format source files.
> $(MAKE) -C docker/webhook_bridge_development build
> docker run --rm -i -t --mount type=tmpfs,destination=/tmp -v "$(shell readlink -f .):/source" --workdir=/source --env CARGO_TARGET_DIR=/target -v "webhook-bridge-cargo-registry:/usr/local/cargo/registry" -v "webhook-bridge-rust-target:/target" webhook-bridge-development cargo fmt
.PHONY: clean
clean:
> $(MAKE) -C docker/webhook_bridge_development clean
> rm -rf target

View File

@@ -0,0 +1,42 @@
#
# Builder
#
FROM nixos/nix:latest AS builder
RUN cp "$(nix --extra-experimental-features "nix-command flakes" --option filter-syscalls false build nixpkgs#cacert --print-out-paths)/etc/ssl/certs/ca-bundle.crt" /tmp/ca-bundle.crt
COPY . /tmp/build
WORKDIR /tmp/build
RUN nix \
--extra-experimental-features "nix-command flakes" \
--option filter-syscalls false \
build '.#docker_env'
# Export the built closure to a folder
RUN mkdir /tmp/nix-store-closure
RUN cp -R $(nix-store -qR result/) /tmp/nix-store-closure
RUN ln -s $(readlink -f /tmp/build/result/bin/sh) /tmp/sh
#
# Runner
#
FROM scratch
WORKDIR /app
ENV PATH="$PATH:/app/bin"
ENV SSL_CERT_FILE=/etc/ssl/certs/ca-bundle.crt
ENV NIX_SSL_CERT_FILE=/etc/ssl/certs/ca-bundle.crt
COPY --from=builder /tmp/ca-bundle.crt /etc/ssl/certs/ca-bundle.crt
COPY --from=builder /tmp/nix-store-closure /nix/store
COPY --from=builder /tmp/build/result /app
COPY --from=builder /tmp/sh /bin/sh
EXPOSE 9988
CMD ["/app/bin/webhook_bridge"]

View File

@@ -0,0 +1,31 @@
SHELL := bash
.ONESHELL:
.SHELLFLAGS := -eu -o pipefail -c
.DELETE_ON_ERROR:
MAKEFLAGS += --warn-undefined-variables
MAKEFLAGS += --no-builtin-rules
ifeq ($(origin .RECIPEPREFIX), undefined)
$(error This Make does not support .RECIPEPREFIX. Please use GNU Make 4.0 or later)
endif
.RECIPEPREFIX = >
IMAGE_NAME:=webhook-bridge
TARGET :=
.PHONY: help
help:
> @grep -h "##" $(MAKEFILE_LIST) | grep -v grep | sed -E 's/^([^:]*): *## */\1: /'
.PHONY: build
build: ## Build the docker image.
> docker build --tag $(IMAGE_NAME) --target=$(TARGET) --file Dockerfile ../../
.PHONY: shell
shell: ## Launch an interactive shell inside the docker image with the source repository mounted at /source.
shell: build
> docker run --rm -i -t --entrypoint /bin/sh --mount type=tmpfs,destination=/tmp $(IMAGE_NAME)
.PHONY: clean
clean:
> docker rmi $(IMAGE_NAME)

View File

@@ -1,6 +1,9 @@
FROM rustlang/rust:nightly-alpine3.19 AS builder
# syntax=docker/dockerfile:1
ARG ALPINE_VERSION="3.20"
RUN apk add --no-cache musl-dev
RUN cargo install --locked --no-default-features --features ci-autoclean cargo-cache
FROM rustlang/rust:nightly-alpine$ALPINE_VERSION AS builder
RUN apk add --no-cache musl-dev pkgconfig libressl3.8-libssl libressl-dev
RUN --mount=type=tmpfs,target=/tmp --mount=type=cache,target=/usr/local/cargo/registry,sharing=locked cargo install --locked --no-default-features --features ci-autoclean cargo-cache
RUN rustup component add rustfmt
RUN rustup component add clippy

View File

@@ -21,6 +21,7 @@ help:
build: ## Build the docker image.
> docker build --tag $(IMAGE_NAME) --target=$(TARGET) --file Dockerfile .
> docker volume create webhook-bridge-cargo-registry
> docker volume create webhook-bridge-rust-target
.PHONY: shell
shell: ## Launch an interactive shell inside the docker image with the source repository mounted at /source.
@@ -31,3 +32,4 @@ shell: build
clean:
> docker rmi $(IMAGE_NAME)
> docker volume rm webhook-bridge-cargo-registry
> docker volume rm webhook-bridge-rust-target

View File

@@ -1,70 +0,0 @@
{
"apiVersion": "tekton.dev/v1",
"kind": "PipelineRun",
"metadata": {
"name": "minimal-test",
"namespace": "lighthouse"
},
"spec": {
"pipelineSpec": {
"tasks": [
{
"name": "echo-variable",
"taskSpec": {
"metadata": {},
"stepTemplate": {
"image": "alpine:3.18",
"computeResources": {
"requests": {
"cpu": "10m",
"memory": "600Mi"
}
}
},
"steps": [
{
"image": "alpine:3.18",
"script": "#!/usr/bin/env sh\necho \"The variable: $(params.LOREM)\"\n"
}
]
},
"params": [
{
"name": "LOREM",
"value": "$(tasks.set-variable.results.ipsum)"
}
]
},
{
"name": "set-variable",
"taskSpec": {
"metadata": {},
"stepTemplate": {
"image": "alpine:3.18",
"computeResources": {
"requests": {
"cpu": "10m",
"memory": "600Mi"
}
}
},
"results": [
{
"name": "ipsum"
}
],
"steps": [
{
"image": "alpine:3.18",
"script": "#!/usr/bin/env sh\necho -n \"dolar\" > \"$(results.ipsum.path)\"\n"
}
]
}
}
]
},
"timeouts": {
"pipeline": "240h0m0s"
}
}
}

View File

@@ -1,43 +0,0 @@
apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
name: minimal-test
namespace: lighthouse
spec:
pipelineSpec:
tasks:
- name: echo-variable
taskSpec:
metadata: {}
stepTemplate:
image: alpine:3.18
computeResources:
requests:
cpu: 10m
memory: 600Mi
steps:
- image: alpine:3.18
script: |
#!/usr/bin/env sh
echo "The variable: $(params.LOREM)"
params:
- name: LOREM
value: $(tasks.set-variable.results.ipsum)
- name: set-variable
taskSpec:
metadata: {}
stepTemplate:
image: alpine:3.18
computeResources:
requests:
cpu: 10m
memory: 600Mi
results:
- name: ipsum
steps:
- image: alpine:3.18
script: |
#!/usr/bin/env sh
echo -n "dolar" > "$(results.ipsum.path)"
timeouts:
pipeline: 240h0m0s

48
flake.lock generated Normal file
View File

@@ -0,0 +1,48 @@
{
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1777578337,
"narHash": "sha256-Ad49moKWeXtKBJNy2ebiTQUEgdLyvGmTeykAQ9xM+Z4=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "15f4ee454b1dce334612fa6843b3e05cf546efab",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs",
"rust-overlay": "rust-overlay"
}
},
"rust-overlay": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1777691680,
"narHash": "sha256-sdCAzrPAaKu+yo7L2pWddy5PN6U9bO++WEWc1zcr7aQ=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "4757db4358c77c1cbe878fa5990e6ea88d82f6b5",
"type": "github"
},
"original": {
"owner": "oxalica",
"repo": "rust-overlay",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

92
flake.nix Normal file
View File

@@ -0,0 +1,92 @@
{
description = "webhook-bridge development environment";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
rust-overlay = {
url = "github:oxalica/rust-overlay";
inputs = {
nixpkgs.follows = "nixpkgs";
};
};
};
outputs =
{
self,
nixpkgs,
rust-overlay,
}:
let
forAllSystems =
func:
builtins.listToAttrs (
map (system: {
name = system;
value = func system;
}) nixpkgs.lib.systems.flakeExposed
);
in
{
devShells = forAllSystems (
system:
let
overlays = [ (import rust-overlay) ];
pkgs = import nixpkgs {
inherit system overlays;
};
rustToolchain = pkgs.pkgsBuildHost.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml;
in
{
default = pkgs.mkShell {
nativeBuildInputs = [
pkgs.pkg-config
rustToolchain
pkgs.openssl
];
buildInputs = with pkgs; [
# sqlx-cli # For sqlx CLI to manage migrations
# sqlite # To access the database (sqlite is bundled into the together_alone binary but this is for manually accessing the db).
];
};
}
);
packages = forAllSystems (
system:
let
overlays = [ (import rust-overlay) ];
pkgs = import nixpkgs {
inherit system overlays;
};
rustToolchain = pkgs.pkgsBuildHost.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml;
in
rec {
app = pkgs.rustPlatform.buildRustPackage {
pname = "webhook-bridge";
version = "0.0.0";
src = ./.;
# If you have a Cargo.lock file, use this:
cargoLock.lockFile = ./Cargo.lock;
nativeBuildInputs = [
pkgs.pkg-config
];
buildInputs = [
pkgs.openssl
];
};
docker_env = pkgs.buildEnv {
name = "webhook-bridge";
paths = with pkgs; [
app
bash
uutils-coreutils-noprefix
# toybox # Smaller than uutils-coreutils?
];
};
default = app;
}
);
};
}

View File

@@ -4,4 +4,4 @@ set -euo pipefail
IFS=$'\n\t'
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
curl -vv -H "Authorization: token $(cat /bridge/git/mrmanager/k8s/lighthouse/secrets/lighthouse/lighthouse/OAUTH_TOKEN)" 'https://code.fizz.buzz/api/v1/repos/talexander/organic/git/trees/841a348dd02f31ee8828f069b2a948712369069d?recursive=true&per_page=10&page=60'
curl -vv -H "Authorization: token $(cat /bridge/git/mrmanager/k8s/webhook-bridge/secrets/webhook-bridge/webhook-bridge/OAUTH_TOKEN)" 'https://code.fizz.buzz/api/v1/repos/talexander/organic/git/trees/841a348dd02f31ee8828f069b2a948712369069d?recursive=true&per_page=10&page=60'

212
local_payload.json Normal file
View File

@@ -0,0 +1,212 @@
{
"ref": "refs/heads/main",
"before": "1f52dd8995987337a3a33ce675625647545490c2",
"after": "f55834712245bd546a5ca982d95ecf47669ba4ab",
"compare_url": "https://code.fizz.buzz/talexander/webhook_bridge/compare/1f52dd8995987337a3a33ce675625647545490c2...f55834712245bd546a5ca982d95ecf47669ba4ab",
"commits": [
{
"id": "f55834712245bd546a5ca982d95ecf47669ba4ab",
"message": "Update to the latest catalog.\n",
"url": "https://code.fizz.buzz/talexander/webhook_bridge/commit/f55834712245bd546a5ca982d95ecf47669ba4ab",
"author": {
"name": "Tom Alexander",
"email": "tom@fizz.buzz",
"username": ""
},
"committer": {
"name": "Tom Alexander",
"email": "tom@fizz.buzz",
"username": ""
},
"verification": null,
"timestamp": "2026-05-02T17:50:49-04:00",
"added": [],
"removed": [],
"modified": [
".webhook_bridge/pipeline-build-semver.yaml",
".webhook_bridge/pipeline-format.yaml",
".webhook_bridge/pipeline-rust-clippy.yaml",
".webhook_bridge/pipeline-rust-test.yaml",
".webhook_bridge/pipeline-semver.yaml",
"local_payload.json",
"run.bash"
]
}
],
"total_commits": 1,
"head_commit": {
"id": "f55834712245bd546a5ca982d95ecf47669ba4ab",
"message": "Update to the latest catalog.\n",
"url": "https://code.fizz.buzz/talexander/webhook_bridge/commit/f55834712245bd546a5ca982d95ecf47669ba4ab",
"author": {
"name": "Tom Alexander",
"email": "tom@fizz.buzz",
"username": ""
},
"committer": {
"name": "Tom Alexander",
"email": "tom@fizz.buzz",
"username": ""
},
"verification": null,
"timestamp": "2026-05-02T17:50:49-04:00",
"added": [],
"removed": [],
"modified": [
".webhook_bridge/pipeline-build-semver.yaml",
".webhook_bridge/pipeline-format.yaml",
".webhook_bridge/pipeline-rust-clippy.yaml",
".webhook_bridge/pipeline-rust-test.yaml",
".webhook_bridge/pipeline-semver.yaml",
"local_payload.json",
"run.bash"
]
},
"repository": {
"id": 21,
"owner": {
"id": 1,
"login": "talexander",
"login_name": "",
"source_id": 0,
"full_name": "",
"email": "gitea@local.domain",
"avatar_url": "https://code.fizz.buzz/avatars/9d402a89b5a0786f83c1b8c5486fc7ff3d083a54fe20e55c0a776a1932c30289",
"html_url": "https://code.fizz.buzz/talexander",
"language": "",
"is_admin": false,
"last_login": "0001-01-01T00:00:00Z",
"created": "2023-07-05T22:03:28Z",
"restricted": false,
"active": false,
"prohibit_login": false,
"location": "",
"website": "",
"description": "",
"visibility": "public",
"followers_count": 0,
"following_count": 0,
"starred_repos_count": 0,
"username": "talexander"
},
"name": "webhook_bridge",
"full_name": "talexander/webhook_bridge",
"description": "A server that receives webhooks from gitea and fires off Tekton jobs in response.",
"empty": false,
"private": false,
"fork": false,
"template": false,
"mirror": false,
"size": 193,
"language": "",
"languages_url": "https://code.fizz.buzz/api/v1/repos/talexander/webhook_bridge/languages",
"html_url": "https://code.fizz.buzz/talexander/webhook_bridge",
"url": "https://code.fizz.buzz/api/v1/repos/talexander/webhook_bridge",
"link": "",
"ssh_url": "git@git.example.com:talexander/webhook_bridge.git",
"clone_url": "https://code.fizz.buzz/talexander/webhook_bridge.git",
"original_url": "",
"website": "",
"stars_count": 0,
"forks_count": 0,
"watchers_count": 1,
"open_issues_count": 0,
"open_pr_counter": 0,
"release_counter": 0,
"default_branch": "main",
"archived": false,
"created_at": "2024-07-14T18:48:52Z",
"updated_at": "2026-05-02T22:11:33Z",
"archived_at": "1970-01-01T00:00:00Z",
"permissions": {
"admin": true,
"push": true,
"pull": true
},
"has_code": true,
"has_issues": true,
"internal_tracker": {
"enable_time_tracker": true,
"allow_only_contributors_to_track_time": true,
"enable_issue_dependencies": true
},
"has_wiki": false,
"has_pull_requests": true,
"has_projects": false,
"projects_mode": "all",
"has_releases": true,
"has_packages": false,
"has_actions": false,
"ignore_whitespace_conflicts": false,
"allow_merge_commits": true,
"allow_rebase": true,
"allow_rebase_explicit": true,
"allow_squash_merge": true,
"allow_fast_forward_only_merge": false,
"allow_rebase_update": true,
"allow_manual_merge": false,
"autodetect_manual_merge": false,
"default_delete_branch_after_merge": false,
"default_merge_style": "merge",
"default_allow_maintainer_edit": false,
"avatar_url": "",
"internal": false,
"mirror_interval": "",
"object_format_name": "sha1",
"mirror_updated": "0001-01-01T00:00:00Z",
"topics": [],
"licenses": [
"0BSD"
]
},
"pusher": {
"id": 1,
"login": "talexander",
"login_name": "",
"source_id": 0,
"full_name": "",
"email": "talexander@noreply.code.fizz.buzz",
"avatar_url": "https://code.fizz.buzz/avatars/9d402a89b5a0786f83c1b8c5486fc7ff3d083a54fe20e55c0a776a1932c30289",
"html_url": "https://code.fizz.buzz/talexander",
"language": "",
"is_admin": false,
"last_login": "0001-01-01T00:00:00Z",
"created": "2023-07-05T22:03:28Z",
"restricted": false,
"active": false,
"prohibit_login": false,
"location": "",
"website": "",
"description": "",
"visibility": "public",
"followers_count": 0,
"following_count": 0,
"starred_repos_count": 0,
"username": "talexander"
},
"sender": {
"id": 1,
"login": "talexander",
"login_name": "",
"source_id": 0,
"full_name": "",
"email": "talexander@noreply.code.fizz.buzz",
"avatar_url": "https://code.fizz.buzz/avatars/9d402a89b5a0786f83c1b8c5486fc7ff3d083a54fe20e55c0a776a1932c30289",
"html_url": "https://code.fizz.buzz/talexander",
"language": "",
"is_admin": false,
"last_login": "0001-01-01T00:00:00Z",
"created": "2023-07-05T22:03:28Z",
"restricted": false,
"active": false,
"prohibit_login": false,
"location": "",
"website": "",
"description": "",
"visibility": "public",
"followers_count": 0,
"following_count": 0,
"starred_repos_count": 0,
"username": "talexander"
}
}

View File

@@ -4,4 +4,13 @@ set -euo pipefail
IFS=$'\n\t'
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
RUST_LOG=webhook_bridge=DEBUG WEBHOOK_BRIDGE_API_ROOT="https://code.fizz.buzz/api" WEBHOOK_BRIDGE_HMAC_SECRET=$(cat /bridge/git/mrmanager/k8s/lighthouse/secrets/lighthouse/lighthouse/HMAC_TOKEN) WEBHOOK_BRIDGE_OAUTH_TOKEN=$(cat /bridge/git/mrmanager/k8s/lighthouse/secrets/lighthouse/lighthouse/OAUTH_TOKEN) cargo run
function main {
exec env RUST_LOG=webhookbridge=DEBUG WEBHOOK_BRIDGE_API_ROOT="https://code.fizz.buzz/api" WEBHOOK_BRIDGE_HMAC_SECRET="$(decrypt_k8s_secret -n webhook-bridge webhook-bridge | jq -r '.HMAC_TOKEN')" WEBHOOK_BRIDGE_OAUTH_TOKEN="$(decrypt_k8s_secret -n webhook-bridge webhook-bridge | jq -r '.OAUTH_TOKEN')" WEBHOOK_BRIDGE_REPO_WHITELIST="talexander/webhook_bridge,talexander/homepage,talexander/natter,talexander/poudboot,talexander/ta_waybar_pipewire,talexander/organic" cargo run "${@}"
#"${@}"
}
function decrypt_k8s_secret {
kubectl get secret -o json "${@}" | jq '.data[] |= @base64d | .data'
}
main "${@}"

16
run_docker.bash Executable file
View File

@@ -0,0 +1,16 @@
#!/usr/bin/env bash
#
set -euo pipefail
IFS=$'\n\t'
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
function main {
make -C docker/webhook_bridge build
docker run --rm -i -t -p 9988:9988 -e RUST_LOG=webhookbridge=DEBUG -e WEBHOOK_BRIDGE_API_ROOT="https://code.fizz.buzz/api" -e WEBHOOK_BRIDGE_HMAC_SECRET="$(decrypt_k8s_secret -n webhook-bridge webhook-bridge | jq -r '.HMAC_TOKEN')" -e WEBHOOK_BRIDGE_OAUTH_TOKEN="$(decrypt_k8s_secret -n webhook-bridge webhook-bridge | jq -r '.OAUTH_TOKEN')" -e WEBHOOK_BRIDGE_REPO_WHITELIST="talexander/webhook_bridge,talexander/homepage,talexander/natter,talexander/poudboot,talexander/ta_waybar_pipewire,talexander/organic" webhook-bridge:latest
}
function decrypt_k8s_secret {
kubectl get secret -o json "${@}" | jq '.data[] |= @base64d | .data'
}
main "${@}"

4
rust-toolchain.toml Normal file
View File

@@ -0,0 +1,4 @@
[toolchain]
channel = "nightly"
profile = "default"
components = ["clippy", "rustfmt"]

14
rustfmt.toml Normal file
View File

@@ -0,0 +1,14 @@
imports_granularity = "Item"
group_imports = "StdExternalCrate"
# In rustfmt 2.0 I will want to adjust these settings.
#
# max_width controls the max length of a line before rustfmt gives up
# but that also scales the length of a bunch of other lines
# automaticaly due to width_heuristics. I want to find a way to enable
# rustfmt to work on longer lines when necessary without making my
# regular code too wide.
#
# max_width = 100
# error_on_line_overflow = true
# width_heuristics = "Off"

7
src/app_state.rs Normal file
View File

@@ -0,0 +1,7 @@
use std::collections::HashSet;
use std::sync::Arc;
#[derive(Clone)]
pub(crate) struct AppState {
pub(crate) allowed_repos: Arc<HashSet<String>>,
}

12
src/bin_local_trigger.rs Normal file
View File

@@ -0,0 +1,12 @@
#![forbid(unsafe_code)]
use webhookbridge::init_tracing;
use webhookbridge::local_trigger;
const EXAMPLE_WEBHOOK_PAYLOAD: &str = include_str!("../local_payload.json");
#[tokio::main]
#[allow(clippy::needless_return)]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
init_tracing().await?;
local_trigger(EXAMPLE_WEBHOOK_PAYLOAD).await
}

View File

@@ -14,11 +14,40 @@ use serde_json::Value;
plural = "pipelineruns"
)]
#[kube(namespaced)]
pub struct PipelineRunSpec {
#[serde(deny_unknown_fields)]
pub(crate) struct PipelineRunSpec {
/// Contents of the Pipeline
#[serde(default, skip_serializing_if = "Option::is_none")]
pub pipelineSpec: Option<Value>,
#[serde(
rename = "pipelineSpec",
default,
skip_serializing_if = "Option::is_none"
)]
pub(crate) pipeline_spec: Option<Value>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub timeouts: Option<Value>,
pub(crate) timeouts: Option<Value>,
#[serde(
rename = "taskRunTemplate",
default,
skip_serializing_if = "Option::is_none"
)]
pub(crate) task_run_template: Option<Value>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(crate) workspaces: Option<Value>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(crate) params: Option<Vec<PipelineParam>>,
}
#[derive(Serialize, Deserialize, Clone, Debug, JsonSchema)]
#[serde(deny_unknown_fields)]
pub(crate) struct PipelineParam {
/// Contents of the Pipeline
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(crate) name: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(crate) value: Option<Value>,
}

View File

@@ -1,54 +1,52 @@
use std::path::Path;
use std::path::PathBuf;
use regex::Regex;
use tracing::debug;
use crate::crd_pipeline_run::PipelineRun;
use crate::gitea_client::GiteaClient;
use crate::gitea_client::Tree;
use crate::gitea_client::TreeFileReference;
use crate::in_repo_config::InRepoConfig;
use regex::Regex;
use tracing::debug;
use crate::remote_config::RemoteConfig;
pub(crate) async fn discover_webhook_bridge_config(
gitea: &GiteaClient,
repo_tree: &Tree,
) -> Result<InRepoConfig, Box<dyn std::error::Error>> {
let in_repo_config_reference = repo_tree
) -> Result<RemoteConfig, Box<dyn std::error::Error>> {
let remote_config_reference = repo_tree
.files
.iter()
.filter(|file_reference| file_reference.path == ".webhook_bridge/webhook_bridge.toml")
.next()
.find(|file_reference| file_reference.path == ".webhook_bridge/webhook_bridge.toml")
.ok_or("File not found in remote repo: .webhook_bridge/webhook_bridge.toml.")?;
let in_repo_config_contents =
String::from_utf8(gitea.read_file(in_repo_config_reference).await?)?;
let parsed_in_repo_config = InRepoConfig::from_str(in_repo_config_contents)?;
let remote_config_contents =
String::from_utf8(gitea.read_file(remote_config_reference).await?)?;
let parsed_remote_config = RemoteConfig::from_str(remote_config_contents)?;
Ok(parsed_in_repo_config)
Ok(parsed_remote_config)
}
pub(crate) async fn discover_matching_push_triggers<RE: AsRef<str>>(
gitea: &GiteaClient,
repo_tree: &Tree,
git_ref: RE,
in_repo_config: &InRepoConfig,
remote_config: &RemoteConfig,
) -> Result<Vec<PipelineTemplate>, Box<dyn std::error::Error>> {
let mut ret = Vec::new();
let ref_to_branch_regex = Regex::new(r"refs/heads/(?P<branch>.+)")?;
let ref_to_branch_regex = Regex::new(r"refs/(heads|tags)/(?P<branch>.+)")?;
let captures = ref_to_branch_regex
.captures(git_ref.as_ref())
.ok_or("Could not find branch name.")?;
let branch = &captures["branch"];
debug!("Detected branch from push as {:?}", branch);
let push_triggers = in_repo_config.get_push_triggers_for_branch(branch)?;
let push_triggers = remote_config.get_push_triggers_for_branch(branch)?;
for trigger in push_triggers {
let path_to_source = normalize_path(Path::new(".webhook_bridge").join(&trigger.source));
let pipeline_template = repo_tree
.files
.iter()
.filter(|file_reference| Path::new(&file_reference.path) == path_to_source.as_path())
.next()
.find(|file_reference| Path::new(&file_reference.path) == path_to_source.as_path())
.ok_or("Trigger source not found in remote repo.")?;
let pipeline_contents = String::from_utf8(gitea.read_file(pipeline_template).await?)?;
debug!("Pipeline template contents: {}", pipeline_contents);

View File

@@ -2,7 +2,9 @@ use std::error::Error;
#[derive(Debug, Clone)]
pub(crate) enum GiteaClientError {
#[allow(dead_code)]
Static(#[allow(dead_code)] &'static str),
#[allow(dead_code)]
String(#[allow(dead_code)] String),
NoTotalCountHeaderInResponse,
}

View File

@@ -1,4 +1,5 @@
use base64::{engine::general_purpose, Engine as _};
use base64::engine::general_purpose;
use base64::Engine as _;
use serde::Deserialize;
use tracing::debug;
@@ -37,7 +38,7 @@ impl GiteaClient {
owner = owner.as_ref(),
repo = repo.as_ref(),
commit = commit.as_ref(),
page = page.map(|num| format!("&page={}", num)).unwrap_or_else(|| String::new())
page = page.map(|num| format!("&page={}", num)).unwrap_or_default()
);
let response = self
.http_client
@@ -97,22 +98,39 @@ impl GiteaClient {
/// A single API response for GetTree containing only one page.
#[derive(Debug, Deserialize)]
#[serde(deny_unknown_fields)]
struct ResponseGetTree {
#[allow(dead_code)]
sha: String,
#[allow(dead_code)]
url: String,
tree: Vec<ResponseObjectReference>,
#[allow(dead_code)]
truncated: bool,
page: u64,
#[allow(dead_code)]
total_count: u64,
}
#[derive(Debug, Deserialize)]
#[serde(deny_unknown_fields)]
struct ResponseObjectReference {
path: String,
#[allow(dead_code)]
mode: String,
#[allow(dead_code)]
#[serde(rename = "type")]
object_type: String,
#[allow(dead_code)]
size: u64,
#[allow(dead_code)]
sha: String,
url: String,
}
@@ -144,10 +162,17 @@ impl TreeFileReference {
}
#[derive(Debug, Deserialize)]
#[serde(deny_unknown_fields)]
struct ResponseReadFile {
content: String,
encoding: String,
#[allow(dead_code)]
url: String,
#[allow(dead_code)]
sha: String,
#[allow(dead_code)]
size: u64,
}

View File

@@ -1,3 +1,6 @@
use std::borrow::Cow;
use regex::Regex;
use serde::Deserialize;
use serde_json::Value;
@@ -5,13 +8,14 @@ use serde_json::Value;
#[derive(Debug, Deserialize)]
pub(crate) struct HookPush {
#[serde(rename = "ref")]
ref_field: String,
pub(crate) ref_field: String,
before: String,
after: String,
compare_url: String,
commits: Vec<HookCommit>,
total_commits: u64,
head_commit: HookCommit,
repository: HookRepository,
pub(crate) repository: HookRepository,
pusher: HookUser,
sender: HookUser,
}
@@ -22,9 +26,12 @@ pub(crate) struct HookUser {
id: u64,
login: String,
login_name: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
source_id: Option<u64>,
full_name: String,
email: String,
avatar_url: String,
html_url: String,
language: String,
is_admin: bool,
last_login: String, // TODO: parse to datetime
@@ -48,13 +55,12 @@ pub(crate) struct HookRepository {
id: u64,
owner: HookUser,
name: String,
full_name: String,
pub(crate) full_name: String,
description: String,
empty: bool,
private: bool,
fork: bool,
template: bool,
parent: Value, // Was null in test hook
mirror: bool,
size: u64,
language: String,
@@ -79,10 +85,12 @@ pub(crate) struct HookRepository {
archived_at: String, // TODO: parse to datetime
permissions: HookRepositoryPermissions,
has_issues: bool,
internal_tracker: HookRepositoryInternalTracker,
#[serde(default, skip_serializing_if = "Option::is_none")]
internal_tracker: Option<HookRepositoryInternalTracker>,
has_wiki: bool,
has_pull_requests: bool,
has_projects: bool,
projects_mode: String,
has_releases: bool,
has_packages: bool,
has_actions: bool,
@@ -91,6 +99,7 @@ pub(crate) struct HookRepository {
allow_rebase: bool,
allow_rebase_explicit: bool,
allow_squash_merge: bool,
allow_fast_forward_only_merge: bool,
allow_rebase_update: bool,
default_delete_branch_after_merge: bool,
default_merge_style: String,
@@ -98,8 +107,8 @@ pub(crate) struct HookRepository {
avatar_url: String,
internal: bool,
mirror_interval: String,
object_format_name: String,
mirror_updated: String, // TODO: parse to datetime
repo_transfer: Value, // Was null in test hook
}
#[allow(dead_code)]
@@ -140,3 +149,42 @@ pub(crate) struct HookGitUser {
email: String,
username: String,
}
pub(crate) trait PipelineParamters {
fn get_pull_base_ref(&self) -> Result<Cow<str>, Box<dyn std::error::Error>>;
fn get_pull_base_sha(&self) -> Result<Cow<str>, Box<dyn std::error::Error>>;
fn get_repo_url(&self) -> Result<Cow<str>, Box<dyn std::error::Error>>;
fn get_repo_name(&self) -> Result<Cow<str>, Box<dyn std::error::Error>>;
fn get_repo_owner(&self) -> Result<Cow<str>, Box<dyn std::error::Error>>;
}
impl PipelineParamters for HookPush {
fn get_pull_base_ref(&self) -> Result<Cow<str>, Box<dyn std::error::Error>> {
let ref_to_branch_regex = Regex::new(r"refs/(heads|tags)/(?P<branch>.+)")?;
let captures = ref_to_branch_regex
.captures(self.ref_field.as_str())
.ok_or("Could not find branch name.")?;
let branch = &captures["branch"];
Ok(Cow::Owned(branch.to_owned()))
}
fn get_pull_base_sha(&self) -> Result<Cow<str>, Box<dyn std::error::Error>> {
Ok(Cow::Borrowed(self.after.as_str()))
}
fn get_repo_url(&self) -> Result<Cow<str>, Box<dyn std::error::Error>> {
Ok(Cow::Borrowed(self.repository.clone_url.as_str()))
}
fn get_repo_name(&self) -> Result<Cow<str>, Box<dyn std::error::Error>> {
Ok(Cow::Borrowed(self.repository.name.as_str()))
}
fn get_repo_owner(&self) -> Result<Cow<str>, Box<dyn std::error::Error>> {
Ok(Cow::Borrowed(self.repository.owner.username.as_str()))
}
}

125
src/kubernetes.rs Normal file
View File

@@ -0,0 +1,125 @@
use std::borrow::Borrow;
use std::borrow::Cow;
use kube::api::PostParams;
use kube::Api;
use kube::CustomResourceExt;
use regex::Regex;
use tracing::debug;
use tracing::info;
use crate::crd_pipeline_run::PipelineParam;
use crate::crd_pipeline_run::PipelineRun;
use crate::discovery::PipelineTemplate;
use crate::hook_push::HookPush;
use crate::hook_push::PipelineParamters;
pub(crate) async fn run_pipelines(
hook: HookPush,
pipelines: Vec<PipelineTemplate>,
kubernetes_client: kube::Client,
) -> Result<(), Box<dyn std::error::Error>> {
// let jobs: Api<PipelineRun> = Api::namespaced(kubernetes_client, "webhook-bridge");
let jobs: Api<PipelineRun> = Api::default_namespaced(kubernetes_client);
tracing::debug!("Using crd: {}", serde_json::to_string(&PipelineRun::crd())?);
for mut pipeline in pipelines {
info!(
"Kicking off {} for repo {}/{}",
pipeline.name,
hook.get_repo_owner()?,
hook.get_repo_name()?,
);
if pipeline.pipeline.spec.params.is_none() {
pipeline.pipeline.spec.params = Some(Vec::new());
}
if let Some(param_list) = pipeline.pipeline.spec.params.as_mut() {
param_list.push(PipelineParam {
name: Some("JOB_NAME".to_owned()),
value: Some(serde_json::Value::String(pipeline.name.clone())),
});
param_list.push(PipelineParam {
name: Some("REPO_OWNER".to_owned()),
value: Some(serde_json::Value::String(
hook.get_repo_owner()?.into_owned(),
)),
});
param_list.push(PipelineParam {
name: Some("REPO_NAME".to_owned()),
value: Some(serde_json::Value::String(
hook.get_repo_name()?.into_owned(),
)),
});
let hook_repo_url = hook.get_repo_url()?;
param_list.push(PipelineParam {
name: Some("REPO_URL".to_owned()),
value: pipeline
.clone_uri
.map(serde_json::Value::String)
.or_else(|| Some(serde_json::Value::String(hook_repo_url.into_owned()))),
});
param_list.push(PipelineParam {
name: Some("PULL_BASE_SHA".to_owned()),
value: Some(serde_json::Value::String(
hook.get_pull_base_sha()?.into_owned(),
)),
});
param_list.push(PipelineParam {
name: Some("PULL_BASE_REF".to_owned()),
value: Some(serde_json::Value::String(
hook.get_pull_base_ref()?.into_owned(),
)),
});
}
if pipeline.pipeline.metadata.generate_name.is_none()
&& pipeline.pipeline.metadata.name.is_some()
{
std::mem::swap(
&mut pipeline.pipeline.metadata.generate_name,
&mut pipeline.pipeline.metadata.name,
);
if let Some(ref mut name) = pipeline.pipeline.metadata.generate_name {
let mut new_name_stub = sanitize_kubernetes_identifier(format!(
"{}-{}-{}",
name,
hook.get_repo_name()?,
hook.get_repo_owner()?
))?
.into_owned();
new_name_stub.truncate(63);
(*name) = new_name_stub + "-";
debug!("Using generate name: {}", name);
}
}
let pp = PostParams::default();
let created_run = jobs.create(&pp, &pipeline.pipeline).await?;
info!("Created PipelineRun {:?}", created_run.metadata.name);
}
Ok(())
}
fn sanitize_kubernetes_identifier<'a, O: Into<Cow<'a, str>>>(
original: O,
) -> Result<Cow<'a, str>, Box<dyn std::error::Error>> {
let validate_identifier_regex =
Regex::new(r"[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*")?;
let original = original.into();
if !validate_identifier_regex.is_match(original.borrow()) {
return Ok(original);
}
let mut clean_identifier = String::with_capacity(original.len());
for c in original.chars() {
match c {
'a'..='z' | 'A'..='Z' | '0'..='9' | '.' | '-' => {
clean_identifier.push(c);
}
_ => {
clean_identifier.push('-');
}
};
}
Ok(Cow::Owned(clean_identifier))
}

136
src/lib.rs Normal file
View File

@@ -0,0 +1,136 @@
#![forbid(unsafe_code)]
use std::collections::HashSet;
use std::sync::Arc;
use std::time::Duration;
use axum::http::StatusCode;
use axum::middleware;
use axum::routing::get;
use axum::routing::post;
use axum::Json;
use axum::Router;
use kube::Client;
use serde::Serialize;
use tokio::signal;
use tower_http::timeout::TimeoutLayer;
use tower_http::trace::TraceLayer;
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::util::SubscriberInitExt;
use self::app_state::AppState;
use self::gitea_client::GiteaClient;
use self::hook_push::HookPush;
use self::webhook::handle_push;
use self::webhook::hook;
use self::webhook::verify_signature;
mod app_state;
mod crd_pipeline_run;
mod discovery;
mod gitea_client;
mod hook_push;
mod kubernetes;
mod remote_config;
mod webhook;
pub async fn init_tracing() -> Result<(), Box<dyn std::error::Error>> {
tracing_subscriber::registry()
.with(
tracing_subscriber::EnvFilter::try_from_default_env().unwrap_or_else(|_| {
"webhookbridge=info,webhook_bridge=info,local_trigger=info,tower_http=debug,axum::rejection=trace"
.into()
}),
)
.with(tracing_subscriber::fmt::layer())
.init();
Ok(())
}
pub async fn launch_server() -> Result<(), Box<dyn std::error::Error>> {
let allowed_repos = std::env::var("WEBHOOK_BRIDGE_REPO_WHITELIST")?;
let allowed_repos: HashSet<_> = allowed_repos
.split(",")
.filter(|s| !s.is_empty())
.map(str::to_owned)
.collect();
tracing::debug!("Using repo whitelist: {:?}", allowed_repos);
let app = Router::new()
.route("/hook", post(hook))
.layer(middleware::from_fn(verify_signature))
.route("/health", get(health))
.layer((
TraceLayer::new_for_http(),
// Add a timeout layer so graceful shutdown can't wait forever.
TimeoutLayer::new(Duration::from_secs(600)),
))
.with_state(AppState {
allowed_repos: Arc::new(allowed_repos),
});
let listener = tokio::net::TcpListener::bind("0.0.0.0:9988").await?;
tracing::info!("listening on {}", listener.local_addr().unwrap());
axum::serve(listener, app)
.with_graceful_shutdown(shutdown_signal())
.await?;
Ok(())
}
pub async fn local_trigger(payload: &str) -> Result<(), Box<dyn std::error::Error>> {
let kubernetes_client: Client = Client::try_default()
.await
.expect("Set KUBECONFIG to a valid kubernetes config.");
let gitea_api_root = std::env::var("WEBHOOK_BRIDGE_API_ROOT")?;
let gitea_api_token = std::env::var("WEBHOOK_BRIDGE_OAUTH_TOKEN")?;
let gitea = GiteaClient::new(gitea_api_root, gitea_api_token);
let allowed_repos = std::env::var("WEBHOOK_BRIDGE_REPO_WHITELIST")
.ok()
.unwrap_or_default();
let allowed_repos: HashSet<_> = allowed_repos
.split(",")
.filter(|s| !s.is_empty())
.map(str::to_owned)
.collect();
tracing::debug!("Using repo whitelist: {:?}", allowed_repos);
let webhook_payload: HookPush = serde_json::from_str(payload)?;
handle_push(gitea, kubernetes_client, &allowed_repos, webhook_payload).await?;
Ok(())
}
async fn shutdown_signal() {
let ctrl_c = async {
signal::ctrl_c()
.await
.expect("failed to install Ctrl+C handler");
};
#[cfg(unix)]
let terminate = async {
signal::unix::signal(signal::unix::SignalKind::terminate())
.expect("failed to install signal handler")
.recv()
.await;
};
#[cfg(not(unix))]
let terminate = std::future::pending::<()>();
tokio::select! {
_ = ctrl_c => {},
_ = terminate => {},
}
}
async fn health() -> (StatusCode, Json<HealthResponse>) {
(StatusCode::OK, Json(HealthResponse { ok: true }))
}
#[derive(Serialize)]
struct HealthResponse {
ok: bool,
}

View File

@@ -1,138 +1,10 @@
#![forbid(unsafe_code)]
use std::sync::Arc;
use std::time::Duration;
use axum::http::StatusCode;
use axum::middleware;
use axum::routing::get;
use axum::routing::post;
use axum::Json;
use axum::Router;
use kube::api::PostParams;
use kube::Api;
use kube::Client;
use serde::Serialize;
use tokio::signal;
use tower_http::timeout::TimeoutLayer;
use tower_http::trace::TraceLayer;
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::util::SubscriberInitExt;
use self::crd_pipeline_run::PipelineRun;
use self::discovery::discover_matching_push_triggers;
use self::discovery::discover_webhook_bridge_config;
use self::gitea_client::GiteaClient;
use self::in_repo_config::InRepoConfig;
use self::webhook::hook;
use self::webhook::verify_signature;
use kube::CustomResourceExt;
mod crd_pipeline_run;
mod discovery;
mod gitea_client;
mod hook_push;
mod in_repo_config;
mod webhook;
const EXAMPLE_PIPELINE_RUN: &'static str = include_str!("../example_pipeline_run.json");
use webhookbridge::init_tracing;
use webhookbridge::launch_server;
#[tokio::main]
#[allow(clippy::needless_return)]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
tracing_subscriber::registry()
.with(
tracing_subscriber::EnvFilter::try_from_default_env().unwrap_or_else(|_| {
"webhook_bridge=info,tower_http=debug,axum::rejection=trace".into()
}),
)
.with(tracing_subscriber::fmt::layer())
.init();
let kubernetes_client: Client = Client::try_default()
.await
.expect("Set KUBECONFIG to a valid kubernetes config.");
let gitea_api_root = std::env::var("WEBHOOK_BRIDGE_API_ROOT")?;
let gitea_api_token = std::env::var("WEBHOOK_BRIDGE_OAUTH_TOKEN")?;
let gitea = GiteaClient::new(gitea_api_root, gitea_api_token);
let repo_tree = gitea
.get_tree(
"talexander",
"webhook_bridge",
"6d3b9e9db82d7857baa114d89efcb1bf470f448d",
)
.await?;
let in_repo_config = discover_webhook_bridge_config(&gitea, &repo_tree).await?;
let pipelines =
discover_matching_push_triggers(&gitea, &repo_tree, "refs/heads/main", &in_repo_config)
.await?;
// let jobs: Api<PipelineRun> = Api::namespaced(kubernetes_client, "lighthouse");
// let jobs: Api<PipelineRun> = Api::default_namespaced(kubernetes_client);
// tracing::info!("Using crd: {}", serde_json::to_string(&PipelineRun::crd())?);
// let test_run: PipelineRun = serde_json::from_str(EXAMPLE_PIPELINE_RUN)?;
// let pp = PostParams::default();
// let created_run = jobs.create(&pp, &test_run).await?;
// let app = Router::new()
// .route("/hook", post(hook))
// .layer(middleware::from_fn(verify_signature))
// .route("/health", get(health))
// .layer((
// TraceLayer::new_for_http(),
// // Add a timeout layer so graceful shutdown can't wait forever.
// TimeoutLayer::new(Duration::from_secs(600)),
// ))
// .with_state(AppState {
// kubernetes_client,
// gitea,
// });
// let listener = tokio::net::TcpListener::bind("0.0.0.0:9988").await?;
// tracing::info!("listening on {}", listener.local_addr().unwrap());
// axum::serve(listener, app)
// .with_graceful_shutdown(shutdown_signal())
// .await?;
Ok(())
}
#[derive(Clone)]
struct AppState {
kubernetes_client: Client,
gitea: GiteaClient,
}
async fn shutdown_signal() {
let ctrl_c = async {
signal::ctrl_c()
.await
.expect("failed to install Ctrl+C handler");
};
#[cfg(unix)]
let terminate = async {
signal::unix::signal(signal::unix::SignalKind::terminate())
.expect("failed to install signal handler")
.recv()
.await;
};
#[cfg(not(unix))]
let terminate = std::future::pending::<()>();
tokio::select! {
_ = ctrl_c => {},
_ = terminate => {},
}
}
async fn health() -> (StatusCode, Json<HealthResponse>) {
(StatusCode::OK, Json(HealthResponse { ok: true }))
}
#[derive(Serialize)]
struct HealthResponse {
ok: bool,
init_tracing().await?;
launch_server().await
}

View File

@@ -4,7 +4,8 @@ use serde::Serialize;
/// The webhook_bridge.toml file that lives inside repos that have their CI triggered by webhook_bridge.
#[derive(Serialize, Deserialize, Clone, Debug)]
pub(crate) struct InRepoConfig {
#[serde(deny_unknown_fields)]
pub(crate) struct RemoteConfig {
pub(crate) version: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
@@ -13,6 +14,7 @@ pub(crate) struct InRepoConfig {
/// A config for a job that is triggered by a push to a git repo.
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
pub(crate) struct TriggerPush {
pub(crate) name: String,
pub(crate) source: String,
@@ -27,16 +29,16 @@ pub(crate) struct TriggerPush {
pub(crate) skip_branches: Vec<String>,
}
impl InRepoConfig {
impl RemoteConfig {
pub(crate) fn from_str<S: AsRef<str>>(
contents: S,
) -> Result<InRepoConfig, Box<dyn std::error::Error>> {
let parsed_in_repo_config: InRepoConfig = toml::from_str(contents.as_ref())?;
) -> Result<RemoteConfig, Box<dyn std::error::Error>> {
let parsed_remote_config: RemoteConfig = toml::from_str(contents.as_ref())?;
assert!(
parsed_in_repo_config.version == "0.0.1",
parsed_remote_config.version == "0.0.1",
"We only support version 0.0.1 currently."
);
Ok(parsed_in_repo_config)
Ok(parsed_remote_config)
}
pub(crate) fn get_push_triggers_for_branch<B: AsRef<str>>(

View File

@@ -1,5 +1,6 @@
use std::borrow::Borrow;
use std::collections::HashSet;
use std::future::Future;
use std::sync::Arc;
use axum::async_trait;
use axum::body::Body;
@@ -14,7 +15,8 @@ use axum::response::IntoResponse;
use axum::response::Response;
use axum::Json;
use axum::RequestExt;
use base64::{engine::general_purpose, Engine as _};
use base64::engine::general_purpose;
use base64::Engine as _;
use hmac::Hmac;
use hmac::Mac;
use http_body_util::BodyExt;
@@ -22,8 +24,13 @@ use serde::Serialize;
use sha2::Sha256;
use tracing::debug;
use crate::app_state::AppState;
use crate::discovery::discover_matching_push_triggers;
use crate::discovery::discover_webhook_bridge_config;
use crate::gitea_client::GiteaClient;
use crate::hook_push::HookPush;
use crate::AppState;
use crate::hook_push::PipelineParamters;
use crate::kubernetes::run_pipelines;
type HmacSha256 = Hmac<Sha256>;
@@ -34,15 +41,58 @@ pub(crate) async fn hook(
) -> (StatusCode, Json<HookResponse>) {
debug!("REQ: {:?}", payload);
match payload {
HookRequest::Push(_payload) => (
HookRequest::Push(webhook_payload) => {
let kubernetes_client: kube::Client = kube::Client::try_default()
.await
.expect("Set KUBECONFIG to a valid kubernetes config.");
let gitea_api_root = std::env::var("WEBHOOK_BRIDGE_API_ROOT");
let gitea_api_token = std::env::var("WEBHOOK_BRIDGE_OAUTH_TOKEN");
let (gitea_api_root, gitea_api_token) = match (gitea_api_root, gitea_api_token) {
(Ok(r), Ok(t)) => (r, t),
_ => {
return (
StatusCode::OK,
Json(HookResponse {
ok: true,
message: None,
}),
);
}
};
let gitea = GiteaClient::new(gitea_api_root, gitea_api_token);
let push_result = handle_push(
gitea,
kubernetes_client,
state.allowed_repos.borrow(),
webhook_payload,
)
.await;
match push_result {
Ok(_) => (
StatusCode::OK,
Json(HookResponse {
ok: true,
message: None,
}),
),
Err(e) => {
tracing::error!("Failed to handle push event: {}", e);
(
// StatusCode::INTERNAL_SERVER_ERROR,
StatusCode::OK,
Json(HookResponse {
ok: false,
message: Some("Failed to handle push event.".to_string()),
}),
)
}
}
}
HookRequest::Unrecognized(payload) => (
StatusCode::BAD_REQUEST,
// StatusCode::BAD_REQUEST,
StatusCode::OK,
Json(HookResponse {
ok: false,
message: Some(format!("unrecognized event type: {payload}")),
@@ -129,9 +179,9 @@ where
}
async fn check_hash(body: Bytes, secret: String, signature: Vec<u8>) -> Result<Bytes, Response> {
tracing::info!("Checking signature {:02x?}", signature.as_slice());
tracing::info!("Using secret {:?}", secret);
tracing::info!("and body {}", general_purpose::STANDARD.encode(&body));
tracing::debug!("Checking signature {:02x?}", signature.as_slice());
// tracing::info!("Using secret {:?}", secret);
tracing::debug!("and body {}", general_purpose::STANDARD.encode(&body));
let mut mac = HmacSha256::new_from_slice(secret.as_bytes())
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()).into_response())?;
mac.update(&body);
@@ -153,3 +203,34 @@ fn hex_to_bytes(s: &str) -> Option<Vec<u8>> {
None
}
}
pub(crate) async fn handle_push(
gitea: GiteaClient,
kubernetes_client: kube::Client,
allowed_repos: &HashSet<String>,
webhook_payload: HookPush,
) -> Result<(), Box<dyn std::error::Error>> {
let repo_owner = webhook_payload.get_repo_owner()?;
let repo_name = webhook_payload.get_repo_name()?;
let pull_base_sha = webhook_payload.get_pull_base_sha()?;
if !allowed_repos.contains(&webhook_payload.repository.full_name) {
tracing::info!(
"{} is not an allowed repository.",
webhook_payload.repository.full_name
);
return Ok(());
}
let repo_tree = gitea.get_tree(repo_owner, repo_name, pull_base_sha).await?;
let remote_config = discover_webhook_bridge_config(&gitea, &repo_tree).await?;
let pipelines = discover_matching_push_triggers(
&gitea,
&repo_tree,
&webhook_payload.ref_field,
&remote_config,
)
.await?;
run_pipelines(webhook_payload, pipelines, kubernetes_client).await?;
Ok(())
}

File diff suppressed because one or more lines are too long