chore: migrate CI to Gitea actions and update module path

This commit is contained in:
2026-07-26 20:29:01 +02:00
parent 1b700f7975
commit db3860328b
13 changed files with 60 additions and 60 deletions
@@ -6,7 +6,7 @@ on:
jobs: jobs:
build: build:
runs-on: codeberg-small runs-on: fedora
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -20,9 +20,9 @@ jobs:
- goos: freebsd - goos: freebsd
goarch: arm64 goarch: arm64
steps: steps:
- uses: https://data.forgejo.org/actions/checkout@v4 - uses: actions/checkout@v4
- uses: https://data.forgejo.org/actions/setup-go@v5 - uses: actions/setup-go@v5
with: with:
go-version: "1.26" go-version: "1.26"
@@ -32,7 +32,7 @@ jobs:
- name: Build - name: Build
id: build id: build
env: env:
REF: ${{ forgejo.ref }} REF: ${{ gitea.ref }}
run: | run: |
set -euo pipefail set -euo pipefail
@@ -45,9 +45,9 @@ jobs:
fi fi
VERSION_NO_V="${VERSION#v}" VERSION_NO_V="${VERSION#v}"
echo "version_no_v=${VERSION_NO_V}" >> "$FORGEJO_OUTPUT" echo "version_no_v=${VERSION_NO_V}" >> "$GITEA_OUTPUT"
LDFLAGS="-s -w -X codeberg.org/petrbalvin/nuntius/internal/version.Version=${VERSION}" LDFLAGS="-s -w -X sourcedock.dev/petrbalvin/nuntius/internal/version.Version=${VERSION}"
mkdir -p bin mkdir -p bin
GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }} \ GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }} \
go build -ldflags "$LDFLAGS" \ go build -ldflags "$LDFLAGS" \
@@ -55,26 +55,26 @@ jobs:
./cmd/server ./cmd/server
- name: Upload artifact - name: Upload artifact
uses: https://data.forgejo.org/actions/upload-artifact@v3 uses: actions/upload-artifact@v3
with: with:
name: nuntius-${{ matrix.goos }}-${{ matrix.goarch }} name: nuntius-${{ matrix.goos }}-${{ matrix.goarch }}
path: bin/nuntius-${{ steps.build.outputs.version_no_v }}-${{ matrix.goos }}-${{ matrix.goarch }} path: bin/nuntius-${{ steps.build.outputs.version_no_v }}-${{ matrix.goos }}-${{ matrix.goarch }}
if-no-files-found: error if-no-files-found: error
release: release:
runs-on: codeberg-tiny runs-on: fedora
needs: build needs: build
steps: steps:
- uses: https://data.forgejo.org/actions/checkout@v4 - uses: actions/checkout@v4
- name: Download all artifacts - name: Download all artifacts
uses: https://data.forgejo.org/actions/download-artifact@v3 uses: actions/download-artifact@v3
with: with:
path: dist path: dist
- name: Extract CHANGELOG section - name: Extract CHANGELOG section
env: env:
VERSION: ${{ forgejo.ref_name }} VERSION: ${{ gitea.ref_name }}
run: | run: |
set -euo pipefail set -euo pipefail
VERSION_NO_V="${VERSION#v}" VERSION_NO_V="${VERSION#v}"
@@ -96,7 +96,7 @@ jobs:
- name: Create release - name: Create release
env: env:
FORGEJO_TOKEN: ${{ secrets.FORGEJO_TOKEN }} GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
run: | run: |
set -euo pipefail set -euo pipefail
# JSON-escape the release body with sed: backslashes first, then # JSON-escape the release body with sed: backslashes first, then
@@ -111,13 +111,13 @@ jobs:
BODY="\"${BODY}\"" BODY="\"${BODY}\""
response=$(curl -sS -w '\n%{http_code}' \ response=$(curl -sS -w '\n%{http_code}' \
-H "Authorization: token ${FORGEJO_TOKEN}" \ -H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-X POST \ -X POST \
"${FORGEJO_SERVER_URL}/api/v1/repos/${FORGEJO_REPOSITORY}/releases" \ "${GITEA_SERVER_URL}/api/v1/repos/${GITEA_REPOSITORY}/releases" \
-d "{ -d "{
\"tag_name\": \"${FORGEJO_REF_NAME}\", \"tag_name\": \"${GITEA_REF_NAME}\",
\"name\": \"${FORGEJO_REF_NAME}\", \"name\": \"${GITEA_REF_NAME}\",
\"body\": ${BODY}, \"body\": ${BODY},
\"draft\": false, \"draft\": false,
\"prerelease\": false \"prerelease\": false
@@ -139,7 +139,7 @@ jobs:
- name: Upload assets - name: Upload assets
env: env:
FORGEJO_TOKEN: ${{ secrets.FORGEJO_TOKEN }} GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
run: | run: |
set -euo pipefail set -euo pipefail
RELEASE_ID=$(cat release-id.txt) RELEASE_ID=$(cat release-id.txt)
@@ -150,11 +150,11 @@ jobs:
fname=$(basename "$binary") fname=$(basename "$binary")
echo "Uploading ${fname}..." echo "Uploading ${fname}..."
http_code=$(curl -sS -o /dev/null -w '%{http_code}' \ http_code=$(curl -sS -o /dev/null -w '%{http_code}' \
-H "Authorization: token ${FORGEJO_TOKEN}" \ -H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/octet-stream" \ -H "Content-Type: application/octet-stream" \
-X POST \ -X POST \
--data-binary "@${binary}" \ --data-binary "@${binary}" \
"${FORGEJO_SERVER_URL}/api/v1/repos/${FORGEJO_REPOSITORY}/releases/${RELEASE_ID}/assets?name=${fname}") "${GITEA_SERVER_URL}/api/v1/repos/${GITEA_REPOSITORY}/releases/${RELEASE_ID}/assets?name=${fname}")
echo " HTTP ${http_code}" echo " HTTP ${http_code}"
if [ "$http_code" != "201" ]; then if [ "$http_code" != "201" ]; then
echo "Failed to upload ${fname}" echo "Failed to upload ${fname}"
@@ -163,5 +163,5 @@ jobs:
done done
echo echo
echo "Release ${FORGEJO_REF_NAME} is live with the following assets:" echo "Release ${GITEA_REF_NAME} is live with the following assets:"
ls -lh dist/nuntius-*/ ls -lh dist/nuntius-*/
@@ -8,11 +8,11 @@ on:
jobs: jobs:
vet: vet:
runs-on: codeberg-small runs-on: fedora
steps: steps:
- uses: https://data.forgejo.org/actions/checkout@v4 - uses: actions/checkout@v4
- uses: https://data.forgejo.org/actions/setup-go@v5 - uses: actions/setup-go@v5
with: with:
go-version: "1.26" go-version: "1.26"
@@ -28,12 +28,12 @@ jobs:
run: go vet ./... run: go vet ./...
test: test:
runs-on: codeberg-small runs-on: fedora
needs: vet needs: vet
steps: steps:
- uses: https://data.forgejo.org/actions/checkout@v4 - uses: actions/checkout@v4
- uses: https://data.forgejo.org/actions/setup-go@v5 - uses: actions/setup-go@v5
with: with:
go-version: "1.26" go-version: "1.26"
+2 -2
View File
@@ -11,7 +11,7 @@ First stable release of nuntius: a small, opinionated, modular contact form
backend written in Go. A single static binary, four form kinds out of the box, backend written in Go. A single static binary, four form kinds out of the box,
SMTP delivery, a JSONL newsletter log, strict TOML configuration, and env-var SMTP delivery, a JSONL newsletter log, strict TOML configuration, and env-var
secrets. Its only dependency outside the standard library is the first-party secrets. Its only dependency outside the standard library is the first-party
[interpres](https://codeberg.org/petrbalvin/interpres) TOML parser. [interpres](https://sourcedock.dev/petrbalvin/interpres)
### Added ### Added
@@ -49,4 +49,4 @@ secrets. Its only dependency outside the standard library is the first-party
- **docs/** — `architecture.md`, `configuration.md`, `api-reference.md`, - **docs/** — `architecture.md`, `configuration.md`, `api-reference.md`,
`deployment.md`, `security.md`, `library-usage.md`. `deployment.md`, `security.md`, `library-usage.md`.
[1.0.0]: https://codeberg.org/petrbalvin/nuntius/releases/tag/v1.0.0 [1.0.0]: https://sourcedock.dev/petrbalvin/nuntius/releases/tag/v1.0.0
+11 -11
View File
@@ -24,7 +24,7 @@ See [Cutting a release](#cutting-a-release) for the full procedure.
### Quick Start ### Quick Start
```bash ```bash
git clone https://codeberg.org/petrbalvin/nuntius.git git clone https://sourcedock.dev/petrbalvin/nuntius.git
cd nuntius cd nuntius
just install # go mod tidy + go mod download (no third-party modules — no-op for this project) just install # go mod tidy + go mod download (no third-party modules — no-op for this project)
just build # → ./bin/nuntius (with -ldflags="-s -w") just build # → ./bin/nuntius (with -ldflags="-s -w")
@@ -203,11 +203,11 @@ graph TD
## CI ## CI
This project uses **Forgejo Actions** for continuous integration. The two workflow files live under `.forgejo/workflows/` and are the source of truth for what runs on every push and on every tagged release. This project uses **Gitea Actions** for continuous integration. The two workflow files live under `.gitea/workflows/` and are the source of truth for what runs on every push and on every tagged release.
### Test workflow — `.forgejo/workflows/test.yml` ### Test workflow — `.gitea/workflows/test.yml`
Triggered on every push to `development` and on every pull request targeting `development`. `main` is excluded on purpose — it only ever receives release tags, and the release workflow builds the binaries itself. Three jobs run in sequence, all on the `codeberg-small` runner: Triggered on every push to `development` and on every pull request targeting `development`. `main` is excluded on purpose — it only ever receives release tags, and the release workflow builds the binaries itself. Three jobs run in sequence, all on the `fedora` runner:
| Job | What it does | Why it exists | | Job | What it does | Why it exists |
|---|---|---| |---|---|---|
@@ -225,23 +225,23 @@ just build
./bin/nuntius --version # sanity-check the new flag ./bin/nuntius --version # sanity-check the new flag
``` ```
### Release workflow — `.forgejo/workflows/release.yml` ### Release workflow — `.gitea/workflows/release.yml`
Triggered by pushing a tag that matches `v*.*.*` (e.g. `v1.0.0`, `v1.2.3`) onto `main`. The merge from `development` into `main` is the maintainer's responsibility and happens before the tag is pushed — this workflow does not merge anything. Two jobs: Triggered by pushing a tag that matches `v*.*.*` (e.g. `v1.0.0`, `v1.2.3`) onto `main`. The merge from `development` into `main` is the maintainer's responsibility and happens before the tag is pushed — this workflow does not merge anything. Two jobs:
1. **`build`** — Runs on a `codeberg-small` runner in a 4-way matrix: `linux/amd64`, `linux/arm64`, `freebsd/amd64`, `freebsd/arm64`. The default `actions/checkout@v4` checks out the tagged commit (the trigger was a tag push), which is exactly the commit on `main` we want to ship. The version is baked in via `-ldflags`: 1. **`build`** — Runs on a `fedora` runner in a 4-way matrix: `linux/amd64`, `linux/arm64`, `freebsd/amd64`, `freebsd/arm64`. The default `actions/checkout@v4` checks out the tagged commit (the trigger was a tag push), which is exactly the commit on `main` we want to ship. The version is baked in via `-ldflags`:
```bash ```bash
-X codeberg.org/petrbalvin/nuntius/internal/version.Version=${VERSION#v} -X sourcedock.dev/petrbalvin/nuntius/internal/version.Version=${VERSION#v}
``` ```
The resulting binary is uploaded as a workflow artifact and smoke-tested with `--version` on the build host. The resulting binary is uploaded as a workflow artifact and smoke-tested with `--version` on the build host.
2. **`release`** — Runs on a `codeberg-tiny` runner (no Go toolchain needed). Downloads all artifacts, extracts the matching section from `CHANGELOG.md` for the tagged version, creates a release via the Forgejo REST API, and uploads each binary as a release asset. The release is **non-draft, non-prerelease**; if the CHANGELOG section is missing, the job fails fast so a release cannot ship without notes. 2. **`release`** — Runs on a `fedora` runner (no Go toolchain needed). Downloads all artifacts, extracts the matching section from `CHANGELOG.md` for the tagged version, creates a release via the Gitea REST API, and uploads each binary as a release asset. The release is **non-draft, non-prerelease**; if the CHANGELOG section is missing, the job fails fast so a release cannot ship without notes.
### Cutting a release ### Cutting a release
1. Bump `Version` in `internal/version/version.go`. 1. Bump `Version` in `internal/version/version.go`.
2. Add a new `## [X.Y.Z] — YYYY-MM-DD` section at the top of `CHANGELOG.md`. 2. Add a new `## [X.Y.Z] — YYYY-MM-DD` section at the top of `CHANGELOG.md`.
3. Make sure CI is green on `development` (pushes and PRs against `development` are what the test workflow runs on). 3. Make sure CI is green on `development` (pushes and PRs against `development` are what the test workflow runs on).
4. Merge `development` into `main` (e.g. open a PR on Forgejo, or `git checkout main && git merge --no-ff development && git push origin main`). This is the **only** step where `main` is updated outside of a tag push. 4. Merge `development` into `main` (e.g. open a PR on Gitea, or `git checkout main && git merge --no-ff development && git push origin main`). This is the **only** step where `main` is updated outside of a tag push.
5. Tag the `main` tip and push the tag: 5. Tag the `main` tip and push the tag:
```bash ```bash
git tag -a vX.Y.Z -m "nuntius vX.Y.Z" git tag -a vX.Y.Z -m "nuntius vX.Y.Z"
@@ -250,7 +250,7 @@ Triggered by pushing a tag that matches `v*.*.*` (e.g. `v1.0.0`, `v1.2.3`) onto
``` ```
6. The release workflow builds the four platform binaries and creates the release with the CHANGELOG section as the body. No CI step performs the merge — that already happened in step 4. 6. The release workflow builds the four platform binaries and creates the release with the CHANGELOG section as the body. No CI step performs the merge — that already happened in step 4.
If the release job fails, the tag can be deleted and re-pushed; the workflow re-runs on the new tag push. Do not re-tag an already-released commit — the Forgejo API rejects duplicate release tag names. If the release job fails, the tag can be deleted and re-pushed; the workflow re-runs on the new tag push. Do not re-tag an already-released commit — the Gitea API rejects duplicate release tag names.
## Adding a New Form Type ## Adding a New Form Type
@@ -264,7 +264,7 @@ The four current types (`contact`, `feedback`, `newsletter`, `generic`) live in
## Report a Bug ## Report a Bug
Open an issue at <https://codeberg.org/petrbalvin/nuntius/issues> with: Open an issue at <https://sourcedock.dev/petrbalvin/nuntius/issues> with:
- nuntius version (`./bin/nuntius --version`). - nuntius version (`./bin/nuntius --version`).
- Operating system and architecture. - Operating system and architecture.
+3 -3
View File
@@ -28,7 +28,7 @@
```bash ```bash
# 1. Clone # 1. Clone
git clone https://codeberg.org/petrbalvin/nuntius.git git clone https://sourcedock.dev/petrbalvin/nuntius.git
cd nuntius cd nuntius
# 2. Build # 2. Build
@@ -121,7 +121,7 @@ await fetch(`${import.meta.env.VITE_NUNTIUS_URL || ''}/api/nuntius/contact`, {
`pkg/contactform` is a small, dependency-free Go package that you can import into any project: `pkg/contactform` is a small, dependency-free Go package that you can import into any project:
```go ```go
import "codeberg.org/petrbalvin/nuntius/pkg/contactform" import "sourcedock.dev/petrbalvin/nuntius/pkg/contactform"
req := &contactform.Request{ req := &contactform.Request{
Name: "Jane", Name: "Jane",
@@ -170,7 +170,7 @@ Form types and full schema: [`docs/configuration.md`](docs/configuration.md). Se
- **Go 1.26+** (uses Go 1.22+ `http.ServeMux` method patterns and `log/slog`) - **Go 1.26+** (uses Go 1.22+ `http.ServeMux` method patterns and `log/slog`)
- An **SMTP** account (Yandex, Mailgun, Postmark, your own Postfix, …) - An **SMTP** account (Yandex, Mailgun, Postmark, your own Postfix, …)
- **No other runtime dependencies.** No Node, no Python, no Redis, no Postgres. Configuration is TOML parsed via the first-party [`interpres`](https://codeberg.org/petrbalvin/interpres) library; newsletter storage is an append-only JSONL file via `bufio`. - **No other runtime dependencies.** No Node, no Python, no Redis, no Postgres. Configuration is TOML parsed via the first-party [`interpres`](https://sourcedock.dev/petrbalvin/interpres) library; newsletter storage is an append-only JSONL file via `bufio`.
## Development ## Development
+3 -3
View File
@@ -19,9 +19,9 @@ import (
"syscall" "syscall"
"time" "time"
"codeberg.org/petrbalvin/nuntius/internal/config" "sourcedock.dev/petrbalvin/nuntius/internal/config"
"codeberg.org/petrbalvin/nuntius/internal/handler" "sourcedock.dev/petrbalvin/nuntius/internal/handler"
"codeberg.org/petrbalvin/nuntius/internal/version" "sourcedock.dev/petrbalvin/nuntius/internal/version"
) )
func main() { func main() {
+3 -3
View File
@@ -5,7 +5,7 @@
## Installation ## Installation
```bash ```bash
go get codeberg.org/petrbalvin/nuntius/pkg/contactform go get sourcedock.dev/petrbalvin/nuntius/pkg/contactform
``` ```
Because nuntius ships with no `go.sum` entries from third-party modules, this import pulls in only stdlib transitively. Because nuntius ships with no `go.sum` entries from third-party modules, this import pulls in only stdlib transitively.
@@ -118,7 +118,7 @@ import (
"fmt" "fmt"
"os" "os"
"codeberg.org/petrbalvin/nuntius/pkg/contactform" "sourcedock.dev/petrbalvin/nuntius/pkg/contactform"
) )
func main() { func main() {
@@ -175,7 +175,7 @@ import (
"log" "log"
"net/http" "net/http"
"codeberg.org/petrbalvin/nuntius/pkg/contactform" "sourcedock.dev/petrbalvin/nuntius/pkg/contactform"
) )
func contactHandler(w http.ResponseWriter, r *http.Request) { func contactHandler(w http.ResponseWriter, r *http.Request) {
+1 -1
View File
@@ -8,7 +8,7 @@ import (
"fmt" "fmt"
"os" "os"
"codeberg.org/petrbalvin/nuntius/pkg/contactform" "sourcedock.dev/petrbalvin/nuntius/pkg/contactform"
) )
func main() { func main() {
+2 -2
View File
@@ -1,5 +1,5 @@
module codeberg.org/petrbalvin/nuntius module sourcedock.dev/petrbalvin/nuntius
go 1.26 go 1.26
require codeberg.org/petrbalvin/interpres v1.0.0 require sourcedock.dev/petrbalvin/interpres v1.1.1
+2 -2
View File
@@ -1,2 +1,2 @@
codeberg.org/petrbalvin/interpres v1.0.0 h1:bnY6zSekKklss+w/95O/0GCO1col05pV4HE8JsVXQN4= sourcedock.dev/petrbalvin/interpres v1.1.1 h1:W0HYj8kHikuy1BZePPL4RaSEuv3TNX7YpdP1vvpkP54=
codeberg.org/petrbalvin/interpres v1.0.0/go.mod h1:sWgi5ijKNNLu5sCtjix9jG/guhdnDRlROENrFhrIt90= sourcedock.dev/petrbalvin/interpres v1.1.1/go.mod h1:kyJWrbwVykxCiW250V6zZO2QUKNlAeFn+pwqzr+Hn2U=
+1 -1
View File
@@ -16,7 +16,7 @@ import (
"strconv" "strconv"
"strings" "strings"
"codeberg.org/petrbalvin/interpres" "sourcedock.dev/petrbalvin/interpres"
) )
// ValidFormTypes lists the form types nuntius knows how to handle. // ValidFormTypes lists the form types nuntius knows how to handle.
+2 -2
View File
@@ -10,8 +10,8 @@ import (
"net/smtp" "net/smtp"
"time" "time"
"codeberg.org/petrbalvin/nuntius/internal/config" "sourcedock.dev/petrbalvin/nuntius/internal/config"
"codeberg.org/petrbalvin/nuntius/pkg/contactform" "sourcedock.dev/petrbalvin/nuntius/pkg/contactform"
) )
// FormSender delivers contact form submissions for a single form // FormSender delivers contact form submissions for a single form
+4 -4
View File
@@ -11,10 +11,10 @@ import (
"sync" "sync"
"time" "time"
"codeberg.org/petrbalvin/nuntius/internal/config" "sourcedock.dev/petrbalvin/nuntius/internal/config"
"codeberg.org/petrbalvin/nuntius/internal/email" "sourcedock.dev/petrbalvin/nuntius/internal/email"
"codeberg.org/petrbalvin/nuntius/internal/storage" "sourcedock.dev/petrbalvin/nuntius/internal/storage"
"codeberg.org/petrbalvin/nuntius/pkg/contactform" "sourcedock.dev/petrbalvin/nuntius/pkg/contactform"
) )
// ContactHandler serves one or more contact forms, dispatched by URL path. // ContactHandler serves one or more contact forms, dispatched by URL path.