Skip to content

Commit 9c93284

Browse files
nikmel2803Copilot
andauthored
v2 — GitRepository support (#3)
* update deps * update Dockerfile to use golang 1.25 as builder * implement support for push webhooks and gitrepos * upd readme * upd rbac * refactor * refactor name * add makefile * add gitignore * wip * refactor to dynamic client * upd tests * fixes * Update cmd/client.go Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update README.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * fix errors handling * add workflow for tests * Refactor branch reconciliation logic in ReconcileGitRepositories to default to "master" if no branch is specified * adjust tests * update versions in readme --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent a8b7b5d commit 9c93284

File tree

16 files changed

+1123
-257
lines changed

16 files changed

+1123
-257
lines changed

.github/workflows/test.yaml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
name: Test
2+
3+
on:
4+
push:
5+
6+
jobs:
7+
test:
8+
runs-on: ubuntu-latest
9+
10+
steps:
11+
- name: Checkout code
12+
uses: actions/checkout@v4
13+
14+
- name: Set up Go
15+
uses: actions/setup-go@v5
16+
with:
17+
go-version: '1.25.0'
18+
19+
- name: Cache Go modules
20+
uses: actions/cache@v4
21+
with:
22+
path: ~/go/pkg/mod
23+
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
24+
restore-keys: |
25+
${{ runner.os }}-go-
26+
27+
- name: Download dependencies
28+
run: go mod download
29+
30+
- name: Run tests
31+
run: go test ./...
32+
33+
- name: Run go vet
34+
run: go vet ./...
35+
36+
- name: Check formatting
37+
run: |
38+
if [ "$(gofmt -d .)" ]; then
39+
echo "Code is not formatted. Please run 'go fmt ./...'"
40+
gofmt -d .
41+
exit 1
42+
fi

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
bin
2+
*.local.yaml

Dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM --platform=${BUILDPLATFORM:-linux/amd64} golang:1.21 as builder
1+
FROM --platform=${BUILDPLATFORM:-linux/amd64} golang:1.25 as builder
22

33
ARG TARGETPLATFORM
44
ARG BUILDPLATFORM
@@ -16,4 +16,4 @@ FROM --platform=${TARGETPLATFORM:-linux/amd64} scratch
1616
WORKDIR /app/
1717
COPY --from=builder /app/flux-webhook-authreconciler /app/flux-webhook-authreconciler
1818
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
19-
ENTRYPOINT ["/app/flux-webhook-authreconciler"]
19+
ENTRYPOINT ["/app/flux-webhook-authreconciler"]

Makefile

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
.PHONY: build test test-verbose test-coverage clean fmt vet lint help run
2+
3+
# Binary name
4+
BINARY_NAME=flux-webhook-autoreconciler
5+
# Build directory
6+
BUILD_DIR=bin
7+
# Main package path
8+
MAIN_PACKAGE=./cmd
9+
10+
# Default target
11+
.DEFAULT_GOAL := help
12+
13+
## build: Build the binary
14+
build:
15+
@echo "Building $(BINARY_NAME)..."
16+
@mkdir -p $(BUILD_DIR)
17+
@go build -o $(BUILD_DIR)/$(BINARY_NAME) $(MAIN_PACKAGE)
18+
@echo "Build complete: $(BUILD_DIR)/$(BINARY_NAME)"
19+
20+
## test: Run tests
21+
test:
22+
@echo "Running tests..."
23+
@go test ./...
24+
25+
## test-verbose: Run tests with verbose output
26+
test-verbose:
27+
@echo "Running tests with verbose output..."
28+
@go test -v ./...
29+
30+
## test-coverage: Run tests with coverage report
31+
test-coverage:
32+
@echo "Running tests with coverage..."
33+
@go test -coverprofile=coverage.out ./...
34+
@go tool cover -html=coverage.out -o coverage.html
35+
@echo "Coverage report generated: coverage.html"
36+
37+
## test-reconciler: Run reconciler tests specifically
38+
test-reconciler:
39+
@echo "Running reconciler tests..."
40+
@go test -v ./cmd -run TestReconcile
41+
42+
## clean: Remove build artifacts
43+
clean:
44+
@echo "Cleaning build artifacts..."
45+
@rm -rf $(BUILD_DIR)
46+
@rm -f coverage.out coverage.html
47+
@echo "Clean complete"
48+
49+
## fmt: Format Go code
50+
fmt:
51+
@echo "Formatting code..."
52+
@go fmt ./...
53+
@echo "Format complete"
54+
55+
## vet: Run go vet
56+
vet:
57+
@echo "Running go vet..."
58+
@go vet ./...
59+
@echo "Vet complete"
60+
61+
## lint: Run golangci-lint (if installed)
62+
lint:
63+
@echo "Running linter..."
64+
@if command -v golangci-lint >/dev/null 2>&1; then \
65+
golangci-lint run ./...; \
66+
else \
67+
echo "golangci-lint not installed. Install it with: go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest"; \
68+
fi
69+
70+
## mod-tidy: Tidy go.mod and go.sum
71+
mod-tidy:
72+
@echo "Tidying go.mod..."
73+
@go mod tidy
74+
@echo "Tidy complete"
75+
76+
## mod-download: Download dependencies
77+
mod-download:
78+
@echo "Downloading dependencies..."
79+
@go mod download
80+
@echo "Download complete"
81+
82+
## run: Run the application (requires config file)
83+
run: build
84+
@echo "Running $(BINARY_NAME)..."
85+
@./$(BUILD_DIR)/$(BINARY_NAME) -config config/server.yaml
86+
87+
## run-client: Run the application in client mode
88+
run-client: build
89+
@echo "Running $(BINARY_NAME) in client mode..."
90+
@./$(BUILD_DIR)/$(BINARY_NAME) -config config/client.yaml
91+
92+
## help: Show this help message
93+
help:
94+
@echo "Available targets:"
95+
@sed -n 's/^##//p' ${MAKEFILE_LIST} | column -t -s ':' | sed -e 's/^/ /'

README.md

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
# flux-webhook-autoreconciler
22

3-
This project aims to solve the problem of having to manually setup webhooks for each repository in a cluster to reconcile Flux sources.
3+
This project aims to solve the problem of having to manually setup webhooks for each repository in a cluster to reconcile Flux sources.
44

5-
Normally, you'd need to set up a Receiver for each source, then a webhook for that receiver ([official docs](https://fluxcd.io/flux/guides/webhook-receivers/)).
5+
Normally, you'd need to set up a Receiver for each source, then a webhook for that receiver ([official docs](https://fluxcd.io/flux/guides/webhook-receivers/)).
66
This can get pretty annoying and it's easy to mess up, especially when you have tons of repos you want to deploy with Flux.
77

8-
This project tackles this by giving you a single webhook receiver. You hook it up to your entire GitHub organization,
8+
This project tackles this by giving you a single webhook receiver. You hook it up to your entire GitHub organization,
99
and it'll automatically keep the Flux sources in sync across all your repos.
1010

1111
## How it works
@@ -15,7 +15,7 @@ This project has two main parts:
1515
- `Server`: It gets the webhooks, reconciles the sources, and tells the clients about what happened.
1616
- `Client`: (Optional) It listens to the server and reconciles the sources. You can run just the server if you want, but having a client is handy if you have multiple clusters. You send one webhook to the server, and it’ll reconcile the sources in all your clusters through their clients.
1717

18-
Basically, the server waits for webhooks on the `/webhook` endpoint, and the client connects to the server on the `/subscribe` endpoint using WebSockets. You can have as many clients as you want (like, one client for each Kubernetes cluster). Both the server and client take care of reconciling the sources.
18+
Basically, the server waits for webhooks on the `/webhook` endpoint, and the client connects to the server on the `/subscribe` endpoint using WebSockets. You can have as many clients as you want (like, one client for each Kubernetes cluster). Both the server and client take care of reconciling the sources.
1919

2020
To figure out which sources need reconciling when a webhook comes in, the reconciler takes the package name from the webhook data, checks out all the sources, and then matches it up with the package name in each source. If there's a match, that source gets reconciled.
2121

@@ -25,7 +25,7 @@ There is helm chart available published as OCI artifact in GitHub Packages [here
2525
You can install it using [Helm CLI](https://helm.sh/docs/topics/registries/) or by using Flux itself:
2626

2727
```yaml
28-
apiVersion: source.toolkit.fluxcd.io/v1beta2
28+
apiVersion: source.toolkit.fluxcd.io/v1
2929
kind: HelmRepository
3030
metadata:
3131
name: flux-webhook-autoreconciler
@@ -34,7 +34,7 @@ spec:
3434
type: oci
3535
url: oci://ghcr.io/codex-team/flux-webhook-autoreconciler/chart
3636
---
37-
apiVersion: helm.toolkit.fluxcd.io/v2beta1
37+
apiVersion: helm.toolkit.fluxcd.io/v2
3838
kind: HelmRelease
3939
metadata:
4040
name: flux-webhook-autoreconciler
@@ -44,7 +44,7 @@ spec:
4444
chart:
4545
spec:
4646
chart: flux-webhook-autoreconciler
47-
version: '1.0.0' # replace with the latest version from here https://github.com/codex-team/flux-webhook-autoreconciler/pkgs/container/flux-webhook-autoreconciler%2Fchart%2Fflux-webhook-autoreconciler
47+
version: '2.0.0' # replace with the latest version from here https://github.com/codex-team/flux-webhook-autoreconciler/pkgs/container/flux-webhook-autoreconciler%2Fchart%2Fflux-webhook-autoreconciler
4848
sourceRef:
4949
kind: HelmRepository
5050
name: flux-webhook-autoreconciler
@@ -67,22 +67,23 @@ The configuration is done via YAML file that is passed to the container via `--c
6767

6868
You can find the example configuration in [config](./config) folder both for `server` and `client` modes.
6969

70-
You'll also need to set up a GitHub webhook. You have the choice to do this for your whole organization or on a per-repo basis. For the how-to, check out the [official docs](https://docs.github.com/en/webhooks/using-webhooks/creating-webhooks).
70+
You'll also need to set up a GitHub webhook. You have the choice to do this for your whole organization or on a per-repo basis. For the how-to, check out the [official docs](https://docs.github.com/en/webhooks/using-webhooks/creating-webhooks).
7171
To get the webhook working, you'll need to sort out a few things:
7272

7373
- Payload URL: `https://<your-domain>/webhook`
7474
- Content type: `application/json`
7575
- Secret (optional but recommended)
76-
- In the section "Which events would you like to trigger this webhook?", go for "Let me select individual events." and then tick the box for the "Registry packages" event.
76+
- In the section "Which events would you like to trigger this webhook?", go for "Let me select individual events." and then tick the boxes for the "Registry packages" and "Pushes" events.
7777

78-
And that’s it! Now you can push a new package to your GitHub registry and it will be automatically reconciled by Flux.
78+
And that’s it! Now when you push a new package to your GitHub registry or push commits to a GitHub repository, the matching Flux `OCIRepository` and `GitRepository` resources will be automatically reconciled.
7979

80-
## Todo
80+
## Limitations
8181

82-
- [ ] Add support for other kinds of sources. Right now, it’s just `OCIRepository`.
83-
- [ ] Make it work with other types of webhook data. For now, it’s only set up for GitHub-like payloads.
84-
- [ ] Add different filtering abilities, like filtering by package name or repo labels.
82+
- It only supports GitHub webhooks.
83+
- It only supports `OCIRepository` and `GitRepository` resources.
84+
- It only supports `published` events for `OCIRepository` resources.
85+
- It only supports `push` events for `GitRepository` resources.
8586

8687
# Contribute
8788

88-
Feel free to contribute to this project by creating issues and pull requests.
89+
Feel free to contribute to this project by creating issues and pull requests.

chart/Chart.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
apiVersion: v2
22
name: flux-webhook-autoreconciler
3-
description: A Helm chart for Kubernetes
3+
description: A Helm chart for a Flux webhook auto-reconciler that exposes a single GitHub webhook endpoint and automatically reconciles matching Flux sources across clusters.
44
type: application
5-
version: "1.0.0"
6-
appVersion: "v1.0.0"
5+
version: "2.0.0"
6+
appVersion: "v2.0.0"

chart/templates/rbac.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ rules:
99
- source.toolkit.fluxcd.io
1010
resources:
1111
- ocirepositories
12+
- gitrepositories
1213
verbs:
1314
- get
1415
- list

cmd/client.go

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@ package main
33
import (
44
"context"
55
"encoding/json"
6+
"net/url"
7+
"time"
8+
69
"github.com/gorilla/websocket"
710
"github.com/prometheus/client_golang/prometheus"
811
"go.uber.org/zap"
9-
"net/url"
10-
"time"
1112
)
1213

1314
const (
@@ -76,8 +77,22 @@ func (r *Client) Run(ctx context.Context) {
7677
break
7778
}
7879

79-
r.logger.Info("Received message", zap.String("ociUrl", payload.OciUrl), zap.String("tag", payload.Tag))
80-
r.reconciler.ReconcileSources(payload.OciUrl, payload.Tag)
80+
r.logger.Info("Received message",
81+
zap.String("ociUrl", payload.OciUrl),
82+
zap.String("tag", payload.Tag),
83+
zap.String("gitRepo", payload.GitRepo),
84+
zap.String("ref", payload.Ref),
85+
)
86+
87+
// Reconcile OCI repositories when OCI info is present
88+
if payload.OciUrl != "" && payload.Tag != "" {
89+
r.reconciler.ReconcileOciSources(payload.OciUrl, payload.Tag)
90+
}
91+
92+
// Reconcile GitRepository resources when both gitRepo and ref are present
93+
if payload.GitRepo != "" && payload.Ref != "" {
94+
r.reconciler.ReconcileGitRepositories(payload.GitRepo, payload.Ref)
95+
}
8196
processedMessages.With(prometheus.Labels{"status": "success"}).Inc()
8297
}
8398
}()

cmd/config.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
package main
22

33
import (
4+
"os"
5+
46
"github.com/go-playground/validator/v10"
57
"gopkg.in/yaml.v3"
6-
"os"
78
)
89

910
type Config struct {

0 commit comments

Comments
 (0)