diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..ef2e5af --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,16 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file + +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + # Check for updates to GitHub Actions every day + interval: "daily" + time: "09:00" + timezone: "UTC" + assignees: + - "jimboid" diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml new file mode 100644 index 0000000..6845596 --- /dev/null +++ b/.github/workflows/build.yaml @@ -0,0 +1,185 @@ +name: ci/cd +on: + pull_request: + repository_dispatch: + types: [build] + workflow_dispatch: + +jobs: + build: + strategy: + fail-fast: false + matrix: + platform: + - linux/amd64 + - linux/arm64 + runs-on: ${{ matrix.platform == 'linux/amd64' && 'ubuntu-24.04' || matrix.platform == 'linux/arm64' && 'ubuntu-24.04-arm' }} + name: build ${{ matrix.platform }} + outputs: + tag: ${{ steps.envvars.outputs.tag }} + steps: + - name: checkout + uses: actions/checkout@v5.0.0 + + - name: Prepare env + id: envvars + run: | + platform=${{ matrix.platform }} + echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV + if [ ${{ github.event.client_payload.tag }} != 'null' ]; then + echo "tag=${{ github.event.client_payload.tag }}" >> $GITHUB_OUTPUT + else + echo "tag=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT + fi + + - name: Metadata + id: meta + uses: docker/metadata-action@v5.8.0 + with: + images: ghcr.io/${{ vars.ORG_REPO }}/${{ github.event.repository.name }} + + - name: Authenticate with GHCR + id: auth + uses: docker/login-action@v3.5.0 + with: + registry: ghcr.io + username: ${{github.actor}} + password: ${{secrets.BUILD_TOKEN}} + + - name: Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@v3.11.1 + + - name: Build and push by digest + id: build + uses: docker/build-push-action@v6.18.0 + with: + file: ./docker/Dockerfile + platforms: ${{ matrix.platform }} + labels: ${{ steps.meta.outputs.labels }} + tags: ghcr.io/${{ vars.ORG_REPO }}/${{ github.event.repository.name }} + outputs: type=image,push-by-digest=true,name-canonical=true,push=true + + - name: Export digest + run: | + mkdir -p ${{ runner.temp }}/digests + digest="${{ steps.build.outputs.digest }}" + touch "${{ runner.temp }}/digests/${digest#sha256:}" + + - name: Upload digest + uses: actions/upload-artifact@v4.6.2 + with: + name: digests-${{ env.PLATFORM_PAIR }} + path: ${{ runner.temp }}/digests/* + if-no-files-found: error + retention-days: 1 + + merge: + runs-on: ubuntu-24.04 + name: merge into multiarch manifest + needs: + - build + steps: + - name: Download digests + uses: actions/download-artifact@v5.0.0 + with: + path: ${{ runner.temp }}/digests + pattern: digests-* + merge-multiple: true + + - name: Authenticate with GHCR + id: auth + uses: docker/login-action@v3.5.0 + with: + registry: ghcr.io + username: ${{github.actor}} + password: ${{secrets.BUILD_TOKEN}} + + - name: Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@v3.11.1 + + - name: Metadata + id: meta + uses: docker/metadata-action@v5.8.0 + with: + images: ghcr.io/${{ vars.ORG_REPO }}/${{ github.event.repository.name }} + tags: dev + + - name: Create manifest list and push + id: annotate + continue-on-error: true + working-directory: ${{ runner.temp }}/digests + run: | + docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ + --annotation='index:org.opencontainers.image.description=${{ github.event.repository.description }}' \ + --annotation='index:org.opencontainers.image.licenses=MIT' \ + --annotation='index:org.opencontainers.image.created=${{ steps.timestamp.outputs.timestamp }}' \ + --annotation='index:org.opencontainers.image.url=${{ github.event.repository.url }}' \ + --annotation='index:org.opencontainers.image.source=${{ github.event.repository.url }}' \ + $(printf 'ghcr.io/${{ vars.ORG_REPO }}/${{ github.event.repository.name }}@sha256:%s ' *) + + - name: Create manifest list and push without annotations + if: steps.annotate.outcome == 'failure' + working-directory: ${{ runner.temp }}/digests + run: | + docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ + $(printf 'ghcr.io/${{ vars.ORG_REPO }}/${{ github.event.repository.name }}@sha256:%s ' *) + + - name: Inspect image + run: | + docker buildx imagetools inspect ghcr.io/${{ vars.ORG_REPO }}/${{ github.event.repository.name }}:dev + + tests: + strategy: + fail-fast: false + matrix: + platform: + - linux/amd64 + - linux/arm64 + runs-on: ${{ matrix.platform == 'linux/amd64' && 'ubuntu-latest' || matrix.platform == 'linux/arm64' && 'ubuntu-24.04-arm' }} + name: testing on ${{ matrix.platform }} + timeout-minutes: 360 + needs: + - build + - merge + steps: + + - name: Test notebooks + shell: bash + run: | + docker run -t ghcr.io/${{ vars.ORG_REPO }}/${{ github.event.repository.name }}:dev bash -c " \ + pip install pytest nbmake; \ + find . -name '*.ipynb' | pytest --nbmake --nbmake-timeout=3600;" + + tags: + runs-on: ubuntu-24.04 + if: github.event_name != 'pull_request' + name: add tags + needs: + - build + - tests + steps: + - name: Authenticate with GHCR + id: auth + uses: docker/login-action@v3.5.0 + with: + registry: "ghcr.io" + username: ${{github.actor}} + password: ${{secrets.BUILD_TOKEN}} + + - name: tag release versions + shell: bash + run: | + docker buildx imagetools create \ + --tag ghcr.io/${{ vars.ORG_REPO }}/${{ github.event.repository.name }}:latest \ + --tag ghcr.io/${{ vars.ORG_REPO }}/${{ github.event.repository.name }}:${{ needs.build.outputs.tag }} \ + ghcr.io/${{ vars.ORG_REPO }}/${{ github.event.repository.name }}:dev + + - name: Post version update to dash + uses: peter-evans/repository-dispatch@v3.0.0 + with: + token: ${{ secrets.BUILD_TOKEN }} + repository: jimboid/biosim-workshops-dash + event-type: build + client-payload: '{"repo": "${{ github.event.repository.name }}", "tag": "${{ needs.build.outputs.tag }}"}' diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index c50fdfc..0000000 --- a/Dockerfile +++ /dev/null @@ -1,37 +0,0 @@ -# This is the container for the CCPBioSim basic-analysis-workshop - -# Start with ccpbiosimbase. -FROM ccpbiosim/ccpbiosimbase:latest - -LABEL maintainer="James Gebbie-Rayet " - -# Root to install "rooty" things -USER root - -# Update and Install c-shell. -RUN apt-get update -y -RUN apt-get install -y csh - -# Back to jovyan user -USER $NB_USER - -# Python Dependencies for the md_workshop -RUN pip install --user numpy -RUN pip install --user cython -RUN pip install --user scipy -RUN pip install --user pandas -RUN pip install --user matplotlib -RUN pip install --user mdtraj -RUN pip install --user ipywidgets -RUN pip install --user nglview - -# Initialise NGLView. -RUN jupyter-nbextension install nglview --py --sys-prefix && \ - jupyter-nbextension enable nglview --py --sys-prefix - -# Add all of the workshop files to the home directory -ADD --chown=jovyan:100 *.ipynb $HOME/ -ADD --chown=jovyan:100 data $HOME/data - -# Always finish with non-root user as a precaution. -USER $NB_USER diff --git a/README.md b/README.md index da1e3b8..1212c86 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,20 @@ -# CCP-BioSim Training Course: Basic MD data analysis with MDTraj -IPython (Jupyter) notebooks are a great environment in which to do exploratory analysis of MD data. This workshop illustrates how two key Python packages - *numpy* and *matplotlib* - can be used with the MD analysis package [mdtraj](http://mdtraj.org/1.9.3/) for some simple standard analysis tasks. +# CCPBioSim Basic Analysis Workshop -## Requirements -A basic knowledge of Python and MD simulation methods. +[![build](https://github.com/ccpbiosim/basic-analysis-workshop/actions/workflows/build.yaml/badge.svg?branch=main)](https://github.com/ccpbiosim/basic-analysis-workshop/actions/workflows/build.yaml) -## Training material -A Jupyter notebook and example data files. +## Docker + +This container is derived from the CCPBioSim JupyterHub image. This container +adds the necessary software packages and notebook content to form a deployable +course container. The source content for this course can be found at +https://github.com/CCPBioSim/basic-analysis-workshop + +## How to Use + +In our containers we are using the JupyterHub default port 8888, so you should +forward this port when deploying locally:: + + docker run -p 8888:8888 ghcr.io/jimboid/biosim-basic-analysis-workshop:latest ## Contact Please direct all questions and feedback to [Charlie Laughton](mailto:charles.laughton@nottingham.ac.uk) diff --git a/_config.yml b/_config.yml deleted file mode 100644 index 418b47b..0000000 --- a/_config.yml +++ /dev/null @@ -1,3 +0,0 @@ -theme: jekyll-theme-slate -title: [An Introduction to Basic Interactive Analysis of MD Data] -description: [This workshop shows how Jupyter notebooks and the Python package MDTraj can be used for the interactive analysis of MD trajectory data.] diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000..8de0541 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,29 @@ +# Start with BioSim base image. +ARG BASE_IMAGE=latest +FROM ghcr.io/ccpbiosim/jupyterhub-base:$BASE_IMAGE + +LABEL maintainer="James Gebbie-Rayet " +LABEL org.opencontainers.image.source=https://github.com/ccpbiosim/biosim-basic-analysis-workshop +LABEL org.opencontainers.image.description="A container environment for the ccpbiosim workshop on basic analysis." +LABEL org.opencontainers.image.licenses=MIT + +# Switch to jovyan user. +USER $NB_USER +WORKDIR $HOME + +# Install workshop deps +RUN conda install matplotlib numpy nglview ipywidgets -y +RUN pip install mdtraj + +# Get workshop files and move them to jovyan directory. +COPY --chown=1000:100 . . +RUN rm -rf AUTHORS LICENSE README.md docker .git .github + +# Copy lab workspace +COPY --chown=1000:100 docker/default-37a8.jupyterlab-workspace /home/jovyan/.jupyter/lab/workspaces/default-37a8.jupyterlab-workspace + +# UNCOMMENT THIS LINE FOR REMOTE DEPLOYMENT +COPY docker/jupyter_notebook_config.py /etc/jupyter/ + +# Always finish with non-root user as a precaution. +USER $NB_USER diff --git a/docker/default-37a8.jupyterlab-workspace b/docker/default-37a8.jupyterlab-workspace new file mode 100644 index 0000000..7304bb5 --- /dev/null +++ b/docker/default-37a8.jupyterlab-workspace @@ -0,0 +1 @@ +{"data":{"layout-restorer:data":{"main":{"dock":{"type":"tab-area","currentIndex":0,"widgets":["notebook:Basic analysis.ipynb"]},"current":"notebook:Basic analysis.ipynb"},"left":{"collapsed":false,"current":"filebrowser","widgets":["filebrowser","running-sessions","@jupyterlab/toc:plugin","extensionmanager.main-view"]},"right":{"collapsed":true,"widgets":["jp-property-inspector"]}},"notebook:Basic analysis.ipynb":{"data":{"path":"Basic analysis.ipynb","factory":"Notebook"}}},"metadata":{"id":"default"}} diff --git a/docker/jupyter_notebook_config.py b/docker/jupyter_notebook_config.py new file mode 100644 index 0000000..a3e5d82 --- /dev/null +++ b/docker/jupyter_notebook_config.py @@ -0,0 +1,2 @@ + +c.JupyterHub.authenticator_class = 'tmpauthenticator.TmpAuthenticator'