nlopt Update Check #1
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: nlopt Update Check | |
| on: | |
| schedule: | |
| # 04:00 UTC daily | |
| - cron: "0 4 * * *" | |
| workflow_dispatch: | |
| concurrency: | |
| cancel-in-progress: false | |
| group: nlopt-update-check | |
| env: | |
| GH_TOKEN: ${{ secrets.NLOPT_UPDATE_PAT }} | |
| jobs: | |
| check-and-update: | |
| name: Check for new nlopt release and update PR | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| pull-requests: read | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| token: ${{ secrets.NLOPT_UPDATE_PAT }} | |
| fetch-depth: 0 | |
| - name: Configure git identity | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| - name: Check for a new nlopt release tag | |
| id: check | |
| run: | | |
| set -euo pipefail | |
| REPO_URL="https://github.com/stevengj/nlopt.git" | |
| current_sha=$(git rev-parse HEAD:extern/nlopt) | |
| latest_line=$(git ls-remote --tags "$REPO_URL" \ | |
| | awk '{ ref=$2; peeled=(ref ~ /\^\{\}$/); sub(/\^\{\}$/,"",ref); sub(/^refs\/tags\//,"",ref); | |
| if (ref ~ /^v[0-9]+\.[0-9]+\.[0-9]+$/) { if (!(ref in sha) || peeled) sha[ref]=$1 } } | |
| END { for (t in sha) print t, sha[t] }' \ | |
| | sort -V | tail -n1) | |
| latest_tag=$(cut -d' ' -f1 <<<"$latest_line") | |
| latest_sha=$(cut -d' ' -f2 <<<"$latest_line") | |
| if [[ -z "$latest_tag" ]]; then | |
| echo "::error::Could not determine the latest nlopt release tag from $REPO_URL" | |
| exit 1 | |
| fi | |
| echo "Currently pinned commit: $current_sha" | |
| echo "Latest upstream tag: $latest_tag ($latest_sha)" | |
| if [[ "$latest_sha" == "$current_sha" ]]; then | |
| echo "update_available=false" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "update_available=true" >> "$GITHUB_OUTPUT" | |
| echo "latest_tag=$latest_tag" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Find existing bump PR | |
| id: find-pr | |
| if: steps.check.outputs.update_available == 'true' | |
| run: | | |
| set -euo pipefail | |
| pr_number=$(gh pr list --head chore/bump-nlopt --state open --json number --jq '.[0].number // empty') | |
| echo "pr_number=$pr_number" >> "$GITHUB_OUTPUT" | |
| if [[ -n "$pr_number" ]]; then | |
| echo "Existing open bump PR: #$pr_number" | |
| else | |
| echo "No existing open bump PR." | |
| fi | |
| - name: Sync existing bump PR with master | |
| id: sync | |
| if: steps.check.outputs.update_available == 'true' && steps.find-pr.outputs.pr_number != '' | |
| env: | |
| LATEST_TAG: ${{ steps.check.outputs.latest_tag }} | |
| PR_NUMBER: ${{ steps.find-pr.outputs.pr_number }} | |
| run: | | |
| set -euo pipefail | |
| git fetch origin | |
| git checkout chore/bump-nlopt | |
| before=$(git rev-parse HEAD) | |
| if ! git merge origin/master --no-edit; then | |
| git merge --abort | |
| gh pr comment "$PR_NUMBER" --body "Auto-sync from \`master\` hit a conflict — please resolve manually." | |
| echo "::error::Merge conflict syncing chore/bump-nlopt with master" | |
| exit 1 | |
| fi | |
| git submodule update --init extern/nlopt | |
| git -C extern/nlopt fetch --tags --quiet | |
| git -C extern/nlopt checkout --quiet "$LATEST_TAG" | |
| git add extern/nlopt | |
| if ! git diff --cached --quiet; then | |
| git commit -m "Bump nlopt submodule to $LATEST_TAG" | |
| gh pr edit "$PR_NUMBER" --title "Bump nlopt to $LATEST_TAG" | |
| fi | |
| if [[ "$(git rev-parse HEAD)" != "$before" ]]; then | |
| git push origin chore/bump-nlopt | |
| else | |
| echo "chore/bump-nlopt already up to date; nothing to push." | |
| fi | |
| - name: Bump submodule on a fresh branch | |
| id: bump | |
| if: steps.check.outputs.update_available == 'true' && steps.find-pr.outputs.pr_number == '' | |
| env: | |
| LATEST_TAG: ${{ steps.check.outputs.latest_tag }} | |
| run: | | |
| set -euo pipefail | |
| git checkout -b chore/bump-nlopt | |
| git submodule update --init extern/nlopt | |
| git -C extern/nlopt fetch --tags --quiet | |
| git -C extern/nlopt checkout --quiet "$LATEST_TAG" | |
| git add extern/nlopt | |
| version=$(grep -oP 'NLOPT_(MAJOR|MINOR|BUGFIX)_VERSION *"\K[^"]+' extern/nlopt/CMakeLists.txt | paste -sd. -) | |
| echo "version=$version" >> "$GITHUB_OUTPUT" | |
| git commit -m "Bump nlopt submodule to $LATEST_TAG" | |
| git push origin chore/bump-nlopt | |
| - name: Open PR | |
| if: steps.check.outputs.update_available == 'true' && steps.find-pr.outputs.pr_number == '' | |
| env: | |
| LATEST_TAG: ${{ steps.check.outputs.latest_tag }} | |
| VERSION: ${{ steps.bump.outputs.version }} | |
| run: | | |
| set -euo pipefail | |
| gh pr create \ | |
| --base master \ | |
| --head chore/bump-nlopt \ | |
| --title "Bump nlopt to $LATEST_TAG" \ | |
| --assignee DanielBok \ | |
| --reviewer DanielBok \ | |
| --body "$(cat <<EOF | |
| Automated bump of the \`extern/nlopt\` submodule to upstream release [$LATEST_TAG](https://github.com/stevengj/nlopt/releases/tag/$LATEST_TAG). | |
| Computed package version: \`$VERSION\` | |
| - [ ] Check whether \`.github/workflows/build.yml\` / \`manual-deploy.yml\`'s OS/Python matrix needs updating for this release (see release notes) | |
| - [ ] Review CI results on this PR (full wheel build + \`t_python.py\` test matrix) | |
| - [ ] Optional: dry-run publish via \`manual-deploy.yml\` (target: testpypi) | |
| - [ ] Cut a GitHub Release (tag \`v$VERSION\`) to publish to PyPI once merged | |
| This PR is kept in sync automatically: if \`master\` changes while this is open, or a newer nlopt release appears, this branch will be updated in place rather than a new PR being opened. | |
| EOF | |
| )" | |
| notify-on-failure: | |
| name: Open/update issue on failure | |
| needs: check-and-update | |
| if: failure() | |
| runs-on: ubuntu-latest | |
| permissions: | |
| issues: write | |
| steps: | |
| - name: Find or create failure issue | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const title = "nlopt update check failing"; | |
| const runUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`; | |
| const body = `The nlopt update check workflow failed on ${new Date().toISOString().slice(0, 10)}.\n\nSee the failed run: ${runUrl}`; | |
| const { data: issues } = await github.rest.issues.listForRepo({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| state: "open", | |
| labels: "nlopt-update-check-failure", | |
| }); | |
| if (issues.length > 0) { | |
| const issue = issues[0]; | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: issue.number, | |
| body, | |
| }); | |
| } else { | |
| await github.rest.issues.create({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| title, | |
| body, | |
| labels: ["nlopt-update-check-failure"], | |
| }); | |
| } |