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

[INFRA] test docker builds in CI #487

Merged
merged 71 commits into from
Feb 7, 2023
Merged
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
ea9b2cd
add docker build workflow
Remi-Gau Jan 7, 2023
536e3c8
always run
Remi-Gau Jan 7, 2023
bd6f910
add install
Remi-Gau Jan 7, 2023
c87551c
test docker file
Remi-Gau Jan 7, 2023
ff62820
typo fix
Remi-Gau Jan 7, 2023
8f4d71c
add different base image
Remi-Gau Jan 7, 2023
e33cd91
use proper package manager
Remi-Gau Jan 7, 2023
d73acb5
try some shell conditional
Remi-Gau Jan 7, 2023
148a8c4
do not fail fast
Remi-Gau Jan 7, 2023
e2cd1f3
add version
Remi-Gau Jan 7, 2023
d5a422b
add jinja template
Remi-Gau Jan 7, 2023
d201c3f
add jinja template
Remi-Gau Jan 7, 2023
a0da149
deal with install method
Remi-Gau Jan 7, 2023
47eeae1
draw the rest of F owl
Remi-Gau Jan 7, 2023
d507c89
remove centos that fails across the board
Remi-Gau Jan 7, 2023
a5ce4d2
add matlab mcr
Remi-Gau Jan 7, 2023
725a2b8
add matlab mcr
Remi-Gau Jan 7, 2023
dbb7f18
add debian and cat12
Remi-Gau Jan 7, 2023
879aa18
update dashboard
Remi-Gau Jan 7, 2023
2ef1864
add intermediate versions
Remi-Gau Jan 7, 2023
055d3c5
rm old dockerfile
Remi-Gau Jan 7, 2023
4ca682e
fix name of debian distro
Remi-Gau Jan 7, 2023
18e1139
just say yes
Remi-Gau Jan 7, 2023
814a3ee
update debian stretch name
Remi-Gau Jan 7, 2023
e3f05be
actually update the workflows
Remi-Gau Jan 7, 2023
1bdf467
add mcr for ants
Remi-Gau Jan 7, 2023
16a534a
rm centos 8
Remi-Gau Jan 7, 2023
7788dc2
add afni python option
Remi-Gau Jan 7, 2023
54c4e19
update to mcr base version and ants mcr dependency version
Remi-Gau Jan 8, 2023
19c47bc
add fsl versions$
Remi-Gau Jan 8, 2023
2316725
rm -
Remi-Gau Jan 8, 2023
2355a03
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 10, 2023
7705a07
Update README.md
Remi-Gau Jan 10, 2023
0f71109
Update README.md
Remi-Gau Jan 10, 2023
f7048d0
test all versions
Remi-Gau Jan 14, 2023
f63915e
add other softwares
Remi-Gau Jan 14, 2023
b42fb12
add more softwares, a dashboard and cron schedule to run the builds
Remi-Gau Jan 14, 2023
43c5b45
minor fixes
Remi-Gau Jan 14, 2023
1a9aa0d
minor fixes
Remi-Gau Jan 14, 2023
1ee8df3
rm duplicate
Remi-Gau Jan 14, 2023
995be58
Update neurodocker/templates/afni.yaml
Remi-Gau Jan 14, 2023
91a50a2
fix typo
Remi-Gau Jan 14, 2023
d7d185e
Merge branch 'master' into test_build
satra Jan 14, 2023
e87a71d
Update README.md
Remi-Gau Jan 16, 2023
50c473f
start bootstrap
Remi-Gau Jan 17, 2023
6a36db7
try to commit in CI
Remi-Gau Jan 17, 2023
038719e
try using proper auth
Remi-Gau Jan 17, 2023
06fb483
try manual
Remi-Gau Jan 17, 2023
357461f
set upstream
Remi-Gau Jan 17, 2023
6e30561
try with token
Remi-Gau Jan 17, 2023
4aa546b
try repo secret
Remi-Gau Jan 17, 2023
4eacd92
try another token
Remi-Gau Jan 18, 2023
c6394ee
run test on the proper branch
Remi-Gau Jan 18, 2023
d8a9d8c
adapt before merge and comment
Remi-Gau Jan 18, 2023
b4c4234
allow to run workflow manually
Remi-Gau Jan 18, 2023
3301e48
test dashbord build
Remi-Gau Jan 18, 2023
e9b082e
rm no jekyll
Remi-Gau Jan 18, 2023
42c1af6
reactivate testing workflows
Remi-Gau Jan 18, 2023
b9f4896
Merge branch 'master' into test_build
Remi-Gau Jan 18, 2023
76a3b20
rm dashboard
Remi-Gau Jan 18, 2023
a2fb4ba
Update .github/workflows/bootstrap.yml
satra Feb 3, 2023
bc03b51
Update .github/workflows/bootstrap.yml
satra Feb 3, 2023
5c9caf7
Apply suggestions from code review
satra Feb 3, 2023
3bddeeb
Update .github/workflows/bootstrap.yml
satra Feb 3, 2023
940eb7a
Merge branch 'master' into test_build
satra Feb 3, 2023
3b03838
run black
Remi-Gau Feb 4, 2023
ed39d30
precommit checks
satra Feb 4, 2023
6adc00b
update black
satra Feb 4, 2023
5caa937
update black commits
satra Feb 4, 2023
a24c771
update black commits for github workflow
satra Feb 4, 2023
b21787e
Merge pull request #7 from ReproNim/ci-test
Remi-Gau Feb 7, 2023
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
72 changes: 72 additions & 0 deletions .github/workflows/bootstrap.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# this workflow bootstraps the testing of the build the docker images
#
# - this will run the python script used to generate the workflows
# based on a the jinja template
# - commit and push the generated workflows to the branch test_docker_build
# where they will be executed

