Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
187 changes: 187 additions & 0 deletions .github/workflows/homebrew-release.yml
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

High-level Suggestion

Replace the brittle sed and awk commands used for modifying the Homebrew formula with a more robust Ruby script. This makes the release automation less likely to fail due to future formatting changes in the formula file. [High-level, importance: 8]

Solution Walkthrough:

Before:

# In .github/workflows/homebrew-release.yml
- name: Update formula
  run: |
    FORMULA="homebrew-mfc/Formula/mfc.rb"
    # Update URL with sed
    sed -i "s|url \"https...\"|url \"https...${VERSION}.tar.gz\"|" "$FORMULA"

    # Update SHA256 with awk, assuming it's after the url
    awk -v newsha="$SHA256" '
      /^  url "/ { found_url=1 }
      found_url && /^  sha256 "/ { ... sub(...) ... }
      { print }
    ' "$FORMULA" > "$FORMULA.tmp" && mv "$FORMULA.tmp" "$FORMULA"

    # Remove bottle block with awk
    awk '/^  bottle do/,/^  end/ { next } { print }' "$FORMULA" > ...

After:

# In .github/workflows/homebrew-release.yml
- name: Update formula
  run: |
    # Use a dedicated Ruby script for safer manipulation
    ruby ./path/to/update_formula.rb \
      --file="homebrew-mfc/Formula/mfc.rb" \
      --version="${{ steps.version.outputs.version }}" \
      --sha256="${{ steps.sha256.outputs.sha256 }}"

# In ./path/to/update_formula.rb (conceptual)
# ... Ruby code to parse arguments ...
content = File.read(formula_path)
# Use robust regex to replace url and sha256
content.sub!(/url "[^"]+"/, "url \"...v#{version}.tar.gz\"")
content.sub!(/sha256 "[^"]+"/, "sha256 \"#{sha256}\"")
# Remove bottle block
content.gsub!(/  bottle do\n(.+\n)+?  end\n/, "")
File.write(formula_path, content)

Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
name: Update Homebrew Formula on Release

# Triggers when a new version tag is pushed
on:
push:
tags:
- 'v*'
Comment on lines +4 to +7
Copy link

Copilot AI Feb 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both deploy-tap.yml (line 17) and this new homebrew-release.yml workflow will trigger when a version tag is pushed. This could lead to a race condition where both workflows try to update the homebrew-mfc tap simultaneously. Consider:

  1. Disabling tag handling in deploy-tap.yml by removing the create: trigger and adding a path filter to exclude tag events, or
  2. Coordinating the two workflows so only one handles tag releases

The two workflows have different approaches: deploy-tap.yml updates the formula in this repo first then pushes to the tap, while homebrew-release.yml directly updates the tap repo. Having both active for tag events could cause conflicts.

Copilot uses AI. Check for mistakes.
pull_request:
branches: [master]
paths:
- '.github/workflows/homebrew-release.yml'
workflow_dispatch:
inputs:
version:
description: 'Version to release (without v prefix, e.g., 5.2.0)'
required: true
type: string
dry_run:
description: 'Dry run (skip push to homebrew-mfc)'
required: false
type: boolean
default: false

jobs:
update-homebrew-tap:
name: Update homebrew-mfc tap
runs-on: ubuntu-latest
Comment on lines +24 to +27
Copy link

Copilot AI Feb 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This workflow doesn't explicitly declare permissions at the workflow or job level. While it will inherit default permissions, explicitly declaring permissions is a security best practice. Consider adding permissions: contents: read at the workflow level to follow the principle of least privilege, similar to deploy-tap.yml line 20-21.

Copilot uses AI. Check for mistakes.

steps:
- name: Determine version
id: version
run: |
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
VERSION="${{ inputs.version }}"
elif [[ "${{ github.event_name }}" == "pull_request" ]]; then
# Use existing version for PR testing
VERSION="5.2.0"
echo "::notice::PR test mode - using version $VERSION"
Comment on lines +35 to +38
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Instead of hard-coding the version for pull request tests, dynamically extract the version from the packaging/homebrew/mfc.rb file. [general, importance: 6]

Suggested change
elif [[ "${{ github.event_name }}" == "pull_request" ]]; then
# Use existing version for PR testing
VERSION="5.2.0"
echo "::notice::PR test mode - using version $VERSION"
elif [[ "${{ github.event_name }}" == "pull_request" ]]; then
# Extract version from formula to avoid hard-coding
VERSION=$(grep -Po 'refs/tags/v\K[0-9]+\.[0-9]+\.[0-9]+' packaging/homebrew/mfc.rb)
echo "::notice::PR test mode - using version $VERSION (extracted from formula)"

