Mermaid Version Watch #189
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Mermaid Version Watch | |
| on: | |
| workflow_dispatch: | |
| schedule: | |
| - cron: "17 */6 * * *" | |
| permissions: | |
| contents: write | |
| issues: write | |
| pull-requests: write | |
| concurrency: | |
| group: ${{ github.workflow }} | |
| cancel-in-progress: false | |
| jobs: | |
| watch: | |
| name: Watch Mermaid releases | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Fetch Sources | |
| uses: actions/checkout@v7 | |
| with: | |
| fetch-depth: 0 | |
| - name: Setup Node | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: 24 | |
| - name: Compare bundled runtime with upstream | |
| id: mermaid | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| ruby <<'RUBY' | |
| require "json" | |
| runtime_path = "src/main/resources/mermaid/mermaid.min.js" | |
| runtime = File.read(runtime_path) | |
| versions = runtime.scan(/version:"(\d+\.\d+\.\d+)"/).flatten.uniq | |
| abort("Missing Mermaid version in #{runtime_path}") if versions.empty? | |
| abort("Ambiguous Mermaid versions in #{runtime_path}: #{versions.join(", ")}") if versions.length != 1 | |
| current_version = versions.first | |
| releases = [] | |
| page = 1 | |
| loop do | |
| json = `gh api "repos/mermaid-js/mermaid/releases?per_page=100&page=#{page}"` | |
| abort("Failed to fetch Mermaid releases page #{page}") unless $?.success? | |
| page_releases = JSON.parse(json) | |
| break if page_releases.empty? | |
| releases.concat(page_releases) | |
| page += 1 | |
| end | |
| candidates = releases.filter_map do |release| | |
| next if release["draft"] || release["prerelease"] | |
| match = release["tag_name"].to_s.match(/\Amermaid@(\d+\.\d+\.\d+)\z/) | |
| next unless match | |
| release.merge("version" => match[1]) | |
| end | |
| abort("No stable mermaid@x.y.z releases found") if candidates.empty? | |
| latest = candidates.max_by { |release| release["version"].split(".").map(&:to_i) } | |
| latest_version = latest.fetch("version") | |
| update_available = (latest_version.split(".").map(&:to_i) <=> current_version.split(".").map(&:to_i)).positive? | |
| release_body_path = File.join(ENV.fetch("RUNNER_TEMP"), "mermaid-release-body.md") | |
| File.write(release_body_path, latest["body"].to_s) | |
| File.open(ENV.fetch("GITHUB_OUTPUT"), "a") do |output| | |
| output.puts("current_version=#{current_version}") | |
| output.puts("latest_version=#{latest_version}") | |
| output.puts("latest_tag=#{latest.fetch("tag_name")}") | |
| output.puts("latest_url=#{latest.fetch("html_url")}") | |
| output.puts("release_body_path=#{release_body_path}") | |
| output.puts("update_available=#{update_available}") | |
| end | |
| File.open(ENV.fetch("GITHUB_STEP_SUMMARY"), "a") do |summary| | |
| summary.puts("### Mermaid Version Watch") | |
| summary.puts | |
| summary.puts("- Bundled runtime: `#{current_version}`") | |
| summary.puts("- Latest upstream: [`#{latest.fetch("tag_name")}`](#{latest.fetch("html_url")})") | |
| summary.puts("- Update available: `#{update_available}`") | |
| end | |
| RUBY | |
| - name: Ensure sync labels | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| gh label create upstream-mermaid \ | |
| --description "Tracks bundled Mermaid runtime updates" \ | |
| --color ff3670 \ | |
| --force \ | |
| || true | |
| gh label create dependencies \ | |
| --description "Pull requests that update a dependency file" \ | |
| --color 0366d6 \ | |
| --force \ | |
| || true | |
| gh label create github_actions \ | |
| --description "Pull requests that update GitHub Actions code" \ | |
| --color 000000 \ | |
| --force \ | |
| || true | |
| gh label create automated-pr \ | |
| --description "Pull requests opened by repository automation" \ | |
| --color ededed \ | |
| --force \ | |
| || true | |
| - name: Create or update sync issue | |
| id: issue | |
| if: ${{ steps.mermaid.outputs.update_available == 'true' }} | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| CURRENT_VERSION: ${{ steps.mermaid.outputs.current_version }} | |
| LATEST_VERSION: ${{ steps.mermaid.outputs.latest_version }} | |
| LATEST_TAG: ${{ steps.mermaid.outputs.latest_tag }} | |
| LATEST_URL: ${{ steps.mermaid.outputs.latest_url }} | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| title="chore: sync Mermaid runtime to ${LATEST_VERSION}" | |
| body="$(mktemp)" | |
| cat > "$body" <<BODY | |
| ## Summary | |
| A newer stable Mermaid runtime is available. | |
| - Bundled version: \`${CURRENT_VERSION}\` | |
| - Latest upstream version: [\`${LATEST_TAG}\`](${LATEST_URL}) | |
| - Bundled file: \`src/main/resources/mermaid/mermaid.min.js\` | |
| ## Automation | |
| This workflow will open or update a linked sync pull request. | |
| ## Checklist | |
| - [ ] Update the bundled Mermaid runtime. | |
| - [ ] Update the Mermaid version badges in \`README.md\` and \`README_zh.md\`. | |
| - [ ] Update \`CHANGELOG.md\` and \`CHANGELOG_zh.md\`. | |
| - [ ] Confirm example Mermaid diagrams render without preview errors. | |
| BODY | |
| issue_number="$( | |
| gh issue list \ | |
| --state open \ | |
| --label upstream-mermaid \ | |
| --json number \ | |
| --jq '.[0].number // ""' | |
| )" | |
| if [[ -n "$issue_number" ]]; then | |
| gh issue edit "$issue_number" \ | |
| --title "$title" \ | |
| --body-file "$body" | |
| issue_url="$(gh issue view "$issue_number" --json url --jq '.url')" | |
| else | |
| issue_url="$(gh issue create \ | |
| --title "$title" \ | |
| --body-file "$body" \ | |
| --label upstream-mermaid)" | |
| issue_number="${issue_url##*/}" | |
| fi | |
| { | |
| echo "issue_number=$issue_number" | |
| echo "issue_url=$issue_url" | |
| } >> "$GITHUB_OUTPUT" | |
| - name: Require sync token | |
| if: ${{ steps.mermaid.outputs.update_available == 'true' }} | |
| env: | |
| MERMAID_SYNC_TOKEN: ${{ secrets.MERMAID_SYNC_TOKEN }} | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| if [[ -z "${MERMAID_SYNC_TOKEN}" ]]; then | |
| echo "::error::MERMAID_SYNC_TOKEN is required to push the sync branch and create a PR that triggers CI." | |
| exit 1 | |
| fi | |
| - name: Prepare sync branch | |
| id: sync | |
| if: ${{ steps.mermaid.outputs.update_available == 'true' }} | |
| env: | |
| MERMAID_SYNC_TOKEN: ${{ secrets.MERMAID_SYNC_TOKEN }} | |
| LATEST_VERSION: ${{ steps.mermaid.outputs.latest_version }} | |
| LATEST_TAG: ${{ steps.mermaid.outputs.latest_tag }} | |
| LATEST_URL: ${{ steps.mermaid.outputs.latest_url }} | |
| RELEASE_BODY_PATH: ${{ steps.mermaid.outputs.release_body_path }} | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| branch="ci/sync-mermaid-runtime-${LATEST_VERSION}" | |
| git config user.name "github-actions[bot]" | |
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | |
| git remote set-url origin "https://x-access-token:${MERMAID_SYNC_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" | |
| git fetch origin main | |
| git switch -C "$branch" origin/main | |
| package_dir="$(mktemp -d)" | |
| tarball_name="$(npm pack "mermaid@${LATEST_VERSION}" --pack-destination "$package_dir" --silent)" | |
| tar -xzf "$package_dir/$tarball_name" -C "$package_dir" | |
| cp "$package_dir/package/dist/mermaid.min.js" src/main/resources/mermaid/mermaid.min.js | |
| ruby .github/scripts/update-mermaid-runtime.rb "$LATEST_VERSION" "$LATEST_TAG" "$LATEST_URL" | |
| git add \ | |
| src/main/resources/mermaid/mermaid.min.js \ | |
| README.md \ | |
| README_zh.md \ | |
| CHANGELOG.md \ | |
| CHANGELOG_zh.md | |
| if git diff --cached --quiet; then | |
| echo "No runtime sync changes detected." | |
| echo "changes=false" >> "$GITHUB_OUTPUT" | |
| echo "branch=$branch" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| commit_message="$(mktemp)" | |
| { | |
| echo "chore: sync Mermaid runtime to ${LATEST_VERSION}" | |
| echo | |
| echo "Upstream release: ${LATEST_URL}" | |
| echo | |
| echo "Release notes:" | |
| cat "$RELEASE_BODY_PATH" | |
| echo | |
| echo "Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>" | |
| echo "Co-authored-by: give me a 98K <240642031+inhuman-0@users.noreply.github.com>" | |
| } > "$commit_message" | |
| git commit \ | |
| --author="ark-65 <25193106+ark-65@users.noreply.github.com>" \ | |
| -F "$commit_message" | |
| git push --force-with-lease --set-upstream origin "$branch" | |
| { | |
| echo "changes=true" | |
| echo "branch=$branch" | |
| } >> "$GITHUB_OUTPUT" | |
| - name: Create or update sync pull request | |
| id: pull_request | |
| if: ${{ steps.sync.outputs.changes == 'true' }} | |
| env: | |
| GH_TOKEN: ${{ secrets.MERMAID_SYNC_TOKEN }} | |
| CURRENT_VERSION: ${{ steps.mermaid.outputs.current_version }} | |
| LATEST_VERSION: ${{ steps.mermaid.outputs.latest_version }} | |
| LATEST_TAG: ${{ steps.mermaid.outputs.latest_tag }} | |
| LATEST_URL: ${{ steps.mermaid.outputs.latest_url }} | |
| RELEASE_BODY_PATH: ${{ steps.mermaid.outputs.release_body_path }} | |
| ISSUE_NUMBER: ${{ steps.issue.outputs.issue_number }} | |
| SYNC_BRANCH: ${{ steps.sync.outputs.branch }} | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| title="chore: sync Mermaid runtime to ${LATEST_VERSION}" | |
| body="$(mktemp)" | |
| cat > "$body" <<BODY | |
| Closes #${ISSUE_NUMBER} | |
| ## Summary | |
| - Update the bundled Mermaid runtime from \`${CURRENT_VERSION}\` to \`${LATEST_VERSION}\`. | |
| - Update README badges and bilingual changelogs for the bundled runtime. | |
| - Keep the sync issue associated through GitHub Development. | |
| ## Upstream | |
| [${LATEST_TAG}](${LATEST_URL}) | |
| ## Labels | |
| - \`upstream-mermaid\` | |
| - \`dependencies\` | |
| - \`github_actions\` | |
| - \`automated-pr\` | |
| ## Validation | |
| - GitHub CI will run Gradle checks and example Mermaid preview rendering. | |
| ## Upstream Release Notes | |
| BODY | |
| cat "$RELEASE_BODY_PATH" >> "$body" | |
| pr_number="$( | |
| gh pr list \ | |
| --head "$SYNC_BRANCH" \ | |
| --base main \ | |
| --state open \ | |
| --json number \ | |
| --jq '.[0].number // ""' | |
| )" | |
| if [[ -n "$pr_number" ]]; then | |
| gh pr edit "$pr_number" \ | |
| --title "$title" \ | |
| --body-file "$body" | |
| pr_url="$(gh pr view "$pr_number" --json url --jq '.url')" | |
| else | |
| pr_url="$(gh pr create \ | |
| --title "$title" \ | |
| --body-file "$body" \ | |
| --base main \ | |
| --head "$SYNC_BRANCH")" | |
| pr_number="${pr_url##*/}" | |
| fi | |
| gh pr edit "$pr_number" \ | |
| --add-label upstream-mermaid \ | |
| --add-label dependencies \ | |
| --add-label github_actions \ | |
| --add-label automated-pr | |
| { | |
| echo "pr_number=$pr_number" | |
| echo "pr_url=$pr_url" | |
| } >> "$GITHUB_OUTPUT" | |
| - name: Link issue to sync pull request | |
| if: ${{ steps.pull_request.outputs.pr_url != '' }} | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| CURRENT_VERSION: ${{ steps.mermaid.outputs.current_version }} | |
| LATEST_VERSION: ${{ steps.mermaid.outputs.latest_version }} | |
| LATEST_TAG: ${{ steps.mermaid.outputs.latest_tag }} | |
| LATEST_URL: ${{ steps.mermaid.outputs.latest_url }} | |
| ISSUE_NUMBER: ${{ steps.issue.outputs.issue_number }} | |
| PR_URL: ${{ steps.pull_request.outputs.pr_url }} | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| body="$(mktemp)" | |
| cat > "$body" <<BODY | |
| ## Summary | |
| A newer stable Mermaid runtime is available. | |
| - Bundled version: \`${CURRENT_VERSION}\` | |
| - Latest upstream version: [\`${LATEST_TAG}\`](${LATEST_URL}) | |
| - Bundled file: \`src/main/resources/mermaid/mermaid.min.js\` | |
| - Sync PR: ${PR_URL} | |
| ## Automation | |
| The sync PR includes \`Closes #${ISSUE_NUMBER}\`, so GitHub Development links this issue to the PR and closes it after merge. | |
| ## Checklist | |
| - [ ] Update the bundled Mermaid runtime. | |
| - [ ] Update the Mermaid version badges in \`README.md\` and \`README_zh.md\`. | |
| - [ ] Update \`CHANGELOG.md\` and \`CHANGELOG_zh.md\`. | |
| - [ ] Confirm example Mermaid diagrams render without preview errors. | |
| BODY | |
| gh issue edit "$ISSUE_NUMBER" --body-file "$body" | |
| - name: Close resolved sync issue | |
| if: ${{ steps.mermaid.outputs.update_available == 'false' }} | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| CURRENT_VERSION: ${{ steps.mermaid.outputs.current_version }} | |
| LATEST_VERSION: ${{ steps.mermaid.outputs.latest_version }} | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| issue_number="$( | |
| gh issue list \ | |
| --state open \ | |
| --label upstream-mermaid \ | |
| --json number \ | |
| --jq '.[0].number // ""' | |
| )" | |
| if [[ -n "$issue_number" ]]; then | |
| gh issue comment "$issue_number" \ | |
| --body "Bundled Mermaid runtime ${CURRENT_VERSION} is up to date with upstream ${LATEST_VERSION}. Closing this reminder." | |
| gh issue close "$issue_number" --reason completed | |
| fi |