release: v0.1.0

This commit is contained in:
Peter Steinberger 2026-03-08 02:07:27 +00:00
parent 6f51441590
commit 18b0b506f3
9 changed files with 238 additions and 11 deletions

View File

@ -42,7 +42,7 @@ jobs:
run: go vet ./...
- name: Staticcheck
run: "$(go env GOPATH)/bin/staticcheck" ./...
run: '"$(go env GOPATH)/bin/staticcheck" ./...'
- name: Gofumpt
run: |
@ -113,7 +113,7 @@ jobs:
run: go install golang.org/x/vuln/cmd/govulncheck@v1.1.4
- name: Run govulncheck
run: "$(go env GOPATH)/bin/govulncheck" ./...
run: '"$(go env GOPATH)/bin/govulncheck" ./...'
secrets:
runs-on: ubuntu-latest

46
.github/workflows/release.yml vendored Normal file
View File

@ -0,0 +1,46 @@
name: release
on:
push:
tags:
- "v*"
workflow_dispatch:
inputs:
tag:
description: "Tag to (re)release (e.g. v0.1.0)"
required: true
type: string
permissions:
contents: write
jobs:
goreleaser:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6.0.2
with:
fetch-depth: 0
- name: Setup Go
uses: actions/setup-go@v6.3.0
with:
go-version-file: go.mod
cache: true
- name: Stash GoReleaser config
run: cp .goreleaser.yaml /tmp/.goreleaser.yaml
- name: Checkout release tag
if: ${{ github.event_name == 'workflow_dispatch' }}
run: git checkout ${{ inputs.tag }}
- name: GoReleaser
uses: goreleaser/goreleaser-action@v6
with:
distribution: goreleaser
version: latest
args: release --clean --config /tmp/.goreleaser.yaml
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

36
.goreleaser.yaml Normal file
View File

@ -0,0 +1,36 @@
version: 2
project_name: discrawl
changelog:
disable: true
builds:
- id: discrawl
main: ./cmd/discrawl
binary: discrawl
env:
- CGO_ENABLED=0
ldflags:
- -s -w -X github.com/steipete/discrawl/internal/cli.version={{ .Version }}
targets:
- darwin_amd64
- darwin_arm64
- linux_amd64
- linux_arm64
- windows_amd64
- windows_arm64
archives:
- ids:
- discrawl
formats:
- tar.gz
name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
format_overrides:
- goos: windows
formats:
- zip
checksum:
name_template: checksums.txt

View File

@ -2,12 +2,18 @@
All notable changes to `discrawl` will be documented in this file.
## 0.1.0 - 2026-03-07
## 0.1.0 - 2026-03-08
- initial public release of the `discrawl` CLI
- added local SQLite archive, FTS search, raw SQL, sync, tail, status, doctor, members, and channels commands
- added OpenClaw/env token resolution and local runtime config
- added linting, CI, secret scanning, and coverage enforcement
- fixed targeted channel sync to avoid unnecessary guild-wide refresh work
- fixed inaccessible channel handling so sync marks and skips `403 Missing Access` channels
- fixed empty-channel sync state so full crawls can prove completion for quiet channels
- initial public release of `discrawl`
- multi-guild Discord crawler with single-guild default UX
- local SQLite archive with FTS5 search
- commands: `init`, `sync`, `tail`, `search`, `messages`, `mentions`, `sql`, `members`, `channels`, `status`, `doctor`
- OpenClaw config reuse plus env-based bot token discovery
- resumable full-history sync, live gateway tailing, repair sync loop, targeted channel sync
- attachment-text indexing for small text-like uploads
- structured user and role mention indexing/querying
- empty-message filtering based on real searchable/displayable content instead of raw body only
- CI with lint, tests, secret scanning, and `80%+` coverage enforcement
- release plumbing via GoReleaser, GitHub Actions, and Homebrew tap packaging
- sync correctness fixes for empty channels, inaccessible channels, unknown channels, and large-channel resume behavior
- SQLite/FTS performance fixes for backfill throughput and lower write amplification

98
docs/RELEASING.md Normal file
View File

