Build DD-Turnip weekly and hold scheduled builds as prereleases until promoted

Scheduled runs go back to Wednesdays with a minor bump and publish only a
prerelease here, which DroidDeck never sees. promote.yml publishes an approved
prerelease to Drivers-CI and marks it latest. A newer build with the same
version replaces an unpromoted prerelease.
This commit is contained in:
maxjivi05 committed 2026-10-24 15:21:26 -04:00
1 parent 6c3f859253
commit 93985202c7
6 files changed
+100 -15

No files matched your search

+45
View File
@@ -0,0 +1,45 @@
name: DD-Turnip promote
on:
workflow_dispatch:
inputs:
tag:
description: Prerelease to publish, e.g. DD-Turnip-v0.4.0
required: true
type: string
concurrency:
group: dd-turnip-release
cancel-in-progress: false
permissions:
contents: write
jobs:
promote:
runs-on: ubuntu-24.04
steps:
- name: Publish ${{ inputs.tag }}
env:
GH_TOKEN: ${{ github.token }}
CI_TOKEN: ${{ secrets.DRIVERS_CI_TOKEN }}
TAG: ${{ inputs.tag }}
run: |
set -euo pipefail
if [[ ! "$TAG" =~ ^DD-Turnip-v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "::error::$TAG is not a DD-Turnip release tag"
exit 1
fi
if [[ -z "$CI_TOKEN" ]]; then
echo "::error::DRIVERS_CI_TOKEN is not set, so $TAG cannot be published to Droid-Deck/Drivers-CI"
exit 1
fi
gh release view "$TAG" --repo "$GITHUB_REPOSITORY" --json name,body > release.json
jq -r .body release.json > notes.md
gh release download "$TAG" --repo "$GITHUB_REPOSITORY" --dir dist \
--pattern "$TAG.zip" --pattern "$TAG.zip.sha256" --pattern "$TAG-source.tar.xz"
(cd dist && sha256sum -c "$TAG.zip.sha256")
GH_TOKEN="$CI_TOKEN" gh release view "$TAG" --repo Droid-Deck/Drivers-CI >/dev/null 2>&1 \
|| GH_TOKEN="$CI_TOKEN" gh release create "$TAG" "dist/$TAG.zip" "dist/$TAG.zip.sha256" "dist/$TAG-source.tar.xz" \
--repo Droid-Deck/Drivers-CI --target main --title "$(jq -r .name release.json)" --notes-file notes.md --latest
gh release edit "$TAG" --repo "$GITHUB_REPOSITORY" --prerelease=false --latest
+23 -4
View File
@@ -2,13 +2,20 @@ name: DD-Turnip release
on:
schedule:
- cron: '0 12 * * *'
- cron: '0 12 * * 3'
workflow_dispatch:
inputs:
hotfix:
description: Hotfix (bump the patch version instead of the minor version)
type: boolean
default: false
prerelease:
description: Prerelease (stays off Drivers-CI until promoted with promote.yml)
type: boolean
default: false
env:
PRERELEASE: ${{ github.event_name == 'schedule' || inputs.prerelease }}
concurrency:
group: dd-turnip-release
@@ -36,7 +43,7 @@ jobs:
id: version
env:
GH_TOKEN: ${{ github.token }}
HOTFIX: ${{ github.event_name == 'schedule' || inputs.hotfix }}
HOTFIX: ${{ github.event_name == 'workflow_dispatch' && inputs.hotfix }}
run: |
set -euo pipefail
gh api --paginate --slurp "repos/$GITHUB_REPOSITORY/releases?per_page=100" > releases.json
@@ -46,7 +53,9 @@ jobs:
GH_TOKEN: ${{ github.token }}
TAG: ${{ steps.version.outputs.tag }}
run: |
if gh api "repos/$GITHUB_REPOSITORY/git/ref/tags/$TAG" --silent 2>/dev/null \
if [[ "$(gh release view "$TAG" --repo "$GITHUB_REPOSITORY" --json isPrerelease --jq .isPrerelease 2>/dev/null)" == true ]]; then
echo "$TAG is an unpromoted prerelease and will be replaced"
elif gh api "repos/$GITHUB_REPOSITORY/git/ref/tags/$TAG" --silent 2>/dev/null \
|| gh release view "$TAG" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
echo "::error::$TAG already exists"
exit 1
@@ -153,10 +162,20 @@ jobs:
TAG: ${{ needs.prepare.outputs.tag }}
VERSION: ${{ needs.prepare.outputs.version }}
run: |
set -euo pipefail
if [[ "$(gh release view "$TAG" --repo "$GITHUB_REPOSITORY" --json isPrerelease --jq .isPrerelease 2>/dev/null)" == true ]]; then
gh release delete "$TAG" --repo "$GITHUB_REPOSITORY" --cleanup-tag --yes
fi
if [[ "$PRERELEASE" == true ]]; then
flags=(--prerelease --latest=false)
else
flags=(--latest)
fi
gh release view "$TAG" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1 \
|| gh release create "$TAG" "dist/$TAG.zip" "dist/$TAG.zip.sha256" "dist/$TAG-source.tar.xz" --repo "$GITHUB_REPOSITORY" \
--target "$GITHUB_SHA" --title "DD-Turnip v$VERSION" --notes-file notes.md --latest
--target "$GITHUB_SHA" --title "DD-Turnip v$VERSION" --notes-file notes.md "${flags[@]}"
- name: Publish to Drivers-CI
if: env.PRERELEASE != 'true'
env:
GH_TOKEN: ${{ secrets.DRIVERS_CI_TOKEN }}
TAG: ${{ needs.prepare.outputs.tag }}
+14 -6
View File
@@ -84,8 +84,10 @@ Tags are `DD-Turnip-vX.Y.Z`. The next version comes from the highest published (
| Trigger | Rule | Examples |
|---|---|---|
| No release yet | `0.1.0` | → `0.1.0` |
| Manual run without Hotfix | minor + 1, patch reset; minor 9 rolls into the next major | `0.1.0` → `0.2.0`, `0.1.5` → `0.2.0`, `0.9.0` → `1.0.0`, `1.9.3` → `2.0.0` |
| Daily schedule, or manual run with Hotfix | patch + 1 | `0.1.0` → `0.1.1` → `0.1.2`, `0.9.0` → `0.9.1` |
| Weekly schedule, or manual run without Hotfix | minor + 1, patch reset; minor 9 rolls into the next major | `0.1.0` → `0.2.0`, `0.1.5` → `0.2.0`, `0.9.0` → `1.0.0`, `1.9.3` → `2.0.0` |
| Manual run with Hotfix | patch + 1 | `0.1.0` → `0.1.1` → `0.1.2`, `0.9.0` → `0.9.1` |
An unpromoted prerelease does not count, so the next build with the same version replaces it.
## Release notes
@@ -97,20 +99,26 @@ Tags are `DD-Turnip-vX.Y.Z`. The next version comes from the highest published (
## Workflows
- `release.yml` runs every day at 12:00 UTC and on manual dispatch (`Hotfix` checkbox). A scheduled run only
builds when Mesa main has Turnip, Vulkan runtime or gralloc commits since the last release, or this repository
changed (`scripts/turnip_changed.py`). When a scheduled run fails, usually because a patch no longer applies, it
opens an issue (or comments on the open one), and the next scheduled release closes it. It resolves the
- `release.yml` runs every Wednesday at 12:00 UTC and on manual dispatch (`Hotfix` and `Prerelease` checkboxes).
A scheduled run only builds when Mesa main has Turnip, Vulkan runtime or gralloc commits since the last release
or prerelease, or this repository changed (`scripts/turnip_changed.py`). When a scheduled run fails, usually
because a patch no longer applies, it opens an issue (or comments on the open one), and the next scheduled
build closes it. Scheduled runs and `Prerelease` runs publish a prerelease here only, which DroidDeck never
sees; `promote.yml` publishes an approved prerelease to Drivers-CI and marks it latest. It resolves the
version and the Mesa main commit, builds Android and Linux in parallel from that commit, packages and verifies
the bundle, and publishes the release here and to the public
[Droid-Deck/Drivers-CI](https://github.com/Droid-Deck/Drivers-CI), which carries only the release assets
(bundle, `.sha256`, source archive) and is where DroidDeck downloads drivers from. Publishing there needs the `DRIVERS_CI_TOKEN` secret:
a fine-grained token with Contents read and write on Drivers-CI.
- `promote.yml` runs on manual dispatch with the prerelease tag, copies its assets and notes to Drivers-CI and
marks it the latest release in both repositories.
- `check.yml` runs the version tests and applies the patch set to Mesa main on every push and pull request.
```sh
gh workflow run release.yml
gh workflow run release.yml -f hotfix=true
gh workflow run release.yml -f prerelease=true
gh workflow run promote.yml -f tag=DD-Turnip-v0.4.0
```
## Local build
+6 -2
View File
@@ -13,9 +13,13 @@ def parse(tag):
return tuple(map(int, match.groups())) if match else None
def newest_release(releases):
built = [r for r in releases if not r['draft'] and parse(r['tag_name'])]
return max(built, key=lambda r: parse(r['tag_name']), default=None)
def latest_release(releases):
published = [r for r in releases if not r['draft'] and not r['prerelease'] and parse(r['tag_name'])]
return max(published, key=lambda r: parse(r['tag_name']), default=None)
return newest_release([r for r in releases if not r['prerelease']])
def next_version(current, hotfix):
+2 -2
View File
@@ -6,7 +6,7 @@ import tempfile
from datetime import datetime, timedelta
from release_notes import TURNIP_PATHS, fetch_history, log, previous_mesa_commit
from release_version import latest_release
from release_version import newest_release
def turnip_commits(release, commit):
@@ -44,7 +44,7 @@ if __name__ == '__main__':
parser.add_argument('--recipe', required=True)
args = parser.parse_args()
with open(args.releases) as f:
release = latest_release([r for page in json.load(f) for r in page])
release = newest_release([r for page in json.load(f) for r in page])
build, reason = decide(release, args.mesa_commit, args.recipe)
print(f'changed={"true" if build else "false"}')
print(f'reason={reason}')
+10 -1
View File
@@ -4,7 +4,7 @@ from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent.parent / 'scripts'))
from release_version import latest_release, next_version, parse, version_string
from release_version import latest_release, newest_release, next_version, parse, version_string
def release(tag, draft=False, prerelease=False):
@@ -58,6 +58,15 @@ class ReleaseVersionTest(unittest.TestCase):
self.assertEqual(latest['tag_name'], 'DD-Turnip-v0.1.10')
self.assertIsNone(latest_release([release('DD-Turnip-v0.1.0', draft=True)]))
def test_newest_includes_prereleases_but_not_drafts(self):
releases = [
release('DD-Turnip-v0.3.0'),
release('DD-Turnip-v0.4.0', prerelease=True),
release('DD-Turnip-v0.5.0', draft=True),
]
self.assertEqual(newest_release(releases)['tag_name'], 'DD-Turnip-v0.4.0')
self.assertEqual(latest_release(releases)['tag_name'], 'DD-Turnip-v0.3.0')
if __name__ == '__main__':
unittest.main()