name: bootstrap

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

on:
push:
branches: [ "master" ]

# Uses the cron schedule for github actions
#
# https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#scheduled-events
#
# ┌───────────── minute (0 - 59)
# │ ┌───────────── hour (0 - 23)
# │ │ ┌───────────── day of the month (1 - 31)
# │ │ │ ┌───────────── month (1 - 12 or JAN-DEC)
# │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT)
# │ │ │ │ │
# │ │ │ │ │
# │ │ │ │ │
# * * * * *

schedule:
- cron: 0 0 1,15 * *

# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
permissions:
contents: write
jobs:
bootstrap:
runs-on: ubuntu-22.04

steps:
- uses: actions/checkout@v3

- name: Set up Python
uses: actions/setup-python@v3
with:
python-version: '3.11'

- name: Install dependencies
run: python -m pip install jinja2 pyyaml

- name: Create workflows
run: |
python .github/workflows/create_workflows.py
ls -l .github/workflows

- name: Push workflows to branch test_docker_build
# action: https://github.com/marketplace/actions/git-auto-commit
uses: stefanzweifel/git-auto-commit-action@v4
with:
commit_message: add workflows
branch: test_docker_build
commit_options: '--no-verify --signoff'
commit_user_name: github-actions
commit_user_email: [email protected]
push_options: '--force'
skip_dirty_check: true
skip_fetch: true
skip_checkout: true
create_branch: true
195 changes: 195 additions & 0 deletions .github/workflows/create_workflows.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
"""
This scripts uses a jinja template to create CI workflows to test.

- different linux distributions (split by the package manager they use)
- different softwares that neurodocker supports
- different install method for a given software

All of those are defined in a python dictionary.

Versions to install are read from the neurodocker template for a given software.
It is possible to skip a version by adding a "skip_versions" key to the software.

Each workflow:

- installs the latest version of neurodocker
- builds a dockerfile for a combination of OS / software / version / install method
- cat the dockerfile
- attempts to build the corresponding image

This script will also create a "dashboard" saved in docs/README.md
to be picked up to be rendered by the github pages.
This requires for you to build the pages from the docs folder
and on the branch where the workflows are pushed to (currently "test_docker_build").

"""
from pathlib import Path

import yaml # type: ignore
from jinja2 import Environment, FileSystemLoader, select_autoescape