else
# Extract version from tag (remove 'v' prefix)
VERSION="${GITHUB_REF#refs/tags/v}"
fi

if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
Copy link

Copilot AI Feb 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The version validation regex ^[0-9]+\.[0-9]+\.[0-9]+$ only accepts semantic versions with exactly three numeric components (X.Y.Z). This doesn't support pre-release versions like 5.2.0-beta1 or 5.2.0-rc1. If MFC uses pre-release tags, this validation will reject them. Consider whether pre-release versions need to be supported, and if so, update the regex accordingly.

Copilot uses AI. Check for mistakes.
echo "::error::Invalid version format: $VERSION (expected X.Y.Z)"
exit 1
fi

echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "Version: $VERSION"

- name: Compute SHA256 of release tarball
id: sha256
run: |
VERSION="${{ steps.version.outputs.version }}"
URL="https://github.com/MFlowCode/MFC/archive/refs/tags/v${VERSION}.tar.gz"
Comment on lines +52 to +56
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Add set -euo pipefail to the beginning of multi-line run steps to enable stricter error handling in the bash scripts. [general, importance: 5]

Suggested change
- name: Compute SHA256 of release tarball
id: sha256
run: |
VERSION="${{ steps.version.outputs.version }}"
URL="https://github.com/MFlowCode/MFC/archive/refs/tags/v${VERSION}.tar.gz"
- name: Compute SHA256 of release tarball
id: sha256
run: |
set -euo pipefail
VERSION="${{ steps.version.outputs.version }}"
URL="https://github.com/MFlowCode/MFC/archive/refs/tags/v${VERSION}.tar.gz"


echo "Downloading tarball from: $URL"

# Verify URL is reachable
HTTP_CODE=$(curl -sI -w "%{http_code}" -o /dev/null "$URL")
if [[ "$HTTP_CODE" != "200" && "$HTTP_CODE" != "302" ]]; then
echo "::error::Release tarball not found at $URL (HTTP $HTTP_CODE)"
echo "::error::Make sure the tag v${VERSION} exists and the release is published"
exit 1
fi

# Compute SHA256
SHA256=$(curl -sL "$URL" | sha256sum | awk '{print $1}')
Copy link

Copilot AI Feb 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This workflow uses sha256sum which is the Linux version, but other workflows in this repository (deploy-tap.yml line 58 and homebrew.yml line 104) use shasum -a 256 instead. While both work on ubuntu-latest, using shasum would be more consistent with the existing codebase conventions and also more portable if the runner ever changes to macOS.

Copilot uses AI. Check for mistakes.

if [[ -z "$SHA256" || "$SHA256" == "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" ]]; then
echo "::error::Failed to compute SHA256 (empty file or download failed)"
exit 1
fi

echo "sha256=$SHA256" >> "$GITHUB_OUTPUT"
echo "SHA256: $SHA256"

- name: PR test summary
if: ${{ github.event_name == 'pull_request' }}
run: |
echo "## PR Test Mode" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Validated:" >> $GITHUB_STEP_SUMMARY
echo "- Version parsing: v${{ steps.version.outputs.version }}" >> $GITHUB_STEP_SUMMARY
echo "- SHA256 computation: \`${{ steps.sha256.outputs.sha256 }}\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Skipped (secrets not available for fork PRs):" >> $GITHUB_STEP_SUMMARY
echo "- Checkout homebrew-mfc" >> $GITHUB_STEP_SUMMARY
echo "- Update formula" >> $GITHUB_STEP_SUMMARY
echo "- Push to tap" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "The full workflow will run when a \`v*\` tag is pushed after merge." >> $GITHUB_STEP_SUMMARY

- name: Checkout homebrew-mfc tap
if: ${{ github.event_name != 'pull_request' }}
uses: actions/checkout@v4
with:
repository: MFlowCode/homebrew-mfc
token: ${{ secrets.TAP_REPO_TOKEN }}
path: homebrew-mfc

- name: Update formula
if: ${{ github.event_name != 'pull_request' }}
run: |
VERSION="${{ steps.version.outputs.version }}"
SHA256="${{ steps.sha256.outputs.sha256 }}"
FORMULA="homebrew-mfc/Formula/mfc.rb"

