diff --git a/.bbp-project.yaml b/.bbp-project.yaml index 638867d28..49d547a65 100644 --- a/.bbp-project.yaml +++ b/.bbp-project.yaml @@ -5,6 +5,7 @@ tools: match: - ext/.* - src/language/templates/* + - test/usecases/*/* ClangTidy: enable: true option: '' diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 000000000..8eb1d2d42 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,119 @@ +include: + - project: hpc/gitlab-pipelines + file: + - spack-build-components.gitlab-ci.yml + - github-project-pipelines.gitlab-ci.yml + - project: hpc/gitlab-upload-logs + file: enable-upload.yml + +variables: + CVF_BRANCH: + description: Branch of the channel validation framework (CVF) to trigger the CI of + value: main + SPACK_BRANCH: + description: Branch of BlueBrain Spack to use for the CI pipeline + value: develop + BLUECONFIGS_BRANCH: + description: Branch of blueconfigs to trigger the simulation stack pipeline from + value: main + NEURON_BRANCH: + description: Branch of neuron to build BlueBrain models against in the simulation stack pipeline (NEURON_COMMIT and NEURON_TAG also possible) + value: master + LIBSONATA_REPORT_BRANCH: + description: Branch of libsonata-report to build BlueBrain models against in the simulation stack pipeline (LIBSONATA_REPORT_COMMIT and LIBSONATA_REPORT_TAG also possible) + value: master + SPACK_DEPLOYMENT_SUFFIX: + description: Extra path component used when finding deployed software. Set to something like `pulls/1497` use software built for https://github.com/BlueBrain/spack/pull/1497. You probably want to set SPACK_BRANCH to the branch used in the relevant PR if you set this. + value: '' + +trigger cvf: + # Stop the globally-defined CVF_BRANCH above from being set in the child pipeline + inherit: + variables: false + needs: [spack_setup] # for SPACK_SETUP_COMMIT_MAPPING_URL + stage: .pre + rules: + # Don't run on PRs targeting the LLVM development branch + - if: '$CI_EXTERNAL_PULL_REQUEST_TARGET_BRANCH_NAME == "llvm"' + when: never + # Otherwise always run this + - when: always + trigger: + branch: ${CVF_BRANCH} + project: hpc/cvf + # Make the NMODL CI status depend on the CVF CI status + strategy: depend + variables: + # Tell CVF to use the same commits/branches as NMODL. + SPACK_ENV_FILE_URL: $SPACK_SETUP_COMMIT_MAPPING_URL + +simulation_stack: + stage: .pre + # Take advantage of GitHub PR description parsing in the spack_setup job. + needs: [spack_setup] + trigger: + branch: ${BLUECONFIGS_BRANCH} + project: hpc/sim/blueconfigs + # NMODL CI status depends on the BlueConfigs CI status. + strategy: depend + variables: + SPACK_ENV_FILE_URL: $SPACK_SETUP_COMMIT_MAPPING_URL + NMODL_RUN: "true" + # SPACK_SETUP_IGNORE_PACKAGE_VARIABLES needs to be set for + # the blueconfigs CI as well to let it know about both CVF + # and BLUECONFIGS + SPACK_SETUP_IGNORE_PACKAGE_VARIABLES: "CVF BLUECONFIGS" + +.spack_nmodl: + variables: + SPACK_PACKAGE: nmodl + SPACK_PACKAGE_SPEC: +python + +spack_setup: + extends: .spack_setup_ccache + script: + - !reference [.spack_setup_ccache, script] + # Setting {CVF, BLUECONFIGS}_BRANCH in the PR description will cause them to + # be set in the environment of this job, but because we put CVF and BLUECONFIGS + # in SPACK_SETUP_IGNORE_PACKAGE_VARIABLES then nothing will be done with it. + - echo "CVF_BRANCH=${CVF_BRANCH}" >> spack_clone_variables.env + - echo "BLUECONFIGS_BRANCH=${BLUECONFIGS_BRANCH}" >> spack_clone_variables.env + variables: + NMODL_COMMIT: ${CI_COMMIT_SHA} + # Enable fetching GitHub PR descriptions and parsing them to find out what + # branches to build of other projects. + PARSE_GITHUB_PR_DESCRIPTIONS: "true" + # Ignore CVF ang BLUECONFIGS branches since those don't have a spack package + SPACK_SETUP_IGNORE_PACKAGE_VARIABLES: "CVF BLUECONFIGS" + +build:intel: + extends: + - .spack_build + - .spack_nmodl + variables: + SPACK_PACKAGE_COMPILER: oneapi + +build:nvhpc: + extends: + - .spack_build + - .spack_nmodl + variables: + SPACK_PACKAGE_COMPILER: nvhpc + SPACK_PACKAGE_DEPENDENCIES: ^bison%gcc^flex%gcc^py-jinja2%gcc^py-sympy%gcc^py-pyyaml%gcc + +.nmodl_tests: + variables: + # https://github.com/BlueBrain/nmodl/issues/737 + bb5_ntasks: 1 + +test:intel: + extends: + - .ctest + - .nmodl_tests + needs: ["build:intel"] + +test:nvhpc: + extends: + - .ctest + - .nmodl_tests + needs: ["build:nvhpc"] diff --git a/.gitmodules b/.gitmodules index f9af32cc5..9f50db609 100644 --- a/.gitmodules +++ b/.gitmodules @@ -25,3 +25,6 @@ [submodule "ext/backward"] path = ext/backward url = https://github.com/bombela/backward-cpp.git +[submodule "test/usecases/references"] + path = test/usecases/references + url = https://github.com/BlueBrain/nmodl-references.git diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index abb1c7584..c7ad6e594 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -165,6 +165,33 @@ The HPC coding conventions formatter installs any dependencies into a Python virtual environment. +Updating Golden References +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Run + +.. code:: bash + + cmake --build --target generate_references + +to regenerate the golden references. They are saved in a submodule +``tests/usecases/references``, which points to ``BlueBrain/nmodl-references``. + +Create a PR for the changes to the references and update the SHA in the NMODL +repo. It might be useful to change to SSH authentication: + +.. code:: bash + + git remote set-url origin ssh://git@github.com/BlueBrain/nmodl-references + +(from inside ``tests/usecases/references``). + +Remember the rules of submodules: They're checked out on a specific commit, +i.e. detached HEAD. If you want to modify the submodule, it's usual best to +checkout ``main`` from then on the submodule will behave much like a Git repo +that happens to be located inside a Git repo. + + Validate the Python package ~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/test/usecases/CMakeLists.txt b/test/usecases/CMakeLists.txt index d18ef2a76..3f555d9db 100644 --- a/test/usecases/CMakeLists.txt +++ b/test/usecases/CMakeLists.txt @@ -7,8 +7,37 @@ set(NMODL_USECASE_DIRS func_proc func_proc_pnt) +file(GLOB NMODL_GOLDEN_REFERENCES "${CMAKE_CURRENT_SOURCE_DIR}/references/*") +if(NMODL_GOLDEN_REFERENCES STREQUAL "") + cpp_cc_init_git_submodule(${CMAKE_CURRENT_SOURCE_DIR}/references) +endif() +unset(NMODL_GOLDEN_REFERNCES) + +add_custom_target(generate_references) foreach(usecase ${NMODL_USECASE_DIRS}) + # Non-existant dependencies are a way of unconditionally running commands in CMake. + if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/references/${usecase}/_does_not_exist_weiohbge) + message( + FATAL_ERROR + "The file: '${CMAKE_CURRENT_SOURCE_DIR}/references/${usecase}/_does_not_exist_weiohbge' must not exist." + ) + endif() + add_test(NAME usecase_${usecase} COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/run_test.sh ${CMAKE_BINARY_DIR}/bin/nmodl ${CMAKE_CURRENT_SOURCE_DIR}/${usecase}) + + add_test(NAME golden_${usecase} + COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/check_references.sh ${CMAKE_BINARY_DIR}/bin/nmodl + ${CMAKE_CURRENT_SOURCE_DIR}/${usecase}) + + add_custom_command( + OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/references/${usecase}/_does_not_exist_weiohbge + COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/generate_references.sh ${CMAKE_BINARY_DIR}/bin/nmodl + ${CMAKE_CURRENT_SOURCE_DIR}/${usecase}) + + add_custom_target( + generate_${usecase} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/references/${usecase}/_does_not_exist_weiohbge) + add_dependencies(generate_references generate_${usecase}) endforeach() diff --git a/test/usecases/check_references.sh b/test/usecases/check_references.sh new file mode 100755 index 000000000..0789afff1 --- /dev/null +++ b/test/usecases/check_references.sh @@ -0,0 +1,18 @@ +#! /usr/bin/env bash +set -u + +script_dir="$(dirname "$(realpath "$0")")" +nmodl="$1" +usecase_dir="$2" +references_dir="${script_dir}/references/$(basename "$2")" +output_dir="$(mktemp -d)" + +"${script_dir}"/generate_references.sh ${nmodl} "${usecase_dir}" "${output_dir}" + +diff -U 8 -r "${references_dir}" "${output_dir}" + +exit_code=$? + +rm -r "${output_dir}" + +exit $exit_code diff --git a/test/usecases/generate_references.sh b/test/usecases/generate_references.sh new file mode 100755 index 000000000..ef21a838e --- /dev/null +++ b/test/usecases/generate_references.sh @@ -0,0 +1,33 @@ +#! /usr/bin/env bash +set -eu + +nmodl="$1" +usecase_dir="$2" + +if [[ $# -eq 3 ]] +then + output_dir="$3" +else + script_dir="$(dirname "$(realpath "$0")")" + output_dir="${script_dir}/references/$(basename "$2")" +fi + +function sanitize() { + for f in "${1}"/*.cpp + do + if [[ "$(uname)" == 'Darwin' ]] + then + sed_cmd="sed -i''" + else + sed_cmd="sed -i" + fi + ${sed_cmd} "s/Created : .*$/Created : DATE/" "$f" + ${sed_cmd} "s/NMODL Compiler : .*$/NMODL Compiler : VERSION/" "$f" + done +} + +"${nmodl}" "${usecase_dir}"/*.mod --neuron -o "${output_dir}/neuron" +sanitize "${output_dir}/neuron" + +"${nmodl}" "${usecase_dir}"/*.mod -o "${output_dir}"/coreneuron +sanitize "${output_dir}/coreneuron" diff --git a/test/usecases/references b/test/usecases/references new file mode 160000 index 000000000..86ea3be28 --- /dev/null +++ b/test/usecases/references @@ -0,0 +1 @@ +Subproject commit 86ea3be28505f69fe6073498fc995c61f493326d diff --git a/test/usecases/run_test.sh b/test/usecases/run_test.sh index 858751c89..ff18c6a34 100755 --- a/test/usecases/run_test.sh +++ b/test/usecases/run_test.sh @@ -1,5 +1,10 @@ #! /usr/bin/env bash -set -e +set -eu + +if [[ $# -ne 2 ]] +then + echo "Usage: $0 NMODL USECASE_DIR" +fi nmodl="$1" output_dir="$(uname -m)"