diff --git a/.github/workflows/Breakage.yml b/.github/workflows/Breakage.yml index 3883812..d3cfd0c 100644 --- a/.github/workflows/Breakage.yml +++ b/.github/workflows/Breakage.yml @@ -123,6 +123,213 @@ jobs: name: breakage-${{ matrix.pkg }}-${{ matrix.pkgversion }} path: breakage/breakage-* + upload: + needs: break + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/download-artifact@v4 + with: + path: breakage + pattern: breakage-* + merge-multiple: true + + - run: ls -R + - run: | + cd breakage + echo "| Package name | latest | stable |" > summary.md + echo "|--|--|--|" >> summary.md + count=0 + for file in breakage-* + do + if [ $count == "0" ]; then + name=$(echo $file | cut -f2 -d-) + echo -n "| $name | " + else + echo -n "| " + fi + cat $file + if [ $count == "0" ]; then + echo -n " " + count=1 + else + echo " |" + count=0 + fi + done >> summary.md + + - name: Display summary in CI logs + run: | + echo "### Breakage Summary" >> $GITHUB_STEP_SUMMARY + cat breakage/summary.md >> $GITHUB_STEP_SUMMARY + + - name: PR comment with file + if: github.event.pull_request.head.repo.fork == false + uses: actions/github-script@main + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + // Import file content from summary.md + const fs = require('fs') + const filePath = 'breakage/summary.md' + const msg = fs.readFileSync(filePath, 'utf8') + + // Get the current PR number from context + const prNumber = context.payload.pull_request.number + + // Fetch existing comments on the PR + const { data: comments } = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber + }) + + // Find a previous comment by the bot to update + const botComment = comments.find(comment => comment.user.id === 41898282) + + if (botComment) { + // Update the existing comment + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: botComment.id, + body: msg + }) + } else { + // Create a new comment + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + body: msg + }) + } +# Ref: https://securitylab.github.com/research/github-actions-preventing-pwn-requests +name: Breakage + +# read-only repo token +# no access to secrets +on: + pull_request: + +jobs: + # Build dynamically the matrix on which the "break" job will run. + # The matrix contains the packages that depend on ${{ env.pkg }}. + # Job "setup_matrix" outputs variable "matrix", which is in turn + # the output of the "getmatrix" step. + # The contents of "matrix" is a JSON description of a matrix used + # in the next step. It has the form + # { + # "pkg": [ + # "PROPACK", + # "LLSModels", + # "FletcherPenaltySolver" + # ] + # } + setup_matrix: + runs-on: ubuntu-latest + outputs: + matrix: ${{ steps.getmatrix.outputs.matrix }} + env: + pkg: ${{ github.event.repository.name }} + steps: + - uses: actions/checkout@v4 + - uses: julia-actions/setup-julia@v2 + with: + version: 1 + arch: x64 + - id: getmatrix + run: | + julia -e 'using Pkg; Pkg.Registry.add(RegistrySpec(url = "https://github.com/JuliaRegistries/General.git"))' + julia --project=.breakage -e 'using Pkg; Pkg.update(); Pkg.instantiate()' + pkgs=$(julia --project=.breakage .breakage/get_jso_users.jl ${{ env.pkg }}) + vs='["latest", "stable"]' + # Check if pkgs is empty, and set it to a JSON array if necessary + if [[ -z "$pkgs" || "$pkgs" == "String[]" ]]; then + echo "No packages found; exiting successfully." + exit 0 + fi + vs='["latest", "stable"]' + matrix=$(jq -cn --argjson deps "$pkgs" --argjson vers "$vs" '{pkg: $deps, pkgversion: $vers}') # don't escape quotes like many posts suggest + echo "matrix=$matrix" >> "$GITHUB_OUTPUT" + + break: + needs: setup_matrix + if: needs.setup_matrix.result == 'success' && needs.setup_matrix.outputs.matrix != '' + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: ${{ fromJSON(needs.setup_matrix.outputs.matrix) }} + + steps: + - uses: actions/checkout@v4 + + # Install Julia + - uses: julia-actions/setup-julia@v2 + with: + version: 1 + arch: x64 + - uses: actions/cache@v4 + env: + cache-name: cache-artifacts + with: + path: ~/.julia/artifacts + key: ${{ runner.os }}-test-${{ env.cache-name }}-${{ hashFiles('**/Project.toml') }} + restore-keys: | + ${{ runner.os }}-test-${{ env.cache-name }}- + ${{ runner.os }}-test- + ${{ runner.os }}- + - uses: julia-actions/julia-buildpkg@v1 + + # Breakage test + - name: 'Breakage of ${{ matrix.pkg }}, ${{ matrix.pkgversion }} version' + env: + PKG: ${{ matrix.pkg }} + VERSION: ${{ matrix.pkgversion }} + run: | + set -v + mkdir -p ./breakage + git clone https://github.com/JuliaSmoothOptimizers/$PKG.jl.git + cd $PKG.jl + if [ $VERSION == "stable" ]; then + TAG=$(git tag -l "v*" --sort=-creatordate | head -n1) + if [ -z "$TAG" ]; then + TAG="no_tag" + else + git checkout $TAG + fi + else + TAG=$VERSION + fi + export TAG + julia -e 'using Pkg; + PKG, TAG, VERSION = ENV["PKG"], ENV["TAG"], ENV["VERSION"] + joburl = joinpath(ENV["GITHUB_SERVER_URL"], ENV["GITHUB_REPOSITORY"], "actions/runs", ENV["GITHUB_RUN_ID"]) + open("../breakage/breakage-$PKG-$VERSION", "w") do io + try + TAG == "no_tag" && error("No tag for $VERSION") + pkg"activate ."; + pkg"instantiate"; + pkg"dev ../"; + if TAG == "latest" + global TAG = chomp(read(`git rev-parse --short HEAD`, String)) + end + pkg"build"; + pkg"test"; + + print(io, "[![](https://img.shields.io/badge/$TAG-Pass-green)]($joburl)"); + catch e + @error e; + print(io, "[![](https://img.shields.io/badge/$TAG-Fail-red)]($joburl)"); + end; + end' + + - uses: actions/upload-artifact@v4 + with: + name: breakage-${{ matrix.pkg }}-${{ matrix.pkgversion }} + path: breakage/breakage-* + upload: needs: break runs-on: ubuntu-latest diff --git a/test/MOI_wrapper.jl b/test/MOI_wrapper.jl index 4f410c8..57cbb93 100644 --- a/test/MOI_wrapper.jl +++ b/test/MOI_wrapper.jl @@ -117,10 +117,13 @@ function test_runtests() r"test_basic_VectorNonlinearFunction_Zeros$", r"test_constraint_qcp_duplicate_off_diagonal$", r"test_nonlinear_expression_hs109$", + r"test_nonlinear_expression_hs110$", r"test_nonlinear_expression_overrides_objective$", # ITERATION_LIMIT r"test_quadratic_constraint_LessThan$", r"test_quadratic_constraint_GreaterThan$", + r"test_objective_qp_ObjectiveFunction_zero_ofdiag$", + r"test_objective_qp_ObjectiveFunction_edge_cases$", # FIXME Segfault r"test_linear_integration_delete_variables$", # https://github.com/jump-dev/MathOptInterface.jl/issues/2323