Skip to content

Commit acac367

Browse files
authored
Phase H: distribution — GoReleaser, install script, landing + docs site (#11)
1 parent fe82615 commit acac367

52 files changed

Lines changed: 11215 additions & 20 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.githooks/pre-push

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#!/bin/sh
2+
# Pre-push gate for the web/ app. Runs ESLint + Prettier-check before a push
3+
# touches the Next.js site; a failure aborts the push so unformatted or
4+
# lint-broken web code never reaches the remote. (Go code is gated by CI.)
5+
#
6+
# Change-aware: if the push range contains no web/ changes, this exits
7+
# immediately so Go-only pushes don't pay the npm startup cost.
8+
#
9+
# Enable once per clone: git config core.hooksPath .githooks
10+
# Bypass in an emergency: git push --no-verify
11+
set -eu
12+
13+
REPO_ROOT=$(git rev-parse --show-toplevel)
14+
WEB_DIR="$REPO_ROOT/web"
15+
16+
# git feeds the hook "<local ref> <local sha> <remote ref> <remote sha>" lines
17+
# on stdin, one per ref being pushed. We collect the local shas to diff.
18+
z40=0000000000000000000000000000000000000000
19+
changed_web=0
20+
21+
while read -r _local_ref local_sha _remote_ref remote_sha; do
22+
# Skip a branch deletion (local sha is all-zero).
23+
[ "$local_sha" = "$z40" ] && continue
24+
25+
if [ "$remote_sha" = "$z40" ]; then
26+
# New branch on the remote: diff against the upstream default so we only
27+
# consider this branch's own commits. If origin/main is unknown locally we
28+
# cannot compute a real range — fail closed and run the checks rather than
29+
# diffing against the working tree (which could skip committed web/ changes).
30+
if git rev-parse --quiet --verify origin/main >/dev/null 2>&1; then
31+
range="origin/main..$local_sha"
32+
else
33+
changed_web=1
34+
break
35+
fi
36+
else
37+
range="$remote_sha..$local_sha"
38+
fi
39+
40+
# Any web/ files in this range?
41+
if git diff --name-only "$range" 2>/dev/null | grep -q '^web/'; then
42+
changed_web=1
43+
break
44+
fi
45+
done
46+
47+
if [ "$changed_web" -eq 0 ]; then
48+
echo "pre-push: no web/ changes in this push — skipping web checks."
49+
exit 0
50+
fi
51+
52+
echo "pre-push: web/ changed — running lint + format check…"
53+
cd "$WEB_DIR"
54+
55+
if [ ! -d node_modules ]; then
56+
echo "pre-push: web/node_modules missing — run 'npm install' in web/ first." >&2
57+
exit 1
58+
fi
59+
60+
npm run lint || { echo "pre-push: ESLint failed — fix it or run 'npm run lint:fix'." >&2; exit 1; }
61+
npm run format:check || { echo "pre-push: formatting issues — run 'npm run format'." >&2; exit 1; }
62+
63+
echo "pre-push: web checks passed."
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
name: Bug report
2+
description: Something siphon did wrong — a crash, wrong output, or a failed operation.
3+
labels: ["bug"]
4+
body:
5+
- type: markdown
6+
attributes:
7+
value: |
8+
Thanks for the report. Please include enough to reproduce — siphon shells
9+
out to native dump/restore tools, so the exact command and engine matter.
10+
- type: textarea
11+
id: what-happened
12+
attributes:
13+
label: What happened
14+
description: What you ran and what went wrong. Paste the command and the error.
15+
placeholder: |
16+
$ siphon backup prod
17+
✗ ...
18+
validations:
19+
required: true
20+
- type: textarea
21+
id: expected
22+
attributes:
23+
label: What you expected
24+
validations:
25+
required: true
26+
- type: input
27+
id: version
28+
attributes:
29+
label: siphon version
30+
description: Output of `siphon --version`.
31+
placeholder: "v1.0.0"
32+
validations:
33+
required: true
34+
- type: dropdown
35+
id: engine
36+
attributes:
37+
label: Database engine
38+
options:
39+
- PostgreSQL
40+
- MySQL
41+
- MariaDB
42+
- Cross-engine (specify in details)
43+
- Not engine-specific
44+
validations:
45+
required: true
46+
- type: dropdown
47+
id: os
48+
attributes:
49+
label: OS
50+
options: [Linux, macOS, Windows]
51+
validations:
52+
required: true
53+
- type: input
54+
id: exit-code
55+
attributes:
56+
label: Exit code
57+
description: siphon uses a POSIX exit-code taxonomy; the number helps classify the failure.
58+
placeholder: "e.g. 1 (user), 70 (system), 65 (integrity)"
59+
- type: textarea
60+
id: details
61+
attributes:
62+
label: Anything else
63+
description: Profile config (redact secrets), storage backend, logs, repro steps.

.github/ISSUE_TEMPLATE/config.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
blank_issues_enabled: false
2+
contact_links:
3+
- name: Question or discussion
4+
url: https://github.com/nixrajput/siphon/discussions
5+
about: For usage questions and ideas, start a discussion instead of an issue.
6+
- name: Security vulnerability
7+
url: https://github.com/nixrajput/siphon/security/policy
8+
about: Please report security issues privately, not as a public issue.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
name: Feature request
2+
description: Suggest a capability or improvement.
3+
labels: ["enhancement"]
4+
body:
5+
- type: textarea
6+
id: problem
7+
attributes:
8+
label: The problem
9+
description: What are you trying to do that siphon makes hard or impossible today?
10+
validations:
11+
required: true
12+
- type: textarea
13+
id: proposal
14+
attributes:
15+
label: Proposed solution
16+
description: What you'd like siphon to do. A command sketch helps.
17+
validations:
18+
required: true
19+
- type: textarea
20+
id: alternatives
21+
attributes:
22+
label: Alternatives considered
23+
- type: dropdown
24+
id: area
25+
attributes:
26+
label: Area
27+
options:
28+
- Backup / restore
29+
- Sync / CDC / cross-engine
30+
- Storage backends
31+
- Retention
32+
- Secrets / auth / audit
33+
- TUI
34+
- Drivers (new engine)
35+
- Other
36+
validations:
37+
required: true

.github/pull_request_template.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
## What & why
2+
3+
<!-- What this changes and the reason. Link any issue: Closes #123. -->
4+
5+
## How it was verified
6+
7+
<!-- Commands run and their outcome — evidence, not assertions. -->
8+
9+
- [ ] `make test` passes
10+
- [ ] `make lint` passes (0 issues)
11+
- [ ] `make test-integration` (if the change touches a live DB / storage path)
12+
- [ ] Docs updated (README / `docs/*.md` / CHANGELOG) for any user-facing change
13+
- [ ] `web/` builds (`npm run build`) — only if the site changed
14+
15+
## Notes for reviewers
16+
17+
<!-- Anything non-obvious: a deliberate scope decision, a deferred follow-up,
18+
a tradeoff, or a place you'd especially like eyes. -->

.github/workflows/release.yml

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
name: Release
2+
3+
# Auto-releases when a version tag (vX.Y.Z) is pushed. GoReleaser builds the
4+
# cross-platform binaries, SHA-256 checksums, and cosign-keyless signatures,
5+
# publishes a GitHub Release, and — when the tap repos + tokens exist — pushes
6+
# the Homebrew formula and Scoop manifest.
7+
#
8+
# A validation gate (test + lint + config check) runs first, so a broken tag
9+
# never publishes. workflow_dispatch runs a snapshot dry-run (no publish) to
10+
# rehearse a release without tagging.
11+
on:
12+
push:
13+
tags:
14+
- "v*"
15+
workflow_dispatch: {}
16+
17+
permissions:
18+
contents: read
19+
20+
jobs:
21+
# Gate: the same checks CI runs, plus goreleaser config validation. The
22+
# release job depends on this, so a failing test/lint aborts before publish.
23+
validate:
24+
name: Validate
25+
runs-on: ubuntu-latest
26+
steps:
27+
- uses: actions/checkout@v6
28+
with:
29+
fetch-depth: 0
30+
persist-credentials: false # don't leave the token in .git/config
31+
- uses: actions/setup-go@v6
32+
with:
33+
go-version-file: go.mod # reproducible: pin the toolchain to go.mod
34+
cache: true
35+
- name: Test
36+
run: go test ./... github.com/nixrajput/siphon/internal/driver/_mysqlcommon
37+
- name: Lint
38+
uses: golangci/golangci-lint-action@v6
39+
- name: GoReleaser check
40+
uses: goreleaser/goreleaser-action@v6
41+
with:
42+
version: "~> v2"
43+
args: check
44+
45+
release:
46+
name: Release
47+
needs: validate
48+
runs-on: ubuntu-latest
49+
permissions:
50+
contents: write # create the GitHub Release
51+
id-token: write # cosign keyless signing via GitHub OIDC
52+
steps:
53+
- uses: actions/checkout@v6
54+
with:
55+
fetch-depth: 0
56+
persist-credentials: false # don't leave the token in .git/config # GoReleaser needs full history + tags for the changelog
57+
58+
- uses: actions/setup-go@v6
59+
with:
60+
go-version-file: go.mod # reproducible: pin the toolchain to go.mod
61+
cache: true
62+
63+
- name: Install cosign
64+
uses: sigstore/cosign-installer@v3
65+
66+
# On a tag push: full release. On manual dispatch: snapshot dry-run that
67+
# builds everything locally and publishes nothing (rehearsal).
68+
- name: Set release args
69+
id: args
70+
run: |
71+
if [ "${{ github.ref_type }}" = "tag" ]; then
72+
echo "args=release --clean" >> "$GITHUB_OUTPUT"
73+
else
74+
echo "args=release --clean --snapshot" >> "$GITHUB_OUTPUT"
75+
fi
76+
77+
- name: Run GoReleaser
78+
uses: goreleaser/goreleaser-action@v6
79+
with:
80+
version: "~> v2"
81+
args: ${{ steps.args.outputs.args }}
82+
env:
83+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
84+
# Tap-push tokens. These secrets may be unset on early releases; a
85+
# GitHub Actions secret expression yields "" when absent, so the
86+
# GoReleaser token template still resolves and skip_upload: auto
87+
# quietly skips the brew/scoop push instead of erroring. Provision
88+
# these (PATs with repo scope on the tap repos) to enable publishing.
89+
HOMEBREW_TAP_GITHUB_TOKEN: ${{ secrets.HOMEBREW_TAP_GITHUB_TOKEN }}
90+
SCOOP_TAP_GITHUB_TOKEN: ${{ secrets.SCOOP_TAP_GITHUB_TOKEN }}

.golangci.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,12 @@ linters:
5757
- pkg: "github.com/nixrajput/siphon/internal/app"
5858
desc: "Drivers must not depend on Application — dependency flows down"
5959
exclusions:
60+
# web/ is the Next.js site; its node_modules can vendor stray .go files
61+
# (e.g. flatted/golang) that are not siphon code. Keep the Go linters off
62+
# the JS subtree. (node_modules is gitignored, so CI never sees it on a
63+
# fresh checkout; this keeps local lint consistent with CI.)
64+
paths:
65+
- web
6066
rules:
6167
- path: _test\.go
6268
linters:

0 commit comments

Comments
 (0)