name: DSH Upstream Update on: schedule: - cron: "0 4 * * *" workflow_dispatch: concurrency: group: dsh-upstream-update cancel-in-progress: false permissions: contents: read env: BASE_BRANCH: dev CANDIDATE_BRANCH: automation/dsh-upstream-candidate DSH_PACKAGE: "@deepseek-ai/dsh" SUPPORTED_TARGET: release/supported-target.json ENVIRONMENT_DEFINITION: container/environment/definition.json jobs: discover: name: Discover and propose upstream DSH runs-on: ubuntu-latest permissions: contents: write pull-requests: write outputs: changed: ${{ steps.candidate.outputs.changed }} current: ${{ steps.candidate.outputs.current }} upstream: ${{ steps.candidate.outputs.upstream }} environment: ${{ steps.candidate.outputs.environment }} pull_request_url: ${{ steps.propose.outputs.pull_request_url }} pull_request_number: ${{ steps.propose.outputs.pull_request_number }} head_sha: ${{ steps.propose.outputs.head_sha }} steps: - name: Checkout protected branch uses: actions/checkout@v6 with: ref: ${{ env.BASE_BRANCH }} fetch-depth: 0 - name: Set up Node.js uses: actions/setup-node@v6 with: node-version: 24 - name: Resolve latest official DSH id: upstream run: | npm view "${DSH_PACKAGE}@latest" version --json > "$RUNNER_TEMP/dsh-version.json" version="$(jq -er 'if type == "string" then . else error("expected one version") end' "$RUNNER_TEMP/dsh-version.json")" printf 'version=%s\n' "$version" >> "$GITHUB_OUTPUT" - name: Advance candidate Supported Target id: candidate env: GH_TOKEN: ${{ github.token }} UPSTREAM_VERSION: ${{ steps.upstream.outputs.version }} run: | base_sha="$(git rev-parse HEAD)" current="$(jq -er '.latestSupportedDsh' "$SUPPORTED_TARGET")" trusted_platform="$RUNNER_TEMP/trusted-platform" mkdir -p "$trusted_platform/tools" cp -R container/platform/lib "$trusted_platform/lib" cp container/platform/tools/supported-target.mjs "$trusted_platform/tools/supported-target.mjs" git config user.name "github-actions[bot]" git config user.email "41898282+github-actions[bot]@users.noreply.github.com" candidate_remote_sha="$(git ls-remote --heads origin "$CANDIDATE_BRANCH" | cut -f 1)" git switch --create "$CANDIDATE_BRANCH" "$base_sha" result="$(node "$trusted_platform/tools/supported-target.mjs" advance \ "$SUPPORTED_TARGET" "$ENVIRONMENT_DEFINITION" "$UPSTREAM_VERSION")" changed="$(jq -r 'if (.changed | type) == "boolean" then .changed else error("expected boolean changed") end' <<<"$result")" environment="$(jq -er '.target.environment' <<<"$result")" { printf 'changed=%s\n' "$changed" printf 'current=%s\n' "$current" printf 'upstream=%s\n' "$UPSTREAM_VERSION" printf 'environment=%s\n' "$environment" printf 'candidate_remote_sha=%s\n' "$candidate_remote_sha" } >> "$GITHUB_OUTPUT" # shellcheck disable=SC2016 { printf '### DSH upstream discovery\n\n' printf -- '- Latest Supported: `%s`\n' "$current" printf -- '- Latest Official: `%s`\n' "$UPSTREAM_VERSION" printf -- '- Environment: `%s`\n' "$environment" printf -- '- Candidate required: `%s`\n' "$changed" } >> "$GITHUB_STEP_SUMMARY" - name: Create or update candidate pull request id: propose if: steps.candidate.outputs.changed == 'true' env: GH_TOKEN: ${{ github.token }} CURRENT_VERSION: ${{ steps.candidate.outputs.current }} UPSTREAM_VERSION: ${{ steps.candidate.outputs.upstream }} ENVIRONMENT_VERSION: ${{ steps.candidate.outputs.environment }} run: | git add -- "$SUPPORTED_TARGET" git commit -m "chore(dsh): validate ${UPSTREAM_VERSION}" candidate_remote_sha="${{ steps.candidate.outputs.candidate_remote_sha }}" if [ -n "$candidate_remote_sha" ]; then git push --force-with-lease="refs/heads/$CANDIDATE_BRANCH:$candidate_remote_sha" \ origin "HEAD:refs/heads/$CANDIDATE_BRANCH" else git push origin "HEAD:refs/heads/$CANDIDATE_BRANCH" fi body="$RUNNER_TEMP/dsh-candidate-pr.md" # shellcheck disable=SC2016 { printf '## DSH candidate validation\n\n' printf '| State | Version |\n|---|---|\n' printf '| Latest Supported | `%s` |\n' "$CURRENT_VERSION" printf '| Latest Official candidate | `%s` |\n' "$UPSTREAM_VERSION" printf '| Current Environment | `%s` |\n\n' "$ENVIRONMENT_VERSION" printf 'This PR changes only the candidate Supported Target. Compatibility CI validates the new DSH with the current Environment. Merge into dev records the validated candidate; promotion from dev to main remains the production publication gate.\n' } > "$body" pr_number="$(gh pr list --state open --head "$CANDIDATE_BRANCH" --json number --jq '.[0].number // empty')" if [ -z "$pr_number" ]; then pr_url="$(gh pr create \ --base "$BASE_BRANCH" \ --head "$CANDIDATE_BRANCH" \ --title "chore(dsh): validate ${UPSTREAM_VERSION}" \ --body-file "$body")" pr_number="$(gh pr view "$pr_url" --json number --jq .number)" else gh pr edit "$pr_number" \ --base "$BASE_BRANCH" \ --title "chore(dsh): validate ${UPSTREAM_VERSION}" \ --body-file "$body" pr_url="$(gh pr view "$pr_number" --json url --jq .url)" fi { printf 'pull_request_url=%s\n' "$pr_url" printf 'pull_request_number=%s\n' "$pr_number" printf 'head_sha=%s\n' "$(git rev-parse HEAD)" } >> "$GITHUB_OUTPUT" printf 'Candidate PR: %s\n' "$pr_url" >> "$GITHUB_STEP_SUMMARY" validate-candidate: name: Validate candidate Runtime needs: discover if: needs.discover.outputs.changed == 'true' permissions: contents: read uses: ./.github/workflows/dsh-candidate-validation.yml with: ref: ${{ needs.discover.outputs.head_sha }} report-validation: name: Report candidate validation needs: [discover, validate-candidate] if: always() && needs.discover.outputs.changed == 'true' runs-on: ubuntu-latest permissions: contents: read pull-requests: write statuses: write steps: - name: Publish commit status and PR report env: GH_TOKEN: ${{ github.token }} HEAD_SHA: ${{ needs.discover.outputs.head_sha }} PR_NUMBER: ${{ needs.discover.outputs.pull_request_number }} VALIDATION_RESULT: ${{ needs.validate-candidate.result }} UPSTREAM_VERSION: ${{ needs.discover.outputs.upstream }} ENVIRONMENT_VERSION: ${{ needs.discover.outputs.environment }} run: | if [ "$VALIDATION_RESULT" = success ]; then state=success label=passed description="Candidate Runtime validation passed" else state=failure label=failed description="Candidate Runtime validation failed" fi run_url="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}" gh api --method POST "/repos/${GITHUB_REPOSITORY}/statuses/${HEAD_SHA}" \ -f state="$state" \ -f context='DSH candidate Runtime' \ -f description="$description" \ -f target_url="$run_url" >/dev/null gh pr comment "$PR_NUMBER" \ --repo "$GITHUB_REPOSITORY" \ --body "DSH \`${UPSTREAM_VERSION}\` with Environment \`${ENVIRONMENT_VERSION}\` **${label}** compatibility validation. [Open workflow run](${run_url})." printf 'Candidate validation %s: %s\n' "$label" "$run_url" >> "$GITHUB_STEP_SUMMARY" notify-discovered: name: Notify upstream discovery needs: discover if: needs.discover.outputs.changed == 'true' uses: yjrszcq/github-workflows/.github/workflows/gotify-notify.yml@c4c7fe9e17854cd4962913ac2792513eab0be988 with: title: 发现 DSH 上游新版本 ${{ needs.discover.outputs.upstream }} message: >- 当前支持版本:${{ needs.discover.outputs.current }};上游候选版本:${{ needs.discover.outputs.upstream }}。 候选 Environment:${{ needs.discover.outputs.environment }}。 候选 PR:${{ needs.discover.outputs.pull_request_url }} priority: 6 secrets: gotify_url: ${{ secrets.GOTIFY_URL }} gotify_token: ${{ secrets.GOTIFY_TOKEN }} notify-result: name: Notify upstream check result needs: [discover, validate-candidate] if: >- always() && (needs.discover.result == 'failure' || needs.discover.outputs.changed == 'true') uses: yjrszcq/github-workflows/.github/workflows/gotify-notify.yml@c4c7fe9e17854cd4962913ac2792513eab0be988 with: title: >- ${{ needs.discover.result == 'failure' && 'DSH 上游检查失败' || (needs.validate-candidate.result == 'success' && format('DSH {0} 候选版本验证通过', needs.discover.outputs.upstream) || format('DSH {0} 候选版本验证失败', needs.discover.outputs.upstream)) }} message: >- ${{ needs.discover.result == 'failure' && format('获取或生成 DSH 上游候选版本失败。工作流:{0}/{1}/actions/runs/{2}', github.server_url, github.repository, github.run_id) || (needs.validate-candidate.result == 'success' && format('DSH {0} 已通过 Environment {1} 兼容性验证。请审核并合并:{2}', needs.discover.outputs.upstream, needs.discover.outputs.environment, needs.discover.outputs.pull_request_url) || format('DSH {0} 未通过 Environment {1} 兼容性验证,需要适配 Environment。工作流:{2}/{3}/actions/runs/{4}', needs.discover.outputs.upstream, needs.discover.outputs.environment, github.server_url, github.repository, github.run_id)) }} priority: ${{ (needs.discover.result == 'failure' || needs.validate-candidate.result != 'success') && 8 || 7 }} secrets: gotify_url: ${{ secrets.GOTIFY_URL }} gotify_token: ${{ secrets.GOTIFY_TOKEN }}