From 9590a883c919d9827c16817a5cac581243517dca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=82=B9=E6=B0=B8=E8=B5=AB?= <1259085392@qq.com> Date: Sat, 21 Feb 2026 10:45:58 +0900 Subject: [PATCH 1/9] ci add daily nightly schedule alongside tag polling --- .github/workflows/build-desktop-tauri.yml | 72 ++++++++++++++++------- 1 file changed, 50 insertions(+), 22 deletions(-) diff --git a/.github/workflows/build-desktop-tauri.yml b/.github/workflows/build-desktop-tauri.yml index c1f6bf5a..120c0a8e 100644 --- a/.github/workflows/build-desktop-tauri.yml +++ b/.github/workflows/build-desktop-tauri.yml @@ -18,6 +18,7 @@ on: default: true schedule: - cron: '0 * * * *' + - cron: '0 3 * * *' permissions: contents: read @@ -35,6 +36,8 @@ jobs: source_git_ref: ${{ steps.resolve.outputs.source_git_ref }} astrbot_version: ${{ steps.resolve.outputs.astrbot_version }} should_build: ${{ steps.resolve.outputs.should_build }} + build_mode: ${{ steps.resolve.outputs.build_mode }} + publish_release: ${{ steps.resolve.outputs.publish_release }} steps: - name: Checkout uses: actions/checkout@v6.0.2 @@ -52,15 +55,21 @@ jobs: ASTRBOT_SOURCE_GIT_REF: ${{ env.ASTRBOT_SOURCE_GIT_REF }} WORKFLOW_SOURCE_GIT_URL: ${{ github.event.inputs.source_git_url }} WORKFLOW_SOURCE_GIT_REF: ${{ github.event.inputs.source_git_ref }} + WORKFLOW_PUBLISH_RELEASE: ${{ github.event.inputs.publish_release }} GITHUB_TOKEN: ${{ github.token }} GH_REPOSITORY: ${{ github.repository }} GITHUB_EVENT_NAME: ${{ github.event_name }} + GITHUB_EVENT_SCHEDULE: ${{ github.event.schedule }} run: | set -euo pipefail + TAG_POLL_CRON='0 * * * *' + NIGHTLY_CRON='0 3 * * *' source_git_url="${ASTRBOT_SOURCE_GIT_URL}" source_git_ref="${ASTRBOT_SOURCE_GIT_REF}" should_build="true" + build_mode="manual" + publish_release="false" if [ "${GITHUB_EVENT_NAME}" = "workflow_dispatch" ]; then if [ -n "${WORKFLOW_SOURCE_GIT_URL:-}" ]; then @@ -69,30 +78,45 @@ jobs: if [ -n "${WORKFLOW_SOURCE_GIT_REF:-}" ]; then source_git_ref="${WORKFLOW_SOURCE_GIT_REF}" fi + if [ "${WORKFLOW_PUBLISH_RELEASE:-true}" = "true" ]; then + publish_release="true" + fi fi if [ "${GITHUB_EVENT_NAME}" = "schedule" ]; then - latest_tag="$(git ls-remote --tags --refs "${source_git_url}" \ - | awk '{print $2}' \ - | sed 's#refs/tags/##' \ - | sort -V \ - | tail -n 1)" - if [ -z "${latest_tag}" ]; then - echo "Unable to resolve latest tag from ${source_git_url}" >&2 - exit 1 - fi - source_git_ref="${latest_tag}" - echo "Scheduled run detected latest upstream tag: ${source_git_ref}" - - http_status="$(curl -sS -o /dev/null -w '%{http_code}' \ - -H "Authorization: Bearer ${GITHUB_TOKEN}" \ - -H "Accept: application/vnd.github+json" \ - "https://api.github.com/repos/${GH_REPOSITORY}/releases/tags/${source_git_ref}")" - if [ "${http_status}" = "200" ]; then - should_build="false" - echo "Release ${source_git_ref} already exists. Tag unchanged, skipping build." + if [ "${GITHUB_EVENT_SCHEDULE:-}" = "${NIGHTLY_CRON}" ]; then + build_mode="nightly" + publish_release="false" + echo "Scheduled nightly run: building from ${source_git_ref}" else - echo "Release ${source_git_ref} not found (HTTP ${http_status}). Build will run." + build_mode="tag-poll" + publish_release="true" + if [ "${GITHUB_EVENT_SCHEDULE:-}" != "${TAG_POLL_CRON}" ]; then + echo "WARN: unknown schedule '${GITHUB_EVENT_SCHEDULE:-}', fallback to tag polling mode." + fi + + latest_tag="$(git ls-remote --tags --refs "${source_git_url}" \ + | awk '{print $2}' \ + | sed 's#refs/tags/##' \ + | sort -V \ + | tail -n 1)" + if [ -z "${latest_tag}" ]; then + echo "Unable to resolve latest tag from ${source_git_url}" >&2 + exit 1 + fi + source_git_ref="${latest_tag}" + echo "Scheduled tag polling run detected latest upstream tag: ${source_git_ref}" + + http_status="$(curl -sS -o /dev/null -w '%{http_code}' \ + -H "Authorization: Bearer ${GITHUB_TOKEN}" \ + -H "Accept: application/vnd.github+json" \ + "https://api.github.com/repos/${GH_REPOSITORY}/releases/tags/${source_git_ref}")" + if [ "${http_status}" = "200" ]; then + should_build="false" + echo "Release ${source_git_ref} already exists. Tag unchanged, skipping build." + else + echo "Release ${source_git_ref} not found (HTTP ${http_status}). Build will run." + fi fi fi @@ -122,15 +146,19 @@ jobs: echo "source_git_ref=${source_git_ref}" echo "astrbot_version=${version}" echo "should_build=${should_build}" + echo "build_mode=${build_mode}" + echo "publish_release=${publish_release}" } >> "${GITHUB_OUTPUT}" echo "Resolved source: ${source_git_url}@${source_git_ref}" echo "Resolved AstrBot version: ${version}" echo "Build enabled: ${should_build}" + echo "Build mode: ${build_mode}" + echo "Publish release: ${publish_release}" sync_repo_version: name: Sync Repository Version needs: resolve_build_context - if: ${{ needs.resolve_build_context.outputs.should_build == 'true' && github.event_name == 'schedule' }} + if: ${{ needs.resolve_build_context.outputs.should_build == 'true' && needs.resolve_build_context.outputs.build_mode == 'tag-poll' }} runs-on: ubuntu-latest permissions: contents: write @@ -456,7 +484,7 @@ jobs: release: name: Publish GitHub Release - if: ${{ needs.resolve_build_context.outputs.should_build == 'true' && (github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && github.event.inputs.publish_release == 'true')) }} + if: ${{ needs.resolve_build_context.outputs.should_build == 'true' && needs.resolve_build_context.outputs.publish_release == 'true' }} needs: - resolve_build_context - build-linux From a1ffa19dcecaed4f9ca4062374d65acb60872107 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=82=B9=E6=B0=B8=E8=B5=AB?= <1259085392@qq.com> Date: Sat, 21 Feb 2026 10:48:57 +0900 Subject: [PATCH 2/9] ci release nightly builds from upstream master with nightly suffix --- .github/workflows/build-desktop-tauri.yml | 43 ++++++++++++++++++++--- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-desktop-tauri.yml b/.github/workflows/build-desktop-tauri.yml index 120c0a8e..74892ef0 100644 --- a/.github/workflows/build-desktop-tauri.yml +++ b/.github/workflows/build-desktop-tauri.yml @@ -38,6 +38,9 @@ jobs: should_build: ${{ steps.resolve.outputs.should_build }} build_mode: ${{ steps.resolve.outputs.build_mode }} publish_release: ${{ steps.resolve.outputs.publish_release }} + release_tag: ${{ steps.resolve.outputs.release_tag }} + release_name: ${{ steps.resolve.outputs.release_name }} + release_prerelease: ${{ steps.resolve.outputs.release_prerelease }} steps: - name: Checkout uses: actions/checkout@v6.0.2 @@ -70,6 +73,9 @@ jobs: should_build="true" build_mode="manual" publish_release="false" + release_tag="" + release_name="" + release_prerelease="false" if [ "${GITHUB_EVENT_NAME}" = "workflow_dispatch" ]; then if [ -n "${WORKFLOW_SOURCE_GIT_URL:-}" ]; then @@ -86,8 +92,16 @@ jobs: if [ "${GITHUB_EVENT_NAME}" = "schedule" ]; then if [ "${GITHUB_EVENT_SCHEDULE:-}" = "${NIGHTLY_CRON}" ]; then build_mode="nightly" - publish_release="false" - echo "Scheduled nightly run: building from ${source_git_ref}" + publish_release="true" + source_git_ref="$( + git ls-remote "${source_git_url}" refs/heads/master \ + | awk 'NR==1{print $1}' + )" + if [ -z "${source_git_ref}" ]; then + echo "Unable to resolve latest commit from ${source_git_url} refs/heads/master" >&2 + exit 1 + fi + echo "Scheduled nightly run: building from master@${source_git_ref}" else build_mode="tag-poll" publish_release="true" @@ -141,6 +155,19 @@ jobs: fi fi + if [ "${build_mode}" = "nightly" ] && [ "${should_build}" = "true" ]; then + nightly_date="$(date -u +%Y%m%d)" + short_sha="$(printf '%s' "${source_git_ref}" | cut -c1-8)" + version="${version}-nightly.${nightly_date}.${short_sha}" + release_tag="v${version}" + release_name="AstrBot Desktop ${version}" + release_prerelease="true" + elif [ "${publish_release}" = "true" ] && [ "${should_build}" = "true" ]; then + release_tag="v${version}" + release_name="AstrBot Desktop v${version}" + release_prerelease="false" + fi + { echo "source_git_url=${source_git_url}" echo "source_git_ref=${source_git_ref}" @@ -148,12 +175,17 @@ jobs: echo "should_build=${should_build}" echo "build_mode=${build_mode}" echo "publish_release=${publish_release}" + echo "release_tag=${release_tag}" + echo "release_name=${release_name}" + echo "release_prerelease=${release_prerelease}" } >> "${GITHUB_OUTPUT}" echo "Resolved source: ${source_git_url}@${source_git_ref}" echo "Resolved AstrBot version: ${version}" echo "Build enabled: ${should_build}" echo "Build mode: ${build_mode}" echo "Publish release: ${publish_release}" + echo "Release tag: ${release_tag:-}" + echo "Release prerelease: ${release_prerelease}" sync_repo_version: name: Sync Repository Version @@ -516,13 +548,16 @@ jobs: - name: Create or update release uses: softprops/action-gh-release@v2.5.0 with: - tag_name: v${{ needs.resolve_build_context.outputs.astrbot_version }} - name: AstrBot Desktop v${{ needs.resolve_build_context.outputs.astrbot_version }} + tag_name: ${{ needs.resolve_build_context.outputs.release_tag }} + name: ${{ needs.resolve_build_context.outputs.release_name }} body: | Automated desktop package release. - Source: `${{ needs.resolve_build_context.outputs.source_git_url }}` - Ref: `${{ needs.resolve_build_context.outputs.source_git_ref }}` + - Mode: `${{ needs.resolve_build_context.outputs.build_mode }}` - Windows tip: prefer `nsis-web` installer for smaller downloads and faster install startup. generate_release_notes: true + prerelease: ${{ needs.resolve_build_context.outputs.release_prerelease == 'true' }} + make_latest: ${{ needs.resolve_build_context.outputs.release_prerelease != 'true' }} files: release-artifacts/**/* fail_on_unmatched_files: true From b03be044e0874f420b6328715ea048af0692eb29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=82=B9=E6=B0=B8=E8=B5=AB?= <1259085392@qq.com> Date: Sat, 21 Feb 2026 10:52:27 +0900 Subject: [PATCH 3/9] ci align nightly release naming and cron sync note --- .github/workflows/build-desktop-tauri.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-desktop-tauri.yml b/.github/workflows/build-desktop-tauri.yml index 74892ef0..03b95e89 100644 --- a/.github/workflows/build-desktop-tauri.yml +++ b/.github/workflows/build-desktop-tauri.yml @@ -66,6 +66,7 @@ jobs: run: | set -euo pipefail + # Keep these in sync with `on.schedule` above. TAG_POLL_CRON='0 * * * *' NIGHTLY_CRON='0 3 * * *' source_git_url="${ASTRBOT_SOURCE_GIT_URL}" @@ -160,7 +161,7 @@ jobs: short_sha="$(printf '%s' "${source_git_ref}" | cut -c1-8)" version="${version}-nightly.${nightly_date}.${short_sha}" release_tag="v${version}" - release_name="AstrBot Desktop ${version}" + release_name="AstrBot Desktop v${version}" release_prerelease="true" elif [ "${publish_release}" = "true" ] && [ "${should_build}" = "true" ]; then release_tag="v${version}" From ff59d431618572db9c2c064029bf857efee32562 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=82=B9=E6=B0=B8=E8=B5=AB?= <1259085392@qq.com> Date: Sat, 21 Feb 2026 10:56:05 +0900 Subject: [PATCH 4/9] ci make nightly source configurable and decouple mode from cron strings --- .github/workflows/build-desktop-tauri.yml | 121 ++++++++++++++-------- 1 file changed, 79 insertions(+), 42 deletions(-) diff --git a/.github/workflows/build-desktop-tauri.yml b/.github/workflows/build-desktop-tauri.yml index 03b95e89..110bf238 100644 --- a/.github/workflows/build-desktop-tauri.yml +++ b/.github/workflows/build-desktop-tauri.yml @@ -16,9 +16,17 @@ on: required: false type: boolean default: true + build_mode: + description: Build mode (`auto` | `tag-poll` | `nightly`) + required: false + type: choice + default: auto + options: + - auto + - tag-poll + - nightly schedule: - cron: '0 * * * *' - - cron: '0 3 * * *' permissions: contents: read @@ -26,6 +34,8 @@ permissions: env: ASTRBOT_SOURCE_GIT_URL: ${{ vars.ASTRBOT_SOURCE_GIT_URL || 'https://github.com/AstrBotDevs/AstrBot.git' }} ASTRBOT_SOURCE_GIT_REF: ${{ vars.ASTRBOT_SOURCE_GIT_REF || 'master' }} + ASTRBOT_NIGHTLY_SOURCE_GIT_REF: ${{ vars.ASTRBOT_NIGHTLY_SOURCE_GIT_REF || 'master' }} + ASTRBOT_NIGHTLY_UTC_HOUR: ${{ vars.ASTRBOT_NIGHTLY_UTC_HOUR || '3' }} jobs: resolve_build_context: @@ -59,18 +69,20 @@ jobs: WORKFLOW_SOURCE_GIT_URL: ${{ github.event.inputs.source_git_url }} WORKFLOW_SOURCE_GIT_REF: ${{ github.event.inputs.source_git_ref }} WORKFLOW_PUBLISH_RELEASE: ${{ github.event.inputs.publish_release }} + WORKFLOW_BUILD_MODE: ${{ github.event.inputs.build_mode }} GITHUB_TOKEN: ${{ github.token }} GH_REPOSITORY: ${{ github.repository }} GITHUB_EVENT_NAME: ${{ github.event_name }} - GITHUB_EVENT_SCHEDULE: ${{ github.event.schedule }} + ASTRBOT_NIGHTLY_SOURCE_GIT_REF: ${{ env.ASTRBOT_NIGHTLY_SOURCE_GIT_REF }} + ASTRBOT_NIGHTLY_UTC_HOUR: ${{ env.ASTRBOT_NIGHTLY_UTC_HOUR }} run: | set -euo pipefail - # Keep these in sync with `on.schedule` above. - TAG_POLL_CRON='0 * * * *' - NIGHTLY_CRON='0 3 * * *' source_git_url="${ASTRBOT_SOURCE_GIT_URL}" source_git_ref="${ASTRBOT_SOURCE_GIT_REF}" + nightly_source_git_ref="${ASTRBOT_NIGHTLY_SOURCE_GIT_REF:-master}" + nightly_utc_hour="${ASTRBOT_NIGHTLY_UTC_HOUR:-3}" + requested_build_mode="$(printf '%s' "${WORKFLOW_BUILD_MODE:-auto}" | tr '[:upper:]' '[:lower:]')" should_build="true" build_mode="manual" publish_release="false" @@ -78,6 +90,23 @@ jobs: release_name="" release_prerelease="false" + case "${requested_build_mode}" in + auto|tag-poll|nightly) ;; + *) + echo "WARN: invalid build_mode input '${requested_build_mode}', fallback to auto." + requested_build_mode="auto" + ;; + esac + + case "${nightly_utc_hour}" in + ''|*[!0-9]*) nightly_utc_hour="3" ;; + esac + if [ "${nightly_utc_hour}" -gt 23 ] 2>/dev/null; then + echo "WARN: invalid ASTRBOT_NIGHTLY_UTC_HOUR=${nightly_utc_hour}, fallback to 3." + nightly_utc_hour="3" + fi + nightly_utc_hour_padded="$(printf '%02d' "${nightly_utc_hour}")" + if [ "${GITHUB_EVENT_NAME}" = "workflow_dispatch" ]; then if [ -n "${WORKFLOW_SOURCE_GIT_URL:-}" ]; then source_git_url="${WORKFLOW_SOURCE_GIT_URL}" @@ -88,50 +117,58 @@ jobs: if [ "${WORKFLOW_PUBLISH_RELEASE:-true}" = "true" ]; then publish_release="true" fi + if [ "${requested_build_mode}" = "tag-poll" ]; then + build_mode="tag-poll" + elif [ "${requested_build_mode}" = "nightly" ]; then + build_mode="nightly" + fi fi if [ "${GITHUB_EVENT_NAME}" = "schedule" ]; then - if [ "${GITHUB_EVENT_SCHEDULE:-}" = "${NIGHTLY_CRON}" ]; then + current_utc_hour="$(date -u +%H)" + if [ "${current_utc_hour}" = "${nightly_utc_hour_padded}" ]; then build_mode="nightly" publish_release="true" - source_git_ref="$( - git ls-remote "${source_git_url}" refs/heads/master \ - | awk 'NR==1{print $1}' - )" - if [ -z "${source_git_ref}" ]; then - echo "Unable to resolve latest commit from ${source_git_url} refs/heads/master" >&2 - exit 1 - fi - echo "Scheduled nightly run: building from master@${source_git_ref}" + echo "Scheduled nightly run at UTC hour ${current_utc_hour}." else build_mode="tag-poll" publish_release="true" - if [ "${GITHUB_EVENT_SCHEDULE:-}" != "${TAG_POLL_CRON}" ]; then - echo "WARN: unknown schedule '${GITHUB_EVENT_SCHEDULE:-}', fallback to tag polling mode." - fi - - latest_tag="$(git ls-remote --tags --refs "${source_git_url}" \ - | awk '{print $2}' \ - | sed 's#refs/tags/##' \ - | sort -V \ - | tail -n 1)" - if [ -z "${latest_tag}" ]; then - echo "Unable to resolve latest tag from ${source_git_url}" >&2 - exit 1 - fi - source_git_ref="${latest_tag}" - echo "Scheduled tag polling run detected latest upstream tag: ${source_git_ref}" - - http_status="$(curl -sS -o /dev/null -w '%{http_code}' \ - -H "Authorization: Bearer ${GITHUB_TOKEN}" \ - -H "Accept: application/vnd.github+json" \ - "https://api.github.com/repos/${GH_REPOSITORY}/releases/tags/${source_git_ref}")" - if [ "${http_status}" = "200" ]; then - should_build="false" - echo "Release ${source_git_ref} already exists. Tag unchanged, skipping build." - else - echo "Release ${source_git_ref} not found (HTTP ${http_status}). Build will run." - fi + echo "Scheduled tag polling run at UTC hour ${current_utc_hour}." + fi + fi + + if [ "${build_mode}" = "nightly" ]; then + source_git_ref="$( + git ls-remote "${source_git_url}" "refs/heads/${nightly_source_git_ref}" \ + | awk 'NR==1{print $1}' + )" + if [ -z "${source_git_ref}" ]; then + echo "Unable to resolve latest commit from ${source_git_url} refs/heads/${nightly_source_git_ref}" >&2 + exit 1 + fi + echo "Nightly source resolved from ${nightly_source_git_ref}@${source_git_ref}" + elif [ "${build_mode}" = "tag-poll" ]; then + latest_tag="$(git ls-remote --tags --refs "${source_git_url}" \ + | awk '{print $2}' \ + | sed 's#refs/tags/##' \ + | sort -V \ + | tail -n 1)" + if [ -z "${latest_tag}" ]; then + echo "Unable to resolve latest tag from ${source_git_url}" >&2 + exit 1 + fi + source_git_ref="${latest_tag}" + echo "Tag polling run detected latest upstream tag: ${source_git_ref}" + + http_status="$(curl -sS -o /dev/null -w '%{http_code}' \ + -H "Authorization: Bearer ${GITHUB_TOKEN}" \ + -H "Accept: application/vnd.github+json" \ + "https://api.github.com/repos/${GH_REPOSITORY}/releases/tags/${source_git_ref}")" + if [ "${http_status}" = "200" ]; then + should_build="false" + echo "Release ${source_git_ref} already exists. Tag unchanged, skipping build." + else + echo "Release ${source_git_ref} not found (HTTP ${http_status}). Build will run." fi fi @@ -191,7 +228,7 @@ jobs: sync_repo_version: name: Sync Repository Version needs: resolve_build_context - if: ${{ needs.resolve_build_context.outputs.should_build == 'true' && needs.resolve_build_context.outputs.build_mode == 'tag-poll' }} + if: ${{ github.event_name == 'schedule' && needs.resolve_build_context.outputs.should_build == 'true' && needs.resolve_build_context.outputs.build_mode == 'tag-poll' }} runs-on: ubuntu-latest permissions: contents: write From 5d51565a721041c6945233ac261a823ec03341a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=82=B9=E6=B0=B8=E8=B5=AB?= <1259085392@qq.com> Date: Sat, 21 Feb 2026 10:59:33 +0900 Subject: [PATCH 5/9] ci warn on non-numeric nightly hour fallback --- .github/workflows/build-desktop-tauri.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-desktop-tauri.yml b/.github/workflows/build-desktop-tauri.yml index 110bf238..c7002b43 100644 --- a/.github/workflows/build-desktop-tauri.yml +++ b/.github/workflows/build-desktop-tauri.yml @@ -99,7 +99,13 @@ jobs: esac case "${nightly_utc_hour}" in - ''|*[!0-9]*) nightly_utc_hour="3" ;; + '') + nightly_utc_hour="3" + ;; + *[!0-9]*) + echo "WARN: non-numeric ASTRBOT_NIGHTLY_UTC_HOUR=${nightly_utc_hour}, fallback to 3." + nightly_utc_hour="3" + ;; esac if [ "${nightly_utc_hour}" -gt 23 ] 2>/dev/null; then echo "WARN: invalid ASTRBOT_NIGHTLY_UTC_HOUR=${nightly_utc_hour}, fallback to 3." From 9bf47803cdc5619e2a7a21cb2913e07fa6d26686 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=82=B9=E6=B0=B8=E8=B5=AB?= <1259085392@qq.com> Date: Sat, 21 Feb 2026 11:05:15 +0900 Subject: [PATCH 6/9] ci fail on invalid build_mode and centralize nightly hour default --- .github/workflows/build-desktop-tauri.yml | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build-desktop-tauri.yml b/.github/workflows/build-desktop-tauri.yml index c7002b43..1a7e3af5 100644 --- a/.github/workflows/build-desktop-tauri.yml +++ b/.github/workflows/build-desktop-tauri.yml @@ -17,7 +17,7 @@ on: type: boolean default: true build_mode: - description: Build mode (`auto` | `tag-poll` | `nightly`) + description: Build mode (`auto` | `tag-poll` | `nightly`); for workflow_dispatch, `auto` behaves as `manual` required: false type: choice default: auto @@ -78,10 +78,11 @@ jobs: run: | set -euo pipefail + DEFAULT_NIGHTLY_UTC_HOUR='3' source_git_url="${ASTRBOT_SOURCE_GIT_URL}" source_git_ref="${ASTRBOT_SOURCE_GIT_REF}" nightly_source_git_ref="${ASTRBOT_NIGHTLY_SOURCE_GIT_REF:-master}" - nightly_utc_hour="${ASTRBOT_NIGHTLY_UTC_HOUR:-3}" + nightly_utc_hour="${ASTRBOT_NIGHTLY_UTC_HOUR:-${DEFAULT_NIGHTLY_UTC_HOUR}}" requested_build_mode="$(printf '%s' "${WORKFLOW_BUILD_MODE:-auto}" | tr '[:upper:]' '[:lower:]')" should_build="true" build_mode="manual" @@ -93,23 +94,23 @@ jobs: case "${requested_build_mode}" in auto|tag-poll|nightly) ;; *) - echo "WARN: invalid build_mode input '${requested_build_mode}', fallback to auto." - requested_build_mode="auto" + echo "::error::invalid build_mode input '${requested_build_mode}'; expected one of: auto, tag-poll, nightly." + exit 1 ;; esac case "${nightly_utc_hour}" in '') - nightly_utc_hour="3" + nightly_utc_hour="${DEFAULT_NIGHTLY_UTC_HOUR}" ;; *[!0-9]*) - echo "WARN: non-numeric ASTRBOT_NIGHTLY_UTC_HOUR=${nightly_utc_hour}, fallback to 3." - nightly_utc_hour="3" + echo "WARN: non-numeric ASTRBOT_NIGHTLY_UTC_HOUR=${nightly_utc_hour}, fallback to ${DEFAULT_NIGHTLY_UTC_HOUR}." + nightly_utc_hour="${DEFAULT_NIGHTLY_UTC_HOUR}" ;; esac if [ "${nightly_utc_hour}" -gt 23 ] 2>/dev/null; then - echo "WARN: invalid ASTRBOT_NIGHTLY_UTC_HOUR=${nightly_utc_hour}, fallback to 3." - nightly_utc_hour="3" + echo "WARN: invalid ASTRBOT_NIGHTLY_UTC_HOUR=${nightly_utc_hour}, fallback to ${DEFAULT_NIGHTLY_UTC_HOUR}." + nightly_utc_hour="${DEFAULT_NIGHTLY_UTC_HOUR}" fi nightly_utc_hour_padded="$(printf '%02d' "${nightly_utc_hour}")" @@ -127,6 +128,8 @@ jobs: build_mode="tag-poll" elif [ "${requested_build_mode}" = "nightly" ]; then build_mode="nightly" + else + echo "workflow_dispatch build_mode=auto: using manual mode." fi fi From bb841d642cbd48288cbf34deedebfc15d82e9a10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=82=B9=E6=B0=B8=E8=B5=AB?= <1259085392@qq.com> Date: Sat, 21 Feb 2026 11:08:30 +0900 Subject: [PATCH 7/9] ci normalize nightly branch ref and improve errors --- .github/workflows/build-desktop-tauri.yml | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-desktop-tauri.yml b/.github/workflows/build-desktop-tauri.yml index 1a7e3af5..bf925b23 100644 --- a/.github/workflows/build-desktop-tauri.yml +++ b/.github/workflows/build-desktop-tauri.yml @@ -147,15 +147,30 @@ jobs: fi if [ "${build_mode}" = "nightly" ]; then + nightly_branch="${nightly_source_git_ref}" + if [ -z "${nightly_branch}" ]; then + echo "ASTRBOT_NIGHTLY_SOURCE_GIT_REF must be set to a branch name or refs/heads/ for nightly builds." >&2 + exit 1 + fi + case "${nightly_branch}" in + refs/heads/*) + echo "Normalizing nightly source ref '${nightly_branch}' to branch name for git ls-remote." + nightly_branch="${nightly_branch#refs/heads/}" + ;; + refs/*) + echo "ASTRBOT_NIGHTLY_SOURCE_GIT_REF must be a branch name or refs/heads/; got '${nightly_branch}'." >&2 + exit 1 + ;; + esac source_git_ref="$( - git ls-remote "${source_git_url}" "refs/heads/${nightly_source_git_ref}" \ + git ls-remote "${source_git_url}" "refs/heads/${nightly_branch}" \ | awk 'NR==1{print $1}' )" if [ -z "${source_git_ref}" ]; then - echo "Unable to resolve latest commit from ${source_git_url} refs/heads/${nightly_source_git_ref}" >&2 + echo "Unable to resolve latest commit from ${source_git_url} refs/heads/${nightly_branch} (configured ASTRBOT_NIGHTLY_SOURCE_GIT_REF='${nightly_source_git_ref}')." >&2 exit 1 fi - echo "Nightly source resolved from ${nightly_source_git_ref}@${source_git_ref}" + echo "Nightly source resolved from ${nightly_branch}@${source_git_ref} (configured ASTRBOT_NIGHTLY_SOURCE_GIT_REF='${nightly_source_git_ref}')." elif [ "${build_mode}" = "tag-poll" ]; then latest_tag="$(git ls-remote --tags --refs "${source_git_url}" \ | awk '{print $2}' \ From 152650f1dbffae30b77bc26cd9c6007506de6e2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=82=B9=E6=B0=B8=E8=B5=AB?= <1259085392@qq.com> Date: Sat, 21 Feb 2026 11:12:45 +0900 Subject: [PATCH 8/9] ci extract build-context resolver and harden nightly ref resolution --- .github/workflows/build-desktop-tauri.yml | 173 +-------------- scripts/ci/resolve-build-context.sh | 259 ++++++++++++++++++++++ 2 files changed, 260 insertions(+), 172 deletions(-) create mode 100755 scripts/ci/resolve-build-context.sh diff --git a/.github/workflows/build-desktop-tauri.yml b/.github/workflows/build-desktop-tauri.yml index bf925b23..a9cf495a 100644 --- a/.github/workflows/build-desktop-tauri.yml +++ b/.github/workflows/build-desktop-tauri.yml @@ -75,179 +75,8 @@ jobs: GITHUB_EVENT_NAME: ${{ github.event_name }} ASTRBOT_NIGHTLY_SOURCE_GIT_REF: ${{ env.ASTRBOT_NIGHTLY_SOURCE_GIT_REF }} ASTRBOT_NIGHTLY_UTC_HOUR: ${{ env.ASTRBOT_NIGHTLY_UTC_HOUR }} - run: | - set -euo pipefail - - DEFAULT_NIGHTLY_UTC_HOUR='3' - source_git_url="${ASTRBOT_SOURCE_GIT_URL}" - source_git_ref="${ASTRBOT_SOURCE_GIT_REF}" - nightly_source_git_ref="${ASTRBOT_NIGHTLY_SOURCE_GIT_REF:-master}" - nightly_utc_hour="${ASTRBOT_NIGHTLY_UTC_HOUR:-${DEFAULT_NIGHTLY_UTC_HOUR}}" - requested_build_mode="$(printf '%s' "${WORKFLOW_BUILD_MODE:-auto}" | tr '[:upper:]' '[:lower:]')" - should_build="true" - build_mode="manual" - publish_release="false" - release_tag="" - release_name="" - release_prerelease="false" - - case "${requested_build_mode}" in - auto|tag-poll|nightly) ;; - *) - echo "::error::invalid build_mode input '${requested_build_mode}'; expected one of: auto, tag-poll, nightly." - exit 1 - ;; - esac - - case "${nightly_utc_hour}" in - '') - nightly_utc_hour="${DEFAULT_NIGHTLY_UTC_HOUR}" - ;; - *[!0-9]*) - echo "WARN: non-numeric ASTRBOT_NIGHTLY_UTC_HOUR=${nightly_utc_hour}, fallback to ${DEFAULT_NIGHTLY_UTC_HOUR}." - nightly_utc_hour="${DEFAULT_NIGHTLY_UTC_HOUR}" - ;; - esac - if [ "${nightly_utc_hour}" -gt 23 ] 2>/dev/null; then - echo "WARN: invalid ASTRBOT_NIGHTLY_UTC_HOUR=${nightly_utc_hour}, fallback to ${DEFAULT_NIGHTLY_UTC_HOUR}." - nightly_utc_hour="${DEFAULT_NIGHTLY_UTC_HOUR}" - fi - nightly_utc_hour_padded="$(printf '%02d' "${nightly_utc_hour}")" - - if [ "${GITHUB_EVENT_NAME}" = "workflow_dispatch" ]; then - if [ -n "${WORKFLOW_SOURCE_GIT_URL:-}" ]; then - source_git_url="${WORKFLOW_SOURCE_GIT_URL}" - fi - if [ -n "${WORKFLOW_SOURCE_GIT_REF:-}" ]; then - source_git_ref="${WORKFLOW_SOURCE_GIT_REF}" - fi - if [ "${WORKFLOW_PUBLISH_RELEASE:-true}" = "true" ]; then - publish_release="true" - fi - if [ "${requested_build_mode}" = "tag-poll" ]; then - build_mode="tag-poll" - elif [ "${requested_build_mode}" = "nightly" ]; then - build_mode="nightly" - else - echo "workflow_dispatch build_mode=auto: using manual mode." - fi - fi - - if [ "${GITHUB_EVENT_NAME}" = "schedule" ]; then - current_utc_hour="$(date -u +%H)" - if [ "${current_utc_hour}" = "${nightly_utc_hour_padded}" ]; then - build_mode="nightly" - publish_release="true" - echo "Scheduled nightly run at UTC hour ${current_utc_hour}." - else - build_mode="tag-poll" - publish_release="true" - echo "Scheduled tag polling run at UTC hour ${current_utc_hour}." - fi - fi - - if [ "${build_mode}" = "nightly" ]; then - nightly_branch="${nightly_source_git_ref}" - if [ -z "${nightly_branch}" ]; then - echo "ASTRBOT_NIGHTLY_SOURCE_GIT_REF must be set to a branch name or refs/heads/ for nightly builds." >&2 - exit 1 - fi - case "${nightly_branch}" in - refs/heads/*) - echo "Normalizing nightly source ref '${nightly_branch}' to branch name for git ls-remote." - nightly_branch="${nightly_branch#refs/heads/}" - ;; - refs/*) - echo "ASTRBOT_NIGHTLY_SOURCE_GIT_REF must be a branch name or refs/heads/; got '${nightly_branch}'." >&2 - exit 1 - ;; - esac - source_git_ref="$( - git ls-remote "${source_git_url}" "refs/heads/${nightly_branch}" \ - | awk 'NR==1{print $1}' - )" - if [ -z "${source_git_ref}" ]; then - echo "Unable to resolve latest commit from ${source_git_url} refs/heads/${nightly_branch} (configured ASTRBOT_NIGHTLY_SOURCE_GIT_REF='${nightly_source_git_ref}')." >&2 - exit 1 - fi - echo "Nightly source resolved from ${nightly_branch}@${source_git_ref} (configured ASTRBOT_NIGHTLY_SOURCE_GIT_REF='${nightly_source_git_ref}')." - elif [ "${build_mode}" = "tag-poll" ]; then - latest_tag="$(git ls-remote --tags --refs "${source_git_url}" \ - | awk '{print $2}' \ - | sed 's#refs/tags/##' \ - | sort -V \ - | tail -n 1)" - if [ -z "${latest_tag}" ]; then - echo "Unable to resolve latest tag from ${source_git_url}" >&2 - exit 1 - fi - source_git_ref="${latest_tag}" - echo "Tag polling run detected latest upstream tag: ${source_git_ref}" - - http_status="$(curl -sS -o /dev/null -w '%{http_code}' \ - -H "Authorization: Bearer ${GITHUB_TOKEN}" \ - -H "Accept: application/vnd.github+json" \ - "https://api.github.com/repos/${GH_REPOSITORY}/releases/tags/${source_git_ref}")" - if [ "${http_status}" = "200" ]; then - should_build="false" - echo "Release ${source_git_ref} already exists. Tag unchanged, skipping build." - else - echo "Release ${source_git_ref} not found (HTTP ${http_status}). Build will run." - fi - fi - - version="" - if [ "${should_build}" = "true" ]; then - if printf '%s' "${source_git_ref}" | grep -Eq '^v[0-9]+(\.[0-9]+){1,2}([.-][0-9A-Za-z.-]+)?$'; then - version="${source_git_ref#v}" - echo "Resolved version directly from source tag: ${source_git_ref}" - else - workdir="$(mktemp -d)" - repo_dir="${workdir}/AstrBot" - git init "${repo_dir}" - git -C "${repo_dir}" remote add origin "${source_git_url}" - git -C "${repo_dir}" fetch --depth 1 origin "${source_git_ref}" - git -C "${repo_dir}" checkout --detach FETCH_HEAD - version="$(python3 scripts/ci/read-project-version.py "${repo_dir}/pyproject.toml")" - fi - else - version="${source_git_ref#v}" - if [ -z "${version}" ] || [ "${version}" = "${source_git_ref}" ]; then - version="unknown" - fi - fi - - if [ "${build_mode}" = "nightly" ] && [ "${should_build}" = "true" ]; then - nightly_date="$(date -u +%Y%m%d)" - short_sha="$(printf '%s' "${source_git_ref}" | cut -c1-8)" - version="${version}-nightly.${nightly_date}.${short_sha}" - release_tag="v${version}" - release_name="AstrBot Desktop v${version}" - release_prerelease="true" - elif [ "${publish_release}" = "true" ] && [ "${should_build}" = "true" ]; then - release_tag="v${version}" - release_name="AstrBot Desktop v${version}" - release_prerelease="false" - fi + run: bash scripts/ci/resolve-build-context.sh - { - echo "source_git_url=${source_git_url}" - echo "source_git_ref=${source_git_ref}" - echo "astrbot_version=${version}" - echo "should_build=${should_build}" - echo "build_mode=${build_mode}" - echo "publish_release=${publish_release}" - echo "release_tag=${release_tag}" - echo "release_name=${release_name}" - echo "release_prerelease=${release_prerelease}" - } >> "${GITHUB_OUTPUT}" - echo "Resolved source: ${source_git_url}@${source_git_ref}" - echo "Resolved AstrBot version: ${version}" - echo "Build enabled: ${should_build}" - echo "Build mode: ${build_mode}" - echo "Publish release: ${publish_release}" - echo "Release tag: ${release_tag:-}" - echo "Release prerelease: ${release_prerelease}" sync_repo_version: name: Sync Repository Version diff --git a/scripts/ci/resolve-build-context.sh b/scripts/ci/resolve-build-context.sh new file mode 100755 index 00000000..4f68f110 --- /dev/null +++ b/scripts/ci/resolve-build-context.sh @@ -0,0 +1,259 @@ +#!/usr/bin/env bash + +set -euo pipefail + +DEFAULT_NIGHTLY_UTC_HOUR='3' +DEFAULT_LS_REMOTE_RETRY_ATTEMPTS='3' +DEFAULT_LS_REMOTE_RETRY_SLEEP_SECONDS='2' + +is_transient_git_error() { + local message="$1" + printf '%s' "${message}" | grep -Eiq \ + '(Could not resolve host|Failed to connect|Connection (timed out|reset|refused)|Operation timed out|Temporary failure|TLS|SSL|HTTP [0-9]*5[0-9]{2}|The requested URL returned error: 5[0-9]{2}|network is unreachable)' +} + +sanitize_positive_int() { + local raw="$1" + local fallback="$2" + local max_value="$3" + case "${raw}" in + ''|*[!0-9]*) printf '%s\n' "${fallback}" ;; + *) + if [ "${raw}" -lt 1 ] 2>/dev/null; then + printf '%s\n' "${fallback}" + elif [ "${raw}" -gt "${max_value}" ] 2>/dev/null; then + printf '%s\n' "${max_value}" + else + printf '%s\n' "${raw}" + fi + ;; + esac +} + +git_ls_remote_with_retry() { + local source_url="$1" + local source_ref="$2" + local label="$3" + local attempts="$4" + local sleep_seconds="$5" + + local attempt=1 + local output="" + local error_class="" + + while [ "${attempt}" -le "${attempts}" ]; do + if output="$(git ls-remote "${source_url}" "${source_ref}" 2>&1)"; then + printf '%s\n' "${output}" + return 0 + fi + + if is_transient_git_error "${output}"; then + error_class="transient-network" + else + error_class="non-transient" + fi + echo "::warning::git ls-remote failed (${label}) attempt ${attempt}/${attempts}, class=${error_class}: ${output}" + + if [ "${error_class}" != "transient-network" ]; then + break + fi + if [ "${attempt}" -lt "${attempts}" ]; then + sleep "${sleep_seconds}" + fi + attempt=$((attempt + 1)) + done + + echo "::error::Unable to resolve ${label} from ${source_url} after ${attempt} attempt(s)." + return 1 +} + +source_git_url="${ASTRBOT_SOURCE_GIT_URL}" +source_git_ref="${ASTRBOT_SOURCE_GIT_REF}" +nightly_source_git_ref="${ASTRBOT_NIGHTLY_SOURCE_GIT_REF:-master}" +nightly_utc_hour="${ASTRBOT_NIGHTLY_UTC_HOUR:-${DEFAULT_NIGHTLY_UTC_HOUR}}" +requested_build_mode="$(printf '%s' "${WORKFLOW_BUILD_MODE:-auto}" | tr '[:upper:]' '[:lower:]')" +should_build="true" +build_mode="manual" +publish_release="false" +release_tag="" +release_name="" +release_prerelease="false" + +case "${requested_build_mode}" in + auto|tag-poll|nightly) ;; + *) + echo "::error::invalid build_mode input '${requested_build_mode}'; expected one of: auto, tag-poll, nightly." + exit 1 + ;; +esac + +case "${nightly_utc_hour}" in + '') + nightly_utc_hour="${DEFAULT_NIGHTLY_UTC_HOUR}" + ;; + *[!0-9]*) + echo "WARN: non-numeric ASTRBOT_NIGHTLY_UTC_HOUR=${nightly_utc_hour}, fallback to ${DEFAULT_NIGHTLY_UTC_HOUR}." + nightly_utc_hour="${DEFAULT_NIGHTLY_UTC_HOUR}" + ;; +esac +if [ "${nightly_utc_hour}" -gt 23 ] 2>/dev/null; then + echo "WARN: invalid ASTRBOT_NIGHTLY_UTC_HOUR=${nightly_utc_hour}, fallback to ${DEFAULT_NIGHTLY_UTC_HOUR}." + nightly_utc_hour="${DEFAULT_NIGHTLY_UTC_HOUR}" +fi +nightly_utc_hour_padded="$(printf '%02d' "${nightly_utc_hour}")" +echo "Nightly UTC hour normalized to ${nightly_utc_hour_padded} (raw='${ASTRBOT_NIGHTLY_UTC_HOUR:-}')." + +if [ "${GITHUB_EVENT_NAME}" = "workflow_dispatch" ]; then + if [ -n "${WORKFLOW_SOURCE_GIT_URL:-}" ]; then + source_git_url="${WORKFLOW_SOURCE_GIT_URL}" + fi + if [ -n "${WORKFLOW_SOURCE_GIT_REF:-}" ]; then + source_git_ref="${WORKFLOW_SOURCE_GIT_REF}" + fi + if [ "${WORKFLOW_PUBLISH_RELEASE:-true}" = "true" ]; then + publish_release="true" + fi + if [ "${requested_build_mode}" = "tag-poll" ]; then + build_mode="tag-poll" + elif [ "${requested_build_mode}" = "nightly" ]; then + build_mode="nightly" + else + echo "workflow_dispatch build_mode=auto: using manual mode." + fi +fi + +if [ "${GITHUB_EVENT_NAME}" = "schedule" ]; then + current_utc_hour="$(date -u +%H)" + if [ "${current_utc_hour}" = "${nightly_utc_hour_padded}" ]; then + build_mode="nightly" + publish_release="true" + echo "Scheduled nightly run at UTC hour ${current_utc_hour}." + else + build_mode="tag-poll" + publish_release="true" + echo "Scheduled tag polling run at UTC hour ${current_utc_hour}." + fi +fi + +retry_attempts="$( + sanitize_positive_int \ + "${ASTRBOT_LS_REMOTE_RETRY_ATTEMPTS:-${DEFAULT_LS_REMOTE_RETRY_ATTEMPTS}}" \ + "${DEFAULT_LS_REMOTE_RETRY_ATTEMPTS}" \ + "10" +)" +retry_sleep_seconds="$( + sanitize_positive_int \ + "${ASTRBOT_LS_REMOTE_RETRY_SLEEP_SECONDS:-${DEFAULT_LS_REMOTE_RETRY_SLEEP_SECONDS}}" \ + "${DEFAULT_LS_REMOTE_RETRY_SLEEP_SECONDS}" \ + "60" +)" + +if [ "${build_mode}" = "nightly" ]; then + nightly_branch="${nightly_source_git_ref}" + if [ -z "${nightly_branch}" ]; then + echo "ASTRBOT_NIGHTLY_SOURCE_GIT_REF must be set to a branch name or refs/heads/ for nightly builds." >&2 + exit 1 + fi + case "${nightly_branch}" in + refs/heads/*) + echo "Normalizing nightly source ref '${nightly_branch}' to branch name for git ls-remote." + nightly_branch="${nightly_branch#refs/heads/}" + ;; + refs/*) + echo "ASTRBOT_NIGHTLY_SOURCE_GIT_REF must be a branch name or refs/heads/; got '${nightly_branch}'." >&2 + exit 1 + ;; + esac + + nightly_remote_output="$( + git_ls_remote_with_retry \ + "${source_git_url}" \ + "refs/heads/${nightly_branch}" \ + "nightly branch refs/heads/${nightly_branch}" \ + "${retry_attempts}" \ + "${retry_sleep_seconds}" + )" + source_git_ref="$(printf '%s\n' "${nightly_remote_output}" | awk 'NR==1{print $1}')" + if [ -z "${source_git_ref}" ]; then + echo "Unable to resolve latest commit from ${source_git_url} refs/heads/${nightly_branch} (configured ASTRBOT_NIGHTLY_SOURCE_GIT_REF='${nightly_source_git_ref}')." >&2 + exit 1 + fi + echo "Nightly source resolved from ${nightly_branch}@${source_git_ref} (configured ASTRBOT_NIGHTLY_SOURCE_GIT_REF='${nightly_source_git_ref}')." +elif [ "${build_mode}" = "tag-poll" ]; then + latest_tag="$(git ls-remote --tags --refs "${source_git_url}" \ + | awk '{print $2}' \ + | sed 's#refs/tags/##' \ + | sort -V \ + | tail -n 1)" + if [ -z "${latest_tag}" ]; then + echo "Unable to resolve latest tag from ${source_git_url}" >&2 + exit 1 + fi + source_git_ref="${latest_tag}" + echo "Tag polling run detected latest upstream tag: ${source_git_ref}" + + http_status="$(curl -sS -o /dev/null -w '%{http_code}' \ + -H "Authorization: Bearer ${GITHUB_TOKEN}" \ + -H "Accept: application/vnd.github+json" \ + "https://api.github.com/repos/${GH_REPOSITORY}/releases/tags/${source_git_ref}")" + if [ "${http_status}" = "200" ]; then + should_build="false" + echo "Release ${source_git_ref} already exists. Tag unchanged, skipping build." + else + echo "Release ${source_git_ref} not found (HTTP ${http_status}). Build will run." + fi +fi + +version="" +if [ "${should_build}" = "true" ]; then + if printf '%s' "${source_git_ref}" | grep -Eq '^v[0-9]+(\.[0-9]+){1,2}([.-][0-9A-Za-z.-]+)?$'; then + version="${source_git_ref#v}" + echo "Resolved version directly from source tag: ${source_git_ref}" + else + workdir="$(mktemp -d)" + repo_dir="${workdir}/AstrBot" + git init "${repo_dir}" + git -C "${repo_dir}" remote add origin "${source_git_url}" + git -C "${repo_dir}" fetch --depth 1 origin "${source_git_ref}" + git -C "${repo_dir}" checkout --detach FETCH_HEAD + version="$(python3 scripts/ci/read-project-version.py "${repo_dir}/pyproject.toml")" + fi +else + version="${source_git_ref#v}" + if [ -z "${version}" ] || [ "${version}" = "${source_git_ref}" ]; then + version="unknown" + fi +fi + +if [ "${build_mode}" = "nightly" ] && [ "${should_build}" = "true" ]; then + nightly_date="$(date -u +%Y%m%d)" + short_sha="$(printf '%s' "${source_git_ref}" | cut -c1-8)" + version="${version}-nightly.${nightly_date}.${short_sha}" + release_tag="v${version}" + release_name="AstrBot Desktop v${version}" + release_prerelease="true" +elif [ "${publish_release}" = "true" ] && [ "${should_build}" = "true" ]; then + release_tag="v${version}" + release_name="AstrBot Desktop v${version}" + release_prerelease="false" +fi + +{ + echo "source_git_url=${source_git_url}" + echo "source_git_ref=${source_git_ref}" + echo "astrbot_version=${version}" + echo "should_build=${should_build}" + echo "build_mode=${build_mode}" + echo "publish_release=${publish_release}" + echo "release_tag=${release_tag}" + echo "release_name=${release_name}" + echo "release_prerelease=${release_prerelease}" +} >> "${GITHUB_OUTPUT}" + +echo "Resolved source: ${source_git_url}@${source_git_ref}" +echo "Resolved AstrBot version: ${version}" +echo "Build enabled: ${should_build}" +echo "Build mode: ${build_mode}" +echo "Publish release: ${publish_release}" +echo "Release tag: ${release_tag:-}" +echo "Release prerelease: ${release_prerelease}" From 9a365f052c2706a89d2fd02260e6d795d31baae3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=82=B9=E6=B0=B8=E8=B5=AB?= <1259085392@qq.com> Date: Sat, 21 Feb 2026 11:16:31 +0900 Subject: [PATCH 9/9] ci harden build-context retries and cleanup temp dirs --- .github/workflows/build-desktop-tauri.yml | 2 +- scripts/ci/resolve-build-context.sh | 31 +++++++++++++++++++++-- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-desktop-tauri.yml b/.github/workflows/build-desktop-tauri.yml index a9cf495a..12b0e499 100644 --- a/.github/workflows/build-desktop-tauri.yml +++ b/.github/workflows/build-desktop-tauri.yml @@ -17,7 +17,7 @@ on: type: boolean default: true build_mode: - description: Build mode (`auto` | `tag-poll` | `nightly`); for workflow_dispatch, `auto` behaves as `manual` + description: Build mode (`auto` | `tag-poll` | `nightly`); for workflow_dispatch, `auto` behaves as `manual` and disables publish_release required: false type: choice default: auto diff --git a/scripts/ci/resolve-build-context.sh b/scripts/ci/resolve-build-context.sh index 4f68f110..afb478aa 100755 --- a/scripts/ci/resolve-build-context.sh +++ b/scripts/ci/resolve-build-context.sh @@ -6,6 +6,16 @@ DEFAULT_NIGHTLY_UTC_HOUR='3' DEFAULT_LS_REMOTE_RETRY_ATTEMPTS='3' DEFAULT_LS_REMOTE_RETRY_SLEEP_SECONDS='2' +temp_dirs=() +cleanup_temp_dirs() { + local dir + for dir in "${temp_dirs[@]-}"; do + [ -n "${dir}" ] || continue + rm -rf "${dir}" 2>/dev/null || true + done +} +trap cleanup_temp_dirs EXIT + is_transient_git_error() { local message="$1" printf '%s' "${message}" | grep -Eiq \ @@ -63,7 +73,11 @@ git_ls_remote_with_retry() { attempt=$((attempt + 1)) done - echo "::error::Unable to resolve ${label} from ${source_url} after ${attempt} attempt(s)." + local final_attempt="${attempt}" + if [ "${final_attempt}" -gt "${attempts}" ]; then + final_attempt="${attempts}" + fi + echo "::error::Unable to resolve ${label} from ${source_url} after ${final_attempt} attempt(s)." return 1 } @@ -119,6 +133,10 @@ if [ "${GITHUB_EVENT_NAME}" = "workflow_dispatch" ]; then build_mode="nightly" else echo "workflow_dispatch build_mode=auto: using manual mode." + if [ "${publish_release}" = "true" ]; then + echo "::warning::workflow_dispatch with build_mode=auto resolves to manual mode; publish_release=true is normalized to false to avoid unintended release publishing." + publish_release="false" + fi fi fi @@ -180,7 +198,15 @@ if [ "${build_mode}" = "nightly" ]; then fi echo "Nightly source resolved from ${nightly_branch}@${source_git_ref} (configured ASTRBOT_NIGHTLY_SOURCE_GIT_REF='${nightly_source_git_ref}')." elif [ "${build_mode}" = "tag-poll" ]; then - latest_tag="$(git ls-remote --tags --refs "${source_git_url}" \ + tag_remote_output="$( + git_ls_remote_with_retry \ + "${source_git_url}" \ + "refs/tags/*" \ + "upstream tags refs/tags/*" \ + "${retry_attempts}" \ + "${retry_sleep_seconds}" + )" + latest_tag="$(printf '%s\n' "${tag_remote_output}" \ | awk '{print $2}' \ | sed 's#refs/tags/##' \ | sort -V \ @@ -211,6 +237,7 @@ if [ "${should_build}" = "true" ]; then echo "Resolved version directly from source tag: ${source_git_ref}" else workdir="$(mktemp -d)" + temp_dirs+=("${workdir}") repo_dir="${workdir}/AstrBot" git init "${repo_dir}" git -C "${repo_dir}" remote add origin "${source_git_url}"