From 817c438558caa70ff1c970764873d22a452cb09c Mon Sep 17 00:00:00 2001 From: Chris Markiewicz Date: Tue, 24 Sep 2024 15:14:28 -0400 Subject: [PATCH 01/18] CI: Disable CircleCI --- .circleci/config.yml | 520 +------------------------------------------ 1 file changed, 5 insertions(+), 515 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 6d842d2389..302a7d3112 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,524 +1,14 @@ -# reusable anchors -_machine_defaults: &machine_defaults - environment: - TZ: "/usr/share/zoneinfo/America/Los_Angeles" - SCRATCH: "/scratch" - machine: - image: ubuntu-2204:current - docker_layer_caching: true - working_directory: /tmp/src/sdcflows - resource_class: large - -_python_defaults: &python_defaults - docker: - - image: cimg/python:3.10.9 - working_directory: /tmp/src/sdcflows - -_docker_auth: &docker_auth - name: Docker authentication - command: | - if [[ -n $DOCKER_PAT ]]; then - echo "$DOCKER_PAT" | docker login -u $DOCKER_USER --password-stdin - fi - -_setup_docker_registry: &setup_docker_registry - name: Set up Docker registry - command: | - if [[ -f /tmp/images/registry.tar.gz ]]; then - echo "Loading saved registry image" - docker load < /tmp/images/registry.tar.gz - else - echo "Pulling registry image from DockerHub" - docker pull registry:2 - fi - docker run -d -p 5000:5000 --restart=always --name=registry \ - -v /tmp/docker:/var/lib/registry registry:2 - -_pull_from_registry: &pull_from_registry - name: Pull and tag image from local registry - command: | - docker pull localhost:5000/sdcflows - docker tag localhost:5000/sdcflows nipreps/sdcflows:latest - version: 2.1 -orbs: - docker: circleci/docker@2.2.0 - codecov: codecov/codecov@3.2.4 jobs: - cache_test_data: - docker: # executor type - - image: nipreps/miniconda:py39_2209.01 - auth: - username: $DOCKER_USER - password: $DOCKER_PAT - - working_directory: /tmp/data - environment: - - TEMPLATEFLOW_HOME: /tmp/templateflow - steps: - - checkout: - path: /tmp/src/sdcflows - - - run: - name: Configure git (pacify datalad) - command: | - git config --global user.name "First Last" - git config --global user.email "email@domain.com" - - - restore_cache: - keys: - - data-v6-{{ .Branch }}-{{ .Revision }} - - data-v6--{{ .Revision }} - - data-v6-{{ .Branch }}- - - data-v6-main- - - data-v6- - - - run: - name: Ensure some templates are cached - command: | - python -c "from templateflow import api as tfapi; \ - tfapi.get('MNI152NLin2009cAsym', resolution=2, desc='brain', suffix='mask'); \ - tfapi.get('MNI152NLin2009cAsym', resolution=2, desc='fMRIPrep', suffix='boldref');" - - - run: - name: Install ds001600 - command: | - datalad install -r https://github.com/nipreps-data/ds001600.git - datalad update -r --merge -d ds001600/ - datalad get -r -d ds001600/ ds001600/sub-1/ - - - run: - name: Install HCP/sub-101006 - command: | - datalad install -r https://github.com/nipreps-data/HCP101006.git - datalad update -r --merge -d HCP101006/ - datalad get -r -d HCP101006 - - - run: - name: Install ds001771 - command: | - datalad install -r https://github.com/nipreps-data/ds001771.git - datalad update -r --merge -d ds001771/ - datalad get -r -d ds001771/ ds001771/sub-36/* - datalad get -r -d ds001771/derivatives ds001771/derivatives/openneuro/sub-36/* - - - run: - name: Install ds000206 - command: | - datalad install -r https://github.com/nipreps-data/ds000206.git - datalad update -r --merge -d ds000206/ - datalad get -r -d ds000206/ ds000206/sub-05/* - - - run: - name: Install ds000054 - command: | - datalad install -r https://github.com/nipreps-data/ds000054.git - datalad update -r --merge -d ds000054/ - datalad get -r -J 2 -d ds000054/ ds000054/* ds000054/derivatives/* - - - run: - name: Install Brain extraction tests - command: | - datalad install -r https://gin.g-node.org/nipreps-data/brain-extraction-tests - datalad update --merge -d brain-extraction-tests/ - datalad get -r -J 2 -d brain-extraction-tests - - - run: - name: Install HCPh fieldmaps - command: | - datalad install -r https://github.com/nipreps-data/hcph-pilot_fieldmaps.git - datalad update -r --merge -d hcph-pilot_fieldmaps/ - datalad get -r -J 2 -d hcph-pilot_fieldmaps/ hcph-pilot_fieldmaps/* - - - save_cache: - key: data-v6-{{ .Branch }}-{{ .Revision }} - paths: - - /tmp/data - - /tmp/templateflow - - - restore_cache: - keys: - - freesurfer-v0-{{ .BuildNum }} - - freesurfer-v0- - - run: - name: Pull FreeSurfer down - command: | - if [[ ! -d /tmp/freesurfer ]]; then - curl -sSL https://surfer.nmr.mgh.harvard.edu/pub/dist/freesurfer/6.0.1/freesurfer-Linux-centos6_x86_64-stable-pub-v6.0.1.tar.gz | tar zxv --no-same-owner -C /tmp \ - --exclude='freesurfer/diffusion' \ - --exclude='freesurfer/docs' \ - --exclude='freesurfer/fsfast' \ - --exclude='freesurfer/lib/cuda' \ - --exclude='freesurfer/lib/qt' \ - --exclude='freesurfer/matlab' \ - --exclude='freesurfer/mni/share/man' \ - --exclude='freesurfer/subjects/fsaverage_sym' \ - --exclude='freesurfer/subjects/fsaverage3' \ - --exclude='freesurfer/subjects/fsaverage4' \ - --exclude='freesurfer/subjects/cvs_avg35' \ - --exclude='freesurfer/subjects/cvs_avg35_inMNI152' \ - --exclude='freesurfer/subjects/bert' \ - --exclude='freesurfer/subjects/lh.EC_average' \ - --exclude='freesurfer/subjects/rh.EC_average' \ - --exclude='freesurfer/subjects/sample-*.mgz' \ - --exclude='freesurfer/subjects/V1_average' \ - --exclude='freesurfer/trctrain' - echo "b2VzdGViYW5Ac3RhbmZvcmQuZWR1CjMwNzU2CiAqQ1MzYkJ5VXMxdTVNCiBGU2kvUGJsejJxR1V3Cg==" | base64 -d > /tmp/freesurfer/license.txt - else - echo "FreeSurfer was cached." - circleci step halt - fi - - save_cache: - key: freesurfer-v0-{{ .BuildNum }} - paths: - - /tmp/freesurfer - - build_n_pytest: - <<: *machine_defaults - working_directory: /tmp/tests + empty: + machine: + image: ubuntu-2204:current steps: - - restore_cache: - keys: - - build-v2-{{ .Branch }}-{{ epoch }} - - build-v2-{{ .Branch }}- - - build-v2-master- - - build-v2- - paths: - - /tmp/docker - - docker/install-docker-credential-helper - - run: *docker_auth - - run: *setup_docker_registry - - run: - name: Pull Ubuntu/jammy image - command: | - set +e - docker pull localhost:5000/ubuntu - success=$? - set -e - if [[ "$success" = "0" ]]; then - echo "Pulling from local registry" - docker tag localhost:5000/ubuntu ubuntu:jammy - else - echo "Pulling from Docker Hub" - docker pull ubuntu:jammy - docker tag ubuntu:jammy localhost:5000/ubuntu - docker push localhost:5000/ubuntu - fi - - run: - name: Pull SDCFlows Docker image - command: | - set +e - docker pull localhost:5000/sdcflows - success=$? - set -e - if [[ "$success" = "0" ]]; then - echo "Pulling from local registry" - docker tag localhost:5000/sdcflows nipreps/sdcflows:latest - docker tag localhost:5000/sdcflows nipreps/sdcflows - else - echo "Pulling from Docker Hub" - docker pull nipreps/sdcflows:latest - fi - - checkout: - path: /tmp/src/sdcflows - - run: - name: Build Docker image - working_directory: /tmp/src/sdcflows - no_output_timeout: 60m - command: | - export PY3=$( pyenv versions | awk '/^\* 3/ { print $2 }' ) - pyenv local $PY3 - python3 -m pip install -U build hatch hatchling pip twine docutils - - # Get version, update files. - THISVERSION=$( python3 -m hatch version | tail -n1 | xargs ) - if [[ ${THISVERSION:0:1} == "0" ]] ; then - echo "WARNING: latest git tag could not be found" - echo "Please, make sure you fetch all tags from upstream with" - echo "the command ``git fetch --tags --verbose`` and push" - echo "them to your fork with ``git push origin --tags``" - fi - # Build docker image - docker build --rm \ - --cache-from=nipreps/sdcflows \ - -t nipreps/sdcflows:latest \ - --build-arg BUILD_DATE=`date -u +"%Y-%m-%dT%H:%M:%SZ"` \ - --build-arg VCS_REF=`git rev-parse --short HEAD` \ - --build-arg VERSION="${CIRCLE_TAG:-$THISVERSION}" . \ - | tee build-output.log - echo "${CIRCLE_TAG:-$THISVERSION}" >> /tmp/.local-version.txt - - run: - name: Check Docker image - working_directory: /tmp/src/sdcflows - command: | - export PY3=$( pyenv versions | awk '/^\* 3/ { print $2 }' ) - pyenv local $PY3 - # Get version, update files. - THISVERSION=$( python3 -m hatch version | tail -n1 | xargs ) - BUILT_VERSION=$( docker run --rm --entrypoint=python nipreps/sdcflows:latest -c "import sdcflows; print(sdcflows.__version__)" ) - BUILT_VERSION=${BUILT_VERSION%$'\r'} - echo "VERSION: \"$THISVERSION\"" - echo "BUILT: \"$BUILT_VERSION\"" - set -e - test "$BUILT_VERSION" = "$THISVERSION" - - run: - name: Docker push to local registry - no_output_timeout: 40m - command: | - docker tag nipreps/sdcflows:latest localhost:5000/sdcflows - docker push localhost:5000/sdcflows - - run: - name: Docker registry garbage collection - command: | - docker exec -it registry /bin/registry garbage-collect --delete-untagged \ - /etc/docker/registry/config.yml - - save_cache: - key: build-v2-{{ .Branch }}-{{ epoch }} - paths: - - /tmp/docker - - - restore_cache: - keys: - - freesurfer-v0-{{ .BuildNum }} - - freesurfer-v0- - - restore_cache: - keys: - - data-v6-{{ .Branch }}-{{ .Revision }} - - data-v6--{{ .Revision }} - - data-v6-{{ .Branch }}- - - data-v6-main- - - data-v6- - - - restore_cache: - keys: - - workdir-v3-{{ .Branch }}- - - workdir-v3-master- - - workdir-v3- - - run: - name: Refreshing cached intermediate results - working_directory: /tmp/src/sdcflows - command: | - COMMIT_MSG=$( git log --format=oneline -n 1 $CIRCLE_SHA1 ) - set +e - do_refresh="$( echo "${COMMIT_MSG}" | grep -i -E '\[refresh[ _]?cache\]' )" - set -e - if [[ "x${do_refresh}" = "x" ]]; then - echo "Did not refresh the workdir." - else - wget --retry-connrefused --waitretry=5 --read-timeout=20 --timeout=15 -t 0 -q \ - -O /tmp/data/workdir.tar.gz "https://files.osf.io/v1/resources/9sy2a/providers/osfstorage/5dcabd60a1cd9e000c751b3c" - rm -rf /tmp/work - mkdir -p /tmp/work - pushd /tmp/work - tar xzfv /tmp/data/workdir.tar.gz --strip 1 - popd - fi - - wipe_dir=$( echo "${COMMIT_MSG}" | sed -n 's/.*\[wipe \([a-zA-Z0-9_\*]*\)\].*/\1/p' ) - if [[ "x${wipe_dir}" != "x" ]]; then - path=/tmp/work/${wipe_dir} - echo "Found tag [wipe ${wipe_dir}] - clearing up $path ..." - rm -rf ${path} - fi - - run: - name: Run tests - no_output_timeout: 2h - command: | - mkdir -p /tmp/work - docker run -it --rm -w /src/sdcflows \ - -e TEST_WORK_DIR=/work \ - -e TEST_DATA_HOME=/data \ - -e TEST_OUTPUT_DIR=/out \ - -e COVERAGE_FILE=/out/.coverage \ - -e FS_LICENSE=/opt/freesurfer/license.txt \ - -v /tmp/data:/data:ro \ - -v /tmp/src:/src \ - -v /tmp/tests:/out \ - -v /tmp/work:/work \ - -v /tmp/freesurfer:/opt/freesurfer:ro \ - -v /tmp/templateflow:/home/sdcflows/.cache/templateflow \ - nipreps/sdcflows:latest \ - pytest -v --junit-xml=/out/pytest.xml \ - --cov sdcflows --cov-report xml:/out/unittests.xml \ - -n auto sdcflows/ - - save_cache: - key: workdir-v3-{{ .Branch }}-{{ .BuildNum }} - paths: - - /tmp/work - - store_artifacts: - path: /tmp/tests - - store_test_results: - path: /tmp/tests - - - codecov/upload: - file: /tmp/tests/unittests.xml - flags: unittests - - build_docs: - <<: *python_defaults - working_directory: /tmp/gh-pages - environment: - - FSLOUTPUTTYPE: NIFTI - - SUBJECTS_DIR: /tmp/subjects - steps: - - checkout - - run: - name: Create subjects folder - command: mkdir -p $SUBJECTS_DIR - - run: - name: Install Graphviz & pandoc - command: | - sudo apt-get update -y - sudo apt-get install -y --no-install-recommends graphviz pandoc texlive - - run: - name: Install deps - command: | - python -m venv /tmp/venv - source /tmp/venv/bin/activate - python -m pip install -U build hatch hatchling pip twine docutils - python -m pip install .[docs] - - run: - name: Build only this commit - command: | - source /tmp/venv/bin/activate - python -m hatch version | tail -n1 | xargs - BRANCH=$( echo $CIRCLE_BRANCH | sed 's+/+_+g' ) - python -c "from templateflow.api import get; get('MNI152NLin2009cAsym', desc='brain', resolution=1, suffix='T1w')" - make -C docs SPHINXOPTS="-W -v" BUILDDIR="$HOME/docs" OUTDIR=${CIRCLE_TAG:-$BRANCH} html - - store_artifacts: - path: ~/docs/ - - deploy_docker: - <<: *machine_defaults - steps: - - restore_cache: - keys: - - build-v2-{{ .Branch }}-{{ epoch }} - - build-v2-{{ .Branch }}- - - build-v2-master- - - build-v2- - paths: - - /tmp/docker - - docker/install-docker-credential-helper - - run: *docker_auth - - run: *setup_docker_registry - - run: *pull_from_registry - - run: - name: Deploy to Docker Hub - no_output_timeout: 40m - command: | - if [[ -n "$DOCKER_PAT" ]]; then - docker push nipreps/sdcflows:latest - docker tag nipreps/sdcflows nipreps/sdcflows:$CIRCLE_TAG - docker push nipreps/sdcflows:$CIRCLE_TAG - fi - - test_package: - <<: *python_defaults - steps: - - checkout - - run: - name: Prepare environment & build - command: | - python -m venv /tmp/buildenv - source /tmp/buildenv/bin/activate - python3 -m pip install -U build hatch hatchling pip twine docutils - python3 -m build - twine check dist/sdcflows* - - store_artifacts: - path: /tmp/src/sdcflows/dist - - persist_to_workspace: - root: /tmp/src/sdcflows - paths: dist - - - run: - name: Validate version - command: | - source /tmp/buildenv/bin/activate - THISVERSION=$( python -m hatch version | tail -n1 | xargs ) - python -m pip install dist/*.whl - mkdir empty - cd empty - INSTALLED=$( python -c 'import sdcflows; print(sdcflows.__version__)' ) - test "${CIRCLE_TAG:-$THISVERSION}" == "$INSTALLED" - - deploy_pypi: - <<: *python_defaults - steps: - - attach_workspace: - at: /tmp/src/sdcflows - - run: - name: Upload to Pypi - command: | - python -m pip install twine - python -m twine check dist/* - python -m twine upload dist/* --non-interactive + - run: echo Not doing nothing. workflows: version: 2 build_deploy: jobs: - - cache_test_data: - context: - - nipreps-common - - fs-license - filters: - branches: - ignore: - - /docs?\/.*/ - tags: - only: /.*/ - - - build_n_pytest: - requires: - - cache_test_data - filters: - branches: - ignore: - - /docs?\/.*/ - tags: - only: /.*/ - - - test_package: - context: - - nipreps-common - filters: - branches: - ignore: - - /docs?\/.*/ - - /tests?\/.*/ - tags: - only: /.*/ - - - deploy_pypi: - context: - - nipreps-common - requires: - - build_docs - - test_package - - build_n_pytest - filters: - branches: - ignore: /.*/ - tags: - only: /.*/ - - - deploy_docker: - context: - - nipreps-common - requires: - - deploy_pypi - filters: - branches: - ignore: /.*/ - tags: - only: /.*/ - - - build_docs: - filters: - branches: - ignore: - - /tests?\/.*/ - tags: - only: /.*/ + - empty From 8d8b1042add1a1bd03106620432a88c0108cef4d Mon Sep 17 00:00:00 2001 From: Chris Markiewicz Date: Tue, 24 Sep 2024 15:16:14 -0400 Subject: [PATCH 02/18] CI: Remove some GITHUB_ACTIONS skips --- sdcflows/interfaces/tests/test_bspline.py | 1 - sdcflows/tests/test_transform.py | 1 - 2 files changed, 2 deletions(-) diff --git a/sdcflows/interfaces/tests/test_bspline.py b/sdcflows/interfaces/tests/test_bspline.py index 67813a4c29..d10b49684b 100644 --- a/sdcflows/interfaces/tests/test_bspline.py +++ b/sdcflows/interfaces/tests/test_bspline.py @@ -138,7 +138,6 @@ def test_topup_coeffs(tmpdir, testdata_dir): _fix_topup_fieldcoeff("failing.nii.gz", str(testdata_dir / "epi.nii.gz"), "i") -@pytest.mark.skipif(os.getenv("GITHUB_ACTIONS") == "true", reason="this is GH Actions") def test_topup_coeffs_interpolation(tmpdir, testdata_dir): """Check that our interpolation is not far away from TOPUP's.""" tmpdir.chdir() diff --git a/sdcflows/tests/test_transform.py b/sdcflows/tests/test_transform.py index 72e44e0759..3169f8b42c 100644 --- a/sdcflows/tests/test_transform.py +++ b/sdcflows/tests/test_transform.py @@ -139,7 +139,6 @@ def test_displacements_field(tmpdir, testdata_dir, outdir, pe_dir, rotation, fli ).run() -@pytest.mark.skipif(os.getenv("GITHUB_ACTIONS") == "true", reason="this is GH Actions") @pytest.mark.parametrize( "pe0", [ From 5407ec2b20e59ca7a102789036143362c8769026 Mon Sep 17 00:00:00 2001 From: Chris Markiewicz Date: Tue, 24 Sep 2024 15:18:06 -0400 Subject: [PATCH 03/18] CI: Report test durations --- .github/workflows/unittests.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/unittests.yml b/.github/workflows/unittests.yml index 716c30d92c..757ff642e9 100644 --- a/.github/workflows/unittests.yml +++ b/.github/workflows/unittests.yml @@ -175,7 +175,8 @@ jobs: run: | export LD_LIBRARY_PATH=/usr/lib/fsl/5.0:$LD_LIBRARY_PATH export PATH=$ANTSPATH:${AFNI_HOME}:/usr/lib/fsl/5.0:$PATH - pytest -v --cov sdcflows --cov-report xml:cov.xml --doctest-modules -n auto sdcflows + pytest -v --cov sdcflows --cov-report xml:cov.xml --doctest-modules -n auto sdcflows \ + --durations=20 --durations-min=10 - uses: codecov/codecov-action@v4 with: From 1c19ef0d573a4f9122b6af45d96c6c3bfe3cc325 Mon Sep 17 00:00:00 2001 From: Chris Markiewicz Date: Tue, 24 Sep 2024 19:18:13 -0400 Subject: [PATCH 04/18] ci: Add HCPH pilot and brain extraction tests --- .github/workflows/unittests.yml | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/.github/workflows/unittests.yml b/.github/workflows/unittests.yml index 757ff642e9..6a3ecf8fc7 100644 --- a/.github/workflows/unittests.yml +++ b/.github/workflows/unittests.yml @@ -128,7 +128,7 @@ jobs: - uses: actions/cache@v4 with: path: ${{ env.TEST_DATA_HOME }} - key: data-cache-v1 + key: data-cache-v2 restore-keys: | data-cache- - name: Install test data @@ -162,6 +162,17 @@ jobs: datalad update -r --merge -d ds000206/ datalad get -r -d ds000206/ ds000206/sub-05/ + # Brain extraction tests + datalad install -r https://gin.g-node.org/nipreps-data/brain-extraction-tests + datalad update --merge -d brain-extraction-tests/ + datalad get -r -J 2 -d brain-extraction-tests + + # HCPH pilot + datalad install -r https://github.com/nipreps-data/hcph-pilot_fieldmaps.git + datalad update -r --merge -d hcph-pilot_fieldmaps/ + datalad get -r -d hcph-pilot_fieldmaps/ + + - name: Install FreeSurfer's mri_robust_template env: MRI_ROBUST_TEMPLATE: sx2n7/providers/osfstorage/5e825301d0e35400ebb481f2 From a99ebfd298ee7dccf8b68eebddd7cbcc248f1245 Mon Sep 17 00:00:00 2001 From: Chris Markiewicz Date: Tue, 24 Sep 2024 19:44:01 -0400 Subject: [PATCH 05/18] ci: Try un-disabling all tests on GHA --- sdcflows/tests/test_transform.py | 1 - sdcflows/workflows/fit/tests/test_pepolar.py | 3 --- sdcflows/workflows/fit/tests/test_phdiff.py | 3 --- sdcflows/workflows/fit/tests/test_syn.py | 3 --- sdcflows/workflows/tests/test_ancillary.py | 2 -- sdcflows/workflows/tests/test_base.py | 4 ---- sdcflows/workflows/tests/test_integration.py | 2 -- 7 files changed, 18 deletions(-) diff --git a/sdcflows/tests/test_transform.py b/sdcflows/tests/test_transform.py index 3169f8b42c..18e1b71174 100644 --- a/sdcflows/tests/test_transform.py +++ b/sdcflows/tests/test_transform.py @@ -21,7 +21,6 @@ # https://www.nipreps.org/community/licensing/ # """Unit tests of the transform object.""" -import os from subprocess import check_call from itertools import product import pytest diff --git a/sdcflows/workflows/fit/tests/test_pepolar.py b/sdcflows/workflows/fit/tests/test_pepolar.py index 995c867f96..f7dc970d5b 100644 --- a/sdcflows/workflows/fit/tests/test_pepolar.py +++ b/sdcflows/workflows/fit/tests/test_pepolar.py @@ -21,15 +21,12 @@ # https://www.nipreps.org/community/licensing/ # """Test pepolar type of fieldmaps.""" -import os import pytest from nipype.pipeline import engine as pe from ..pepolar import init_topup_wf -@pytest.mark.skipif(os.getenv("TRAVIS") == "true", reason="this is TravisCI") -@pytest.mark.skipif(os.getenv("GITHUB_ACTIONS") == "true", reason="this is GH Actions") @pytest.mark.parametrize("ds", ("ds001771", "HCP101006")) def test_topup_wf(tmpdir, bids_layouts, workdir, outdir, ds): """Test preparation workflow.""" diff --git a/sdcflows/workflows/fit/tests/test_phdiff.py b/sdcflows/workflows/fit/tests/test_phdiff.py index 94af79f2fd..ef278fbe8b 100644 --- a/sdcflows/workflows/fit/tests/test_phdiff.py +++ b/sdcflows/workflows/fit/tests/test_phdiff.py @@ -21,7 +21,6 @@ # https://www.nipreps.org/community/licensing/ # """Test phase-difference type of fieldmaps.""" -import os from pathlib import Path from json import loads @@ -30,8 +29,6 @@ from ..fieldmap import init_fmap_wf, Workflow -@pytest.mark.skipif(os.getenv("TRAVIS") == "true", reason="this is TravisCI") -@pytest.mark.skipif(os.getenv("GITHUB_ACTIONS") == "true", reason="this is GH Actions") @pytest.mark.parametrize( "fmap_file", [ diff --git a/sdcflows/workflows/fit/tests/test_syn.py b/sdcflows/workflows/fit/tests/test_syn.py index d1535983b2..065a594265 100644 --- a/sdcflows/workflows/fit/tests/test_syn.py +++ b/sdcflows/workflows/fit/tests/test_syn.py @@ -21,7 +21,6 @@ # https://www.nipreps.org/community/licensing/ # """Test fieldmap-less SDC-SyN.""" -import os import json import pytest from nipype.pipeline import engine as pe @@ -29,8 +28,6 @@ from ..syn import init_syn_sdc_wf, init_syn_preprocessing_wf, _adjust_zooms, _set_dtype -@pytest.mark.skipif(os.getenv("TRAVIS") == "true", reason="this is TravisCI") -@pytest.mark.skipif(os.getenv("GITHUB_ACTIONS") == "true", reason="this is GH Actions") def test_syn_wf(tmpdir, datadir, workdir, outdir, sloppy_mode): """Build and run an SDC-SyN workflow.""" derivs_path = datadir / "ds000054" / "derivatives" diff --git a/sdcflows/workflows/tests/test_ancillary.py b/sdcflows/workflows/tests/test_ancillary.py index f73d062989..50f01c87bc 100644 --- a/sdcflows/workflows/tests/test_ancillary.py +++ b/sdcflows/workflows/tests/test_ancillary.py @@ -21,7 +21,6 @@ # https://www.nipreps.org/community/licensing/ # """Check the tools submodule.""" -import os import pytest from nipype.pipeline import engine as pe from nipype.interfaces import utility as niu @@ -29,7 +28,6 @@ from ..ancillary import init_brainextraction_wf -@pytest.mark.skipif(os.getenv("GITHUB_ACTIONS") == "true", reason="this is GH Actions") @pytest.mark.parametrize("folder", ["magnitude/ds000054", "magnitude/ds000217"]) def test_brainmasker(tmpdir, datadir, workdir, outdir, folder): """Exercise the brain masking tool.""" diff --git a/sdcflows/workflows/tests/test_base.py b/sdcflows/workflows/tests/test_base.py index b31222fecc..39f37348f2 100644 --- a/sdcflows/workflows/tests/test_base.py +++ b/sdcflows/workflows/tests/test_base.py @@ -22,7 +22,6 @@ # """Test the base workflow.""" from pathlib import Path -import os import pytest from sdcflows import fieldmaps as fm from sdcflows.utils.wrangler import find_estimators @@ -62,9 +61,6 @@ def test_fmap_wf(tmpdir, workdir, outdir, bids_layouts, dataset, subject): if workdir: wf.base_dir = str(workdir) - if os.getenv("GITHUB_ACTIONS") == "true": - return - res = wf.run(plugin="Linear") # Regression test for when out_merge_fmap_coeff was flattened and would diff --git a/sdcflows/workflows/tests/test_integration.py b/sdcflows/workflows/tests/test_integration.py index 6263f7a5f9..86b21646f1 100644 --- a/sdcflows/workflows/tests/test_integration.py +++ b/sdcflows/workflows/tests/test_integration.py @@ -21,7 +21,6 @@ # https://www.nipreps.org/community/licensing/ # """Test the base workflow.""" -import os from pathlib import Path import json import pytest @@ -37,7 +36,6 @@ ) -@pytest.mark.skipif(os.getenv("GITHUB_ACTIONS") == "true", reason="this is GH Actions") @pytest.mark.parametrize("pe0", ["LR", "PA"]) @pytest.mark.parametrize("mode", ["pepolar", "phasediff"]) def test_integration_wf(tmpdir, workdir, outdir, datadir, pe0, mode): From b6140aa07b683b9ddd53cfc8a20c97d25bd31eed Mon Sep 17 00:00:00 2001 From: Chris Markiewicz Date: Tue, 24 Sep 2024 20:04:35 -0400 Subject: [PATCH 06/18] CI: Update datalad get calls --- .github/workflows/unittests.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/.github/workflows/unittests.yml b/.github/workflows/unittests.yml index 6a3ecf8fc7..47589d774b 100644 --- a/.github/workflows/unittests.yml +++ b/.github/workflows/unittests.yml @@ -139,38 +139,39 @@ jobs: # ds001600 datalad install -r https://github.com/nipreps-data/ds001600.git datalad update -r --merge -d ds001600/ - datalad get -r -d ds001600/ ds001600/sub-1/ + datalad get -r -J 2 -d ds001600/ ds001600/sub-1/ # HCP/sub-101006 datalad install -r https://github.com/nipreps-data/HCP101006.git datalad update -r --merge -d HCP101006/ - datalad get -r -d HCP101006 + datalad get -r -J 2 -d HCP101006 HCP101006/* # ds001771 datalad install -r https://github.com/nipreps-data/ds001771.git datalad update -r --merge -d ds001771/ - datalad get -r -d ds001771/ ds001771/sub-36/* - datalad get -r -d ds001771/derivatives ds001771/derivatives/openneuro/sub-36/* + datalad get -r -J 2 -d ds001771/ ds001771/sub-36/* + datalad get -r -J 2 -d ds001771/derivatives ds001771/derivatives/openneuro/sub-36/* # ds000054 datalad install -r https://github.com/nipreps-data/ds000054.git datalad update --merge -d ds000054/ datalad get -r -d ds000054/ ds000054/sub-100185/* + datalad get -r -J 2 -d ds000054/ ds000054/derivatives/smriprep-0.6/sub-100185/anat/ # ds000206 datalad install -r https://github.com/nipreps-data/ds000206.git datalad update -r --merge -d ds000206/ - datalad get -r -d ds000206/ ds000206/sub-05/ + datalad get -r -J 2 -d ds000206/ ds000206/sub-05/ # Brain extraction tests datalad install -r https://gin.g-node.org/nipreps-data/brain-extraction-tests datalad update --merge -d brain-extraction-tests/ - datalad get -r -J 2 -d brain-extraction-tests + datalad get -r -J 2 -d brain-extraction-tests brain-extraction-tests/* # HCPH pilot datalad install -r https://github.com/nipreps-data/hcph-pilot_fieldmaps.git datalad update -r --merge -d hcph-pilot_fieldmaps/ - datalad get -r -d hcph-pilot_fieldmaps/ + datalad get -r -J 2 -d hcph-pilot_fieldmaps/ hcph-pilot_fieldmaps/* - name: Install FreeSurfer's mri_robust_template From 49b5390360feba1d1f3fb37e7acbe7db1dd6156d Mon Sep 17 00:00:00 2001 From: Chris Markiewicz Date: Tue, 24 Sep 2024 21:10:03 -0400 Subject: [PATCH 07/18] fix: Ensure FS_LICENSE is accessible --- .github/workflows/unittests.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/unittests.yml b/.github/workflows/unittests.yml index 47589d774b..952c7b28c4 100644 --- a/.github/workflows/unittests.yml +++ b/.github/workflows/unittests.yml @@ -173,6 +173,8 @@ jobs: datalad update -r --merge -d hcph-pilot_fieldmaps/ datalad get -r -J 2 -d hcph-pilot_fieldmaps/ hcph-pilot_fieldmaps/* + - name: Set FS_LICENSE variable + run: echo "FS_LICENSE=$HOME/.cache/freesurfer/license.txt" >> $GITHUB_ENV - name: Install FreeSurfer's mri_robust_template env: @@ -180,8 +182,8 @@ jobs: run: | curl https://files.osf.io/v1/resources/$MRI_ROBUST_TEMPLATE?direct > mri_robust_template sudo install mri_robust_template /usr/local/bin - mkdir -p $HOME/.cache/freesurfer/ - echo "b2VzdGViYW5Ac3RhbmZvcmQuZWR1CjMwNzU2CiAqQ1MzYkJ5VXMxdTVNCiBGU2kvUGJsejJxR1V3Cg==" | base64 -d > $HOME/.cache/freesurfer/license.txt + mkdir -p $( dirname $FS_LICENSE ) + echo "b2VzdGViYW5Ac3RhbmZvcmQuZWR1CjMwNzU2CiAqQ1MzYkJ5VXMxdTVNCiBGU2kvUGJsejJxR1V3Cg==" | base64 -d > $FS_LICENSE - name: Run pytest with coverage run: | From e232f6e02665166b7767e929743d30c51322f592 Mon Sep 17 00:00:00 2001 From: Chris Markiewicz Date: Tue, 24 Sep 2024 21:10:23 -0400 Subject: [PATCH 08/18] CI: Install ANTs with conda --- .github/workflows/unittests.yml | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/.github/workflows/unittests.yml b/.github/workflows/unittests.yml index 952c7b28c4..89ce32bde5 100644 --- a/.github/workflows/unittests.yml +++ b/.github/workflows/unittests.yml @@ -30,7 +30,6 @@ jobs: AFNI_IMSAVE_WARNINGS: NO AFNI_TTATLAS_DATASET: /opt/afni/atlases AFNI_PLUGINPATH: /opt/afni/plugins - ANTSPATH: /opt/ants strategy: max-parallel: 5 matrix: @@ -66,19 +65,6 @@ jobs: tcsh @update.afni.binaries -package linux_ubuntu_16_64 -bindir ${AFNI_HOME} fi - - uses: actions/cache@v4 - with: - path: /opt/ants - key: ants-v1 - restore-keys: | - ants-v1 - - name: Install ANTS - run: | - if [[ ! -d "${ANTSPATH}" ]]; then - sudo mkdir -p $ANTSPATH - curl -sSL "https://dl.dropbox.com/s/gwf51ykkk5bifyj/ants-Linux-centos6_x86_64-v2.3.4.tar.gz" | sudo tar -xzC $ANTSPATH --strip-components 1 - fi - - name: Git settings (pacify DataLad) run: | git config --global user.name 'NiPreps Bot' @@ -89,11 +75,11 @@ jobs: auto-update-conda: true auto-activate-base: true python-version: ${{ matrix.python-version }} - channels: anaconda,https://fsl.fmrib.ox.ac.uk/fsldownloads/fslconda/public/,conda-forge + channels: https://fsl.fmrib.ox.ac.uk/fsldownloads/fslconda/public/,conda-forge - uses: actions/cache@v4 id: conda env: - CACHE_NUM: v4 + CACHE_NUM: v5 with: path: | ~/conda_pkgs_dir @@ -105,9 +91,9 @@ jobs: run: | conda install git-annex=*=alldep* pip pip install datalad datalad-osf - - name: Install fsl + - name: Install fsl and ANTs run: | - conda install fsl-fugue fsl-topup + conda install fsl-fugue fsl-topup ants - uses: actions/checkout@v4 - name: Install dependencies timeout-minutes: 5 @@ -187,8 +173,8 @@ jobs: - name: Run pytest with coverage run: | - export LD_LIBRARY_PATH=/usr/lib/fsl/5.0:$LD_LIBRARY_PATH - export PATH=$ANTSPATH:${AFNI_HOME}:/usr/lib/fsl/5.0:$PATH + export PATH=${AFNI_HOME}:$PATH + export FSLDIR=${CONDA_PREFIX} pytest -v --cov sdcflows --cov-report xml:cov.xml --doctest-modules -n auto sdcflows \ --durations=20 --durations-min=10 From 4b79240780100ab9efafdad5090ea06133067cbd Mon Sep 17 00:00:00 2001 From: Chris Markiewicz Date: Tue, 24 Sep 2024 21:10:32 -0400 Subject: [PATCH 09/18] TEST: Mark slow tests and run in their own jobs --- .github/workflows/unittests.yml | 10 +++++++++- pyproject.toml | 3 +++ sdcflows/workflows/fit/tests/test_pepolar.py | 1 + sdcflows/workflows/fit/tests/test_phdiff.py | 1 + sdcflows/workflows/fit/tests/test_syn.py | 1 + sdcflows/workflows/tests/test_ancillary.py | 1 + sdcflows/workflows/tests/test_base.py | 1 + 7 files changed, 17 insertions(+), 1 deletion(-) diff --git a/.github/workflows/unittests.yml b/.github/workflows/unittests.yml index 89ce32bde5..be3f82f4e4 100644 --- a/.github/workflows/unittests.yml +++ b/.github/workflows/unittests.yml @@ -34,6 +34,12 @@ jobs: max-parallel: 5 matrix: python-version: ["3.9", "3.10", "3.11", "3.12"] + marks: ["not slow"] + include: + - python-version: "3.9" + marks: "slow" + - python-version: "3.12" + marks: "slow" steps: - uses: actions/cache@v4 @@ -176,7 +182,9 @@ jobs: export PATH=${AFNI_HOME}:$PATH export FSLDIR=${CONDA_PREFIX} pytest -v --cov sdcflows --cov-report xml:cov.xml --doctest-modules -n auto sdcflows \ - --durations=20 --durations-min=10 + --durations=20 --durations-min=10 -m "$MARKS" + env: + MARKS: ${{ matrix.marks }} - uses: codecov/codecov-action@v4 with: diff --git a/pyproject.toml b/pyproject.toml index fbdaae9e94..3a3c0b6ff8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -165,6 +165,9 @@ doctest_optionflags = "ALLOW_UNICODE NORMALIZE_WHITESPACE ELLIPSIS" env = "PYTHONHASHSEED=0" filterwarnings = ["ignore::DeprecationWarning"] junit_family = "xunit2" +markers = [ + "slow: marks tests as slow (deselect with '-m \"not slow\"')", +] [tool.coverage.run] diff --git a/sdcflows/workflows/fit/tests/test_pepolar.py b/sdcflows/workflows/fit/tests/test_pepolar.py index f7dc970d5b..e95128d153 100644 --- a/sdcflows/workflows/fit/tests/test_pepolar.py +++ b/sdcflows/workflows/fit/tests/test_pepolar.py @@ -27,6 +27,7 @@ from ..pepolar import init_topup_wf +@pytest.mark.slow @pytest.mark.parametrize("ds", ("ds001771", "HCP101006")) def test_topup_wf(tmpdir, bids_layouts, workdir, outdir, ds): """Test preparation workflow.""" diff --git a/sdcflows/workflows/fit/tests/test_phdiff.py b/sdcflows/workflows/fit/tests/test_phdiff.py index ef278fbe8b..94932f6243 100644 --- a/sdcflows/workflows/fit/tests/test_phdiff.py +++ b/sdcflows/workflows/fit/tests/test_phdiff.py @@ -29,6 +29,7 @@ from ..fieldmap import init_fmap_wf, Workflow +@pytest.mark.slow @pytest.mark.parametrize( "fmap_file", [ diff --git a/sdcflows/workflows/fit/tests/test_syn.py b/sdcflows/workflows/fit/tests/test_syn.py index 065a594265..905c1d808b 100644 --- a/sdcflows/workflows/fit/tests/test_syn.py +++ b/sdcflows/workflows/fit/tests/test_syn.py @@ -28,6 +28,7 @@ from ..syn import init_syn_sdc_wf, init_syn_preprocessing_wf, _adjust_zooms, _set_dtype +@pytest.mark.slow def test_syn_wf(tmpdir, datadir, workdir, outdir, sloppy_mode): """Build and run an SDC-SyN workflow.""" derivs_path = datadir / "ds000054" / "derivatives" diff --git a/sdcflows/workflows/tests/test_ancillary.py b/sdcflows/workflows/tests/test_ancillary.py index 50f01c87bc..7e407d86e3 100644 --- a/sdcflows/workflows/tests/test_ancillary.py +++ b/sdcflows/workflows/tests/test_ancillary.py @@ -28,6 +28,7 @@ from ..ancillary import init_brainextraction_wf +@pytest.mark.slow @pytest.mark.parametrize("folder", ["magnitude/ds000054", "magnitude/ds000217"]) def test_brainmasker(tmpdir, datadir, workdir, outdir, folder): """Exercise the brain masking tool.""" diff --git a/sdcflows/workflows/tests/test_base.py b/sdcflows/workflows/tests/test_base.py index 39f37348f2..8b74ac9ddf 100644 --- a/sdcflows/workflows/tests/test_base.py +++ b/sdcflows/workflows/tests/test_base.py @@ -28,6 +28,7 @@ from sdcflows.workflows.base import init_fmap_preproc_wf +@pytest.mark.slow @pytest.mark.parametrize( "dataset,subject", [("ds000054", "100185"), ("HCP101006", "101006")] ) From 606e5d8896df3e05fbe6ee260b45b7a6aa06f8ae Mon Sep 17 00:00:00 2001 From: Chris Markiewicz Date: Tue, 24 Sep 2024 21:30:17 -0400 Subject: [PATCH 10/18] CI: Define freesurfer home --- .github/workflows/unittests.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/unittests.yml b/.github/workflows/unittests.yml index be3f82f4e4..620992c3d9 100644 --- a/.github/workflows/unittests.yml +++ b/.github/workflows/unittests.yml @@ -165,8 +165,10 @@ jobs: datalad update -r --merge -d hcph-pilot_fieldmaps/ datalad get -r -J 2 -d hcph-pilot_fieldmaps/ hcph-pilot_fieldmaps/* - - name: Set FS_LICENSE variable - run: echo "FS_LICENSE=$HOME/.cache/freesurfer/license.txt" >> $GITHUB_ENV + - name: Set FreeSurfer variables + run: | + echo "FREESURFER_HOME=$HOME/.cache/freesurfer" >> $GITHUB_ENV + echo "FS_LICENSE=$HOME/.cache/freesurfer/license.txt" >> $GITHUB_ENV - name: Install FreeSurfer's mri_robust_template env: From bc24ff61f36d029b19c0919b8b31b106072be385 Mon Sep 17 00:00:00 2001 From: Chris Markiewicz Date: Wed, 25 Sep 2024 07:53:37 -0400 Subject: [PATCH 11/18] TEST: More slow marks, add veryslow --- pyproject.toml | 3 ++- sdcflows/workflows/fit/tests/test_syn.py | 1 + sdcflows/workflows/tests/test_base.py | 1 + sdcflows/workflows/tests/test_integration.py | 1 + 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 3a3c0b6ff8..ef65fce49e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -160,13 +160,14 @@ per-file-ignores = [ [tool.pytest.ini_options] norecursedirs = [".git"] -addopts = "-svx --doctest-modules" +addopts = "-svx --doctest-modules --strict-markers" doctest_optionflags = "ALLOW_UNICODE NORMALIZE_WHITESPACE ELLIPSIS" env = "PYTHONHASHSEED=0" filterwarnings = ["ignore::DeprecationWarning"] junit_family = "xunit2" markers = [ "slow: marks tests as slow (deselect with '-m \"not slow\"')", + "veryslow: marks tests as very slow (>5min)", ] diff --git a/sdcflows/workflows/fit/tests/test_syn.py b/sdcflows/workflows/fit/tests/test_syn.py index 905c1d808b..262890d03a 100644 --- a/sdcflows/workflows/fit/tests/test_syn.py +++ b/sdcflows/workflows/fit/tests/test_syn.py @@ -28,6 +28,7 @@ from ..syn import init_syn_sdc_wf, init_syn_preprocessing_wf, _adjust_zooms, _set_dtype +@pytest.mark.veryslow @pytest.mark.slow def test_syn_wf(tmpdir, datadir, workdir, outdir, sloppy_mode): """Build and run an SDC-SyN workflow.""" diff --git a/sdcflows/workflows/tests/test_base.py b/sdcflows/workflows/tests/test_base.py index 8b74ac9ddf..2cb77cf089 100644 --- a/sdcflows/workflows/tests/test_base.py +++ b/sdcflows/workflows/tests/test_base.py @@ -28,6 +28,7 @@ from sdcflows.workflows.base import init_fmap_preproc_wf +@pytest.mark.veryslow @pytest.mark.slow @pytest.mark.parametrize( "dataset,subject", [("ds000054", "100185"), ("HCP101006", "101006")] diff --git a/sdcflows/workflows/tests/test_integration.py b/sdcflows/workflows/tests/test_integration.py index 86b21646f1..ac61a48034 100644 --- a/sdcflows/workflows/tests/test_integration.py +++ b/sdcflows/workflows/tests/test_integration.py @@ -36,6 +36,7 @@ ) +@pytest.mark.slow @pytest.mark.parametrize("pe0", ["LR", "PA"]) @pytest.mark.parametrize("mode", ["pepolar", "phasediff"]) def test_integration_wf(tmpdir, workdir, outdir, datadir, pe0, mode): From 3c9dfeda3c6768bdd7718fb0d4b34b96d89b6427 Mon Sep 17 00:00:00 2001 From: Chris Markiewicz Date: Wed, 25 Sep 2024 07:57:22 -0400 Subject: [PATCH 12/18] CI: Run slow and veryslow on two separate jobs --- .github/workflows/unittests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/unittests.yml b/.github/workflows/unittests.yml index 620992c3d9..c037561af9 100644 --- a/.github/workflows/unittests.yml +++ b/.github/workflows/unittests.yml @@ -37,9 +37,9 @@ jobs: marks: ["not slow"] include: - python-version: "3.9" - marks: "slow" + marks: "slow and not veryslow" - python-version: "3.12" - marks: "slow" + marks: "veryslow" steps: - uses: actions/cache@v4 From 7742627cbab45d21efc4f2dc1e473a00957b8c9c Mon Sep 17 00:00:00 2001 From: Chris Markiewicz Date: Wed, 25 Sep 2024 07:57:45 -0400 Subject: [PATCH 13/18] CI: Allow all jobs to run simultaneously --- .github/workflows/unittests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/unittests.yml b/.github/workflows/unittests.yml index c037561af9..76c4755903 100644 --- a/.github/workflows/unittests.yml +++ b/.github/workflows/unittests.yml @@ -31,7 +31,7 @@ jobs: AFNI_TTATLAS_DATASET: /opt/afni/atlases AFNI_PLUGINPATH: /opt/afni/plugins strategy: - max-parallel: 5 + max-parallel: 6 matrix: python-version: ["3.9", "3.10", "3.11", "3.12"] marks: ["not slow"] From e11a7783519fb485dff657d91b3e236abb10a21a Mon Sep 17 00:00:00 2001 From: Chris Markiewicz Date: Wed, 25 Sep 2024 09:37:56 -0400 Subject: [PATCH 14/18] CI: Update config in prep for merge --- .github/workflows/unittests.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/unittests.yml b/.github/workflows/unittests.yml index 76c4755903..12c8b84c01 100644 --- a/.github/workflows/unittests.yml +++ b/.github/workflows/unittests.yml @@ -5,6 +5,12 @@ on: pull_request: schedule: - cron: 0 0 * * 0 + # Allow job to be triggered manually from GitHub interface + workflow_dispatch: + +# Force pytest to use color +env: + FORCE_COLOR: true concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -18,7 +24,7 @@ defaults: shell: bash -el {0} jobs: - build-linux: + test: if: "!contains(github.event.head_commit.message, '[skip ci]' && (github.event_name == 'push' || github.event.pull_request.head.repo.full_name != 'nipreps/sdcflows'))" runs-on: ubuntu-latest env: From 186c36d8db1b238838538702b5a5d5679d24418d Mon Sep 17 00:00:00 2001 From: Chris Markiewicz Date: Wed, 25 Sep 2024 09:58:11 -0400 Subject: [PATCH 15/18] CI: Add build/publish jobs --- .github/workflows/unittests.yml | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/.github/workflows/unittests.yml b/.github/workflows/unittests.yml index 12c8b84c01..d3d5a03551 100644 --- a/.github/workflows/unittests.yml +++ b/.github/workflows/unittests.yml @@ -24,6 +24,19 @@ defaults: shell: bash -el {0} jobs: + build-package: + name: Build & inspect package + runs-on: ubuntu-latest + permissions: + attestations: write + id-token: write + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: hynek/build-and-inspect-python-package@v2 + test: if: "!contains(github.event.head_commit.message, '[skip ci]' && (github.event_name == 'push' || github.event.pull_request.head.repo.full_name != 'nipreps/sdcflows'))" runs-on: ubuntu-latest @@ -199,3 +212,23 @@ jobs: file: cov.xml token: ${{ secrets.CODECOV_TOKEN }} if: ${{ always() }} + + publish: + name: Publish released package to pypi.org + environment: release-pypi + if: github.event.action == 'published' + runs-on: ubuntu-latest + needs: [build-package, test] + permissions: + attestations: write + id-token: write + + steps: + - name: Download packages built by build-and-inspect-python-package + uses: actions/download-artifact@v4 + with: + name: Packages + path: dist + + - name: Upload package to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 From 5a65956fd884abdbc8d63a45b92bc69f3c350f3c Mon Sep 17 00:00:00 2001 From: Chris Markiewicz Date: Wed, 25 Sep 2024 09:58:57 -0400 Subject: [PATCH 16/18] CI: Rename workflows --- .github/workflows/{unittests.yml => build-test-publish.yml} | 0 .github/workflows/{pythonpackage.yml => validate.yml} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{unittests.yml => build-test-publish.yml} (100%) rename .github/workflows/{pythonpackage.yml => validate.yml} (100%) diff --git a/.github/workflows/unittests.yml b/.github/workflows/build-test-publish.yml similarity index 100% rename from .github/workflows/unittests.yml rename to .github/workflows/build-test-publish.yml diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/validate.yml similarity index 100% rename from .github/workflows/pythonpackage.yml rename to .github/workflows/validate.yml From ee166de9d3ec3585dea5cf729fd11ed277024878 Mon Sep 17 00:00:00 2001 From: Chris Markiewicz Date: Wed, 25 Sep 2024 10:00:46 -0400 Subject: [PATCH 17/18] CI: Reduce validation workflow --- .github/workflows/validate.yml | 116 ++------------------------------- 1 file changed, 5 insertions(+), 111 deletions(-) diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 26a7f11751..bd8b7c2b0c 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -1,14 +1,13 @@ -# This workflow will install Python dependencies, run tests and lint with a variety of Python versions -# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions - -name: Python package +name: Validations on: push: branches: [ '*' ] - tags: [ '*' ] pull_request: - branches: [ master, 'maint/*' ] + branches: [ master, main, 'maint/*' ] + +env: + FORCE_COLOR: true concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -18,115 +17,10 @@ permissions: contents: read jobs: - job_metadata: - if: github.repository == 'nipreps/sdcflows' - runs-on: ubuntu-latest - outputs: - commit_message: ${{ steps.get_commit_message.outputs.commit_message }} - version: ${{ steps.show_version.outputs.version }} - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - name: Print head git commit message - id: get_commit_message - run: | - if [[ -z "$COMMIT_MSG" ]]; then - COMMIT_MSG=$(git show -s --format=%s $REF) - fi - echo commit_message=$COMMIT_MSG | tee -a $GITHUB_OUTPUT - env: - COMMIT_MSG: ${{ github.event.head_commit.message }} - REF: ${{ github.event.pull_request.head.sha }} - - name: Detect version - id: show_version - run: | - if [[ "$GITHUB_REF" == refs/tags/* ]]; then - VERSION=${GITHUB_REF##*/} - else - pip install -U build hatch hatchling pip twine docutils - VERSION=$( python -m hatch version | tail -n1 | xargs ) - fi - echo version=$VERSION | tee -a $GITHUB_OUTPUT - - build: - if: github.repository == 'nipreps/sdcflows' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - name: Set up Python 3 - uses: actions/setup-python@v5 - with: - python-version: 3 - - name: Display Python version - run: python -c "import sys; print(sys.version)" - - name: Build sdcflows - run: pipx run build - - name: Check distributions - run: pipx run twine check dist/* - - uses: actions/upload-artifact@v4 - with: - name: dist - path: dist/ - - test: - if: "!startsWith(github.ref, 'refs/tags/') && !contains(github.event.head_commit.message, '[skip ci]')" - needs: [build, job_metadata] - runs-on: ubuntu-latest - strategy: - matrix: - python-version: ["3.9", "3.12"] - install: [repo, sdist, wheel, editable] - - env: - INSTALL_TYPE: ${{ matrix.install }} - - steps: - - uses: actions/checkout@v4 - if: matrix.install == 'repo' || matrix.install == 'editable' - with: - fetch-depth: 0 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v5 - with: - python-version: ${{ matrix.python-version }} - - name: Fetch packages - if: matrix.install == 'sdist' || matrix.install == 'wheel' - uses: actions/download-artifact@v4 - with: - name: dist - path: dist/ - - name: Select archive - run: | - if [ "$INSTALL_TYPE" = "sdist" ]; then - ARCHIVE=$( ls dist/*.tar.gz ) - elif [ "$INSTALL_TYPE" = "wheel" ]; then - ARCHIVE=$( ls dist/*.whl ) - elif [ "$INSTALL_TYPE" = "repo" ]; then - ARCHIVE="." - elif [ "$INSTALL_TYPE" = "editable" ]; then - ARCHIVE="-e ." - fi - echo "ARCHIVE=$ARCHIVE" | tee -a $GITHUB_ENV - - name: Install package - run: python -m pip install $ARCHIVE - - name: Check version - run: | - INSTALLED_VERSION=$(python -c 'import sdcflows; print(sdcflows.__version__, end="")') - echo "INSTALLED: \"${INSTALLED_VERSION}\"" - test "${INSTALLED_VERSION}" = "${VERSION}" - env: - VERSION: ${{ needs.job_metadata.outputs.version }} - flake8: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - name: Set up Python - uses: actions/setup-python@v5 - run: pipx run flake8-pyproject sdcflows/ # codespell: From 2b7e23ed514e4c32b50ad7bc201553add714758b Mon Sep 17 00:00:00 2001 From: Chris Markiewicz Date: Wed, 25 Sep 2024 10:40:09 -0400 Subject: [PATCH 18/18] MNT: Configure check-wheel-contents not to complain about test data --- pyproject.toml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index ef65fce49e..fa54d89b70 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -195,3 +195,8 @@ ignore-words-list = 'nd,mapp,reson' skip = """ ./.git,*.pdf,*.svg,*.min.js,*.ipynb,ORIGINAL_LICENSE,\ ./docs/source/_static/example_anatreport.html""" + +[tool.check-wheel-contents] +ignore = [ + "W002", # Test data contains duplicates +]