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/README.md b/README.md index 4243c52..b69d58e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ -# docking-workflow +# CCPBioSim Docking Workshop + +[![build](https://github.com/ccpbiosim/docking-workshop/actions/workflows/build.yaml/badge.svg?branch=main)](https://github.com/ccpbiosim/docking-workshop/actions/workflows/build.yaml) This is a repository for a set of Jupyter notebooks to create a workflow for docking ligands to multiple protein receptors and analysing the results. @@ -10,10 +12,27 @@ Dependencies: 5. OpenBabel with Python bindings 6. OpenDrugDiscovery -If you are using the prepared virtual machine, all the requirements are installed except ChimeraX. +If you are using the prepared docker container, all the requirements are installed except ChimeraX. To install ChimeraX, go to https://www.rbvi.ucsf.edu/chimerax/download.html and download the correct version for your operating system (you will need to click on other releases to find the linux version) and follow the instructions in the notes column on the website. This is for personal non-commercial use. If results are published, please cite all of the software that you used. https://vina.scripps.edu/manual/#citation https://www.rbvi.ucsf.edu/chimerax/docs/credits.html + +## 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/docking-workflow + +## 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-docking-workshop:latest + + + diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000..36d1fee --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,31 @@ +# 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/docking-workshop +LABEL org.opencontainers.image.description="A container environment for the ccpbiosim workshop on docking." +LABEL org.opencontainers.image.licenses=MIT + +ARG TARGETPLATFORM + +# Switch to jovyan user. +USER $NB_USER +WORKDIR $HOME + +# Install workshop deps +RUN conda install oddt::oddt -y +RUN conda install termcolor matplotlib seaborn pandas openbabel vina + +# Get workshop files and move them to jovyan directory. +COPY --chown=1000:100 . . +RUN rm -rf chimerax_commands.cxc LICENSE README.md docking_with_rescoring 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..fc5ae4b --- /dev/null +++ b/docker/default-37a8.jupyterlab-workspace @@ -0,0 +1 @@ +{"data":{"layout-restorer:data":{"main":{"dock":{"type":"tab-area","currentIndex":0,"widgets":["notebook:simple_docking/MTH_Docking_Part1_Prepare_2.0.ipynb"]},"current":"notebook:simple_docking/MTH_Docking_Part1_Prepare_2.0.ipynb"},"left":{"collapsed":false,"current":"filebrowser","widgets":["filebrowser","running-sessions","@jupyterlab/toc:plugin","extensionmanager.main-view"]},"right":{"collapsed":true,"widgets":["jp-property-inspector"]}},"notebook:simple_docking/MTH_Docking_Part1_Prepare_2.0.ipynb":{"data":{"path":"simple_docking/MTH_Docking_Part1_Prepare_2.0.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'