Skip to content

Activate AMF intra refresh (GDR) - fixing xbox moonlight artefacts #277

Activate AMF intra refresh (GDR) - fixing xbox moonlight artefacts

Activate AMF intra refresh (GDR) - fixing xbox moonlight artefacts #277

Workflow file for this run

---
name: CI
permissions: {}
on:
workflow_dispatch:
push:
branches:
- '**'
tags:
- '*'
pull_request:
branches:
- vibe
- main
- master
concurrency:
group: "${{ github.workflow }}-${{ github.ref }}"
cancel-in-progress: true
jobs:
release-candidate:
name: Release candidate
permissions:
contents: read
runs-on: ubuntu-latest
outputs:
release_commit: ${{ steps.release-candidate.outputs.release_commit }}
release_version: ${{ steps.release-candidate.outputs.release_version }}
should_release: ${{ steps.release-candidate.outputs.should_release }}
tag_name: ${{ steps.release-candidate.outputs.tag_name }}
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- name: Resolve release candidate
id: release-candidate
env:
EVENT_NAME: ${{ github.event_name }}
GH_TOKEN: ${{ secrets.GH_TOKEN || secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
python <<'PY'
import os
import re
import subprocess
import sys
from pathlib import Path
VERSION_RE = re.compile(r"^v?([0-9]+\.[0-9]+\.[0-9]+)([-.][0-9A-Za-z.-]+)?$")
REPO = os.environ["GITHUB_REPOSITORY"]
def run(*args, check=True):
return subprocess.run(args, check=check, text=True, capture_output=True).stdout.strip()
def output(**values):
with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as fh:
for key, value in values.items():
print(f"{key}={value}", file=fh)
def skip(reason):
print(f"::notice::{reason}")
output(should_release="false", tag_name="", release_version="", release_commit="")
sys.exit(0)
def version_key(tag):
match = VERSION_RE.match(tag)
if not match:
return None
major, minor, patch = (int(part) for part in match.group(1).split("."))
suffix = (match.group(2) or "").lstrip("-.").lower()
suffix_parts = re.split(r"[-.]", suffix) if suffix else []
suffix_num = next((int(part) for part in suffix_parts if part.isdigit()), 0)
if not suffix or "stable" in suffix_parts:
suffix_rank = 40
elif "rc" in suffix_parts:
suffix_rank = 30
elif "beta" in suffix_parts:
suffix_rank = 20
elif "alpha" in suffix_parts:
suffix_rank = 10
else:
suffix_rank = 5
return (major, minor, patch, suffix_rank, suffix_num, suffix)
def is_prerelease_key(key):
return key[3] < 40
def release_notes_for(tag, commit):
match = VERSION_RE.match(tag)
if not match:
return None
release_version = tag[1:] if tag.startswith("v") else tag
for candidate in (
Path("release_notes") / f"{release_version}.md",
Path("release_notes") / f"{tag}.md",
):
notes_path = candidate.as_posix()
if subprocess.run(
["git", "cat-file", "-e", f"{commit}:{notes_path}"],
text=True,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
).returncode == 0:
return notes_path
return None
def canonical_release_tag(tag):
return tag if tag.startswith("v") else f"v{tag}"
event_name = os.environ["EVENT_NAME"]
if event_name not in {"push", "workflow_dispatch"}:
skip("Release gate only applies to push and manual workflow_dispatch events.")
run("git", "fetch", "--force", "--tags")
release_tags = set(filter(None, run(
"gh", "api", "--paginate", f"repos/{REPO}/releases", "--jq", ".[].tag_name"
).splitlines()))
release_versions = [version_key(tag) for tag in release_tags]
release_versions = [key for key in release_versions if key is not None]
candidate_tags = run("git", "tag", "--list").splitlines()
valid_candidates = []
for tag in candidate_tags:
key = version_key(tag)
if key is None:
continue
release_tag = canonical_release_tag(tag)
if tag in release_tags or release_tag in release_tags:
print(f"Skipping {tag}: release already exists as {release_tag}.")
continue
comparable_releases = [
release_key for release_key in release_versions
if is_prerelease_key(release_key) == is_prerelease_key(key)
]
current_release_version = max(comparable_releases) if comparable_releases else None
if current_release_version is not None and key <= current_release_version:
print(f"Skipping {tag}: not newer than the current release.")
continue
release_commit = run("git", "rev-list", "-n", "1", tag)
if event_name == "push":
head_commit = run("git", "rev-parse", "HEAD")
if release_commit != head_commit:
print(f"Skipping {tag}: tag commit {release_commit} is not the pushed HEAD.")
continue
if subprocess.run(
["git", "merge-base", "--is-ancestor", release_commit, "HEAD"],
text=True,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
).returncode != 0:
print(f"Skipping {tag}: tag commit {release_commit} is not reachable from this run ref.")
continue
notes_file = release_notes_for(tag, release_commit)
if notes_file is None:
print(f"Skipping {tag}: no exact matching release_notes file in the tag commit.")
continue
valid_candidates.append((key, release_tag, notes_file, release_commit))
if not valid_candidates:
skip("No unreleased newer tag with exact matching release notes was found.")
_, tag_name, notes_file, release_commit = max(valid_candidates, key=lambda item: item[0])
release_version = tag_name[1:] if tag_name.startswith("v") else tag_name
print(f"Release candidate: {tag_name} ({release_commit}) using {notes_file}")
output(
should_release="true",
tag_name=tag_name,
release_version=release_version,
release_commit=release_commit,
)
PY
build-windows:
name: Windows
needs:
- release-candidate
if: github.event_name != 'push' || needs.release-candidate.outputs.should_release == 'true'
permissions:
actions: read
contents: read
uses: ./.github/workflows/ci-windows.yml
with:
release_commit: ${{ needs.release-candidate.outputs.release_commit || github.sha }}
release_version: ${{ needs.release-candidate.outputs.release_version || '0.0.0' }}
release_tag: ${{ needs.release-candidate.outputs.tag_name }}
symbol_product_name: Vibeshine
publish_symbols: ${{ needs.release-candidate.outputs.should_release == 'true' }}
symbol_release_draft: true
symbol_release_prefix: shine
require_signpath_signing: ${{ needs.release-candidate.outputs.should_release == 'true' }}
signpath_signing_policy_slug: ${{ needs.release-candidate.outputs.should_release == 'true' && 'release-signing' || 'test-signing' }}
# A release-signing request requires manual approval. Leave 15 minutes of
# the hosted runner's six-hour limit for job setup and artifact handling.
signpath_wait_for_completion_timeout_in_seconds: ${{ needs.release-candidate.outputs.should_release == 'true' && 20700 || 1800 }}
require_truehdr_runtime: ${{ needs.release-candidate.outputs.should_release == 'true' }}
secrets:
symbol_token: ${{ secrets.SYMBOL_TOKEN }}
signpath_api_token: ${{ secrets.SIGNPATH_API_TOKEN }}
truehdr_runtime_token: ${{ secrets.TRUEHDR_RUNTIME_TOKEN }}
release:
name: Release
if: needs.release-candidate.outputs.should_release == 'true'
needs:
- release-candidate
- build-windows
permissions:
actions: read
contents: write
issues: write
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: ${{ needs.release-candidate.outputs.release_commit }}
- name: Resolve release metadata
id: release-metadata
env:
TAG_NAME: ${{ needs.release-candidate.outputs.tag_name }}
run: |
set -euo pipefail
if [[ "${TAG_NAME}" =~ ^v?([0-9]+\.[0-9]+\.[0-9]+)([-.][0-9A-Za-z.-]+)?$ ]]; then
base_version="${BASH_REMATCH[1]}"
release_version="${TAG_NAME#v}"
else
echo "::error::Unsupported release tag '${TAG_NAME}'. Use a version tag like 1.15.4, v1.15.4, or 1.15.4-beta.1."
exit 1
fi
tag_lower="$(printf '%s' "${release_version}" | tr '[:upper:]' '[:lower:]')"
prerelease=false
channel=stable
if [[ "${tag_lower}" == *alpha* ]]; then
prerelease=true
channel=alpha
elif [[ "${tag_lower}" == *beta* ]]; then
prerelease=true
channel=beta
elif [[ "${tag_lower}" == *rc* ]]; then
prerelease=true
channel=rc
elif [[ "${tag_lower}" == *stable* ]]; then
prerelease=false
channel=stable
fi
if [[ "${prerelease}" == "true" ]]; then
make_latest=false
else
make_latest=true
fi
product_name="Vibeshine"
notes_file=""
for candidate in \
"release_notes/${release_version}.md" \
"release_notes/${TAG_NAME}.md"; do
if [[ -f "${candidate}" ]]; then
notes_file="${candidate}"
break
fi
done
if [[ -z "${notes_file}" ]]; then
echo "::error::Release notes file not found. Expected exact release notes at release_notes/${release_version}.md or release_notes/${TAG_NAME}.md"
exit 1
fi
release_body_file="${RUNNER_TEMP}/release-notes-${release_version}.md"
python .github/scripts/compose_release_notes.py \
--release-version "${release_version}" \
--notes-dir release_notes \
--product-name "${product_name}" \
--output "${release_body_file}"
echo "Using stable-line release notes: ${release_body_file}"
echo "base_version=${base_version}" >> "${GITHUB_OUTPUT}"
echo "channel=${channel}" >> "${GITHUB_OUTPUT}"
echo "make_latest=${make_latest}" >> "${GITHUB_OUTPUT}"
echo "notes_file=${release_body_file}" >> "${GITHUB_OUTPUT}"
echo "prerelease=${prerelease}" >> "${GITHUB_OUTPUT}"
echo "product_name=${product_name}" >> "${GITHUB_OUTPUT}"
echo "release_version=${release_version}" >> "${GITHUB_OUTPUT}"
- name: Download Windows artifacts
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
with:
name: build-Windows
path: artifacts
- name: Debug artifacts
run: ls -l artifacts
- name: Create or update GitHub release
id: create-release
env:
BASE_VERSION: ${{ steps.release-metadata.outputs.base_version }}
CHANNEL: ${{ steps.release-metadata.outputs.channel }}
GH_TOKEN: ${{ secrets.GH_TOKEN || secrets.GITHUB_TOKEN }}
MAKE_LATEST: ${{ steps.release-metadata.outputs.make_latest }}
NOTES_FILE: ${{ steps.release-metadata.outputs.notes_file }}
PRERELEASE: ${{ steps.release-metadata.outputs.prerelease }}
PRODUCT_NAME: ${{ steps.release-metadata.outputs.product_name }}
RELEASE_COMMIT: ${{ needs.release-candidate.outputs.release_commit }}
RELEASE_VERSION: ${{ steps.release-metadata.outputs.release_version }}
TAG_NAME: ${{ needs.release-candidate.outputs.tag_name }}
run: |
set -euo pipefail
release_title="v${RELEASE_VERSION}"
# Keep the installer release asset aligned with the full tag version.
# This preserves prerelease/patch-channel suffixes such as
# -alpha.1, -beta.2, or -stable.3, while plain stable tags fall back
# to just the numeric version (for example, v1.2.3).
versioned_setup="artifacts/${PRODUCT_NAME}Setup-v${RELEASE_VERSION}.exe"
mapfile -t setup_assets < <(find artifacts -maxdepth 1 -type f -name "${PRODUCT_NAME}Setup*.exe" | sort)
if (( ${#setup_assets[@]} != 1 )); then
echo "::error::Expected exactly one ${PRODUCT_NAME} setup artifact, found ${#setup_assets[@]}."
find artifacts -maxdepth 2 -type f -print >&2 || true
exit 1
fi
if [[ "${setup_assets[0]}" != "${versioned_setup}" ]]; then
mv -f "${setup_assets[0]}" "${versioned_setup}"
fi
release_payload="$(
jq -n \
--arg tag_name "${TAG_NAME}" \
--arg target_commitish "${RELEASE_COMMIT}" \
--arg name "${release_title}" \
--rawfile body "${NOTES_FILE}" \
--argjson draft false \
--argjson prerelease "${PRERELEASE}" \
--arg make_latest "${MAKE_LATEST}" \
'{
tag_name: $tag_name,
target_commitish: $target_commitish,
name: $name,
body: $body,
draft: $draft,
prerelease: $prerelease,
make_latest: $make_latest
}'
)"
release_id="$(
gh api --paginate "repos/${GITHUB_REPOSITORY}/releases" \
--jq ".[] | select(.tag_name == \"${TAG_NAME}\") | .id" |
head -n 1
)"
if [[ -n "${release_id}" ]]; then
release_json="$(
gh api \
--method PATCH \
"repos/${GITHUB_REPOSITORY}/releases/${release_id}" \
--input - <<< "${release_payload}"
)"
else
release_json="$(
gh api \
--method POST \
"repos/${GITHUB_REPOSITORY}/releases" \
--input - <<< "${release_payload}"
)"
fi
release_id="$(jq -r '.id // empty' <<< "${release_json}")"
upload_url="$(jq -r '.upload_url // "" | split("{")[0]' <<< "${release_json}")"
if [[ -z "${release_id}" || -z "${upload_url}" ]]; then
echo "::error::Failed to resolve release id/upload URL for ${TAG_NAME}."
exit 1
fi
release_url="$(jq -r '.html_url // empty' <<< "${release_json}")"
if [[ -z "${release_url}" ]]; then
echo "::error::Failed to resolve release URL for ${TAG_NAME}."
exit 1
fi
{
echo "release_id=${release_id}"
echo "release_name=${release_title}"
echo "release_url=${release_url}"
} >> "${GITHUB_OUTPUT}"
existing_asset_ids="$(
gh api "repos/${GITHUB_REPOSITORY}/releases/${release_id}/assets" \
--jq '.[].id'
)"
while IFS= read -r asset_id; do
[[ -z "${asset_id}" ]] && continue
gh api --method DELETE "repos/${GITHUB_REPOSITORY}/releases/assets/${asset_id}" >/dev/null
done <<< "${existing_asset_ids}"
for asset in artifacts/*; do
[[ -f "${asset}" ]] || continue
asset_name="$(basename "${asset}")"
encoded_asset_name="$(jq -rn --arg name "${asset_name}" '$name|@uri')"
gh api \
--method POST \
"${upload_url}?name=${encoded_asset_name}" \
-H "Content-Type: application/octet-stream" \
--input "${asset}" \
>/dev/null
done
- name: Close fixed issues for release
env:
GH_TOKEN: ${{ secrets.GH_TOKEN || secrets.GITHUB_TOKEN }}
RELEASE_ID: ${{ steps.create-release.outputs.release_id }}
RELEASE_NAME: ${{ steps.create-release.outputs.release_name }}
RELEASE_URL: ${{ steps.create-release.outputs.release_url }}
run: |
set -euo pipefail
if [[ -z "${RELEASE_ID}" || -z "${RELEASE_NAME}" || -z "${RELEASE_URL}" ]]; then
echo "::error::Release metadata outputs were not set."
exit 1
fi
label_name="fixed"
release_marker="<!-- fixed-release-follow-up:${RELEASE_ID} -->"
encoded_label="$(jq -rn --arg label "${label_name}" '$label|@uri')"
mapfile -t issue_numbers < <(
gh api --paginate "repos/${GITHUB_REPOSITORY}/issues?state=open&labels=${encoded_label}&per_page=100" \
--jq '.[] | select(.pull_request | not) | .number'
)
if (( ${#issue_numbers[@]} == 0 )); then
echo "No open issues with the '${label_name}' label to close."
exit 0
fi
for issue_number in "${issue_numbers[@]}"; do
comments_file="$(mktemp)"
gh api --paginate "repos/${GITHUB_REPOSITORY}/issues/${issue_number}/comments?per_page=100" \
--jq '.[].body' > "${comments_file}"
if ! grep -Fq "${release_marker}" "${comments_file}"; then
comment_body="${release_marker}"$'\n'"This issue has been fixed in the latest release, [${RELEASE_NAME}](${RELEASE_URL}). Closing this issue now that the release containing the fix is available."
gh api \
--method POST \
"repos/${GITHUB_REPOSITORY}/issues/${issue_number}/comments" \
-f "body=${comment_body}" \
>/dev/null
fi
rm -f "${comments_file}"
gh api \
--method PATCH \
"repos/${GITHUB_REPOSITORY}/issues/${issue_number}" \
-f state=closed \
-f state_reason=completed \
>/dev/null
echo "Closed fixed issue #${issue_number} for ${RELEASE_NAME}."
done