diff --git a/.github/workflows/nlopt-update-check.yml b/.github/workflows/nlopt-update-check.yml new file mode 100644 index 0000000..03ba7cb --- /dev/null +++ b/.github/workflows/nlopt-update-check.yml @@ -0,0 +1,199 @@ +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 < 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"], + }); + } diff --git a/.github/workflows/wc-build.yml b/.github/workflows/wc-build.yml index e2547b4..aef4818 100644 --- a/.github/workflows/wc-build.yml +++ b/.github/workflows/wc-build.yml @@ -274,8 +274,6 @@ jobs: runs-on: ubuntu-latest needs: test-wheels if: inputs.target != 'none' - environment: - name: ${{ inputs.target == 'pypi' && 'prod' || 'dev' }} permissions: id-token: write contents: read