Skip to content

ci: publish standalone Linux binaries with GitHub releases - #112

Merged
shockalotti merged 1 commit into
Calnode:mainfrom
ilbertt:codex/standalone-release-binaries
Oct 27, 2026
Merged

shockalotti merged 1 commit into
Calnode:mainfrom
ilbertt:codex/standalone-release-binaries

Conversation

@ilbertt

@ilbertt ilbertt commented Oct 1, 2026

Copy link
Copy Markdown
Contributor

Publish Linux amd64 and arm64 archives, including the license and SHA-256 checksums, with future tagged releases. This reuses the existing Docker build and adds standalone setup instructions, including the difference in Litestream backup behavior.

Following up on #108: I created nibrun to make open-source apps that ship as a single binary easy to deploy. Official release assets will let me finish Calnode’s one-click preset and app page, then propose a “Deploy on nibrun” button like PicoShare’s.

Validated with go test ./..., make build, and actionlint. Built and packaged both architectures, verified checksums, and ran each extracted binary under a 256 MB limit: health/readiness, database migrations, version metadata, embedded admin UI assets, and restart all passed.

@github-actions

github-actions Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

All contributors have signed the CLA. ✅
Posted by the CLA Assistant Lite bot.

@ilbertt
ilbertt marked this pull request as draft October 1, 2026 09:24
@ilbertt

ilbertt commented Oct 1, 2026

Copy link
Copy Markdown
Contributor Author

I have read the CLA Document and I hereby sign the CLA

github-actions Bot added a commit that referenced this pull request Oct 1, 2026
@ilbertt ilbertt changed the title Publish standalone Linux binaries with GitHub releases ci: publish standalone Linux binaries with GitHub releases Oct 5, 2026

@shockalotti shockalotti left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the diff — build correctness checks out (pure-Go sqlite, CGO_ENABLED=0 already in the builder, tzdata embedded, scratch-stage layout matches the tar paths, checksums attached, release gating correct, Dockerfile default target unaffected, docs accurate including the Litestream caveat).

Not merging yet for one reason: this is still a draft, and the entire new chain (export/package/upload/download/release) has never executed green anywhere — the fork workflow runs sit at action_required. Before merge: approve the fork workflows to run (or push to a non-fork branch) so Docker publish goes green on the PR, and dry-run the release job's download + create step somehow, since that line can never run on a PR by construction.

Optional efficiency nit: gate the export/package/upload steps to tags so every PR/main/dev build doesn't pay multi-arch packaging cost for artifacts only releases consume.

@ilbertt
ilbertt marked this pull request as ready for review October 13, 2026 06:46

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes

  • Standalone export target — adds a scratch stage to Dockerfile that exports the builder's calnode binary (embedded frontend included) plus LICENSE for both architectures.
  • Binary export and packaging — a second buildx build uses type=local,platform-split=true, then tars each linux_* directory into calnode_<version>_<os>_<arch>.tar.gz, writes checksums.txt, and uploads the directory as an artifact.
  • Release attachment — the release job downloads the artifact into dist/release and passes the archives plus checksums to gh release create.
  • Docs — README links to a new DEPLOY.md standalone-binary section covering checksum verification, secrets, proxy/Host and CA requirements, and the Litestream/entrypoint caveat.

The mechanics line up with the surrounding pipeline: semver tags resolve steps.meta.outputs.version to a v-less x.y.z matching the documented archive names, buildx's platform-split output names match the linux_* glob, and time/tzdata is imported in cmd/calnode/main.go, so the "timezone database embedded" claim holds. No blocking or non-blocking correctness issues found.

Pullfrog  | View workflow run | Using deepseek-v4.1-flash | 𝕏

@shockalotti
shockalotti merged commit 4c75085 into Calnode:main Oct 27, 2026
7 of 8 checks passed
@ilbertt
ilbertt deleted the codex/standalone-release-binaries branch October 28, 2026 09:07
@shockalotti

Copy link
Copy Markdown
Contributor

Landed as #223 (merged), so nothing for you to do here. Recording the reasoning while it is fresh.

The one follow-up: your export, packaging and upload steps were all ungated, so every PR and branch push packaged and stored an archive that only the tag-triggered release job ever downloads.

#223 gates only the upload, and the condition deliberately mirrors the release job rather than a bare tag check:

if: startsWith(github.ref, refs/tags/v) || (github.event_name == "workflow_dispatch" && inputs.dry_run)

A plain startsWith(github.ref, "refs/tags/v") would have broken the dry-run rehearsal, since that path runs the release job and its first step is download-artifact.

Export and packaging stay ungated on purpose: they are what proves the standalone stage still builds, so a break shows up on a PR instead of during a release.

Verified both directions: on a PR, export and packaging pass and upload is skipped; on a dry_run=true dispatch against main, upload passes, the release job downloads the artifact and extracts notes, and Create GitHub Release is skipped with no Release created.

Thanks for this one. The static binary was a good call: the embedded UI plus time/tzdata means there really is nothing distro-specific to build, which is why the archives are per-arch and nothing else.

edimitchel pushed a commit to edimitchel/calnode that referenced this pull request Nov 4, 2026
Since Calnode#112 the build job exports and packages the standalone binaries on every
run, then uploads them as an artifact. Only the release job consumes that
artifact, and it runs on a version tag or a dry-run dispatch, so every PR and
branch push currently stores an archive nobody downloads.

Gate just the upload. Export and packaging stay ungated on purpose: they are
what proves the `standalone` stage still builds, and moving that check to
release time is exactly the trap of a gate that cannot fail until it matters.

The condition deliberately mirrors the release job's, including the
workflow_dispatch dry run. A bare `startsWith(github.ref, 'refs/tags/v')` would
make the dry-run rehearsal fail at download-artifact, which is the one path
that exists to prove the release sequence works without cutting a tag.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants