Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .claude/commands/release-syncthing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
description: Prepare a release bumping the bundled Syncthing version, up through opening the PR
argument-hint: [version]
---

Prepare a new release for syncthing $ARGUMENTS (if no version was given, bump to the latest upstream Syncthing release).

Follow the release flow documented in CLAUDE.md, up through opening the PR — stop there,
do not merge, run `task bump`, tag, or push tags without explicit go-ahead.

Before starting:
- If the working tree is dirty (including untracked files unrelated to the bump), report what's
there and ask how to handle it before running the bump scripts, which refuse a dirty tree.
- Confirm what GitHub's `releases/latest` API currently returns for syncthing/syncthing, since
scripts/bump-syncthing.sh always targets "latest" with no explicit-version argument — if it
doesn't match the requested version, stop and report instead of proceeding.
- Compare the upstream `CurrentVersion` constant in lib/config/config.go at the target tag against
the `version` attribute in rootfs/etc/syncthing/config.xml. If they differ, bump the config.xml
schema version too (README.md documents this as a manual step) and note it in the PR. If they
match, note explicitly that no schema change was needed.

Then:
1. `git switch -c release/next`
2. `task bump:syncthing`
3. Verify the resulting diff touches only Dockerfile and README.md as expected
4. Push the branch
5. Run `task preview-changelog`, take the generated `## <next version>...` block as the PR body,
and open the PR with `gh pr create` (title: `feat(syncthing): bump to <version>`)
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,18 @@

All notable changes to this project will be documented in this file.

## 3.3.0 - 2026-08-26

### <!-- 0 -->⬆️ Upstream

* **syncthing**: Bump to 2.1.3

* [Release notes](https://github.com/syncthing/syncthing/releases/tag/v2.1.3)

### <!-- 1 -->🚀 Features

* **tools**: Add /release-syncthing slash command

## 3.2.0 - 2026-06-09

### <!-- 0 -->⬆️ Upstream
Expand Down
52 changes: 52 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## What this repo is

This is not an application codebase — it builds and releases a single Docker image, `nventiveux/syncthing`, which wraps the upstream [Syncthing](https://syncthing.net/) binary for amd64/arm32v6/armv7/arm64. The "code" is the [Dockerfile](Dockerfile), an entrypoint script, and a set of release-automation scripts.

## Commands

Toolchain (`task`, `git-cliff`) is pinned via `asdf` in [.tool-versions](.tool-versions); run `asdf install` once before using `task`.

- `task tests` — build the image and run it locally for manual testing. Requires `DOCKER_TAG` (e.g. `task tests DOCKER_TAG=latest`); there is no automated test suite.
- `task clean` — remove the local `nventiveux/syncthing:latest` image.
- `task preview-changelog` — preview the changelog that `git cliff --bump --unreleased` would generate, without writing anything.
- `task bump:syncthing` — bump to the latest upstream Syncthing release ([scripts/bump-syncthing.sh](scripts/bump-syncthing.sh)): fetches the latest tag from the GitHub API, updates `SYNCTHING_VERSION` in the Dockerfile and the version table in the README, and commits.
- `task bump` — bump this project's own version ([scripts/bump.sh](scripts/bump.sh)): computes the next version via `git-cliff`, updates the README's "Image version" line, regenerates [CHANGELOG.md](CHANGELOG.md), and commits.
- `task tag` — tag a release via `git-cliff` ([scripts/tag.sh](scripts/tag.sh)); push tags manually afterwards (`git push origin --tags`).

All three `scripts/*.sh` bump/tag scripts refuse to run on a dirty working tree.

Dockerfile linting (hadolint) and multi-arch image builds/pushes run in CI ([.github/workflows/ci.yaml](.github/workflows/ci.yaml), [.github/workflows/cd.yaml](.github/workflows/cd.yaml)), not via `task`. [.hadolint.yaml](.hadolint.yaml) intentionally ignores `DL3018` (Alpine package pinning).

## Release flow

1. `git switch -c release/next`
2. `task bump:syncthing` → open PR → CI builds/tests the image
3. Merge, then `task bump` → merge that too
4. `git switch main && git pull && task tag && git push origin --tags`
5. Pushing a `v*.*.*` tag triggers CD: multi-arch build/push to Docker Hub via [docker-bake.hcl](docker-bake.hcl), plus a GitHub release with the git-cliff-generated changelog.

**Important**: when bumping the Syncthing version, also sync the config file's schema `version` attribute in [rootfs/etc/syncthing/config.xml](rootfs/etc/syncthing/config.xml) against upstream's [`lib/config/config.go`](https://github.com/syncthing/syncthing/blob/main/lib/config/config.go#L36) — this is a manual step, not automated by `bump-syncthing.sh`.

## Commit convention

Conventional Commits, enforced by changelog generation ([cliff.toml](cliff.toml)):
- `feat`, `fix`, `doc`, `perf`, `refactor`, `style`, `test` each map to a changelog section.
- `chore` and `bump` commits are excluded from the changelog entirely (used for release/bump commits themselves).
- Scope `(syncthing)` (e.g. `feat(syncthing): bump to 2.1.1`) is special-cased into an "⬆️ Upstream" changelog group regardless of its `feat`/`fix` prefix.

## Runtime architecture

[Dockerfile](Dockerfile): Alpine base, downloads and verifies (sha256) the upstream Syncthing release tarball for `SYNCTHING_ARCH`, copies [rootfs/](rootfs/) over the image root, declares `/etc/syncthing` and `/var/lib/syncthing` as volumes.

[rootfs/docker-entrypoint.sh](rootfs/docker-entrypoint.sh) runs on every container start, before `exec`-ing into Syncthing as an unprivileged user:
1. bcrypt-hashes `SYNCTHING_ADMIN_PASSWORD` (default `admin`) via `python3`/`py3-bcrypt`.
2. Creates or updates the `SYNCTHING_USER`/`SYNCTHING_GROUP` (with `SYNCTHING_USER_UID`/`SYNCTHING_GROUP_GID`) so the container can run as a host-matching UID/GID.
3. `chown`s `/etc/syncthing` and `/var/lib/syncthing` to that user/group if ownership drifted.
4. Rewrites `<user>`/`<password>` in [rootfs/etc/syncthing/config.xml](rootfs/etc/syncthing/config.xml) via `sed` to the configured admin credentials.
5. `exec su-exec syncthing "$@"` — drops privileges and hands off to the actual `syncthing` process (the Dockerfile's `CMD`).

Configuration is entirely environment-variable-driven (`SYNCTHING_USER`, `SYNCTHING_USER_UID`, `SYNCTHING_GROUP`, `SYNCTHING_GROUP_GID`, `SYNCTHING_ADMIN_USER`, `SYNCTHING_ADMIN_PASSWORD`) — see [README.md](README.md) for the full table and an example `docker run` invocation.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ ENV SYNCTHING_USER="syncthing" \
SYNCTHING_GROUP="syncthing" \
SYNCTHING_GROUP_GID=1000 \
SYNCTHING_ADMIN_USER="admin" \
SYNCTHING_VERSION="2.1.1" \
SYNCTHING_VERSION="2.1.3" \
SYNCTHING_ARCH="amd64"

RUN set -x \
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ Following arch are missing tests:
## Available image tags

* [nventiveux/syncthing](https://hub.docker.com/r/nventiveux/syncthing)
* Image version: `latest`, `3.2.0` ([Dockerfile](./Dockerfile))
* Syncthing version: `v2.1.1`
* Image version: `latest`, `3.3.0` ([Dockerfile](./Dockerfile))
* Syncthing version: `v2.1.3`

## Usage

Expand Down
Loading