A GitHub Action that sets up a Fortran development environment using Conda. Inspired by Conda + Fortran.
⚠️ Use your own name and email! Don’t copy the example values.
To enable automatic updates to the CI status table in README.md
via the update_readme_table
job:
- Create a GitHub Personal Access Token (PAT) with
repo
scope. - Add it to your repo secrets, e.g.
GH_PAT
. - Configure these inputs:
update-readme-token: ${{ secrets.GH_PAT }}
update-readme-user-name: "Your Name"
update-readme-user-email: "you@example.com"
💡 Tip: When integrating CI/CD, testing often requires multiple commits and iterations.
To keep your main
branch clean, consider using a separate branch (e.g., dev
) for development and testing. Once everything is working, you can merge it into main.
You can include only the jobs you need in your workflow. This example includes all available jobs to demonstrate a comprehensive CI/CD setup.
This example automates Fortran CI/CD:
-
📦 Fortran compiler setup:
- Supports:
gfortran
,ifx
,lfortran
,flang-new
,nvfortran
- Supports:
-
🖥️ Cross-platform testing:
- Ubuntu, Windows, macOS GitHub runners
-
🧪 Testing:
fpm
test withdebug
andrelease
profilesCMake
withNinja
andCTest
-
📄 Documentation:
-
📊 Status Reporting:
- Auto-generates
STATUS.md
forfpm
/cmake
test results - Injects summary into
README.md
- creates PRs to update the status table in
README.md
- Auto-generates
-
🧹 Linting:
- Runs Fortitude check
To enable automatic CI status table injection, add the following to your README.md
:
<!-- STATUS:setup-fortran-conda:START --> <!-- STATUS:setup-fortran-conda:END -->
Job Name | Description |
---|---|
test_fpm |
Run fpm tests (debug + release) for each OS/compiler |
test_cmake |
Run CMake/Ninja builds and tests |
doc_ford |
Build and deploy FORD-generated docs |
doc_doxygen |
Build and deploy Doxygen-generated docs |
status_fpm |
Generate STATUS.md with fpm test results |
status_cmake |
Generate STATUS.md with cmake test results |
update_readme_table |
Inject CI summary table into README.md and open a pull request |
linter_fortitude |
Run Fortitude linter |
modify this example workflow file to your needs, and save it as .github/workflows/CI-CD.yml
in your repository:
name: Setup Fortran Conda CI/CD
on:
push:
branches: [main, master, dev]
pull_request:
branches: [main, master]
permissions:
contents: write
pull-requests: write
jobs:
# Run FPM tests (debug + release) on all OS/compiler combinations
test_fpm:
name: ${{ matrix.os }}_${{ matrix.compiler }}_fpm
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
compiler: [gfortran, ifx, lfortran, flang-new, nvfortran]
include:
- os: ubuntu-latest
extra-packages: ""
- os: windows-latest
extra-packages: ""
- os: macos-latest
extra-packages: ""
exclude:
- os: macos-latest
compiler: flang-new
- os: macos-latest
compiler: ifx
- os: macos-latest
compiler: nvfortran
- os: windows-latest
compiler: nvfortran
steps:
- name: Setup Fortran
uses: gha3mi/setup-fortran-conda@latest
with:
compiler: ${{ matrix.compiler }}
platform: ${{ matrix.os }}
extra-packages: ${{ matrix.extra-packages }}
- name: fpm test (debug)
run: fpm test --compiler ${{ matrix.compiler }} --profile debug --verbose
- name: fpm test (release)
run: fpm test --compiler ${{ matrix.compiler }} --profile release --verbose
# Run CMake + Ninja build/tests across OS/compiler matrix
test_cmake:
name: ${{ matrix.os }}_${{ matrix.compiler }}_cmake
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
compiler: [gfortran, ifx, lfortran, flang-new, nvfortran]
include:
- os: ubuntu-latest
extra-packages: "cmake, ninja"
- os: windows-latest
extra-packages: "cmake, ninja"
- os: macos-latest
extra-packages: "cmake, ninja"
exclude:
- os: macos-latest
compiler: flang-new
- os: macos-latest
compiler: ifx
- os: macos-latest
compiler: nvfortran
- os: windows-latest
compiler: nvfortran
steps:
- name: Setup Fortran
uses: gha3mi/setup-fortran-conda@latest
with:
compiler: ${{ matrix.compiler }}
platform: ${{ matrix.os }}
extra-packages: ${{ matrix.extra-packages }}
- name: cmake test (debug)
run: |
cmake -S . -B build/debug -DCMAKE_BUILD_TYPE=Debug -DCMAKE_Fortran_COMPILER=${{ matrix.compiler }} -G Ninja
cmake --build build/debug
ctest --test-dir build/debug --output-on-failure
- name: cmake test (release)
run: |
cmake -S . -B build/release -DCMAKE_BUILD_TYPE=Release -DCMAKE_Fortran_COMPILER=${{ matrix.compiler }} -G Ninja
cmake --build build/release
ctest --test-dir build/release --output-on-failure
# Build and deploy FORD documentation
doc_ford:
name: Generate FORD Documentation
runs-on: ubuntu-latest
steps:
- name: Setup and Generate FORD Documentation
uses: gha3mi/setup-fortran-conda@latest
with:
compiler: gfortran
generate-doc-ford: true
ford-working-directory: .
ford-config: README.md
ford-output-directory: doc/ford
ford-branch: gh-pages-ford
ford-target-folder: doc/ford
# Build and deploy Doxygen documentation
doc_doxygen:
name: Generate Doxygen Documentation
runs-on: ubuntu-latest
steps:
- name: Setup and Generate Doxygen Documentation
uses: gha3mi/setup-fortran-conda@latest
with:
compiler: gfortran
generate-doc-doxygen: true
doxygen-working-directory: .
doxygen-config: Doxyfile
doxygen-output-directory: doc/doxygen
doxygen-branch: gh-pages-doxygen
doxygen-target-folder: doc/doxygen
# Generate STATUS.md from FPM job results
status_fpm:
name: Generate STATUS.md
if: always()
needs: test_fpm
runs-on: ubuntu-latest
steps:
- name: Generate summary
uses: gha3mi/setup-fortran-conda@latest
with:
generate-status-fpm: true
# Generate STATUS.md from CMake job results
status_cmake:
name: Generate STATUS.md
if: always()
needs: test_cmake
runs-on: ubuntu-latest
steps:
- name: Generate summary
uses: gha3mi/setup-fortran-conda@latest
with:
generate-status-cmake: true
# Inject CI status table into README.md
update_readme_table:
name: Update README.md status table
if: |
always() &&
github.ref != 'refs/heads/update-readme-table'
needs: [status_fpm, status_cmake]
runs-on: ubuntu-latest
steps:
- name: Update README status
uses: gha3mi/setup-fortran-conda@latest
with:
update-readme-table: true
update-readme-token: ${{ secrets.GH_PAT }} # Update with your GitHub personal access token
update-readme-user-name: "Your Name" # Update with your name
update-readme-user-email: "you@example.com" # Update with your email
# Run Fortran linter with Fortitude
linter_fortitude:
name: Run Fortitude Linter
runs-on: ubuntu-latest
steps:
- name: Run Fortitude Linter
uses: gha3mi/setup-fortran-conda@latest
with:
fortitude-check: true
fortitude-settings: "--output-format github"
By default, the above example installs the latest available versions of each compiler.
To use a specific version, add a compiler-version
entry in your matrix:
matrix:
# os: [ubuntu-latest, macos-latest, windows-latest]
# compiler: [gfortran, ifx, lfortran, flang-new, nvfortran]
include:
# gfortran
- os: ubuntu-latest
compiler: gfortran
compiler-version: 15.1.0
extra-packages: "cmake, ninja"
- os: macos-latest
compiler: gfortran
compiler-version: 15.1.0
extra-packages: "cmake, ninja"
- os: windows-latest
compiler: gfortran
compiler-version: 15.1.0
extra-packages: "cmake, ninja"
Then, reference compiler-version
in the setup step:
- name: Setup Fortran
uses: gha3mi/setup-fortran-conda@latest
with:
compiler: ${{ matrix.compiler }}
compiler-version: ${{ matrix.compiler-version }} # must be specified
platform: ${{ matrix.os }}
extra-packages: ${{ matrix.extra-packages }}
If compiler-version
is set to an empty string ""
, the latest version will be installed.
MPI-based tests can be executed using fpm with the mpifort. This is currently supported on Linux and macOS runners. The following example job sets up the environment and runs parallel MPI tests:
test_mpi_fpm:
name: ${{ matrix.os }}_${{ matrix.compiler }}_mpi_fpm
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest]
compiler: [mpifort]
include:
- os: ubuntu-latest
extra-packages: ""
- os: macos-latest
extra-packages: ""
steps:
- name: Setup Fortran
uses: gha3mi/setup-fortran-conda@latest
with:
compiler: ${{ matrix.compiler }}
platform: ${{ matrix.os }}
extra-packages: ${{ matrix.extra-packages }}
- name: fpm test (debug)
run: fpm test --target mpi_hello --compiler ${{ matrix.compiler }} --profile debug --flag "-cpp -DUSE_MPI" --runner "mpirun -np 4" --verbose
- name: fpm test (release)
run: fpm test --target mpi_hello --compiler ${{ matrix.compiler }} --profile release --flag "-cpp -DUSE_MPI" --runner "mpirun -np 4" --verbose
Compiler | macos | ubuntu | windows |
---|---|---|---|
flang-new |
- | fpm ✅ cmake ✅ | fpm ❌ cmake ✅ |
gfortran |
fpm ✅ cmake ✅ | fpm ✅ cmake ✅ | fpm ✅ cmake ✅ |
ifx |
- | fpm ✅ cmake ✅ | fpm ✅ cmake ✅ |
lfortran |
fpm ✅ cmake ✅ | fpm ✅ cmake ✅ | fpm ✅ cmake ✅ |
mpifort |
mpi_fpm ✅ | mpi_fpm ✅ | - |
nvfortran |
- | fpm ✅ cmake ✅ | - |
This project includes a Bash script for automating GitHub releases.
curl -L https://raw.githubusercontent.com/gha3mi/setup-fortran-conda/main/release.sh -o release.sh
The script automates:
- ✅ Semantic versioning: Calculates the next version (
major
,minor
, orpatch
) based on PR titles and commit messages. - 📝 CHANGELOG generation: Compiles a categorized
CHANGELOG.md
using PR data and commits since the last release. - 🔖 Git tagging: Tags the new version (e.g.,
v1.2.3
) and updates the floatinglatest
tag. - 📤 GitHub Release: Publishes a release with autogenerated notes.
- 💻 Modes:
--dry-run
: Simulates the release steps with no side effects.--local
: Updates files and tags locally, but skips pushing or publishing the release.
- GitHub CLI (
gh
) – must be authenticated (gh auth login
) jq
bash release.sh --help
It’s highly recommended to first run in --dry-run
mode to verify the output, then in --local
mode to update files and tags locally, and finally without any flags to push changes and publish the GitHub release.