echo "Updating formula to v${VERSION}..."

# Update URL
sed -i "s|url \"https://github.com/MFlowCode/MFC/archive/refs/tags/v[^\"]*\.tar\.gz\"|url \"https://github.com/MFlowCode/MFC/archive/refs/tags/v${VERSION}.tar.gz\"|" "$FORMULA"

# Update SHA256 (the one right after url, not bottle SHAs)
# This uses awk to only update the first sha256 after the url line
awk -v newsha="$SHA256" '
/^ url "https:\/\/github.com\/MFlowCode\/MFC/ { found_url=1 }
found_url && /^ sha256 "/ && !updated {
sub(/sha256 "[^"]*"/, "sha256 \"" newsha "\"")
updated=1
}
{ print }
' "$FORMULA" > "$FORMULA.tmp" && mv "$FORMULA.tmp" "$FORMULA"

# Remove existing bottle block (new bottles will be built by bottle.yml)
# This removes everything between "bottle do" and the matching "end"
awk '
/^ bottle do/ { in_bottle=1; next }
in_bottle && /^ end/ { in_bottle=0; next }
!in_bottle { print }
' "$FORMULA" > "$FORMULA.tmp" && mv "$FORMULA.tmp" "$FORMULA"
Comment on lines +128 to +132
Copy link

Copilot AI Feb 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The awk script to remove bottle blocks assumes the bottle block is indented with exactly two spaces (matching the pattern /^ bottle do/ and /^ end/). If the formula structure changes or uses different indentation, this could fail silently and leave the bottle block in place. Consider adding validation after this step to ensure the bottle block was removed, or use a more robust approach like checking for bottle do without the strict indentation requirement.

Copilot uses AI. Check for mistakes.

echo "Updated formula:"
head -30 "$FORMULA"

- name: Validate updated formula
if: ${{ github.event_name != 'pull_request' }}
run: |
cd homebrew-mfc
echo "Checking Ruby syntax..."
ruby -c Formula/mfc.rb

echo "Verifying URL and SHA256 were updated..."
grep -q "v${{ steps.version.outputs.version }}.tar.gz" Formula/mfc.rb || (echo "::error::URL not updated"; exit 1)
grep -q "${{ steps.sha256.outputs.sha256 }}" Formula/mfc.rb || (echo "::error::SHA256 not updated"; exit 1)

echo "Formula validation passed!"

- name: Commit and push to homebrew-mfc
if: ${{ github.event_name != 'pull_request' && github.event.inputs.dry_run != 'true' }}
run: |
cd homebrew-mfc
VERSION="${{ steps.version.outputs.version }}"

git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"

git add Formula/mfc.rb
git commit -m "Update MFC to v${VERSION}"

echo "Pushing to homebrew-mfc..."
git push origin main

echo "Successfully pushed formula update!"
echo "The bottle.yml workflow in homebrew-mfc will now build bottles automatically."
Comment on lines +150 to +166
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Instead of pushing directly to the main branch of the homebrew-mfc repository, modify the workflow to open a pull request with the proposed formula changes. [security, importance: 8]

Suggested change
- name: Commit and push to homebrew-mfc
if: ${{ github.event_name != 'pull_request' && github.event.inputs.dry_run != 'true' }}
run: |
cd homebrew-mfc
VERSION="${{ steps.version.outputs.version }}"
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add Formula/mfc.rb
git commit -m "Update MFC to v${VERSION}"
echo "Pushing to homebrew-mfc..."
git push origin main
echo "Successfully pushed formula update!"
echo "The bottle.yml workflow in homebrew-mfc will now build bottles automatically."
- name: Create Pull Request to homebrew-mfc
if: ${{ github.event_name != 'pull_request' && github.event.inputs.dry_run != 'true' }}
uses: peter-evans/create-pull-request@v6
with:
path: homebrew-mfc
token: ${{ secrets.TAP_REPO_TOKEN }}
commit-message: "Update MFC to v${{ steps.version.outputs.version }}"
title: "Update MFC to v${{ steps.version.outputs.version }}"
body: |
Automated update of the `mfc` formula to version `${{ steps.version.outputs.version }}`.
- **Version:** `${{ steps.version.outputs.version }}`
- **SHA256:** `${{ steps.sha256.outputs.sha256 }}`
This PR was generated automatically by the release workflow.
branch: "release/mfc-v${{ steps.version.outputs.version }}"
base: main
delete-branch: true