apt_based = [
"ubuntu:22.04",
"ubuntu:18.04",
"ubuntu:16.04",
"debian:bullseye-slim",
"debian:buster-slim",
"debian:stretch-slim",
]
yum_based = ["fedora:36", "centos:7"]

"""
Add a "skip_versions" key to the software dictionary if you want to skip
testing a specific version. For example, if you want to skip testing
version 1.0.0 of afni, add the following to the software dictionary:

"afni": {
"skip_versions": ["1.0.0"],
"methods": ["binaries", "source"],
"afni_python": ["true", "false"],
},

"""
softwares: dict[str, dict[str, list[str]]] = {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note that not all the software of neurodocker are listed here

"afni": {
"methods": ["binaries", "source"],
"afni_python": ["true", "false"],
},
"ants": {
"methods": ["binaries", "source"],
},
"cat12": {"methods": ["binaries"]},
"convert3d": {"methods": ["binaries"]},
"dcm2niix": {
"methods": ["binaries", "source"],
},
"freesurfer": {"methods": []},
"fsl": {
"methods": ["binaries"],
},
"matlabmcr": {
"methods": ["binaries"],
},
"mricron": {"methods": ["binaries"]},
"mrtrix3": {
"methods": ["binaries", "source"],
},
"spm12": {"methods": ["binaries"]},
}

output_dir = Path(__file__).parent

template_folder = Path(__file__).parents[2].joinpath("neurodocker", "templates")

build_dashboard_file = Path(__file__).parents[2].joinpath("docs", "README.md")
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dashboard is added to the docs folder and rendered with github pages.

That means that to make test this I had to nuke the .nojekyll file that was in there.


# this has to match the name of the branch where the workflows are pushed to
# see .github/workflows/bootstrap.yml
branch = "test_docker_build"

# Update to match your username and repo name if you are testing things on your fork
# "ReproNim/neurodocker"
repo = "Remi-Gau/neurodocker"


def create_dashboard_file():
"""Create a build dashboard file."""

print("creating build dashboard file...")
print(build_dashboard_file)

gh_actions_url = "http://github-actions.40ants.com/"

with open(build_dashboard_file, "w") as f:
image_base_url = f"{gh_actions_url}{repo}/matrix.svg?branch={branch}"
print(
"""<!-- This page is generated automatically. Do not edit manually. -->
# Build dashboard
""",
file=f,
)

# table of content
for software, _ in softwares.items():
print(f"""- [{software}](#{software})""", file=f)

print("", file=f)

# link to the github actions workflow and image of the build status
for software, _ in softwares.items():
image_url = f"{image_base_url}&only={software}"
print(
f"""## {software}

[{software} workflow](https://github.com/{repo}/actions/workflows/{software}.yml)

![{software} build status]({image_url})
""",
file=f,
)


def get_versions_from_neurodocker_template(software: str) -> list[str]:
"""Load the list of versions to test from the software template."""
template = template_folder.joinpath(software).with_suffix(".yaml")
with open(template, "r") as f:
data = yaml.load(f, Loader=yaml.FullLoader)
return list(data["binaries"]["urls"].keys())


def stringify(some_list: list[str]) -> str:
if len(some_list) == 1:
return f"'{some_list[0]}'"
return "'" + "', '".join(some_list) + "'"


def main():
env = Environment(
loader=FileSystemLoader(Path(__file__).parent),
autoescape=select_autoescape(),
lstrip_blocks=True,
trim_blocks=True,
)

template = env.get_template("docker_build.jinja")

os = {
"apt_based": stringify(apt_based),
"yum_based": stringify(yum_based),
"all": stringify(apt_based + yum_based),
}

for software, spec in softwares.items():
wf = {
"header": "# This is file is automatically generated. Do not edit.",
"os": os,
"software": software,
}

versions = get_versions_from_neurodocker_template(software)
for i in spec.get("skip_versions", []):
versions.remove(i)

if versions is not None and len(versions) > 0:
wf["add_version"] = True
wf["versions"] = stringify(versions)

if spec.get("methods") is not None and len(spec["methods"]) > 0:
wf["add_method"] = True
wf["methods"] = stringify(spec["methods"])

