Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial testing framework #1218

Open
wants to merge 7 commits into
base: develop
Choose a base branch
from
Open
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
22 changes: 22 additions & 0 deletions .ci/env/derecho.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/bin/sh

echo "Setting up derecho environment"
workingDirectory=$PWD
. /etc/profile.d/z00_modules.sh
echo "Loading modules : $*"
cmd="module purge"
echo $cmd && eval "${cmd}"

# We should be handed in the modules to load
while [ $# -gt 0 ]; do
cmd="module load $1"
echo $cmd && eval "${cmd}"
shift
done

# Go back to working directory if for unknown reason HPC config changing your directory on you
if [ "$workingDirectory" != "$PWD" ]; then
echo "derecho module loading changed working directory"
echo " Moving back to $workingDirectory"
cd $workingDirectory
fi
46 changes: 46 additions & 0 deletions .ci/env/helpers.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#!/bin/sh

# Useful string manipulation functions, leaving in for posterity
# https://stackoverflow.com/a/8811800
# contains(string, substring)
#
# Returns 0 if the specified string contains the specified substring,
# otherwise returns 1.
contains()
{
string="$1"
substring="$2"

if [ "${string#*"$substring"}" != "$string" ]; then
echo 0 # $substring is in $string
else
echo 1 # $substring is not in $string
fi
}

setenvStr()
{
# Changing IFS produces the most consistent results
tmpIFS=$IFS
IFS=","
string="$1"
for s in $string; do
if [ ! -z $s ]; then
eval "echo export \"$s\""
eval "export \"$s\""
fi
done
IFS=$tmpIFS
}

banner()
{
lengthBanner=$1
shift
# https://www.shellscript.sh/examples/banner/
printf "#%${lengthBanner}s#\n" | tr " " "="
printf "# %-$(( ${lengthBanner} - 2 ))s #\n" "`date`"
printf "# %-$(( ${lengthBanner} - 2 ))s #\n" " "
printf "# %-$(( ${lengthBanner} - 2 ))s #\n" "$*"
printf "#%${lengthBanner}s#\n" | tr " " "="
}
16 changes: 16 additions & 0 deletions .ci/env/hostenv.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/bin/sh

# Allow selection of hostname, and if none is provided use the current machine
# While this may seem unintuitive at first, it provides the flexibility of using
# "named" configurations without being explicitly tied to fqdn
hostname=$AS_HOST
if [ -z "$hostname" ]; then
hostname=$( python3 -c "import socket; print( socket.getfqdn() )" )
fi

if [ $( contains ${hostname} hsn.de.hpc ) -eq 0 ]; then
# Derecho HPC SuSE PBS
. .ci/env/derecho.sh
else
echo "No known environment for '${hostname}', using current"
fi
1 change: 1 addition & 0 deletions .ci/hpc-workflows
Submodule hpc-workflows added at dfc8e6
42 changes: 42 additions & 0 deletions .ci/mpas_compilation.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"submit_options" :
{
"timelimit" : "00:15:00",
"working_directory" : "..",
"arguments" :
{
"base_env_numprocs" : [ "-e", "NUM_PROCS=4" ],

".*make.*::args_build_core" : [ "-c", "atmosphere" ],
".*debug.*::args_build_debug" : [ "-d" ],
".*make.*::args_build_options" : [ "-b", "-j $NUM_PROCS" ],
".*make.*gnu.*::args_target" : [ "-t", "gnu" ]
},
"hsn.de.hpc" :
{
"submission" : "PBS",
"queue" : "main",
"hpc_arguments" :
{
"node_select" : { "-l " : { "select" : 1, "ncpus" : 16 } },
"priority" : { "-l " : { "job_priority" : "economy" } }
},
"arguments" :
{
"base_env_numprocs" : [ "-e", "NUM_PROCS=16" ],
"very_last_modules" : [ "cray-mpich", "parallel-netcdf" ],
".*gnu.*::test_modules" : [ "gcc/12.2.0" ]
}
}
},
"make-gnu" :
{
"steps" :
{
"optimized" :
{
"command" : ".ci/tests/build.sh"
}
}
}
}
90 changes: 90 additions & 0 deletions .ci/tests/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
#!/bin/sh
help()
{
echo "./build.sh as_host workingdir [options] [-- <hostenv.sh options>]"
echo " as_host First argument must be the host configuration to use for environment loading"
echo " workingdir Second argument must be the working dir to immediate cd to"
echo " -b Additional make arguments passed in"
echo " -c Core to build"
echo " -t Target configuration (gnu, intel, etc)"
echo " -d Debug build"
echo " -e environment variables in comma-delimited list, e.g. var=1,foo,bar=0"
echo " -- <hostenv.sh options> Directly pass options to hostenv.sh, equivalent to hostenv.sh <options>"
echo " -h Print this message"
echo ""
echo "If you wish to use an env var in your arg such as '-b core=\$CORE -e CORE=atmosphere', you must"
echo "you will need to do '-b \\\$CORE -e CORE=atmosphere' to delay shell expansion"
}

echo "Input arguments:"
echo "$*"

