Improve bottle metadata handling in workflow #96
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: Bottle | |
| on: | |
| push: | |
| workflow_dispatch: | |
| permissions: | |
| contents: write | |
| jobs: | |
| test-and-bottle: | |
| name: Test and build bottles per macOS | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [macos-14, macos-15, macos-26] # Sonoma, Sequoia, Tahoe (public preview) | |
| runs-on: ${{ matrix.os }} | |
| steps: | |
| - name: Checkout tap | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Set up Homebrew | |
| uses: Homebrew/actions/setup-homebrew@master | |
| # IMPORTANT: do NOT untap mflowcode/mfc in this job. setup-homebrew manages it and | |
| # its post-cleanup expects the tap directory to exist. | |
| - name: Ensure no leftover local tap | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| brew untap mflowcode/local >/dev/null 2>&1 || true | |
| - name: Determine version and root URL (from checked-out formula) | |
| id: meta | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| FORMULA="Formula/mfc.rb" | |
| URL="$( | |
| grep -Eo 'https://github.com/[^"]+/archive/refs/tags/v[0-9]+\.[0-9]+\.[0-9]+\.tar\.gz' "${FORMULA}" \ | |
| | tail -n 1 | |
| )" | |
| [[ -n "${URL}" ]] | |
| VERSION="$(echo "${URL}" | sed -E 's/.*v([0-9]+\.[0-9]+\.[0-9]+)\.tar\.gz/\1/')" | |
| [[ -n "${VERSION}" ]] | |
| TAG="mfc-${VERSION}" | |
| ROOT_URL="https://github.com/${GITHUB_REPOSITORY}/releases/download/${TAG}" | |
| echo "version=${VERSION}" >> "$GITHUB_OUTPUT" | |
| echo "tag=${TAG}" >> "$GITHUB_OUTPUT" | |
| echo "root_url=${ROOT_URL}" >> "$GITHUB_OUTPUT" | |
| echo "Formula URL: ${URL}" | |
| echo "Formula version: ${VERSION}" | |
| echo "Release tag: ${TAG}" | |
| echo "Bottle root_url: ${ROOT_URL}" | |
| - name: Install formula with --build-bottle (tap formula) | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| echo "Installing mfc with --build-bottle (allowing non-fatal dylib fixup failures)..." | |
| set +e | |
| brew install --build-bottle mflowcode/mfc/mfc 2>&1 | tee /tmp/brew-install.log | |
| brew_exit_code=$? | |
| set -e | |
| if brew list mflowcode/mfc/mfc &>/dev/null; then | |
| echo "✅ mfc installed successfully (ignoring dylib fixup warnings)" | |
| else | |
| echo "❌ mfc installation failed; propagating brew exit code" | |
| exit $brew_exit_code | |
| fi | |
| - name: Run Sod shock tube test case | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| echo "Running a simple test case (1D Sod shock tube) on ${{ matrix.os }}..." | |
| TESTDIR="$(mktemp -d)" | |
| cp "$(brew --prefix mflowcode/mfc/mfc)/examples/1D_sodshocktube/case.py" "$TESTDIR/" | |
| cd "$TESTDIR" | |
| mfc case.py -j 1 | |
| test -d "$TESTDIR/silo_hdf5" | |
| echo "✅ Test case ran successfully and produced output" | |
| - name: Basic installation verification | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| PREFIX="$(brew --prefix mflowcode/mfc/mfc)" | |
| echo "1. Checking binaries..." | |
| test -x "${PREFIX}/bin/pre_process" | |
| test -x "${PREFIX}/bin/simulation" | |
| test -x "${PREFIX}/bin/post_process" | |
| test -x "${PREFIX}/bin/mfc" | |
| echo "2. Checking toolchain..." | |
| test -d "${PREFIX}/toolchain" | |
| echo "3. Checking Python venv..." | |
| test -d "${PREFIX}/libexec/venv" | |
| test -x "${PREFIX}/libexec/venv/bin/python" | |
| echo "4. Checking examples..." | |
| test -d "${PREFIX}/examples" | |
| echo "5. Testing mfc command..." | |
| mfc --help | |
| echo "✅ All verification checks passed on ${{ matrix.os }}" | |
| - name: Build bottle (tap formula) | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| brew bottle --root-url="${{ steps.meta.outputs.root_url }}" --json mflowcode/mfc/mfc | |
| ls -1 *.bottle.* | |
| - name: Upload bottle artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: bottles-${{ matrix.os }} | |
| path: | | |
| *.bottle.* | |
| merge-bottles: | |
| name: Merge bottles and update formula | |
| needs: test-and-bottle | |
| runs-on: macos-14 | |
| steps: | |
| - name: Checkout tap | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Set up Homebrew | |
| uses: Homebrew/actions/setup-homebrew@master | |
| - name: Determine version and root URL (from checked-out formula) | |
| id: meta | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| FORMULA="Formula/mfc.rb" | |
| URL="$( | |
| grep -Eo 'https://github.com/[^"]+/archive/refs/tags/v[0-9]+\.[0-9]+\.[0-9]+\.tar\.gz' "${FORMULA}" \ | |
| | tail -n 1 | |
| )" | |
| [[ -n "${URL}" ]] | |
| VERSION="$(echo "${URL}" | sed -E 's/.*v([0-9]+\.[0-9]+\.[0-9]+)\.tar\.gz/\1/')" | |
| [[ -n "${VERSION}" ]] | |
| TAG="mfc-${VERSION}" | |
| ROOT_URL="https://github.com/${GITHUB_REPOSITORY}/releases/download/${TAG}" | |
| echo "version=${VERSION}" >> "$GITHUB_OUTPUT" | |
| echo "tag=${TAG}" >> "$GITHUB_OUTPUT" | |
| echo "root_url=${ROOT_URL}" >> "$GITHUB_OUTPUT" | |
| - name: Configure git for bottle merge | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| git config --global user.email "github-actions[bot]@users.noreply.github.com" | |
| git config --global user.name "github-actions[bot]" | |
| - name: Download all bottle artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: bottles | |
| - name: Flatten bottle directory | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| echo "Before flattening:" | |
| find bottles -name '*.bottle.*' -type f | |
| find bottles -mindepth 2 -name '*.bottle.*' -type f -exec mv {} bottles/ \; | |
| echo "" | |
| echo "After flattening:" | |
| ls -1 bottles/*.bottle.* | |
| - name: Rename bottles for GitHub release | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| echo "Renaming bottles (mfc-- → mfc-)..." | |
| for file in bottles/mfc--*.bottle.*; do | |
| if [[ -f "$file" ]]; then | |
| newname=$(echo "$file" | sed 's/mfc--/mfc-/') | |
| mv "$file" "$newname" | |
| echo " $file → $newname" | |
| fi | |
| done | |
| echo "" | |
| echo "Bottles ready for upload:" | |
| ls -1 bottles/*.bottle.* | |
| - name: Merge bottle metadata into formula | |
| id: merge | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| shopt -s nullglob | |
| JSON_BOTTLES=(bottles/*.bottle*.json) | |
| if (( ${#JSON_BOTTLES[@]} == 0 )); then | |
| echo "No bottle metadata (*.bottle*.json) found in bottles/" | |
| ls -la bottles/ | |
| exit 1 | |
| fi | |
| echo "Merging bottle metadata from:" | |
| printf '%s\n' "${JSON_BOTTLES[@]}" | |
| BEFORE_SHA="$(git rev-parse HEAD)" | |
| brew bottle --merge --write --root-url="${{ steps.meta.outputs.root_url }}" "${JSON_BOTTLES[@]}" | |
| AFTER_SHA="$(git rev-parse HEAD)" | |
| if [[ "${BEFORE_SHA}" != "${AFTER_SHA}" ]]; then | |
| echo "✅ brew bottle --write created commit ${AFTER_SHA}" | |
| echo "bottle_updated=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "ℹ️ No commit created (bottles unchanged or already present)" | |
| echo "bottle_updated=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Push bottle updates if changed | |
| if: steps.merge.outputs.bottle_updated == 'true' | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| git remote set-url origin "https://x-access-token:${{ github.token }}@github.com/${{ github.repository }}.git" | |
| git push origin HEAD:main | |
| - name: Create/update release and upload bottles | |
| uses: softprops/action-gh-release@v1 | |
| with: | |
| tag_name: ${{ steps.meta.outputs.tag }} | |
| name: MFC bottles ${{ steps.meta.outputs.version }} | |
| files: bottles/*.bottle.* | |
| fail_on_unmatched_files: true | |
| env: | |
| GITHUB_TOKEN: ${{ github.token }} |