- name: Dry run summary
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.dry_run == 'true' }}
run: |
echo "::notice::DRY RUN - skipped push to homebrew-mfc"
echo ""
echo "Would have committed the following changes:"
cd homebrew-mfc
git diff Formula/mfc.rb
Comment on lines +174 to +175
Copy link

Copilot AI Feb 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dry run summary step will fail because it tries to cd homebrew-mfc, but the "Checkout homebrew-mfc tap" step (line 95-101) only runs when github.event_name != 'pull_request'. In dry-run mode during workflow_dispatch, the homebrew-mfc directory won't exist. The condition should also check that the directory was actually checked out.

Suggested change
cd homebrew-mfc
git diff Formula/mfc.rb
if [ -d homebrew-mfc ]; then
cd homebrew-mfc
git diff Formula/mfc.rb
else
echo "::notice::homebrew-mfc tap directory not found; nothing to diff."
fi

Copilot uses AI. Check for mistakes.

- name: Summary
if: ${{ github.event_name != 'pull_request' }}
Copy link

Copilot AI Feb 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Summary step (lines 177-187) will run even in dry-run mode because its condition is github.event_name != 'pull_request', which includes workflow_dispatch dry runs. This will display "Homebrew Formula Updated" even though nothing was actually pushed in dry-run mode. Consider updating the condition to also exclude dry runs: github.event_name != 'pull_request' && github.event.inputs.dry_run != 'true'

Suggested change
if: ${{ github.event_name != 'pull_request' }}
if: ${{ github.event_name != 'pull_request' && github.event.inputs.dry_run != 'true' }}

Copilot uses AI. Check for mistakes.
run: |
VERSION="${{ steps.version.outputs.version }}"
echo "## Homebrew Formula Updated" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "- **Version:** v${VERSION}" >> $GITHUB_STEP_SUMMARY
echo "- **SHA256:** \`${{ steps.sha256.outputs.sha256 }}\`" >> $GITHUB_STEP_SUMMARY
echo "- **Tap:** [MFlowCode/homebrew-mfc](https://github.com/MFlowCode/homebrew-mfc)" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "The [bottle.yml](https://github.com/MFlowCode/homebrew-mfc/actions/workflows/bottle.yml) workflow will now build bottles for this release." >> $GITHUB_STEP_SUMMARY
Comment on lines +26 to +187

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {contents: read}

Copilot Autofix

AI 4 months ago

To fix this, explicitly set least‑privilege GITHUB_TOKEN permissions in the workflow. This workflow does not need to write to the current repository or to issues/PRs; it only needs to read repository contents (and uses a separate PAT secret for pushing to homebrew-mfc). Therefore, the safest fix is to add a top‑level permissions: block with contents: read. Placing it at the root (next to name and on) applies to all jobs, including update-homebrew-tap, without changing any behavior.

Concretely:

  • Edit .github/workflows/homebrew-release.yml.

  • After the existing name: Update Homebrew Formula on Release line, insert:

    permissions:
      contents: read

No additional methods, imports, or other definitions are needed; this is a pure configuration change in the workflow file.

Suggested changeset 1
.github/workflows/homebrew-release.yml

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/.github/workflows/homebrew-release.yml b/.github/workflows/homebrew-release.yml
--- a/.github/workflows/homebrew-release.yml
+++ b/.github/workflows/homebrew-release.yml
@@ -1,4 +1,6 @@
 name: Update Homebrew Formula on Release
+permissions:
+  contents: read
 
 # Triggers when a new version tag is pushed
 on:
EOF
@@ -1,4 +1,6 @@
name: Update Homebrew Formula on Release
permissions:
contents: read

# Triggers when a new version tag is pushed
on:
Copilot is powered by AI and may make mistakes. Always verify output.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Misleading summary output during dry run mode

Low Severity

The "Summary" step runs when dry_run=true because its condition only checks github.event_name != 'pull_request', not the dry_run flag. This causes the job summary to incorrectly state "Homebrew Formula Updated" and "The bottle.yml workflow will now build bottles for this release" even though the push was skipped. The condition at line 178 needs to also exclude dry runs, similar to the commit/push step at line 151.

Fix in Cursor Fix in Web

40 changes: 23 additions & 17 deletions .github/workflows/homebrew.yml
Original file line number Diff line number Diff line change
Expand Up @@ -209,51 +209,57 @@ jobs:
- name: Test MFC installation
run: |
echo "=== Testing MFC Installation ==="


