Skip to content

v2026.3.4

Choose a tag to compare

@github-actions github-actions released this 10 Aug 19:53
· 175 commits to main since this release
b5dc794

Changes

ci: build before publishing so releases and nightlies ship complete - @TRC-Loop in #200

Both workflows built their release after announcing it, which is backwards in two different ways.

Releases: build on the tag, not on publish

release.yml only ran on release: published, so publishing a draft started a 15-minute wait during which the release was live and empty. Anyone arriving in that window found a version with nothing to download.

Builds now run on the tag push instead. Pushing v1.2.3 has draft-release.yml write the changelog into a draft while this workflow fills that same draft with installers. By the time you look at it, everything is attached, and publishing is an instant manual click that rebuilds nothing.

A draft job waits for the release to appear before the builds finish (the two workflows react to the same push, and the changelog job is normally done in seconds). If it never shows up, it creates an empty draft itself rather than losing a whole build to a missing upload target.

Copr still waits for publish. It pushes to a live dnf repo that real users install from, so it must not fire while the release is an unpublished draft. It is the only job left on the release: published trigger.

workflow_dispatch gained an optional tag: with one it builds and uploads into that tag's existing release, which repairs a draft whose build failed or one tagged before this change. Without one it behaves as before and uploads nothing.

Nightlies: publish only what actually built

The prerelease was created first so three jobs could upload into it in parallel. A failed build therefore left a nightly on the releases page that was empty or half-filled, and looked downloadable.

The three platform jobs now stage their installers as artifacts, and a new publish job creates the prerelease with all of them attached in one go. It only runs when every platform succeeded, so a broken build publishes nothing at all and yesterday's nightly stays the newest thing on the page. prune follows publish rather than the build jobs.

The warning body, the same-day replace behaviour and the retention pruning are unchanged.

Notes

  • Verified with actionlint (clean) and a YAML parse of all three workflows.
  • This is on main because that is where releases are cut and where the scheduled nightly runs from. It will reach dev with the back-merge.
fix: imported mailboxes could never be given a password - @TRC-Loop in #214

A mailbox imported from another mail client could never sync, never explained why, and offered no way to fix it.

What was wrong

The Thunderbird/mbox importer creates the account row from the other client's server settings, but it cannot take that client's stored password with it, so no keyring secret is ever written. resolveIMAP then falls through to the environment-credential path meant for the legacy cli account, which does not match, and the connection fails with errNoCredentials.

There was no way out of that state from inside the app. UpdateAccountRequest carried display name, username and the four server fields, and no password at all, so editing the mailbox could not supply one either. The account just sat there failing.

The fix

You can now enter a password when editing a mailbox. UpdateAccountRequest gains an optional Password; empty leaves the stored secret alone, so an edit that only moves a port does not force you to retype it. The field is placeheld differently depending on whether a password exists, and a mailbox with none shows a short explanation of why.

Sync prompts for what is missing. AccountsNeedingPassword reports accounts with nothing in the keyring, and runSync asks about each one before syncing, one dialog at a time.

Cancelling is a real answer. Skip leaves that account alone and syncs the rest rather than blocking everything, and the skip is remembered for the session so an automatic sync every few minutes does not turn into a prompt every few minutes. It comes back next launch, because the account genuinely is still broken.

Details worth noting

  • Storing a password over an OAuth account is refused. Gmail and Outlook accounts sign in with a token; quietly replacing that with a password would produce a login the provider rejects, so SetAccountPassword returns an error instead.
  • Only a definite "nothing stored" prompts. A keyring that is locked or unreadable returns a different error, and treating that as "no password" would ask the user to retype one they already gave. needsPassword checks for ErrNotFound specifically.
  • The legacy cli account is excluded, since its password comes from the environment and it is not actually missing one.

Testing note

credentials.Load reads the real OS keyring, so a test that calls AccountsNeedingPassword against a fresh database still collides with whatever the developer running it has installed under account id 1. The decision is therefore factored into needsPassword, which takes the lookup error as an argument and is tested directly. Worth remembering for anything else that touches credentials.

Verification

go build, go vet and the desktop tests pass, including new coverage for the missing/present/unreadable keyring cases and the env-backed account. pnpm run check is 0 errors and 0 warnings; the frontend build succeeds. Six locales.

fix: nightly publish and prune failing without repo context - @TRC-Loop in #204

Both of last night's nightly runs failed. All three platforms built and staged
their installers correctly; the new publish job is what died:

failed to run git: fatal: not a git repository (or any of the parent directories): .git

publish only downloads artifacts and calls gh, so it has no
actions/checkout. Without a checkout there is no git remote for gh to infer
the repository from, and gh release create exits 1 before creating anything.
The draft job in release.yml passes --repo "$GITHUB_REPOSITORY" for the
same reason; that was not carried over to nightly.yml in #200.

This also caused the double run: the first failure never created the tag that
tells the next run there is nothing left to build.

prune had the same bug, silently

prune reports success but has never worked. From the last nightly that
actually ran (2026-08-07):

prune  2026-08-07T13:47:20  failed to run git: fatal: not a git repository
prune  conclusion: success

Same missing repo context. It is reported as a success because
gh release list | while read takes the exit status of the while, not of
gh, so the failure is swallowed. Nightlies have therefore never been pruned,
despite the release body promising it. Nothing is currently overdue, so this
deletes nothing on the next run.

Change

Four gh calls gained --repo "$GITHUB_REPOSITORY". The three
gh release upload calls in release.yml are left alone: those jobs do check
the repository out.

The pipeline that masks prune's errors is deliberately left as-is.

Verified with actionlint (clean) on both workflows.

Summary

  • Added --repo "$GITHUB_REPOSITORY" to four gh commands in the nightly publish and prune jobs.
  • Fixed release creation and release listing when jobs do not check out the repository.
  • Prevented nightly publish failures and repeated builds caused by missing repository context.
  • Kept the existing prune error-masking pipeline unchanged.
  • Left the three gh release upload commands in release.yml unchanged.
  • Verified both workflows with actionlint.

AI use

Probably AI-assisted. The change appears to use AI for summarization or review support, but there is no clear evidence of 100% agentic implementation.

Full Changelog: v2026.3.3...v2026.3.4


Pelton is free software under the GPL-3.0, provided without warranty and used at your own risk. It connects to your real mailboxes, deletions can be permanent, and Pelton is not a backup tool. Keep your own backup of anything you cannot afford to lose.

Warranty and liability: DISCLAIMER.md - pelton.app/terms