Skip to content

Tests

Tests #121

Workflow file for this run

name: Tests
on:
# Trigger on push or pull request events for the master branch
push:
branches: [ master ]
pull_request:
branches: [ master ]
# Run the workflow Sundays at 0400 UTC
schedule:
- cron: '0 4 * * 0'
# Allow running the workflow manually from the Actions tab
workflow_dispatch:
inputs:
run_name:
description: 'Name of workflow run as it will appear under Actions tab (optional):'
type: string
required: false
default: ''
job_name:
description: 'Select a job from the matrix to run (default: all jobs)'
type: choice
options:
- ''
- 'Ubuntu Baseline'
- 'Ubuntu Baseline, no MPI'
- 'MacOS Baseline'
- 'Ubuntu Latest'
- 'Ubuntu Oldest'
- 'Ubuntu Baseline, no MPI, forced build'
- 'MacOS Baseline, no MPI, forced build'
- 'Ubuntu Latest, no MPI, forced build'
- 'MacOS Baseline on ARM'
required: false
default: ''
debug_enabled:
description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)'
type: boolean
required: false
default: false
run-name: ${{ inputs.run_name }}
jobs:
tests:
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
include:
# test baseline versions on Ubuntu
- NAME: Ubuntu Baseline
OS: ubuntu-latest
PY: '3.12'
NUMPY: '1.26'
SCIPY: '1.13'
MPICC: 4
PYOPTSPARSE: 'default'
# PAROPT: true
SNOPT: 7.7
# test baseline versions on Ubuntu without MPI
- NAME: Ubuntu Baseline, no MPI
OS: ubuntu-latest
PY: '3.12'
NUMPY: '1.26'
SCIPY: '1.13'
PYOPTSPARSE: 'default'
SNOPT: 7.7
# test baseline versions on MacOS
- NAME: MacOS Baseline
OS: macos-13
PY: '3.11'
NUMPY: '1.26'
SCIPY: '1.13'
MPICC: 4
PYOPTSPARSE: 'default'
# PAROPT: true
SNOPT: 7.7
# test latest versions
- NAME: Ubuntu Latest
OS: ubuntu-latest
PY: 3
NUMPY: 1
SCIPY: 1
MPICC: 4
PYOPTSPARSE: 'latest'
# PAROPT: true
SNOPT: 7.7
# test oldest supported versions
- NAME: Ubuntu Oldest
OS: ubuntu-latest
PY: 3.8
NUMPY: 1.22
SCIPY: 1.7
PYOPTSPARSE: 'v2.9.0'
NO_IPOPT: true
SNOPT: 7.2
# test baseline versions on Ubuntu without MPI with forced build
- NAME: Ubuntu Baseline, no MPI, forced build
OS: ubuntu-latest
PY: '3.12'
NUMPY: '1.26'
SCIPY: '1.13'
PYOPTSPARSE: 'default'
SNOPT: 7.7
FORCE_BUILD: true
# test baseline versions on MacOS without MPI with forced build
- NAME: MacOS Baseline, no MPI, forced build
OS: macos-13
PY: '3.11'
NUMPY: '1.26'
SCIPY: '1.13'
PYOPTSPARSE: 'default'
SNOPT: 7.7
FORCE_BUILD: true
XCODE: '14.2'
# test latest versions without MPI with forced build
- NAME: Ubuntu Latest, no MPI, forced build
OS: ubuntu-latest
PY: 3
NUMPY: 1
SCIPY: 1
PYOPTSPARSE: 'latest'
SNOPT: 7.7
FORCE_BUILD: true
# test baseline versions on MacOS latest (ARM64)
- NAME: MacOS Baseline on ARM
OS: macos-latest
PY: '3.12'
NUMPY: '1.26'
SCIPY: '1.13'
BREW: true
MPICC: 4
PYOPTSPARSE: 'default'
SNOPT: 7.7
runs-on: ${{ matrix.OS }}
name: ${{ matrix.NAME }}
defaults:
run:
shell: bash -l {0}
steps:
- name: Display run details
run: |
echo "============================================================="
echo "Run #${GITHUB_RUN_NUMBER}"
echo "Run ID: ${GITHUB_RUN_ID}"
echo "Testing: ${GITHUB_REPOSITORY}"
echo "Triggered by: ${GITHUB_EVENT_NAME}"
echo "Initiated by: ${GITHUB_ACTOR}"
echo "============================================================="
- name: Exit if this job was not selected
if: github.event_name == 'workflow_dispatch' && inputs.job_name != '' && inputs.job_name != matrix.NAME
uses: actions/github-script@v7
with:
script: core.setFailed('The ${{ matrix.NAME }} job was not included in the run, exiting...');
- name: Create SSH key
if: matrix.SNOPT
env:
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
SSH_KNOWN_HOSTS: ${{ secrets.SSH_KNOWN_HOSTS }}
run: |
mkdir -p ~/.ssh/
echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
sudo chmod 600 ~/.ssh/id_rsa
echo "$SSH_KNOWN_HOSTS" > ~/.ssh/known_hosts
- name: Checkout code
uses: actions/checkout@v4
- name: Setup conda
uses: conda-incubator/setup-miniconda@v3
with:
miniconda-version: latest
python-version: ${{ matrix.PY }}
channels: conda-forge
channel-priority: true
- name: Install
run: |
conda install numpy=${{ matrix.NUMPY }} scipy=${{ matrix.SCIPY }} -q -y
if [[ "${{ matrix.BREW }}" ]]; then
brew install swig meson
if [[ "${{ matrix.OS }}" == "macos-latest" ]]; then
ln -s /opt/homebrew/bin/gfortran-13 /opt/homebrew/bin/gfortran
fi
else
conda install compilers cython swig -q -y
fi
if [[ "${{ matrix.XCODE }}" ]]; then
sudo xcode-select -s "/Applications/Xcode_${{ matrix.XCODE }}.app"
fi
echo "============================================================="
echo "Install build_pyoptsparse"
echo "============================================================="
python -m pip install .
- name: Install MPI
if: matrix.MPICC
run: |
echo "============================================================="
echo "Install MPI"
echo "============================================================="
if [[ "${{ matrix.BREW }}" ]]; then
brew install open-mpi mpi4py
else
conda install openmpi-mpicc=${{ matrix.MPICC }} mpi4py -q -y
fi
echo "OMPI_MCA_rmaps_base_oversubscribe=1" >> $GITHUB_ENV
- name: Display environment before
run: |
conda info
conda list
echo "============================================================="
echo "Check installed versions of Python, Numpy and Scipy"
echo "============================================================="
python -c "import sys; assert str(sys.version).startswith(str(${{ matrix.PY }})), \
f'Python version {sys.version} is not the requested version (${{ matrix.PY }})'"
python -c "import numpy; assert str(numpy.__version__).startswith(str(${{ matrix.NUMPY }})), \
f'Numpy version {numpy.__version__} is not the requested version (${{ matrix.NUMPY }})'"
python -c "import scipy; assert str(scipy.__version__).startswith(str(${{ matrix.SCIPY }})), \
f'Scipy version {scipy.__version__} is not the requested version (${{ matrix.SCIPY }})'"
- name: Build pyOptSparse
run: |
echo "============================================================="
echo "Build pyoptsparse"
echo "============================================================="
if [[ "${{ matrix.PYOPTSPARSE }}" == "default" ]]; then
BRANCH=""
elif [[ "${{ matrix.PYOPTSPARSE }}" == "latest" ]]; then
LATEST_URL=`curl -fsSLI -o /dev/null -w %{url_effective} https://github.com/mdolab/pyoptsparse/releases/latest`
LATEST_VER=`echo $LATEST_URL | awk '{split($0,a,"/tag/"); print a[2]}'`
BRANCH="-b $LATEST_VER"
else
BRANCH="-b ${{ matrix.PYOPTSPARSE }}"
fi
if [[ "${{ matrix.PAROPT }}" ]]; then
PAROPT="-a"
fi
if [[ "${{ matrix.SNOPT }}" == "7.7" && "${{ secrets.SNOPT_LOCATION_77 }}" ]]; then
echo " > Secure copying SNOPT 7.7 over SSH"
mkdir SNOPT
scp -qr ${{ secrets.SNOPT_LOCATION_77 }} SNOPT
SNOPT="-s SNOPT/src"
elif [[ "${{ matrix.SNOPT }}" == "7.2" && "${{ secrets.SNOPT_LOCATION_72 }}" ]]; then
echo " > Secure copying SNOPT 7.2 over SSH"
mkdir SNOPT
scp -qr ${{ secrets.SNOPT_LOCATION_72 }} SNOPT
SNOPT="-s SNOPT/source"
elif [[ "${{ matrix.SNOPT }}" ]]; then
echo "SNOPT version ${{ matrix.SNOPT }} was requested but source is not available"
fi
if [[ "${{ matrix.LINEAR_SOLVER }}" == "hsl" ]]; then
if "${{ secrets.HSL_LOCATION }}" ]]; then
scp -q ${{ secrets.HSL_LOCATION }} hsl.tar.gz
LINEAR_SOLVER="-l hsl -t hsl.tar.gz"
else
echo "---------------------------------------------------------------------------"
echo "HSL was requested but source is not available, using default linear solver."
echo "---------------------------------------------------------------------------"
fi
elif [[ "${{ matrix.LINEAR_SOLVER }}" == "pardiso" ]]; then
echo "-------------------------------------------------------------------------------"
echo "Pardiso requires Intel compilers, which are not installed. The build will fail."
echo "-------------------------------------------------------------------------------"
LINEAR_SOLVER="-l pardiso"
fi
if [[ "${{ matrix.NO_IPOPT }}" ]]; then
NO_IPOPT="--no-ipopt"
fi
if [[ "${{ matrix.FORCE_BUILD }}" ]]; then
FORCE_BUILD="--force-build"
fi
echo "build_pyoptsparse -v $BRANCH $FORCE_BUILD $PAROPT $SNOPT $NO_IPOPT $LINEAR_SOLVER"
build_pyoptsparse -v $BRANCH $FORCE_BUILD $PAROPT $SNOPT $NO_IPOPT $LINEAR_SOLVER -d
echo "BRANCH=${BRANCH}" >> $GITHUB_ENV
- name: Display build log
if: failure()
run: |
for f in $(find /tmp/ -name 'meson-log.txt'); do
echo "============================================================="
echo $f
echo "============================================================="
cat $f
done
if test -d /private/var/folders; then
for f in $(find /private/var/folders/ -name 'meson-log.txt'); do
echo "============================================================="
echo $f
echo "============================================================="
cat $f
done
for f in $(find /private/var/folders/ -name 'compile.log'); do
echo "============================================================="
echo $f
echo "============================================================="
cat $f
done
fi
# Enable tmate debugging of manually-triggered workflows if the input option was provided
#
# To access the terminal through the web-interface:
# 1. Click on the web-browser link printed out in this action from the github
# workflow terminal
# 2. Press cntrl + c in the new tab that opens up to reveal the terminal
# 3. To activate the conda environment run:
# $ source $CONDA/etc/profile.d/conda.sh
# $ conda activate test
- name: Setup tmate session
if: github.event_name == 'workflow_dispatch' && inputs.debug_enabled && inputs.job_name == matrix.NAME
uses: mxschmitt/action-tmate@v3
with:
limit-access-to-actor: true
- name: Setup tmate session after failure
if: github.event_name == 'workflow_dispatch' && inputs.debug_enabled && inputs.job_name == matrix.NAME && failure()
uses: mxschmitt/action-tmate@v3
with:
limit-access-to-actor: true
- name: Display environment after
run: |
conda info
conda list
echo "============================================================="
echo "Check installed versions of Python, Numpy and Scipy"
echo "============================================================="
python -c "import sys; assert str(sys.version).startswith(str(${{ matrix.PY }})), \
f'Python version {sys.version} is not the requested version (${{ matrix.PY }})'"
python -c "import numpy; assert str(numpy.__version__).startswith(str(${{ matrix.NUMPY }})), \
f'Numpy version {numpy.__version__} is not the requested version (${{ matrix.NUMPY }})'"
python -c "import scipy; assert str(scipy.__version__).startswith(str(${{ matrix.SCIPY }})), \
f'Scipy version {scipy.__version__} is not the requested version (${{ matrix.SCIPY }})'"
- name: Run tests
run: |
python -m pip install testflo parameterized six
echo "============================================================="
echo "Run tests from pyoptsparse repository"
echo "============================================================="
unset DYLD_LIBRARY_PATH
if [[ "$BRANCH" == "" ]]; then
BRANCH=`python -c "from build_pyoptsparse import build_info; print(build_info['pyoptsparse']['branch'])"`
BRANCH="-b $BRANCH"
fi
echo "git clone $BRANCH https://github.com/mdolab/pyoptsparse"
git clone $BRANCH https://github.com/mdolab/pyoptsparse
cd pyoptsparse/test*/
testflo --pre_announce --timeout=120 --show_skipped .
- name: Audit dependencies
id: audit
continue-on-error: true
run: |
python -m pip install pip-audit
echo "============================================================="
echo "Scan environment for packages with known vulnerabilities"
echo "============================================================="
python -m pip_audit
- name: Slack audit warnings
if: steps.audit.outcome == 'failure' && matrix.NAME != 'Ubuntu Oldest'
uses: act10ns/[email protected]
with:
webhook-url: ${{ secrets.SLACK_WEBHOOK_URL }}
status: 'warning'
message: |
pip-audit detected vulnerabilities.
${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
- name: Notify slack
uses: act10ns/[email protected]
with:
webhook-url: ${{ secrets.SLACK_WEBHOOK_URL }}
status: ${{ job.status }}
if: failure()