Files
voculinux/.github/workflows/snap-promote.yml
T
soubarnak ea7be5f111 feat(identity): rename user-visible identity to voculinux with one-time legacy import
The fork takes its own name everywhere a user can see it: binaries
(voculinux, voculinux-gui), desktop entry, autostart, tray, D-Bus
namespace (com.voculinux.Voculinux, no alias for the old name),
config/data/cache dirs, single-instance lock, IBus engine identity,
tray icons, resource prefixes, VOCULINUX_* environment names, and the
update-checker user agent. The internal Python module stays vocalinux
and the distribution metadata keeps the upstream URLs as provenance.

On first run a previous Vocalinux install's config.json, custom
dictionary, and portal restore token are copied once into the new
locations (new config always wins, no merge, no write-back); models
re-resolve through the pinned-checksum download path. An offline
naming-sweep test proves no old-name strings remain on user-visible
surfaces outside the allowlist.

Refs #18
2026-11-06 01:29:39 +05:30

128 lines
5.0 KiB
YAML

name: Promote snap to stable
# Issue #783, the "safer" option: `v*` tags keep auto-publishing the snap to
# edge + candidate in release.yml; latest/stable stays gated on candidate QA.
# After QA (install, tray, mic, model download, typing into a real app), run:
# gh workflow run snap-promote.yml -f tag=v0.18.0
#
# The candidate revision must carry the tag's version, so a typo'd tag or a
# stale candidate fails the run instead of promoting the wrong revision.
# The `snap-stable` environment is an optional second gate: add required
# reviewers to it in repo settings and each dispatch waits for an approval.
# Caller-supplied tag values stay in the environment, never in run: source.
on:
workflow_dispatch:
inputs:
tag:
description: "Release tag whose candidate snap to promote (e.g. v0.18.0)"
required: true
type: string
permissions:
contents: read
# Promotions serialize: a second dispatch queues instead of racing the first.
concurrency:
group: snap-promote-stable
cancel-in-progress: false
jobs:
promote:
name: Promote latest/candidate to latest/stable
runs-on: ubuntu-latest
permissions:
contents: read
environment:
name: snap-stable
steps:
- name: Require a version tag
env:
TAG: ${{ inputs.tag }}
run: |
set -euo pipefail
case "$TAG" in
v[0-9]*) ;;
*)
echo "refusing tag that is not v<digit>…: $TAG" >&2
exit 1
;;
esac
if printf '%s' "$TAG" | grep -q '[^A-Za-z0-9._-]'; then
echo "refusing tag with unexpected characters: $TAG" >&2
exit 1
fi
- name: Require Snap Store credentials
env:
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_STORE_CREDENTIALS }}
run: |
if [ -z "$SNAPCRAFT_STORE_CREDENTIALS" ]; then
echo "SNAPCRAFT_STORE_CREDENTIALS is unset; cannot promote the snap"
exit 1
fi
- name: Install snapcraft
run: sudo snap install snapcraft --classic
# `snapcraft status` prints the channel map grouped by track and arch.
# The candidate row is normally a continuation line (column 1 is the
# channel), but if candidate ever leads the latest track block it rides
# the track line itself — column 3 is the channel then — so match both.
- name: Resolve the candidate revision
id: candidate
env:
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_STORE_CREDENTIALS }}
TAG: ${{ inputs.tag }}
run: |
set -euo pipefail
VERSION="${TAG#v}"
/snap/bin/snapcraft status voculinux | tee /tmp/snap-status.txt
# POSIX: mawk has no \S — use a literal non-space class.
row=$(awk '/^[^ \t]/ { track = $1 }
track == "latest" && $1 == "candidate" { print $2, $3; exit }
track == "latest" && $3 == "candidate" { print $4, $5; exit }' \
/tmp/snap-status.txt)
read -r seen_version revision <<<"$row"
echo "latest/candidate holds version=${seen_version:-none} revision=${revision:-none}"
case "${revision:-}" in
''|*[!0-9]*)
echo "No promotable revision on latest/candidate (stale or under review?)" >&2
exit 1
;;
esac
if [ "$seen_version" != "$VERSION" ]; then
echo "candidate version '$seen_version' does not match tag version '$VERSION'" >&2
exit 1
fi
echo "revision=$revision" >> "$GITHUB_OUTPUT"
# Re-resolve right before releasing: if a newer release published a
# different candidate after the first check, stable would downgrade.
- name: Re-verify the candidate did not move
env:
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_STORE_CREDENTIALS }}
TAG: ${{ inputs.tag }}
REVISION: ${{ steps.candidate.outputs.revision }}
run: |
set -euo pipefail
VERSION="${TAG#v}"
row=$(awk '/^[^ \t]/ { track = $1 }
track == "latest" && $1 == "candidate" { print $2, $3; exit }
track == "latest" && $3 == "candidate" { print $4, $5; exit }' \
<(/snap/bin/snapcraft status voculinux))
read -r seen_version revision <<<"$row"
if [ "${revision:-}" != "$REVISION" ] || [ "$seen_version" != "$VERSION" ]; then
echo "latest/candidate moved on (now version=${seen_version:-none} revision=${revision:-none}); aborting instead of promoting the stale revision" >&2
exit 1
fi
- name: Release the resolved revision to latest/stable
env:
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_STORE_CREDENTIALS }}
REVISION: ${{ steps.candidate.outputs.revision }}
run: |
set -euo pipefail
/snap/bin/snapcraft release voculinux "$REVISION" latest/stable
/snap/bin/snapcraft status voculinux