# Releasing QDL This document describes how a new QDL release is cut, from preparing the changelog to publishing the GitHub release with prebuilt artifacts. Releases are versioned `vMAJOR.MINOR` (for example `v2.8`). Release candidates append an `-rcN` suffix (`v2.8-rc1`, `v2.8-rc2`, ...). The process is, in short: - [1. Populate the changelog](#1-populate-the-changelog) - [2. Open the changelog PR and tag a release candidate](#2-open-the-changelog-pr-and-tag-a-release-candidate) - [3. Iterate on release candidates](#3-iterate-on-release-candidates) - [4. Merge the changelog PR and apply the release tag](#4-merge-the-changelog-pr-and-apply-the-release-tag) - [5. Create the GitHub release](#5-create-the-github-release) - [Stable branches](#stable-branches) Throughout, export the version once so the commands below can be copied verbatim: ```bash VERSION=v2.8 ``` ## 1. Populate the changelog `CHANGELOG.md` mirrors the GitHub releases: one section per version, listing the pull requests merged since the previous release. Add a new section at the top for the upcoming version. GitHub can produce the raw list of merged PRs for the range, which is the same content used in the existing entries: ```bash # Everything merged since the previous release: gh api repos/linux-msm/qdl/releases/generate-notes \ -f tag_name="${VERSION}" -f target_commitish=master \ -f previous_tag_name="$(git describe --tags --abbrev=0 master)" \ --jq .body ``` Format the output to match the existing entries (PR references as `#NNN` links, a `### What's Changed` and `### New Contributors` subsection, and a `**Full Changelog**` compare link), and prepend it to `CHANGELOG.md` under a new `## [vX.Y](...) - YYYY-MM-DD` heading. Once the changelog draft is ready, ask people to start testing the current `master` so issues are found before the tag is cut. ## 2. Open the changelog PR and tag a release candidate Open a pull request with the changelog update. With that PR up, tag the latest `master` as the first release candidate so testers have a stable reference point to build from: ```bash git fetch upstream git tag "${VERSION}-rc1" upstream/master git push upstream "${VERSION}-rc1" ``` Ask testers to exercise the hardware-in-the-loop (HIL) suite against real hardware. The suite is skipped by default and only runs when pointed at an attached EDL device: ```bash meson setup build QDL_HIL_BUILD=/path/to/build-images \ QDL_HIL_STORAGE= \ meson test -C build --suite hil --print-errorlogs ``` The release must be validated across all four supported host/driver combinations: - Windows + QUD driver: the official Qualcomm QDLoader 9008 driver (`qdl --backend=qud ...`). - Windows + WinUSB driver / libusb (`qdl --backend=usb ...`). - Linux. - macOS. In addition, validate VIP (Validated Image Programming) mode: generate the digest tables with `--create-digests`, sign them, and flash a board with `--vip-table-path` to confirm secure-boot flashing still works end to end. See the VIP section in [README.md](README.md) for the full workflow. ## 3. Iterate on release candidates Collect the testing results. If a regression is found, fix it on `master` and cut the next candidate (`-rc2`, `-rc3`, ...): ```bash git fetch upstream git tag "${VERSION}-rc2" upstream/master git push upstream "${VERSION}-rc2" ``` Repeat until a candidate passes all four configurations (and VIP validation) cleanly. That commit becomes the stable release. ## 4. Merge the changelog PR and apply the release tag Merge the changelog PR. Then tag the resulting `master` commit with the final, immutable release tag. Note on tag type: the history is mixed. `v2.4` is an annotated tag while `v2.5`, `v2.6` and `v2.7` are lightweight tags (that is what GitHub's "create release" UI produces). Prefer an annotated tag for releases: it records the tagger, date and a message, and is what `git describe` expects. ```bash git fetch upstream git tag -a "${VERSION}" -m "qdl ${VERSION}" upstream/master git push upstream "${VERSION}" ``` A tag is a ref, not a branch. `git push upstream "${VERSION}"` publishes the tag itself; it does not push to the `master` branch. Once pushed, treat the tag as immutable: never move or delete it. (If matching the recent lightweight-tag convention is preferred instead, drop the `-a`/`-m` flags: `git tag "${VERSION}" upstream/master`.) ## 5. Create the GitHub release The `Buildtest` workflow already builds and uploads per-platform binaries for every push. Reuse those artifacts for the release rather than rebuilding. Download the artifacts from the green `Buildtest` run for the tagged commit and bundle each platform into its own archive: ```bash # Find the successful Buildtest run that built the tagged commit. Filtering # with --commit happens server-side, so it is not limited to the most recent # runs (a plain `gh run list` only fetches the latest 20). SHA=$(git rev-parse "${VERSION}^{commit}") RUN_ID=$(gh run list --workflow build.yml --commit "${SHA}" --status success \ --json databaseId --jq '.[0].databaseId') # Pull every platform artifact into dist//... rm -rf dist && gh run download "${RUN_ID}" -D dist # Zip each platform directory into a single release asset ( cd dist && for d in */; do name="${d%/}" zip -r "${name}-${VERSION}.zip" "${d}" done ) ``` Extract this release's notes straight from `CHANGELOG.md` (the block between this version's heading and the next `## [` heading) and create the release, attaching the zipped artifacts: ```bash NOTES=$(awk -v v="${VERSION}" ' $0 ~ ("^## \\[" v "\\]") { found=1; next } /^## \[/ && found { exit } found { print } ' CHANGELOG.md | sed '1{/^$/d}') echo "Release notes preview:" echo "---" echo "${NOTES}" echo "---" read -r -p "Create GitHub release ${VERSION}? [y/N] " reply [ "${reply}" = "y" ] || { echo "GitHub release skipped"; exit 0; } gh release create "${VERSION}" dist/*.zip \ --title "${VERSION}" \ --notes "${NOTES}" echo "GitHub release created: $(gh release view "${VERSION}" --json url -q .url)" ``` The release name matches the existing convention (the tag itself, for example `v2.8`). After publishing, sanity-check the release page: confirm the notes rendered correctly and that every platform archive is attached. ## Stable branches After a release, critical fixes reach users through kernel-style stable branches named `qdl-X.Y.y` (for `v2.8`: `qdl-2.8.y`). A point release (`v2.8.1`, `v2.8.2`, ...) is then cut from the stable branch, so urgent fixes never have to wait for - or ship - whatever is in flight on `master`. ### Cut the branch immediately after the release Right after the normal release flow tags the release on `master` (step 4), create the stable branch from the tag: ```bash git fetch upstream git branch "qdl-${VERSION#v}.y" "${VERSION}" git push upstream "qdl-${VERSION#v}.y" ``` ### Maintain the branch (backports) When a bug affecting the release gets fixed, the fix lands on `master` first, through the normal PR flow. Then backport it, with `-x` so the commit message records which `master` commit it was cherry-picked from: ```bash git checkout "qdl-${VERSION#v}.y" git cherry-pick -x ``` Open a pull request targeting the stable branch. CI runs on it unchanged, since the workflows trigger on any pull request regardless of its base branch. ### Cut a point release when warranted When the branch has accumulated fixes worth shipping - or a security fix forces one: - Update `CHANGELOG.md` on the stable branch with a section for the point release (for example `v2.8.1`). - Tag and publish from the stable branch, following the same flow as a normal release (steps 2-5) with `VERSION=v2.8.1` and the stable branch taking the place of `master`.