diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 24c673d..310b674 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -96,3 +96,19 @@ jobs: # the wrong one: the v0.1.0 release tried to publish itself as # v0.1.0-rc.2 and died on an asset that already existed. GORELEASER_CURRENT_TAG: ${{ github.ref_name }} + + # The one published thing that can still be corrected, so it is checked + # after the fact rather than guessed at before. It exists because the + # mechanism failed silently once: the notes were extracted, passed, and + # dropped, and the release went out green with an empty body. + - name: a nota publicada é a nota escrita + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + first=$(grep -m1 . "$RELEASE_NOTES") + if ! gh release view "${{ github.ref_name }}" --json body -q .body | grep -qF "$first"; then + echo "::error::the published notes do not contain the CHANGELOG section that was passed" + gh release view "${{ github.ref_name }}" --json body -q .body + exit 1 + fi + echo "published notes carry the written section" diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 25d293e..0b85db3 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -61,8 +61,20 @@ snapshot: # --release-notes in the workflow. A list of commits says what was touched; # whoever opens a release wants to know what changed for them. See # scripts/release-notes.sh. +# +# This stage stays ENABLED even though nothing here generates the notes, and +# that is not an oversight. `--release-notes` is loaded by this pipe, so +# disabling it drops the flag on the floor: the notes never load, the body comes +# out as the footer alone, and the release still succeeds. v0.1.2 shipped that +# way. The filters below are what the flag would otherwise fall back to. changelog: - disable: true + use: git + filters: + exclude: + - "^Merge pull request" + - "^chore: arquiva" + - "^docs:" + - "^test:" # A distribution package is the shortest path for the target user: a DBA on a # Linux server, with no Go and no Homebrew. The paths below are not our choice, diff --git a/Makefile b/Makefile index cf07ae9..3da19aa 100644 --- a/Makefile +++ b/Makefile @@ -84,6 +84,15 @@ release-check: @v=$$(sed -n 's/^## \[\([0-9][^]]*\)\].*/\1/p' CHANGELOG.md | head -1); \ ./scripts/release-notes.sh "v$$v" > /dev/null; \ echo "release notes ok: $$v" +# `--release-notes` is loaded by goreleaser's changelog pipe, so disabling that +# pipe drops the flag on the floor: the notes never load, the release body comes +# out as the footer alone, and nothing fails. v0.1.2 shipped that way. + @if grep -q -- "--release-notes" .github/workflows/release.yml && \ + sed -n "/^changelog:/,/^[a-z]/p" .goreleaser.yaml | grep -qE "^[[:space:]]+disable:[[:space:]]*true"; then \ + echo "FAILED: the workflow passes --release-notes and .goreleaser.yaml disables the changelog stage that loads it"; \ + exit 1; \ + fi; \ + echo "release notes wiring ok" ## image-check: prove the image builds for both platforms # diff --git a/README.md b/README.md index 04baebe..0f039f3 100644 --- a/README.md +++ b/README.md @@ -30,10 +30,10 @@ `pgfathom` finds the relationships your database has but never declared — and proves them against the data instead of guessing from column names. > [!IMPORTANT] -> **v0.1.1. Early, and measured.** +> **Early, and measured.** > `pgfathom audit` and `pgfathom discover` run end to end, verdicts and reviewable > `.sql` artifacts included, against real production schemas and against a -> [public corpus](#the-public-corpus) anyone can re-run with `make benchmark`. +> [public corpus](#the-measured-corpus) anyone can re-run with `make benchmark`. > Recovery is around 61% on a 1,857-key schema, and the report says what that > number does not measure as plainly as what it does. What the tool never does is > write to your database. The terminal output below is a real run against the @@ -126,6 +126,11 @@ Note the first row: `os_servico.resp_tecnico → funcionario.id`. No name-matchi in the world finds that one — `resp_tecnico` looks nothing like `funcionario`. `pgfathom` finds it by reading the join predicates out of your own view and function definitions. +How often that pays depends entirely on how much SQL your database stores. It is decisive +here and it recovered a single key across the public corpus, for a reason +[measured below](#the-measured-corpus): the schema dumps in it barely contain any joins to +read. A live application database is a different animal. + Output comes as a terminal report, a versioned JSON model, and reviewable `.sql` artifacts. ```console @@ -151,7 +156,7 @@ On Debian, Ubuntu, Fedora or RHEL, take the package for your architecture from t [releases](https://github.com/lvcas-dotcom/pgfathom/releases): ```console -$ sudo dpkg -i pgfathom_0.1.0_linux_amd64.deb # or: sudo rpm -i ...linux_amd64.rpm +$ sudo dpkg -i pgfathom_*_linux_amd64.deb # or: sudo rpm -i pgfathom_*_linux_amd64.rpm $ pgfathom version ``` @@ -417,7 +422,18 @@ already the language's. **Join mining contributes almost nothing measurable here**: one extra key on GitLab, none elsewhere. Reported because a feature that measured smaller than the argument for it should -say so. +say so — and because the reason turns out to be the corpus rather than the extractor. + +Count what there is to mine in these two dumps and the yield stops being surprising. GitLab +declares 336 functions, and **three of them contain a `JOIN` at all** — the rest are trigger +bodies, partition maintenance and `INSERT`/`UPDATE` on a single table. It declares 15 views. +Discourse declares 7 functions with no `JOIN` between them, and one view. A published +`structure.sql` is a schema definition, and analytical SQL is not where it lives. + +That is a fact about this corpus, not about the technique: the demo schema in +[`docs/DEMO.md`](docs/DEMO.md) recovers a relationship no name matching can reach, from one +view. What the corpus establishes is that a schema dump is a poor place to look for joins, +and that anyone quoting these numbers should say so. Three things these tables are not saying. diff --git a/docs/RELEASING.md b/docs/RELEASING.md index df41b41..c1a1a7d 100644 --- a/docs/RELEASING.md +++ b/docs/RELEASING.md @@ -44,20 +44,26 @@ pedir autenticação a quem só quer experimentar. $ scripts/release-notes.sh v0.1.2 ``` -3. Reveja `docs/benchmark/recall.md`. Os números publicados no README saem +3. Se o formato do relatório mudou nesta versão, regrave o exemplo do README. + Ele é execução real contra o schema de `docs/DEMO.md`, e o que o torna útil + é ser verdade — um exemplo que já foi verdade é pior que nenhum, porque + ninguém desconfia dele. O número de versão na gravação pode ficar para trás; + o formato não. + +4. Reveja `docs/benchmark/recall.md`. Os números publicados no README saem dali, e um release que os contradiga é pior do que um release sem eles. -4. Rode `make release-check`. Ele valida a configuração e prova que o binário +5. Rode `make release-check`. Ele valida a configuração e prova que o binário do caminho de release sabe a própria versão. -5. Rode `goreleaser release --snapshot --clean` e abra `dist/`. É a última +6. Rode `goreleaser release --snapshot --clean` e abra `dist/`. É a última chance de olhar o que vai ser publicado antes de existir uma tag. -6. Crie e empurre a tag: +7. Crie e empurre a tag: ```console $ git tag -a v0.1.0 -m 'v0.1.0' $ git push origin v0.1.0 ``` -7. O workflow roda suíte, lint e build cruzado, e só então publica. Acompanhe +8. O workflow roda suíte, lint e build cruzado, e só então publica. Acompanhe até o fim: uma falha depois da metade deixa artefatos parciais, e a resposta certa é corrigir e lançar a versão seguinte, nunca reescrever a tag.