ci: retire Cirrus + GitLab, consolidate on GitHub Actions (#2610)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
k9ert 2026-04-19 18:32:29 +02:00 committed by GitHub
parent 62ea02657b
commit fdd1cd8f3c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
37 changed files with 207 additions and 3415 deletions

View file

@ -6,13 +6,9 @@ This document addresses the build-system part. For the continuous-integration-pa
## pip-packages
```
# in the case of a release, the version needs to be adapted:
# sed -i "s/version=\".*/version=\"$CI_COMMIT_TAG\",/" setup.py
python3 setup.py sdist bdist_wheel
cryptoadvance.specter-vx.y.z-get-replaced-by-release-script.tar.gz
python3 -m build
```
This process is the same for all platforms. The result unfortunately is not stable in terms of identically sh256-hashes, though.
Produces an sdist + wheel under `dist/`. The release pipeline sets `SETUPTOOLS_SCM_PRETEND_VERSION` from the git tag; locally, setuptools-scm derives the version from your working tree. The result is not stable in terms of identical sha256-hashes across machines.
## Electron
The electron build is assuming a node-installation. So make sure you have `node` and `npm` available.
@ -20,7 +16,7 @@ The electron build is assuming a node-installation. So make sure you have `node`
The electron-app is built in a way that it's running the `specterd` (specter-demon) internally. It's not bundled with the electron-binary but downloaded with the first start (including sha256- and gpg-verification).
If someone does not want the download, he can manually choose a specterd-binary from the `preferences/Advanced` menu. Nevertheless the Electron-App is tied, at buildtime, to a specific specterd-binary via a sha256-version. This probably doesn't make so much sense if you build outside of a release but we need it anyway.
So let's cover the build of the specterd-binary first. Below is a manual description of the build-process. There are acripts which are doing this but they are partially optimized for the CI-system. Check the `pyinstaller/build-*` scripts for details.
So let's cover the build of the specterd-binary first. Below is a manual description of the build-process. The canonical CI build lives in `.github/workflows/release.yml` (`build-specterd-*` and `build-electron-*` jobs).
First set the virtualenv:
@ -31,11 +27,6 @@ source .buildenv/bin/activate
### specterd Linux and MacOS
Below doesn't seem to work properly, at least on MacOS, better use the build script. For MacOS, that would be:
```bash
./utils/build-osx.sh --version 0.0.0-pre1 specterd
```
```bash
cd pyinstaller
# prerequisites
@ -98,7 +89,7 @@ node ./set-version v1.3.1-custom ../dist/specterd
npm i
# We assume here that no Apple-developer-ID is used to sign the binary.
# Check `build-osx.sh` if you want to sign
# For signed+notarized builds, see .github/workflows/release.yml (build-electron-macos).
echo "`jq '.build.mac.identity=null' package.json`" > package.json
# finally build

View file

@ -0,0 +1,84 @@
# CI Migration Evidence — Cirrus → GitHub Actions
Evidence artifact per `docs/cirrus-replacement-spec.md` §Acceptance. Captures measured GHA behavior over the side-by-side period so that "did we actually hit SLO?" has a grep-able answer after GH Actions logs are GC'd.
## Snapshot
- **Measurement date:** 2026-04-19
- **PR #1 (`test.yml` added):** merged 2026-04-17 as commit `a24df2eb` (PR [#2606](https://github.com/cryptoadvance/specter-desktop/pull/2606))
- **Cirrus sunset deadline:** 2026-06-30 (~10 weeks remaining)
- **Side-by-side window so far:** ~2 days
## Gate status
Spec §Acceptance requires **all four** to hold before merging the cutover PR:
| # | Criterion | Status | Notes |
|---|----------------------------------------------------------|------------|-----------------------------------------------------------------------|
| 1 | 10 consecutive green master runs | **Not met**| 2 master runs observed, both green |
| 2 | ≥ 3 green PR runs incl. one frontend-touching | **Partial**| 6 green PR runs; none confirmed as frontend-touching yet |
| 3 | Zero new flakes over ≥ 50 total runs | **Not met**| 14 total runs; zero flakes detected; sample too small |
| 4 | Cypress p95 within Cirrus +20% | **Breach** | Cypress p95 **10m10s** vs. Cirrus +20% ceiling **7m14s** — see below |
**Merging PR #2 ahead of the nominal gate is a deliberate choice** driven by Cirrus's hard 2026-06-30 shutdown, preservation of revertability (PR #2 is a pure deletion of dead code + docs updates; revert is one click), and the empirical fact that no flakes have surfaced over the available sample. Gate criteria 1 and 3 will be satisfied by ordinary master-branch activity over the coming weeks; criterion 4 is acknowledged below as a known deviation, with a measurement protocol for re-evaluation.
## Measured wall-clock
n = 8 successful runs (2 master + 6 PR) between 2026-04-17 11:13 UTC and 2026-04-17 20:45 UTC.
| Job | n | median | p95 | min | max | Cirrus median | Cirrus +20% ceiling | Result |
|-----------------------|---|---------|---------|---------|---------|---------------|---------------------|--------------------|
| `test` | 8 | 3m53s | 4m14s | 3m43s | 4m14s | 4m47s | 5m44s | **within ceiling** |
| `cypress` | 8 | 9m42s | 10m10s | 9m28s | 10m10s | 6m02s | 7m14s | **BREACH (+47%)** |
| `extension-smoketest` | 8 | 1m57s | 2m09s | 1m44s | 2m09s | 2m10s | 2m36s | **within ceiling** |
Raw data pulled via `gh api repos/cryptoadvance/specter-desktop/actions/runs/<id>/jobs` for runs `24581485817`, `24585472647` (master), and `24580543016`, `24581562475`, `24582301901`, `24582337498`, `24585550944`, `24562219139` (PR).
Cirrus baselines cited from `docs/cirrus-replacement-spec.md` §SLOs (20-sample baseline captured 2026-04-12).
### Cypress breach — acknowledgement
GHA Cypress p95 is **10m10s**, vs. the spec's Cirrus +20% ceiling of **7m14s** (Cirrus p95 6m55s × 1.20). Root cause not yet investigated. Candidates per spec §Cypress measurement: `--shm-size` bump, spec sharding, or escalation to `ubuntu-22.04-large`.
**Decision:** accepted as a known deviation. Cypress wall-clock is still well under the 30-minute workflow timeout, and the alternative — holding the cutover until after Cirrus shutdown — would leave the project without PR gating. The breach is logged here rather than swept under the rug.
**Follow-up:** re-run the measurement protocol (5× on `ubuntu-22.04` free tier) once 10+ master runs accumulate. If p95 remains >Cirrus+20%, file an issue and walk the escalation ladder (shm → shard → paid runner).
## Flake signal
Over 14 total `test.yml` runs (8 success, 5 failure, 1 action_required):
- **Failures on `kn/cirrus-replacement-spec`** (4): iteration during PR #1 development. Each failure was followed by a targeted fix commit. Confirmed non-flaky by reading `git log` (`fix: cache symlink targets…`, `fix: bash shell for cypress container`, `fix: use VALIDSIG instead of GOODSIG`, `fix: use --status-fd`).
- **Failure on `kn/bump-bitcoind-test-v27.2`** (1): bitcoind version bump branch. Likely a real test failure from the version change, not a CI flake.
- **`action_required`** (1): fork PR (`copilot/fix-livereload-ui-delays`) pending maintainer approval to run workflows. Not a flake.
**Flake count: 0** over this window. Sample size too small (n=14) to assert the steady-state SLO of ≤1% rolling-30-day, but no red flags.
## Sample PR runs
| URL | Branch | Conclusion | Frontend-touching? |
|---------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------|------------|--------------------|
| https://github.com/cryptoadvance/specter-desktop/actions/runs/24585550944 | `dependabot/npm_and_yarn/pyinstaller/electron/multi-20d65b3440`| success | partial (electron deps) |
| https://github.com/cryptoadvance/specter-desktop/actions/runs/24582337498 | `dependabot/npm_and_yarn/pyinstaller/electron/multi-3ffb4d349a`| success | partial (electron deps) |
| https://github.com/cryptoadvance/specter-desktop/actions/runs/24581562475 | `dependabot/npm_and_yarn/multi-6f6dcfc8d5` | success | indirect |
| https://github.com/cryptoadvance/specter-desktop/actions/runs/24562219139 | `kn/cirrus-replacement-spec` | success | no |
Strict frontend-touching coverage (changes under `src/cryptoadvance/specter/static/` or `src/cryptoadvance/specter/templates/`) is **not yet confirmed** in the available sample. Criterion 2 will be rechecked at PR #2 merge time.
## Sign-off
| Field | Value |
|----------------------|------------------------------------------------------------|
| Evidence captured at | 2026-04-19 |
| Latest master commit | `62ea0265` (2026-04-17 20:33 UTC) |
| `test.yml` added at | `a24df2eb` (2026-04-17 18:50 UTC) |
| Author | @k9ert |
## Rollback contract
Per spec §Rollback, if post-cutover breakage emerges:
1. Revert the PR #2 merge commit → restores `.cirrus.yml` and `docker/cirrus-jammy/`.
2. Re-add the Cirrus required-check names to master branch protection.
3. Cirrus assumed operational through 2026-06-30.
After 2026-06-30, no Cirrus fallback exists — forward fix only. Keep the cutover ≥ 4 weeks ahead of that date (target merge date per spec: 2026-05-12).

View file

@ -1,111 +1,60 @@
# Introduction
Specter-Desktop is using GitLab, Cirrus and GitHub-Actions for continuous integration purposes but GitHub-actions only for Blackify so far. It might be more effort using more than one CI-approach but it makes us also more resilient.
GitLab and Cirrus have both advantages and disadvantages so ... let's use both!
GitLab:
* is completely open Source for server- and clients
* the gitlab-runner can run docker and is itself running on docker
* but does not support Pull-Requests
* needs to have bitcoind in a prepared docker-container which binds the build to that version
# Continuous Integration
Cirrus-CI:
* supports the PR-model
* quite easy to setup even though it's using docker
Specter-Desktop runs all CI on **GitHub Actions**. Cirrus CI and GitLab CI were retired in 2026-Q2 — see `docs/ci-migration-evidence.md` for the cutover evidence.
## Gitlab
## Workflows
Gitlab is a great CI/CD-platform and in the meantime it's quite easy to use it for GitHub-repositories.
https://docs.gitlab.com/ee/ci/ci_cd_for_external_repos/github_integration.html
The main file which specifies the jobs on GitLab is .gitlab-ci.yml
We're using a `gitlab-docker-runner` which means that all jobs are running in a container.
However at the same time we're using docker to spinup a bitcoind.
| Workflow | File | Trigger |
|--------------------------------|-------------------------------------------------|----------------------------------------------|
| Lint (black) | `.github/workflows/zblack.yml` | PR, push |
| Tests (pytest + Cypress + extension smoketest) | `.github/workflows/test.yml` | PR, push |
| Release | `.github/workflows/release.yml` | Tag push (`v*`) |
| Electron smoketest | `.github/workflows/electron-smoketest.yml` | PR and push to master on `pyinstaller/electron/**` |
| Extension compatibility | `.github/workflows/extension-compat.yml` | PR; push on `requirements.*` / `pyproject.toml`; `workflow_dispatch` |
| Specterd build smoke | `.github/workflows/test-specterd-build.yml` | PR |
| Docker image push | `.github/workflows/docker-push.yml` | Push to any branch |
| Docker image tag | `.github/workflows/docker-tag.yml` | Tag push (`v*`) |
| Docs table of contents | `.github/workflows/toc.yml` | Push |
The image is created manually (see /docker) and used for running the tests AND also for
spinning up bitcoind.
## Test workflow
For that reason we need to share the docker-socket from the host into the container and
create our own GitLab specific runner as described here:
https://docs.gitlab.com/ee/ci/docker/using_docker_build.html#use-docker-socket-binding
`test.yml` has three jobs, all on `ubuntu-22.04`:
Due to that setup there are some specifics which are mainly addressed in tests/conftest
start_bitcoind-function:
* adding -rpcallowip= (from a docker network) to bitcoind
* not use localhost but the docker-network-ip-address when talking to the bitcoind
- **`test`** — pytest with `--cov=cryptoadvance`. Runs in 45 min. Installs system deps inline; no custom image. Caches bitcoind/elementsd binaries via `actions/cache@v4` keyed on `runner.os × runner.arch × hash(pyproject.toml, tests/install_noded.sh, tests/bitcoin_SHA256SUMS, tests/elements_SHA256SUMS)`.
- **`cypress`** — runs `./utils/test-cypress.sh --debug run` inside `ghcr.io/cryptoadvance/specter-desktop/cypress-python-jammy@sha256:<digest>`. 30-minute timeout. `--shm-size=2g` to avoid Cypress OOMs on the default 64 MB `/dev/shm`. Shares the bitcoind/elements cache with `test`.
- **`extension-smoketest`** — byte-compatible port of the former Cirrus smoketest. 15 min. Smoke-tests `ext gen`, server boot, and log-line / curl assertion. Contract must stay stable — downstream extension developers depend on it.
## Travis-CI
All three jobs use `actions/checkout@v4` with `fetch-depth: 0` so `git describe` resolves annotated tags for `tests/test_util_version.py`.
We're no longer using travis-ci due to the abuse-detection-system going wild on us.
## Caching
## Cirrus-CI
`actions/cache@v4` with `save-always: true` on a key that includes `runner.arch` (prevents ARM/x86 cache poisoning). The key hashes the committed `tests/bitcoin_SHA256SUMS` and `tests/elements_SHA256SUMS` trust anchors — bumping a version in `pyproject.toml` rotates the cache via those files.
[Cirrus-CI](https://cirrus-ci.org) is used by Bitcoin-Core and HWI and is a quite good replacement for travis. We're using it only for PRs so far. The [../.cirrus.yml] file defines the build. We have two task, one for pytest and one for the [cypress-tests](./cypress-testing.md).
### Binary verification
## Releasing
`tests/install_noded.sh` GPG-verifies the upstream `SHA256SUMS.asc` against the Bitcoin Core and Elements release signing keys, and checks the tarball SHA256 against the committed trust anchors on every run (cold cache AND cache hit). A tampered cache entry fails closed on restore. See PR #2606 for the threat model.
### What gets released
## Cypress container
We're mostly releasing automatically. Currently the following artifacts are released:
* specterd (daemon) is a binary for kicking off the specter-desktop service on the command-line. We have binaries for windows, Linux and macOS
* We have an Electron-App which we're also releasing for Windows, Linux and MacOS. Unfortunately the macOS build is not yet automated
* We release a pip-package
* Usually some time after the release, the lncm is releasing [docker-images](https://hub.docker.com/r/lncm/specter-desktop). Very much appreciated, even though we can't guarantee for them, obviously.
`ghcr.io/cryptoadvance/specter-desktop/cypress-python-jammy` is pinned by digest (not tag) in `test.yml`. This makes Dockerfile edits visibly require a workflow bump. When editing `docker/cypress-python-jammy/Dockerfile`, rebuild and push to GHCR with a fresh tag, then update the digest pin.
### How we release
As we have a strict build-only-on-private-hardware build-policy, we're using GitLab private runners in order to build our releases. In order to test and develop the releasing automation, people can setup GitLab-projects which are syncing from their GitHub-forks. With such a setup it's possible to create test-releases and therefore test the whole procedure end-to-end.
## Release pipeline
The automation of that kicks in if someone creates a tag which is named like "vX.Y.Z". This is specified in the gitlab-ci.yml. The release-job will only be triggered in cases of tags. One step will also check that the tag follows the convention above.
The package upload will need a token. How to obtain the token is described in the packaging-tutorial. It's injected via GitLab-variables. ToDo: put the token on a trusted build-node.
See [`release-guide.md`](./release-guide.md). Pushing a tag matching `v[0-9]+.[0-9]+.[0-9]+[-*]?` triggers `release.yml`, which builds pip/specterd/Electron artifacts for Linux/Windows/macOS, signs `SHA256SUMS`, and creates a draft GitHub release. Docker images are built by `lncm/docker-specter-desktop` (triggered via `AARON_TRIGGER` secret).
### pyinstaller system-dependent binaries
The [pyinstaller directory](../pyinstaller) contains scripts to create the platform-specific binaries (plus electron) to use specter-desktop as a desktop-software. Some of them are created and uploaded to [GitHub-releases](https://github.com/cryptoadvance/specter-desktop/releases) via more or less special build-agents.
The [windows-build-agent](https://docs.gitlab.com/runner/install/windows.html) needs manual installation
of git, python and docker. Docker is used to build the innosetup-file.
As docker is available in windows only as a "desktop-edition", one need to also
log into the windows-machine to get docker started.
Clearly there is an opportunity to move all of the creation of the windows-binary to wine on docker,
similiar to the way the innosetup is running within docker.
## Flake policy
## CI/CD-dev-env setup
- Cypress: `retries: { runMode: 1, openMode: 0 }`. Specs retry-to-green emit a warning annotation.
- pytest: `--reruns 0` (fail fast). Flakes are debt, not a coping mechanism.
- Spec flagged flaky twice in 14 days gets `@skip(reason="flaky", issue="#NNNN")` with a 2-week SLA.
Here is a brief description on how to create a setup where the release-procedures can be tested:
* We assume you have a fork of cryptoadvance/specter-desktop. We also assume that your GitLab-user-handle is the exact same as on GitHub.
* Create a GitLab-account and then a mirroring project ([here](https://gitlab.com/projects/new#cicd_for_external_repo)) obviously with the exact same name: "specter-desktop"
* Activate the private runners and deactivate the public runners. Contact @k9ert for that.
* Create an account and an [API token](https://test.pypi.org/manage/account/) on there
* Create a token for GitHub in order to release to your GitHub-fork
* Configure both tokens on the GitLab-variables (GH_BIN_UPLOAD_PW and TWINE_PASSWORD)
* create a tag on your GitHub-fork
* watch the test-release unfolding, ready to hack
## Secrets
### GitLab-runner setup (Windows)
| Secret | Used by | Purpose |
|---------------------------|--------------------------|----------------------------------------------|
| `GITHUB_TOKEN` | (auto-provided) | Checkout, artifact upload, ghcr.io push |
| `GPG_PRIVATE_KEY` + `GPG_PASSPHRASE` | `release.yml` | Sign `SHA256SUMS` |
| `APPLE_*` (six) | `release.yml` macOS | Code signing + notarization (optional) |
| `AARON_TRIGGER` | `release.yml` | Trigger `lncm/docker-specter-desktop` build |
For Windows-releasing, we're using a windows GitLab-runner. Here is a short description on how to set one up.
#### Prerequisites
You need at least Windows Home 10 which is up-to-date. The most complex dependency is setting up docker.
Docker-Desktop needs a WSL2 which is a good idea to install on windows anyway. [Here](https://www.omgubuntu.co.uk/how-to-install-wsl2-on-windows-10) is a description on how to do that.
While installing, make sure you know the locations of where that stuff is installed. We'll later need to verify/adjust the PATH.
* Install Python, i took the [3.7.9 webinstaller](https://www.python.org/ftp/python/3.7.9/python-3.7.9-amd64-webinstall.exe)
* Install Git, e.g. [this](https://github.com/git-for-windows/git/releases/download/v2.29.2.windows.2/Git-2.29.2.2-64-bit.exe) (i had 2.28.2)
* Install [Docker-Desktop](https://desktop.docker.com/win/stable/Docker%20Desktop%20Installer.exe)
Now open and check the "Environment-variables" and check that the following lines are in there:
![](./images/continuous-integration_runner_windows_envvars.png)
#### Runner
The runner itself is easy to [setup](https://docs.gitlab.com/runner/install/windows.html). Follow the link or this very brief description:
* `mkdir \Gitlab-Runner`
* download [this binary](https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-windows-amd64.exe) in that folder and rename to gitlab-runner.exe
* Search for "powershell" in windows an open AS ADMINISTRATOR
* `cd \Gitlab-Runner`
* Copy the Registration-token from [here](https://gitlab.com/k9ert/specter-desktop/-/settings/ci_cd) (unfold runners, see specific runners)
* `./gitlab-runner.exe register`and paste the token (the instance-url is the default)
* give a reasonable description. Make sure to tag this runner with "tag". If that's not possible here, you can do it in the page mentioned above
* `.\gitlab-runner.exe install` will install the runner as system-service
* `.\gitlab-runner.exe start` will start it
Done
No GitLab secrets remain.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 448 KiB

View file

@ -1,160 +1,60 @@
# Release Guide
## Creating release notes
The release pipeline runs on GitHub Actions. Pushing a version tag to `upstream` triggers `.github/workflows/release.yml`, which builds every artifact, creates a draft GitHub release, and signs `SHA256SUMS` with the Specter Signer GPG key.
### Pre-requisites
## Prerequisites
- You need the correct upstream master. You should see
- `upstream` points at `git@github.com:cryptoadvance/specter-desktop.git` (`git remote -v` should show both fetch and push).
- You are on `master` with a clean workspace and `git pull upstream master` applied.
- Release-notes PR has already merged (see [Release notes](#release-notes) below).
## Cut a release
```bash
git remote -v | grep upstream
upstream git@github.com:cryptoadvance/specter-desktop.git (fetch)
upstream git@github.com:cryptoadvance/specter-desktop.git (push)
git tag v1.13.1
git push upstream v1.13.1
```
- You need a GitHub token:
If you don't have one, get one here https://github.com/settings/tokens and make sure to tick the boxes for repo and workflow as below:
That's it. The `Release` workflow on GitHub Actions takes it from here:
![](./images/release-guide/github-token.png)
- **`release-pip`** — builds the sdist/wheel and publishes to PyPI via trusted publishing.
- **`build-specterd-{linux,windows,macos}`** — builds the `specterd` binary on each platform (macOS arm64 on the free `macos-14` runner).
- **`build-electron-{linux,windows,macos}`** — builds the Electron apps using each platform's `specterd` artifact. Windows uses the public `electronuserland/builder:wine` image; macOS signs + notarizes if `APPLE_CERTIFICATE_BASE64` et al. are configured.
- **`create-release`** — collects all artifacts, generates `SHA256SUMS`, signs it with the GPG key from the `GPG_PRIVATE_KEY` secret, generates a release body (with auto-generated "What's Changed" via `gh api .../generate-notes`), and creates a **draft** GitHub release.
- **`trigger-docker`** — POSTs a repository-dispatch to `lncm/docker-specter-desktop` so Aaron's Docker build picks up the new tag (needs `AARON_TRIGGER` secret; skipped otherwise).
Using the new token, run
The release lands as a draft — review and publish it manually on GitHub.
### Required secrets
| Secret | Purpose |
|------------------------------------|--------------------------------------------------------------|
| `GPG_PRIVATE_KEY` | ASCII-armored private key for signing `SHA256SUMS` |
| `GPG_PASSPHRASE` | Passphrase for the above |
| `APPLE_CERTIFICATE_BASE64` | Developer ID cert for macOS signing (optional — unsigned fallback) |
| `APPLE_CERTIFICATE_PASSWORD` | p12 password |
| `APPLE_ID`, `APPLE_APP_SPECIFIC_PASSWORD`, `APPLE_TEAM_ID` | Apple notarization credentials |
| `APPLE_PROVISIONING_PROFILE_BASE64`| Optional provisioning profile |
| `AARON_TRIGGER` | PAT for triggering `lncm/docker-specter-desktop` |
PyPI publishing uses trusted publishing (OIDC) — no secret required.
## Release notes
Update `docs/release-notes.md` via a normal PR before tagging. Use the GitHub API or `gh` to pull "What's Changed" between the previous tag and `master`, prepend a heading, and open a PR. The `create-release` workflow job also appends auto-generated notes to the release body.
## GitHub pages download page
`./utils/generate_downloadpage.sh` still generates the `specter-static` website's download page off `utils/templates/`. Clone `specter-static` alongside `specter-desktop` and run:
```bash
export GH_TOKEN=YOURTOKEN
./utils/generate_downloadpage.sh
```
- You need Docker running
- Checkout the master branch and ensure a clean workspace.
The script installs the markdown prerequisite, regenerates the GH-page and download page, asks whether to replace/update the GitHub release page for the latest version, and offers to commit/push the static-site changes.
Now, you can run
## Troubleshooting
```bash
./utils/release.sh --release-notes
```
If something fails mid-pipeline, re-running individual jobs is safe — they `actions/download-artifact` from prior jobs and overwrite existing release assets via `softprops/action-gh-release`. If the draft release already has assets from a stale run, delete the draft and re-run `create-release`.
Or, if you want to directly set the new version:
```bash
./utils/release.sh --new-version v1.13.1 --release-notes
```
## Creating a new tag
Update your master branch after the release notes PR ([example](https://github.com/cryptoadvance/specter-desktop/commit/65ff6959d7fd85cba745e4d454b30031839f857f/)) has been merged and then run:
```bash
git tag v1.13.1 && git push upstream v1.13.1
```
if you have a proper setup of github- AND gitlab forks (and the remote `origin` on git pointing to your github fork), you can push that tag to origin and this is useful to test the procedures. See "CI/CD-dev-env setup" in [continuous-integration](./continuous-integration.md).
```bash
git tag v1.13.1 && git push origin v1.13.1
```
## GitLab - releasing stage
Creating a tag triggers the release process of the GitLab runners.
There exists a mirror of the GitHub repo on GitLab, but only when a tag is created on GitHub will the release part of the runners execute. You can check the status here:
https://gitlab.com/cryptoadvance/specter-desktop/-/pipelines
There are three stages:
![](./images/release-guide/overview-gitlab-pipline.png)
The first relevant stage is "releasing". Here, the Windows, Linux and pip release are created and uploaded to the Specter Desktop GitHub releases page. After this stage, the following artificats should be available:
- cryptoadvance.specter-1.13.1.tar.gz
- Specter-Setup-v1.13.1.exe
- specterd-v1.13.1-win64.zip
- specterd-v1.13.1-x86_64-linux-gnu.zip
- specter_desktop-v1.13.1-x86_64-linux-gnu.tar.gz
The three jobs in more detail:
- release_binary_windows: is creating a binary for specterd and for Windows (Windows runner)
- release_electron_linux_windows: Creates a specterd for Linux, an AppImage for Linux and an executable for Windows (Linux runner).
- release_pip: Is releasing a pypi package on [pypi](https://pypi.org/project/cryptoadvance.specter/) and creates a tarball of the pip package for the GitHub release page (Linux runner).
For details look at `.gitlab-ci.yml`
## MacOS
Ideally, directly after the tag is created, start with the MacOS release. As the binaries of x86/arm64 are not compatible with each other, we need to build on two MacOS architectures.This has to be done manually, for now. There is a script for this. Start with the build on x86:
### MacOS x64 build
```bash
./utils/build-osx.sh --version v2.0.5-pre4 specterd package upload
```
You can also test this procedure without messing the original project via changing the `orgName` to your `orgName` in `pyinstaller/electron/downloadloc.js`.
This will create three artifacts on github:
* specterd-v2.0.5-pre4-osx_x64.zip
* SHA256SUMS-macos_x64
* SHA256SUMS-macos_x64.asc
### MacOS arm64 build
The electron application will get built on the arm architecture. As it needs to store the sha256 hash in the electron-app, the make-hash target
will not only hash the specterd but also download the other specterd and hash it.
```bash
./utils/build-osx.sh --version v2.0.5-pre4 --appleid "Satoshi Nakamoto (appleid)" --mail "satoshi@gmx.com" specterd make-hash electron sign package upload
```
This will create four artifacts on github:
* Specter-v2.0.5-pre4.dmg
* specterd-v2.0.5-pre4-osx_arm64.zip
* SHA256SUMS-macos_arm64
* SHA256SUMS-macos_arm64.asc
## GitLab - post releasing
Back to GitLab, the final stage is "post releasing".
### release_signatures
In this job, the individual SHA256-hashes and signatures are combined into two final files:
- SHA256SUMS
- SHA256SUMS.asc
Everything, apart from the MacOS files, are pulled from the GitLab environment, the MacOS files from GitHub.
Don't forget to delete the four MacOS files (`SHA256SUMS-macos_arm64` and `SHA256SUMS-macos_arm64.asc` and the two corresponding `_x64` files) on the GitHub release page in the end.
This is difficult to automate as sometimes the manual steps has not succeeded while generating the SHASUM-files. As a result, those hashes are not included. So you might want to run this again. And you can, just delete the two generated files - `SHA256SUMS` and `SHA256SUMS.asc` and run the job again.
### release_docker
There are docker images created by the awesome [Chiang Mai LN dev](https://github.com/lncm/docker-specter-desktop). So the task of this job is to trigger their build-system which is done via `utils/trigger_docker_build.sh`. A prerequisite of this is a token in order to authenticate. That token is from Aaron, one of the maintainers of that repo, and can be found in the gitlab variables section of the CI/CD configuration.
### tag_specterext_dummy_repo
Sometimes there are changes on the plugin architecture. In order to create a plugin, it's quite important to know which version of the plugin system should be used. Because of that, we simply assume that the master of the [specterext-dummy](https://github.com/cryptoadvance/specterext-dummy) repo is compatible with the current master which was just tagged with the new version.
So this job will tag that repo with the same tag and the creation of a plugin will take the version into account.
## Trouble shooting
If the MacOS signatures are missing, it can happen that the following Exception will be raised:
```bash
File "/builds/cryptoadvance/specter-desktop/utils/github.py", line 295, in download_artifact
raise Exception(
Exception: Status-cod04 for url ... )
```
In any case, if the macOS binaries arrive on GitHub too late, you have to manually delete the already created `SHA256SUMS` and `SHA256SUMS.asc`, otherwise the upload to GitHub will fail if you rerun the release signatures job on GitLab - for details see ([this PR](https://github.com/cryptoadvance/specter-desktop/pull/689)). The green arrow in the screenshot is where you rerun the release signatures job on GitLab:
![](./images/release-guide/rerun-release-signatures.png)
## GitHub release page and download page
This is handled by the script `./utils/generate_downloadpage.sh`. As a prerequisite, you need to clone the `specter-static` repo which contains the specter website. Clone it on the same level than specter-desktop.
Running that script will:
- install the prerequisites (basically markdown, see pyproject.toml)
- generate the GH-page and the download-page based on the `utils/templates`.
- Asks whether it should replace/update/initialize the Github Release page for the latest version
- copies over the new download-pages and asks whether it should commit/push those
macOS builds are the most likely to fail due to Apple signing/notarization glitches. The workflow falls back to unsigned builds when `APPLE_CERTIFICATE_BASE64` is empty — useful for smoke-testing the pipeline on forks.