@ -0,0 +1,98 @@
---
summary: "Release checklist for discrawl (GitHub release binaries via GoReleaser + Homebrew tap update)"
---
# Releasing `discrawl`
Always do all steps below. No partial releases.
Assumptions:
- Repo: `steipete/discrawl`
- Binary: `discrawl`
- GoReleaser config: `.goreleaser.yaml`
- Homebrew tap repo: `~/Projects/homebrew-tap`
## 0) Prereqs
- Clean working tree on `main`
- Go toolchain from `go.mod`
- GitHub CLI authenticated
- CI green on `main`
## 1) Verify build + tests
```sh
go run github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.5.0 run
go test ./... -coverprofile=coverage.out
go tool cover -func=coverage.out | tail -n 1
go build -o /tmp/discrawl ./cmd/discrawl
gh run list -L 5 --branch main
```
Coverage floor: `80%+`
## 2) Update changelog
Add a new section in `CHANGELOG.md`.
Example:
- `## 0.2.0 - 2026-03-08`
## 3) Commit, tag, push
```sh
git checkout main
git pull --ff-only origin main
git commit -am "release: vX.Y.Z"
git tag -a vX.Y.Z -m "Release X.Y.Z"
git push origin main --tags
```
## 4) Verify GitHub release assets
The tag push triggers `.github/workflows/release.yml`.
```sh
gh run list -L 5 --workflow release.yml
gh release view vX.Y.Z
```
Confirm assets exist for:
- `darwin_amd64`
- `darwin_arm64`
- `linux_amd64`
- `linux_arm64`
- `windows_amd64`
- `windows_arm64`
## 5) Update Homebrew tap
`discrawl` currently ships a source-build formula in `~/Projects/homebrew-tap/Formula/discrawl.rb`.
After tagging a real release:
1. switch the formula URL from the pinned source-commit tarball to the release tag tarball or release binaries
2. update `sha256`
3. test locally
4. commit + push `homebrew-tap`
Useful commands:
```sh
curl -L -o /tmp/discrawl.tgz https://github.com/steipete/discrawl/archive/refs/tags/vX.Y.Z.tar.gz
shasum -a 256 /tmp/discrawl.tgz
brew uninstall discrawl || true
brew install --build-from-source ./Formula/discrawl.rb
brew test discrawl
```
## Notes
- Build-time version stamping comes from `-X github.com/steipete/discrawl/internal/cli.version={{ .Version }}`
- If release workflow needs a rerun:
```sh
gh workflow run release.yml -f tag=vX.Y.Z
```

3
internal/cli/version.go Normal file
View File

@ -0,0 +1,3 @@
package cli
var version = "0.1.0"

View File

@ -141,6 +141,33 @@ func TestReadOnlyQueryGuards(t *testing.T) {
require.Error(t, err)
}
func TestQueryAndExec(t *testing.T) {
t.Parallel()
ctx := context.Background()
s, err := Open(ctx, filepath.Join(t.TempDir(), "discrawl.db"))
require.NoError(t, err)
defer func() { _ = s.Close() }()
affected, err := s.Exec(ctx, `
insert into sync_state(scope, cursor, updated_at)
values('scope:test-exec', 'cursor-1', '2026-03-08T00:00:00Z')
`)
require.NoError(t, err)
require.Equal(t, int64(1), affected)
cols, rows, err := s.Query(ctx, `select scope, cursor from sync_state where scope = 'scope:test-exec'`)
require.NoError(t, err)
require.Equal(t, []string{"scope", "cursor"}, cols)
require.Equal(t, [][]string{{"scope:test-exec", "cursor-1"}}, rows)
_, _, err = s.Query(ctx, " ")
require.Error(t, err)
_, err = s.Exec(ctx, " ")
require.Error(t, err)
}
func TestUpsertAndDeleteMember(t *testing.T) {
t.Parallel()

View File

@ -3,6 +3,7 @@ package syncer
import (
"bufio"
"context"
"errors"
"io"
"mime"
"net/http"
@ -188,7 +189,7 @@ func fetchAttachmentText(ctx context.Context, url string) (string, error) {
}
reader := bufio.NewReader(resp.Body)
peek, err := reader.Peek(512)
if err != nil && err != io.EOF {
if err != nil && !errors.Is(err, io.EOF) {
return "", err
}
if len(peek) != 0 && !isAllowedFetchedContentType(normalizedMediaType(http.DetectContentType(peek))) {

View File

@ -264,6 +264,16 @@ func TestSyncUsesConfiguredConcurrency(t *testing.T) {
require.GreaterOrEqual(t, maxInFlight, 2)
}
func TestSetAttachmentTextEnabled(t *testing.T) {
t.Parallel()
svc := New(&fakeClient{}, nil, nil)
require.True(t, svc.attachmentTextEnabled)
svc.SetAttachmentTextEnabled(false)
require.False(t, svc.attachmentTextEnabled)
}
func TestSyncChannelSubsetUsesStoredMetadata(t *testing.T) {
t.Parallel()