Compare commits
3
Commits
main
..
d111b3c665
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d111b3c665 | ||
|
|
b2a4f748b7 | ||
|
|
337b319542 |
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
# Lint stage — fast feedback on formatting and lint issues
|
# Lint stage — fast feedback on formatting and lint issues
|
||||||
# golangci/golangci-lint:v2.12.2 (Debian-based), 2026-08-07
|
# golangci/golangci-lint:v2.12.2, 2026-08-07
|
||||||
FROM golangci/golangci-lint:v2.12.2@sha256:5cceeef04e53efe1470638d4b4b4f5ceefd574955ab3941b2d9a68a8c9ad5240 AS lint
|
FROM golangci/golangci-lint@sha256:5cceeef04e53efe1470638d4b4b4f5ceefd574955ab3941b2d9a68a8c9ad5240 AS lint
|
||||||
WORKDIR /src
|
WORKDIR /src
|
||||||
COPY go.mod go.sum ./
|
COPY go.mod go.sum ./
|
||||||
RUN go mod download
|
RUN go mod download
|
||||||
|
|||||||
+2
-2
@@ -9,8 +9,8 @@
|
|||||||
# stage of the main Dockerfile because script/lint must not depend on
|
# stage of the main Dockerfile because script/lint must not depend on
|
||||||
# the rest of that build; the two FROM lines are kept identical by
|
# the rest of that build; the two FROM lines are kept identical by
|
||||||
# script/verify-lint-image-pin, run as a gate below.
|
# script/verify-lint-image-pin, run as a gate below.
|
||||||
# golangci/golangci-lint:v2.12.2 (Debian-based), 2026-08-07
|
# golangci/golangci-lint:v2.12.2, 2026-08-07
|
||||||
FROM golangci/golangci-lint:v2.12.2@sha256:5cceeef04e53efe1470638d4b4b4f5ceefd574955ab3941b2d9a68a8c9ad5240
|
FROM golangci/golangci-lint@sha256:5cceeef04e53efe1470638d4b4b4f5ceefd574955ab3941b2d9a68a8c9ad5240
|
||||||
|
|
||||||
WORKDIR /src
|
WORKDIR /src
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,22 @@
|
|||||||
|
|
||||||
# Completed Steps
|
# Completed Steps
|
||||||
|
|
||||||
|
- refuse an unversioned database that already has a `files` table with
|
||||||
|
a clear schema-version error (2026-09-21, branch `next`, closes
|
||||||
|
https://git.eeqj.de/sneak/sfdupes/issues/11)
|
||||||
|
|
||||||
|
- fix the lint-image pin comments and `FROM` form in `Dockerfile` and
|
||||||
|
`Dockerfile.lint` (2026-08-10, branch `next`, closes
|
||||||
|
https://git.eeqj.de/sneak/sfdupes/issues/25): dropped the false
|
||||||
|
`(Debian-based)` parenthetical (v2.12.1 was Debian too) and the
|
||||||
|
redundant tag, so both pins are the policy `# image:vX.Y.Z,
|
||||||
|
YYYY-MM-DD` comment over a bare `FROM image@sha256:...`. Digest
|
||||||
|
unchanged. `script/verify-lint-image-pin` parses those `FROM` lines
|
||||||
|
and still matches the tagless form; its advice line lost the now
|
||||||
|
meaningless "tag and digest". With no tag in either reference, a
|
||||||
|
tag-only disagreement no longer exists — a one-sided tag is caught as
|
||||||
|
a plain mismatch.
|
||||||
|
|
||||||
- run all linting in Docker via `Dockerfile.lint` and `script/lint`
|
- run all linting in Docker via `Dockerfile.lint` and `script/lint`
|
||||||
(2026-08-10, branch `next`, closes
|
(2026-08-10, branch `next`, closes
|
||||||
https://git.eeqj.de/sneak/sfdupes/issues/46): per the owner ruling, the
|
https://git.eeqj.de/sneak/sfdupes/issues/46): per the owner ruling, the
|
||||||
|
|||||||
@@ -174,9 +174,30 @@ func initSchema(ctx context.Context, db *sql.DB) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// createSchema applies the schema to a fresh database and stamps the
|
// createSchema applies the schema to a fresh database and stamps the
|
||||||
// schema version.
|
// schema version. A database with user_version 0 that already has a
|
||||||
|
// files table was not created by this build — a foreign or partially
|
||||||
|
// initialized file. Adopting it silently could corrupt unrelated data,
|
||||||
|
// so that is a fatal schema-version error telling the operator to
|
||||||
|
// remove the file and rescan.
|
||||||
func createSchema(ctx context.Context, db *sql.DB) error {
|
func createSchema(ctx context.Context, db *sql.DB) error {
|
||||||
_, err := db.ExecContext(ctx, createTableSQL)
|
var name string
|
||||||
|
|
||||||
|
err := db.QueryRowContext(ctx,
|
||||||
|
"SELECT name FROM sqlite_master "+
|
||||||
|
"WHERE type = 'table' AND name = 'files'").Scan(&name)
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case err == nil:
|
||||||
|
return fmt.Errorf(
|
||||||
|
"has a files table but no schema version; "+
|
||||||
|
"remove the file and rescan: %w", errSchemaVersion)
|
||||||
|
case errors.Is(err, sql.ErrNoRows):
|
||||||
|
// Genuinely empty: create the schema below.
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("check for files table: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = db.ExecContext(ctx, createTableSQL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("create schema: %w", err)
|
return fmt.Errorf("create schema: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
+32
@@ -78,6 +78,38 @@ func TestOpenScanDatabaseCreates(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestOpenScanDatabaseUnversionedForeign(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
path := testDBPath(t)
|
||||||
|
|
||||||
|
// A database that has a files table but user_version 0 — a foreign
|
||||||
|
// or partially initialized file. scan must refuse it with a clear
|
||||||
|
// schema-version error, not adopt it and not emit a raw SQLite
|
||||||
|
// "table files already exists".
|
||||||
|
db, err := openDB(path)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = db.ExecContext(t.Context(), "CREATE TABLE files (x INTEGER)")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = db.Close()
|
||||||
|
|
||||||
|
_, err = openScanDatabase(t.Context(), path)
|
||||||
|
if !errors.Is(err, errSchemaVersion) {
|
||||||
|
t.Fatalf("err = %v, want errSchemaVersion", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.Contains(err.Error(), "remove the file and rescan") {
|
||||||
|
t.Fatalf("err = %v, want it to tell the operator to remove and rescan",
|
||||||
|
err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestOpenReportDatabaseMissing(t *testing.T) {
|
func TestOpenReportDatabaseMissing(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
|||||||
@@ -71,9 +71,9 @@ main() {
|
|||||||
"the two pins disagree:" >&2
|
"the two pins disagree:" >&2
|
||||||
echo "verify-lint-image-pin: $LINT_DOCKERFILE: $lint_ref" >&2
|
echo "verify-lint-image-pin: $LINT_DOCKERFILE: $lint_ref" >&2
|
||||||
echo "verify-lint-image-pin: $MAIN_DOCKERFILE: $main_ref" >&2
|
echo "verify-lint-image-pin: $MAIN_DOCKERFILE: $main_ref" >&2
|
||||||
echo "verify-lint-image-pin: bump both FROM lines together, tag and" \
|
echo "verify-lint-image-pin: bump both FROM lines together so" \
|
||||||
"digest, so script/lint and the Dockerfile lint stage keep" \
|
"script/lint and the Dockerfile lint stage keep running the" \
|
||||||
"running the same linter" >&2
|
"same linter" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user