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
- 2. Open the changelog PR and tag a release candidate
- 3. Iterate on release candidates
- 4. Merge the changelog PR and apply the release tag
- 5. Create the GitHub release
- Stable branches
Throughout, export the version once so the commands below can be copied verbatim:
VERSION=v2.8CHANGELOG.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:
# 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 .bodyFormat 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.
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:
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:
meson setup build
QDL_HIL_BUILD=/path/to/build-images \
QDL_HIL_STORAGE=<emmc|ufs|nvme|...> \
meson test -C build --suite hil --print-errorlogsThe 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 for the full workflow.
Collect the testing results. If a regression is found, fix it on master and
cut the next candidate (-rc2, -rc3, ...):
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.
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.
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.)
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:
# 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/<artifact-name>/...
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:
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.
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.
Right after the normal release flow tags the release on master
(step 4), create the stable branch from the tag:
git fetch upstream
git branch "qdl-${VERSION#v}.y" "${VERSION}"
git push upstream "qdl-${VERSION#v}.y"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:
git checkout "qdl-${VERSION#v}.y"
git cherry-pick -x <sha>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.
When the branch has accumulated fixes worth shipping - or a security fix forces one:
- Update
CHANGELOG.mdon the stable branch with a section for the point release (for examplev2.8.1). - Tag and publish from the stable branch, following the same flow as a
normal release (steps 2-5) with
VERSION=v2.8.1and the stable branch taking the place ofmaster.