AS_HOST=$1
shift
if [ $AS_HOST = "-h" ]; then
help
exit 0
fi

workingDirectory=$1
shift

cd $workingDirectory

# Get some helper functions, AS_HOST must be set by this point to work
. .ci/env/helpers.sh

while getopts b:c:t:de:h opt; do
case $opt in
b)
buildCommand="$OPTARG"
;;
c)
core="$OPTARG"
;;
t)
target="$OPTARG"
;;
d)
debug="DEBUG=true"
;;
e)
envVars="$envVars,$OPTARG"
;;
h) help; exit 0 ;;
*) help; exit 1 ;;
:) help; exit 1 ;;
\?) help; exit 1 ;;
esac
done

shift "$((OPTIND - 1))"

# Everything else goes to our env setup, POSIX does not specify how to pass in
# arguments to sourced script, but all args are already shifted. This is left for
# posterity to "show" what is happening and the assumption of the remaining args
. .ci/env/hostenv.sh $*

# Now evaluate env vars in case it pulls from hostenv.sh
if [ ! -z "$envVars" ]; then
setenvStr "$envVars"
fi

# Re-evaluate input values for delayed expansion
eval "core=\"$core\""
eval "target=\"$target\""
eval "buildCommand=\"$buildCommand\""

make clean CORE=$core

echo "Compiling with options $target core=$core $debug $buildCommand"
echo "make $target CORE=$core $debug $buildCommand"
make $target CORE=$core $debug $buildCommand
result=$?

if [ $result -ne 0 ]; then
echo "Failed to compile"
exit 1
fi

echo "TEST $(basename $0) PASS"
95 changes: 95 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
name: Regression Suite
run-name : ${{ github.event_name == 'push' && 'CI' || github.event.label.name }} (${{ github.event_name }})

on:
push:
branches: [ master, develop ]
# See https://stackoverflow.com/a/78444521 and
# https://github.com/orgs/community/discussions/26874#discussioncomment-3253755
# as well as official (but buried) documentation :
# https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#pull-request-events-for-forked-repositories-2
pull_request:
types: [ labeled ]

# https://docs.github.com/en/actions/sharing-automations/reusing-workflows#supported-keywords-for-jobs-that-call-a-reusable-workflow
# Also https://stackoverflow.com/a/74959635
# TL;DR - For public repositories the safest approach will be to use the default read permissions, but at the cost
# of not being able to modify the labels. That will need to be a separate [trusted] workflow that runs from the base repo
# permissions :
# contents : read
# pull-requests : write

# Write our tests out this way for easier legibility
# testsSet :
# - key : value
# key : value
# tests :
# - value
# - value
# - < next test >
# https://stackoverflow.com/a/68940067
jobs:
buildtests:
if : ${{ github.event.label.name == 'compile-tests' || github.event.label.name == 'all-tests' || github.event_name == 'push' }}
strategy:
max-parallel: 4
fail-fast: false
matrix:

testSet :
- host : derecho
hpc-workflows_path : .ci/hpc-workflows
archive : /glade/work/aislas/github/runners/mpas/derecho/logs/
account : NMMM0012
name : "Make Compilation Tests"
id : make-tests
fileroot : mpas_compilation
args : -j='{"node_select":{"-l ":{"select":1}}}'
pool : 8
tpool : 1
mkdirs : true
tests :
- make-gnu
# add new compilation tests here

uses : ./.github/workflows/test_workflow.yml
with :
# This should be the only hard-coded value, we don't use ${{ github.event.label.name }}
# to avoid 'all-tests' to be used in this workflow
label : compile-tests

# Everything below this should remain the same and comes from the testSet matrix
hpc-workflows_path : ${{ matrix.testSet.hpc-workflows_path }}
archive : ${{ matrix.testSet.archive }}
name : ${{ matrix.testSet.name }}
id : ${{ matrix.testSet.id }}
host : ${{ matrix.testSet.host }}
fileroot : ${{ matrix.testSet.fileroot }}
account : ${{ matrix.testSet.account }}
tests : ${{ toJson( matrix.testSet.tests ) }}
mkdirs : ${{ matrix.testSet.mkdirs }}
args : ${{ matrix.testSet.args }}
pool : ${{ matrix.testSet.pool }}
tpool : ${{ matrix.testSet.tpool }}
permissions:
contents: read
pull-requests: write
name : Test ${{ matrix.testSet.name }} on ${{ matrix.testSet.host }}

# In the event that 'all-tests' is used, this final job will be the one to remove
# the label from the PR
removeAllLabel :
if : ${{ !cancelled() && github.event.label.name == 'all-tests' }}
name : Remove 'all-tests' label
runs-on: ubuntu-latest
needs : [ buildtests ] # Put tests here to make this wait for the tests to complete
steps:
- name : Remove '${{ github.event.label.name }}' label
env:
PR_NUMBER: ${{ github.event.number }}
run: |
curl \
-X DELETE \
-H "Accept: application/vnd.github.v3+json" \
-H 'Authorization: token ${{ github.token }}' \
https://api.github.com/repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/labels/${{ github.event.label.name }}
Loading