# Use the full tap-qualified name since we installed from mflowcode/test
MFC_PREFIX="$(brew --prefix mflowcode/test/mfc)"
echo "MFC prefix: $MFC_PREFIX"

echo "1. Checking binaries exist and are executable..."
test -f $(brew --prefix)/bin/mfc && test -x $(brew --prefix)/bin/mfc
Comment on lines +214 to 218
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: In the test step, replace $(brew --prefix) with the tap-specific "$MFC_PREFIX" variable for all file and executable checks to ensure tests target the correct installation. [possible issue, importance: 7]

Suggested change
MFC_PREFIX="$(brew --prefix mflowcode/test/mfc)"
echo "MFC prefix: $MFC_PREFIX"
echo "1. Checking binaries exist and are executable..."
test -f $(brew --prefix)/bin/mfc && test -x $(brew --prefix)/bin/mfc
MFC_PREFIX="$(brew --prefix mflowcode/test/mfc)"
...
test -f "$MFC_PREFIX/bin/mfc" && test -x "$MFC_PREFIX/bin/mfc"

test -f $(brew --prefix)/bin/pre_process && test -x $(brew --prefix)/bin/pre_process
test -f $(brew --prefix)/bin/simulation && test -x $(brew --prefix)/bin/simulation
test -f $(brew --prefix)/bin/post_process && test -x $(brew --prefix)/bin/post_process
echo " ✓ All binaries exist and are executable"

echo "2. Verifying installation structure..."
test -f $(brew --prefix mfc)/libexec/mfc.sh
test -d $(brew --prefix mfc)/toolchain
test -f "$MFC_PREFIX/libexec/mfc.sh"
test -d "$MFC_PREFIX/toolchain"
echo " ✓ Installation structure verified"

echo "3. Checking Python venv..."
test -d $(brew --prefix mfc)/libexec/venv
test -f $(brew --prefix mfc)/libexec/venv/bin/python
test -f $(brew --prefix mfc)/libexec/venv/bin/pip
test -d "$MFC_PREFIX/libexec/venv"
test -f "$MFC_PREFIX/libexec/venv/bin/python"
test -f "$MFC_PREFIX/libexec/venv/bin/pip"
echo " ✓ Python venv exists"

echo "4. Checking examples..."
test -d $(brew --prefix mfc)/examples
test -f $(brew --prefix mfc)/examples/1D_sodshocktube/case.py
test -d "$MFC_PREFIX/examples"
test -f "$MFC_PREFIX/examples/1D_sodshocktube/case.py"
echo " ✓ Examples installed"

echo "5. Testing mfc wrapper..."
mfc --help
echo " ✓ mfc --help succeeded"

echo "=== All tests passed! ==="

- name: Run MFC test case
run: |
echo "Running a simple test case (1D Sod shock tube)..."
MFC_PREFIX="$(brew --prefix mflowcode/test/mfc)"
TESTDIR=$(mktemp -d)
cp $(brew --prefix mfc)/examples/1D_sodshocktube/case.py "$TESTDIR/"
cp "$MFC_PREFIX/examples/1D_sodshocktube/case.py" "$TESTDIR/"

echo "Running with $(sysctl -n hw.ncpu) processors..."
# Use absolute path and shorthand syntax (mfc auto-detects and prepends 'run')
mfc "$TESTDIR/case.py" -j $(sysctl -n hw.ncpu)

echo "Test case completed successfully!"

- name: Uninstall and cleanup
if: always()
run: |
echo "Cleaning up..."
brew uninstall mfc || true
brew uninstall mflowcode/test/mfc || true
brew untap mflowcode/test || true
brew cleanup
4 changes: 2 additions & 2 deletions packaging/homebrew/mfc.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
class Mfc < Formula
desc "Exascale multiphase/multiphysics compressible flow solver"
homepage "https://mflowcode.github.io/"
url "https://github.com/MFlowCode/MFC/archive/refs/tags/v5.1.5.tar.gz"
sha256 "229ba4532d9b31e54e7db67cc6c6a4c069034bb143be7c57cba31c5a56fe6a0b"
url "https://github.com/MFlowCode/MFC/archive/refs/tags/v5.2.0.tar.gz"
sha256 "aaee855302950cb6bd8497170a6737214ed9a47ad3d109258f5b27ee2b78fe3d"
license "MIT"
head "https://github.com/MFlowCode/MFC.git", branch: "master"

Expand Down
Loading