if spec.get("afni_python") is not None and len(spec["afni_python"]) > 0:
wf["add_afni_python"] = True
wf["afni_python"] = stringify(spec["afni_python"])

output_file = output_dir.joinpath(software).with_suffix(".yml")
print("creating workflow")
print(f"{output_file}")
with open(output_file, "w") as f:
print(template.render(wf=wf), file=f)

create_dashboard_file()


if __name__ == "__main__":
main()
78 changes: 78 additions & 0 deletions .github/workflows/docker_build.jinja
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
{{ wf.header }}
name: '{{ wf.software }}'

concurrency:
group: ${{ '{{' }} github.workflow {{ '}}' }}-${{ '{{' }} github.ref {{ '}}' }}
cancel-in-progress: true

on:
push:
branches: ["test_docker_build"]

jobs:

{{ wf.software }}:

runs-on: ubuntu-latest

strategy:
fail-fast: false
matrix:
base_image: [{{ wf.os.all }}]
{% if wf.add_version %}
version: [{{ wf.versions }}]
{% endif %}
{% if wf.add_method %}
method: [{{ wf.methods }}]
{% endif %}
{% if wf.add_afni_python %}
afni_python: [{{ wf.afni_python }}]
{% endif %}

steps:
- uses: actions/checkout@v3

- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: "3.10"

- name: Install neurodocker
run: python -m pip install --editable .[dev]

- name: Generate Dockerfile
run: |

apt_based=({{ wf.os.apt_based }})
if [[ " ${apt_based[*]} " =~ ${{ '{{' }} matrix.base_image {{ '}}' }} ]]; then
pkg_manager="apt"
fi

yum_based=({{ wf.os.yum_based }})
if [[ " ${yum_based[*]} " =~ ${{ '{{' }} matrix.base_image {{ '}}' }} ]]; then
pkg_manager="yum"
fi

neurodocker \
generate docker \
--base-image=${{ '{{' }} matrix.base_image {{ '}}' }} \
--pkg-manager=${pkg_manager} \
--yes \
{% if wf.software == 'cat12' %}
--matlabmcr method='binaries' version='2017b' \
{% endif %}
--{{ wf.software }} \
{% if wf.add_version %}
version=${{ '{{' }} matrix.version {{ '}}' }} \
{% endif %}
{% if wf.add_method %}
method=${{ '{{' }} matrix.method {{ '}}' }} \
{% endif %}
{% if wf.add_afni_python %}
install_python3=${{ '{{' }} matrix.afni_python {{ '}}' }} \
{% endif %} > Dockerfile_tmp

cat Dockerfile_tmp

- name: Build the Docker image
run: docker build -f Dockerfile_tmp .
2 changes: 1 addition & 1 deletion .github/workflows/docs.yml
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@ on:
branches:
- master
permissions:
contents: write
contents: write
jobs:
build_docs:
runs-on: ubuntu-latest
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -139,4 +139,4 @@ dmypy.json
cython_debug/

# Pycharm
.idea/
.idea/
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@ repos:
- id: check-yaml
- id: check-added-large-files
- repo: https://github.com/psf/black
rev: "22.12.0"
rev: "23.1.0"
hooks:
- id: black

10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -15,11 +15,12 @@ Please see our website https://www.repronim.org/neurodocker for more information
Use the _Neurodocker_ Docker image (recommended):

```shell
docker run --rm repronim/neurodocker:0.7.0 --help
docker run --rm repronim/neurodocker:latest --help
```

The Docker images were moved to [repronim/neurodocker](https://hub.docker.com/r/repronim/neurodocker) from [kaczmarj/neurodocker](https://hub.docker.com/r/kaczmarj/neurodocker).


This project can also be installed with `pip`:

```shell
@@ -47,3 +48,10 @@ python -m pip install --no-cache-dir --editable .[all]
```

Before committing changes, initialize `pre-commit` with `pre-commit install`. This will format code with each commit to keep the style consistent. _Neurodocker_ uses `black` for formatting.


## Build status

You can check the status of the build of the Docker images
for several of the neuroimaging software packages that are supported by _Neurodocker_
on [this page](build_dashboard.md).
Empty file removed docs/.nojekyll
Empty file.
Loading