mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-10-02 16:44:33 -04:00
ci(release): open the next version line and clean up after production (#7381)
This commit is contained in:
1 parent
b19f0eab95
commit
b696b1908e
7 files changed
+257
-20
No files matched your search
@@ -13,7 +13,7 @@ name: Docs Release
|
||||
# cycle would cost far more than it refreshes.
|
||||
#
|
||||
# These per-tag prerelease directories accumulate during a version cycle and are
|
||||
# reaped by post-release-cleanup.yml once the production vX.Y.Z tag ships.
|
||||
# reaped by post-release-cleanup.yml, which a production publish dispatches.
|
||||
#
|
||||
# The /main/ snapshot is owned by docs-deploy.yml and is left untouched here.
|
||||
#
|
||||
@@ -43,6 +43,11 @@ jobs:
|
||||
if: github.repository == 'meshtastic/Meshtastic-Android'
|
||||
runs-on: ubuntu-26.04
|
||||
timeout-minutes: 45
|
||||
# actions: write is only for the cleanup dispatch; job permissions replace the
|
||||
# workflow block, so contents: write is restated.
|
||||
permissions:
|
||||
contents: write
|
||||
actions: write
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
@@ -148,3 +153,12 @@ jobs:
|
||||
|
||||
- name: Publish to gh-pages
|
||||
run: scripts/docs/publish-to-gh-pages.sh build/pages_staging ${{ steps.stage.outputs.channels }}
|
||||
|
||||
# The cleanup refuses to reap until /vX.Y.Z/ is on gh-pages, which the push above
|
||||
# just made true. A dispatch is exempt from GITHUB_TOKEN's event suppression.
|
||||
- name: Dispatch post-release cleanup
|
||||
if: steps.version.outputs.is_production == 'true'
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
BASE_VERSION: ${{ steps.version.outputs.docs_version }}
|
||||
run: gh workflow run post-release-cleanup.yml --ref main -f "base_version=$BASE_VERSION" -f confirm_deletion=true
|
||||
@@ -1,5 +1,7 @@
|
||||
name: Post-Release Cleanup
|
||||
|
||||
# docs-release.yml dispatches this with confirm_deletion=true once a production tag's
|
||||
# /vX.Y.Z/ is on gh-pages. A manual dispatch is the retry path and defaults to a dry run.
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
@@ -37,6 +39,18 @@ jobs:
|
||||
env:
|
||||
BASE_VERSION: ${{ github.event.inputs.base_version }}
|
||||
CONFIRM_DELETION: ${{ github.event.inputs.confirm_deletion }}
|
||||
# Keeps the vX.Y.Z-* names on stdin whose X.Y.Z is at or below BASE_VERSION. Anything
|
||||
# above it belongs to a later cycle, whose draft release promote.yml still needs.
|
||||
AT_OR_BELOW: |
|
||||
{
|
||||
v = $0; sub(/^v/, "", v); sub(/-.*/, "", v)
|
||||
split(v, a, "."); split(base, b, ".")
|
||||
for (i = 1; i <= 3; i++) {
|
||||
if (a[i] + 0 < b[i] + 0) { print; next }
|
||||
if (a[i] + 0 > b[i] + 0) next
|
||||
}
|
||||
print
|
||||
}
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
@@ -65,12 +79,12 @@ jobs:
|
||||
# v2.7.14-internal.N draft built while working toward 2.8.0). Scoping this
|
||||
# sweep to "v${BASE_VERSION}-*" misses exactly those, leaving stale drafts
|
||||
# behind forever. Once base_version has shipped as a stable release, every
|
||||
# numbered internal/open/closed pre-release — regardless of which version
|
||||
# it was tagged under — is superseded, so match on the pre-release SHAPE
|
||||
# instead of a version prefix.
|
||||
# numbered internal/open/closed pre-release at or below it is superseded,
|
||||
# so match on the pre-release SHAPE capped by AT_OR_BELOW instead of a
|
||||
# version prefix.
|
||||
TAG_PATTERN='^v[0-9]+\.[0-9]+\.[0-9]+-(internal|open|closed)\.[0-9]+$'
|
||||
echo "Searching for pre-releases matching pattern '$TAG_PATTERN'."
|
||||
RELEASES_TO_DELETE=$(gh release list --json tagName,isPrerelease,isDraft --limit 1000 | jq -r --arg pattern "$TAG_PATTERN" '.[] | select((.isPrerelease == true or .isDraft == true) and .tagName != null and (.tagName | test($pattern))) | .tagName')
|
||||
echo "Searching for pre-releases matching pattern '$TAG_PATTERN' at or below $BASE_VERSION."
|
||||
RELEASES_TO_DELETE=$(gh release list --json tagName,isPrerelease,isDraft --limit 1000 | jq -r --arg pattern "$TAG_PATTERN" '.[] | select((.isPrerelease == true or .isDraft == true) and .tagName != null and (.tagName | test($pattern))) | .tagName' | awk -v base="$BASE_VERSION" "$AT_OR_BELOW")
|
||||
|
||||
if [ -z "$RELEASES_TO_DELETE" ]; then
|
||||
echo "No stale internal/open/closed pre-releases found."
|
||||
@@ -121,13 +135,14 @@ jobs:
|
||||
# dev cycle, including before the version-bump commit lands, so some may
|
||||
# still be named after the PRIOR release (e.g. v2.7.14-open.3 built while
|
||||
# working toward 2.8.0). Once /v${BASE_VERSION}/ is confirmed published
|
||||
# above, every numbered open/closed snapshot is superseded regardless of
|
||||
# which version it was tagged under — so match the snapshot-dir SHAPE
|
||||
# instead of a version prefix.
|
||||
# above, every numbered open/closed snapshot at or below it is superseded,
|
||||
# so match the snapshot-dir SHAPE capped by AT_OR_BELOW instead of a
|
||||
# version prefix.
|
||||
mapfile -t stale < <(
|
||||
find "$work" -maxdepth 1 -mindepth 1 -type d \
|
||||
-regextype posix-extended \
|
||||
-regex ".*/v[0-9]+\.[0-9]+\.[0-9]+-(open|closed)\.[0-9]+" -printf '%f\n' | sort
|
||||
-regex ".*/v[0-9]+\.[0-9]+\.[0-9]+-(open|closed)\.[0-9]+" -printf '%f\n' \
|
||||
| awk -v base="$BASE_VERSION" "$AT_OR_BELOW" | sort
|
||||
)
|
||||
|
||||
if [ ${#stale[@]} -eq 0 ]; then
|
||||
@@ -169,8 +184,8 @@ jobs:
|
||||
run: |
|
||||
set -euo pipefail
|
||||
# Same rationale as the release-cleanup step above: match the
|
||||
# internal/open/closed pre-release tag SHAPE across all versions, not just
|
||||
# tags prefixed with this dispatch's base_version.
|
||||
# internal/open/closed pre-release tag SHAPE at or below base_version,
|
||||
# not just tags prefixed with it.
|
||||
TAG_PATTERN='^v[0-9]+\.[0-9]+\.[0-9]+-(internal|open|closed)\.[0-9]+$'
|
||||
echo "Searching for any remaining remote pre-release tags matching pattern '$TAG_PATTERN'."
|
||||
|
||||
@@ -181,7 +196,7 @@ jobs:
|
||||
REMOTE_TAGS=$(git ls-remote --tags origin "refs/tags/v*" | awk '{print $2}' | sed 's|refs/tags/||')
|
||||
|
||||
# Some tags may have been deleted already by the previous 'release delete' step.
|
||||
TAGS_TO_DELETE=$(grep -E "$TAG_PATTERN" <<<"$REMOTE_TAGS" || true)
|
||||
TAGS_TO_DELETE=$(grep -E "$TAG_PATTERN" <<<"$REMOTE_TAGS" | awk -v base="$BASE_VERSION" "$AT_OR_BELOW" || true)
|
||||
|
||||
if [ -z "$TAGS_TO_DELETE" ]; then
|
||||
echo "No dangling pre-release tags found."
|
||||
|
||||
@@ -357,6 +357,16 @@ jobs:
|
||||
TAG: ${{ inputs.final_tag }}
|
||||
run: gh workflow run msstore-publish.yml --ref main -f "tag=$TAG"
|
||||
|
||||
# Same suppression again: version-bump.yml opens the next patch line on main.
|
||||
- name: Dispatch version bump
|
||||
id: bump
|
||||
if: ${{ inputs.channel == 'production' }}
|
||||
continue-on-error: true
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
TAG: ${{ inputs.final_tag }}
|
||||
run: gh workflow run version-bump.yml --ref main -f "tag=$TAG"
|
||||
|
||||
# docs-release.yml's tag trigger never fires either: the release edit
|
||||
# above creates the tag with GITHUB_TOKEN. Run it on the tag ref, which
|
||||
# publishes /vX.Y.Z/ (plus the root and /api/ for production) or the
|
||||
@@ -543,6 +553,7 @@ jobs:
|
||||
DOCS: ${{ steps.docs.outcome }}
|
||||
WINGET: ${{ steps.winget.outcome }}
|
||||
MSSTORE: ${{ steps.msstore.outcome }}
|
||||
BUMP: ${{ steps.bump.outcome }}
|
||||
STAMP: ${{ steps.stamp.outcome }}
|
||||
STAMP_PR: ${{ steps.stamp.outputs.pr_url }}
|
||||
run: |
|
||||
@@ -581,11 +592,13 @@ jobs:
|
||||
row "CHANGELOG.md stamp" "$STAMP ${STAMP_PR:+- $STAMP_PR}"
|
||||
row "winget dispatched" "$WINGET"
|
||||
row "Microsoft Store dispatched" "$MSSTORE"
|
||||
row "Version bump dispatched" "$BUMP"
|
||||
row "Post-Release Cleanup" "dispatched by Docs Release once /${TAG}/ is published"
|
||||
echo
|
||||
echo "Still by hand:"
|
||||
echo "- Play Console: the production rollout is staged; complete it there."
|
||||
echo "- Flathub: bump flathub/org.meshtastic.MeshtasticDesktop (tag, commit, gradle zip and sha256, flatpak-sources.json)."
|
||||
echo "- Post-Release Cleanup: dispatch with confirm_deletion=true once Docs Release has published /${TAG}/."
|
||||
echo "- Release notes: replace the placeholder <description> the version bump PR wrote for the next line."
|
||||
fi
|
||||
} >> "$GITHUB_STEP_SUMMARY"
|
||||
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
name: Bump Version Name
|
||||
|
||||
# Opens the next patch line once a version ships to production, through a PR that
|
||||
# merges itself: VERSION_NAME_BASE, its AppStream <release> entry and the Play
|
||||
# what's-new, all written by scripts/bump-version-name.py.
|
||||
#
|
||||
# promote.yml flips the release to production with GITHUB_TOKEN, whose events start no
|
||||
# workflows, so it dispatches this one explicitly, as it does winget-publish.yml. The
|
||||
# release trigger covers a release published by hand; workflow_dispatch is the retry path.
|
||||
on:
|
||||
release:
|
||||
types: [released]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: 'Production release tag that shipped (e.g., v2.8.2)'
|
||||
required: true
|
||||
type: string
|
||||
|
||||
# The PR is opened and queued with CROWDIN_GITHUB_TOKEN, as scheduled-updates.yml does:
|
||||
# GITHUB_TOKEN may not enable auto-merge on protected main, and its PRs run no checks.
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
|
||||
# A release event overlapping a dispatch would open two PRs for the same version.
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
bump:
|
||||
if: ${{ github.repository == 'meshtastic/Meshtastic-Android' && !github.event.release.prerelease && !github.event.release.draft }}
|
||||
runs-on: ubuntu-26.04-arm
|
||||
timeout-minutes: 10
|
||||
env:
|
||||
TAG: ${{ inputs.tag || github.event.release.tag_name }}
|
||||
steps:
|
||||
# A release event checks out the tag by default; the bump branches from main.
|
||||
- name: Checkout main
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
ref: main
|
||||
|
||||
- name: Resolve next version
|
||||
id: next
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if [[ ! "$TAG" =~ ^v([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then
|
||||
echo "::error::'$TAG' is not a production tag (vX.Y.Z)."
|
||||
exit 1
|
||||
fi
|
||||
SHIPPED="${BASH_REMATCH[1]}.${BASH_REMATCH[2]}.${BASH_REMATCH[3]}"
|
||||
NEXT="${BASH_REMATCH[1]}.${BASH_REMATCH[2]}.$((BASH_REMATCH[3] + 1))"
|
||||
BRANCH="automation/version-name-${NEXT}"
|
||||
CURRENT=$(sed -n 's/^VERSION_NAME_BASE=//p' config.properties)
|
||||
|
||||
# A hand bump that already landed (a minor line, say) wins over the patch default.
|
||||
if [[ "$CURRENT" != "$SHIPPED" && "$(printf '%s\n%s\n' "$CURRENT" "$SHIPPED" | sort -V | tail -1)" == "$CURRENT" ]]; then
|
||||
echo "::notice::main is already on $CURRENT, past $SHIPPED; nothing to bump."
|
||||
echo "skip=true" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
OPEN=$(gh pr list --state open --limit 200 --json number,title,headRefName \
|
||||
| jq -r --arg b "$BRANCH" --arg n "$NEXT" \
|
||||
'.[] | select(.headRefName != $b and (.title | test("VERSION_NAME_BASE to " + ($n | gsub("[.]"; "[.]")) + "([^0-9.]|$)"))) | .number')
|
||||
if [[ -n "$OPEN" ]]; then
|
||||
echo "::notice::A hand bump to $NEXT is already open: #$OPEN."
|
||||
echo "skip=true" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
{
|
||||
echo "skip=false"
|
||||
echo "shipped=$SHIPPED"
|
||||
echo "next=$NEXT"
|
||||
echo "branch=$BRANCH"
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Bump
|
||||
if: ${{ steps.next.outputs.skip == 'false' }}
|
||||
env:
|
||||
NEXT: ${{ steps.next.outputs.next }}
|
||||
run: python3 scripts/bump-version-name.py "$NEXT"
|
||||
|
||||
# Creates the PR, or updates it on a retry. Pushed with the PAT, so pull-request.yml's
|
||||
# AppStream and what's-new gates run on it like any other bump.
|
||||
- name: Open the bump PR
|
||||
id: pr
|
||||
if: ${{ steps.next.outputs.skip == 'false' }}
|
||||
uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8
|
||||
with:
|
||||
token: ${{ secrets.CROWDIN_GITHUB_TOKEN }}
|
||||
commit-message: 'chore: bump VERSION_NAME_BASE to ${{ steps.next.outputs.next }}'
|
||||
title: 'chore: bump VERSION_NAME_BASE to ${{ steps.next.outputs.next }}'
|
||||
body: |
|
||||
Opens the ${{ steps.next.outputs.next }} line now that v${{ steps.next.outputs.shipped }} has shipped.
|
||||
|
||||
The metainfo `<description>` for ${{ steps.next.outputs.next }} is a placeholder. Rewrite it and re-run `python3 scripts/sync-play-changelog.py` before the ${{ steps.next.outputs.next }} internal cut, or it ships as the release Highlights and the Play what's-new.
|
||||
branch: ${{ steps.next.outputs.branch }}
|
||||
base: main
|
||||
delete-branch: true
|
||||
add-paths: |
|
||||
config.properties
|
||||
desktopApp/packaging/linux/org.meshtastic.MeshtasticDesktop.metainfo.xml
|
||||
fastlane/metadata/android/en-US/changelogs/default.txt
|
||||
labels: |
|
||||
automation
|
||||
skip-changelog
|
||||
|
||||
# Same request as scheduled-updates.yml: the queue sets the merge method, and a PR
|
||||
# that is already mergeable is refused the request and merges directly.
|
||||
- name: Enable auto-merge
|
||||
if: ${{ steps.pr.outputs.pull-request-operation == 'created' || steps.pr.outputs.pull-request-operation == 'updated' }}
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.CROWDIN_GITHUB_TOKEN }}
|
||||
PR_NUMBER: ${{ steps.pr.outputs.pull-request-number }}
|
||||
run: |
|
||||
PR_ID=$(gh pr view "$PR_NUMBER" --json id --jq .id)
|
||||
QUERY=$(cat <<'GQL'
|
||||
mutation($id: ID!) {
|
||||
enablePullRequestAutoMerge(input: { pullRequestId: $id }) {
|
||||
pullRequest { number autoMergeRequest { enabledAt } }
|
||||
}
|
||||
}
|
||||
GQL
|
||||
)
|
||||
gh api graphql -f query="$QUERY" -F id="$PR_ID" \
|
||||
|| gh pr merge "$PR_NUMBER"
|
||||
+4
-3
@@ -27,7 +27,7 @@ The entire release process is managed by a single GitHub Action: **`Create or Pr
|
||||
- **Writes a checklist:** The promotion run's summary lists what it did, what it dispatched, and what is still done by hand.
|
||||
- **Deploys Desktop** *(internal releases)*: Builds native installers (DMG, MSI, EXE, DEB, RPM, AppImage) and Flatpak sources on a matrix of runners and attaches them to the GitHub Release.
|
||||
- **Changelog:** Both the GitHub Release notes and `CHANGELOG.md` are generated from merged PR labels, not raw commit messages — label PRs correctly (`enhancement`, `bugfix`, etc.) to keep them accurate.
|
||||
- **Not part of this workflow:** Firmware/hardware/device-links lists and Crowdin translations are kept current by a separate hourly workflow, `scheduled-updates.yml` ("Scheduled Updates (Firmware, Hardware, Translations)"), which opens its own PR rather than committing directly and enables auto-merge on it, so it lands through the merge queue once its checks pass — it never runs as part of a release. `VERSION_NAME_BASE` in `config.properties` is likewise never written by automation: a maintainer bumps it by hand in an ordinary PR (e.g. "chore: bump VERSION_NAME_BASE to 2.8.2 (#6820)") before starting a release for a new base version, paired with a matching `<release>` entry in `desktopApp/packaging/linux/org.meshtastic.MeshtasticDesktop.metainfo.xml` and its five `<image>` URLs moved to `releases/download/v<version>/` — a `pull-request.yml` check fails the PR if either is missing. `Create or Promote Release` only *reads* `VERSION_NAME_BASE`/`VERSION_CODE_OFFSET` from `config.properties` to compute the build's version name/code.
|
||||
- **Not part of this workflow:** Firmware/hardware/device-links lists and Crowdin translations are kept current by a separate hourly workflow, `scheduled-updates.yml` ("Scheduled Updates (Firmware, Hardware, Translations)"), which opens its own PR rather than committing directly and enables auto-merge on it, so it lands through the merge queue once its checks pass — it never runs as part of a release. `VERSION_NAME_BASE` in `config.properties` moves to the next patch version after each production release: `promote.yml` dispatches `version-bump.yml`, which runs `scripts/bump-version-name.py` and opens a self-merging PR carrying the new `<release>` entry in `desktopApp/packaging/linux/org.meshtastic.MeshtasticDesktop.metainfo.xml`, its five `<image>` URLs moved to `releases/download/v<version>/`, and `fastlane/metadata/android/en-US/changelogs/default.txt` rendered from that entry. `pull-request.yml` fails a bump PR missing any of them; the bot PR is opened with `CROWDIN_GITHUB_TOKEN`, so those checks run on it and the merge queue takes it. The entry's paragraph is a placeholder; replace it and re-run `scripts/sync-play-changelog.py` before the next internal cut, because it becomes the release Highlights and Play's "What's new". A minor or major line is a hand PR running the same script, and the workflow skips when `main` is already past the shipped version. `Create or Promote Release` only *reads* `VERSION_NAME_BASE`/`VERSION_CODE_OFFSET` from `config.properties` to compute the build's version name/code.
|
||||
|
||||
## Release Steps
|
||||
|
||||
@@ -76,8 +76,9 @@ remains by hand.
|
||||
submission in Partner Center, and the pull request opened against `microsoft/winget-pkgs`.
|
||||
Each store workflow warns in its summary when its secrets are not set and it submitted nothing.
|
||||
4. **Flathub** *(production only)*: bump the manifest in `flathub/org.meshtastic.MeshtasticDesktop` (see Flatpak below).
|
||||
5. **Post-Release Cleanup** *(production only)*: once `Docs Release` has published `/vX.Y.Z/`, dispatch `post-release-cleanup.yml` with `confirm_deletion: true` to delete the cycle's pre-releases and tags.
|
||||
6. **Merge:** If a `release/*` branch was used for stabilization (CI runs the same PR checks
|
||||
5. **Post-Release Cleanup** *(production only)*: `Docs Release` dispatches `post-release-cleanup.yml` with `confirm_deletion: true` once it has published `/vX.Y.Z/`, deleting the pre-releases, tags and docs snapshots at or below `X.Y.Z`. Check that run; a manual dispatch is the retry and defaults to a dry run.
|
||||
6. **Next version line** *(production only)*: the `version-bump.yml` PR bumps `VERSION_NAME_BASE` and merges itself. Replace its placeholder `<description>` before the next internal cut.
|
||||
7. **Merge:** If a `release/*` branch was used for stabilization (CI runs the same PR checks
|
||||
against PRs targeting `release/**` as it does for `main`), merge it back into `main` now
|
||||
that production has shipped.
|
||||
|
||||
|
||||
+3
-3
@@ -70,9 +70,9 @@ cycle and are not a documented channel.
|
||||
|
||||
Prerelease snapshots accumulate during a version cycle so testers can read the
|
||||
docs for the exact build they are running. Once the production `vX.Y.Z` tag
|
||||
ships, `/vX.Y.Z/` supersedes them and **Post-Release Cleanup** (run with
|
||||
`base_version=X.Y.Z`) reaps the `vX.Y.Z-open.*` / `vX.Y.Z-closed.*` directories
|
||||
along with the prerelease tags. That workflow defaults to a dry run.
|
||||
ships, `/vX.Y.Z/` supersedes them, and once it is published Docs Release
|
||||
dispatches **Post-Release Cleanup**, which reaps every open and closed directory
|
||||
and prerelease tag at or below `X.Y.Z`. A manual dispatch defaults to a dry run.
|
||||
|
||||
Only production releases own `/` and rebuild `/api/`. Prerelease tags publish
|
||||
their own directory only: `/api/` is unversioned and already refreshed by every
|
||||
|
||||
Executable
+64
@@ -0,0 +1,64 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Open the next version line: VERSION_NAME_BASE plus everything pull-request.yml requires with it.
|
||||
|
||||
That is the AppStream <release> entry in metainfo.xml, its five <image> URLs moved to the
|
||||
new version's release assets, and the Play what's-new rendered from the entry by
|
||||
sync-play-changelog.py. The entry's paragraph is a placeholder; rewrite it and re-run
|
||||
sync-play-changelog.py before the internal cut, or it ships as the store text.
|
||||
|
||||
Running it twice for the same version changes nothing the second time.
|
||||
|
||||
python3 scripts/bump-version-name.py <X.Y.Z>
|
||||
"""
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parent.parent
|
||||
CONFIG = REPO_ROOT / "config.properties"
|
||||
METAINFO = REPO_ROOT / "desktopApp/packaging/linux/org.meshtastic.MeshtasticDesktop.metainfo.xml"
|
||||
SYNC = REPO_ROOT / "scripts/sync-play-changelog.py"
|
||||
PLACEHOLDER = "Stability and reliability fixes."
|
||||
|
||||
|
||||
def bump_config(v: str) -> None:
|
||||
text, n = re.subn(r"^VERSION_NAME_BASE=.*$", f"VERSION_NAME_BASE={v}", CONFIG.read_text(), flags=re.M)
|
||||
if n != 1:
|
||||
sys.exit(f"expected one VERSION_NAME_BASE line in {CONFIG.name}, found {n}")
|
||||
CONFIG.write_text(text)
|
||||
|
||||
|
||||
def bump_metainfo(v: str) -> None:
|
||||
text = METAINFO.read_text()
|
||||
if f'<release version="{v}"' not in text:
|
||||
first = re.search(r"^([ \t]*)<release ", text, re.M)
|
||||
if not first:
|
||||
sys.exit(f"no <release> entry in {METAINFO.name} to insert above")
|
||||
ind = first.group(1)
|
||||
date = datetime.now(timezone.utc).date().isoformat()
|
||||
entry = (
|
||||
f'{ind}<release version="{v}" date="{date}">\n'
|
||||
f"{ind} <description>\n"
|
||||
f"{ind} <p>{PLACEHOLDER}</p>\n"
|
||||
f"{ind} </description>\n"
|
||||
f"{ind}</release>\n"
|
||||
)
|
||||
text = text[: first.start()] + entry + text[first.start() :]
|
||||
text = re.sub(r"(<image>[^<]*/releases/download/)v[^/<]+/", rf"\g<1>v{v}/", text)
|
||||
METAINFO.write_text(text)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
if len(sys.argv) != 2 or not re.fullmatch(r"\d+\.\d+\.\d+", sys.argv[1]):
|
||||
sys.exit("usage: bump-version-name.py <X.Y.Z>")
|
||||
v = sys.argv[1]
|
||||
bump_config(v)
|
||||
bump_metainfo(v)
|
||||
subprocess.run([sys.executable, str(SYNC)], check=True)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in new issue
Block a user