├── .devcontainer └── devcontainer.json ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── draft_workflows │ ├── binder.yaml │ ├── chatops.yaml │ ├── deploy.yaml │ └── test_gcf.yaml └── workflows │ ├── binder.yaml │ ├── release-updates.yaml │ └── test.yaml ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Dockerfile ├── LICENSE ├── README.md ├── RELEASE.md ├── action.yml ├── action_files └── create_deployment.py ├── binder_cache.py ├── bootstrap.sh ├── build_action_container.sh ├── create_docker_image.sh ├── notebooks └── Hello World.ipynb ├── requirements.txt └── trigger_binder.sh /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Test Jupyter Notebook", 3 | "forwardPorts": 8888, 4 | "image": "hamelsmu/repo2docker-test", 5 | "extensions": ["ms-python.python"], 6 | "mounts": [ "source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind" ], 7 | "postCreateCommand_notes": "jupyter lab --no-browser --NotebookApp.token='' --NotebookApp.password='' --NotebookApp.disable_check_xsrf=True --ip 0.0.0.0", 8 | "remoteUser": "hamelsmu" 9 | } -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Additional context** 27 | Add any other context about the problem here. 28 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/draft_workflows/binder.yaml: -------------------------------------------------------------------------------- 1 | name: Binder 2 | on: 3 | pull_request: 4 | types: [opened, reopened] 5 | 6 | jobs: 7 | Create-Binder-Badge: 8 | runs-on: ubuntu-latest 9 | steps: 10 | 11 | - name: checkout pull request branch 12 | uses: actions/checkout@v4 13 | with: 14 | ref: ${{ github.event.pull_request.head.sha }} 15 | 16 | - name: comment on PR with Binder link 17 | uses: actions/github-script@v1 18 | with: 19 | github-token: ${{secrets.GITHUB_TOKEN}} 20 | script: | 21 | var BRANCH_NAME = process.env.BRANCH_NAME; 22 | github.issues.createComment({ 23 | issue_number: context.issue.number, 24 | owner: context.repo.owner, 25 | repo: context.repo.repo, 26 | body: `[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/${context.repo.owner}/${context.repo.repo}/${BRANCH_NAME}) :point_left: Launch a binder notebook on this branch` 27 | }) 28 | env: 29 | BRANCH_NAME: ${{ github.event.pull_request.head.ref }} 30 | REPO: ${{ github.repository }} 31 | -------------------------------------------------------------------------------- /.github/draft_workflows/chatops.yaml: -------------------------------------------------------------------------------- 1 | name: ChatOps 2 | on: [issue_comment] 3 | 4 | jobs: 5 | trigger: 6 | if: github.event.issue.pull_request != null && contains(github.event.comment.body, '/build-notebook') && (github.actor == 'hamelsmu' || github.actor == 'neovintage' || github.actor == 'inc0') 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: machine-learning-apps/actions-chatops@master 10 | id: chatops 11 | with: 12 | APP_PEM: ${{ secrets.APP_PEM }} 13 | APP_ID: ${{ secrets.APP_ID }} 14 | TRIGGER_PHRASE: "/build-notebook" 15 | INDICATOR_LABEL: "Building Notebook" 16 | env: 17 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 18 | 19 | - name: Copy Repository Contents 20 | uses: actions/checkout@master 21 | 22 | - name: create deployment 23 | run: | 24 | pip3 install requests 25 | python3 action_files/create_deployment.py 26 | env: 27 | RUN_ID: "notebook-deploy" 28 | BRANCH_NAME: ${{ steps.chatops.outputs.BRANCH_NAME }} 29 | TOKEN: ${{ steps.chatops.outputs.APP_INSTALLATION_TOKEN }} 30 | -------------------------------------------------------------------------------- /.github/draft_workflows/deploy.yaml: -------------------------------------------------------------------------------- 1 | name: Google Cloud Function Notebook Deploy 2 | 3 | on: deployment 4 | 5 | jobs: 6 | deploy: 7 | if: github.actor == 'pr-chatops[bot]' 8 | runs-on: ubuntu-latest 9 | steps: 10 | 11 | - uses: actions/checkout@v4 12 | 13 | - name: build-environment 14 | id: repo2docker 15 | uses: ./ 16 | with: 17 | DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} 18 | DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} 19 | IMAGE_NAME: "hamelsmu/repo2docker-test" 20 | 21 | - name: paperspace-deploy 22 | id: paperspace 23 | run: | 24 | pip install gradient 25 | gradient apiKey ${PAPERSPACE_TOKEN} 26 | gradient jobs create --container ${IMAGE_NAME} --projectId ${PAPERSPACE_PROJECT_ID} --machineType K80 --ports 8888:8888 27 | env: 28 | PAPERSPACE_TOKEN: ${{ secrets.PAPERSPACE_TOKEN }} 29 | PAPERSPACE_PROJECT_ID: ${{ secrets.PAPERSPACE_PROJECT_ID }} 30 | IMAGE_NAME: ${{ steps.repo2docker.outputs.IMAGE_SHA_NAME }} 31 | 32 | # - uses: exelban/gcloud@master 33 | # env: 34 | # PROJECT_ID: ${{ secrets.GOOGLE_PROJECT_ID }} 35 | # APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }} 36 | # IMAGE_NAME: ${{ steps.repo2docker.outputs.IMAGE_SHA_NAME }} 37 | # with: 38 | # args: --quiet beta run deploy notebook-serve-action --allow-unauthenticated --platform managed --region us-west1 --image $IMAGE_NAME 39 | # - run: | 40 | # curl -d '{"state": "failure"}' -H "Authorization: token $GITHUB_TOKEN" https://api.github.com/repos/"$GITHUB_REPOSITORY"/deployments/"$DEPLOYMENT_ID"/statuses 41 | # if: failure() 42 | # env: 43 | # GITHUB_TOKEN: ${{ github.token }} 44 | # DEPLOYMENT_ID: ${{ github.event.deployment.id }} 45 | # - run: | 46 | # curl -d "{\"state\": \"success\", \"log_url\": \"https://console.cloud.google.com/functions/details/us-central1/predict?project=$GOOGLE_PROJECT_ID\"}" -H "Authorization: token $GITHUB_TOKEN" -H "Accept: application/vnd.github.ant-man-preview+json" https://api.github.com/repos/"$GITHUB_REPOSITORY"/deployments/"$DEPLOYMENT_ID"/statuses 47 | # if: success() 48 | # env: 49 | # GITHUB_TOKEN: ${{ github.token }} 50 | # DEPLOYMENT_ID: ${{ github.event.deployment.id }} 51 | # PROJECT_ID: ${{ secrets.GOOGLE_PROJECT_ID }} 52 | -------------------------------------------------------------------------------- /.github/draft_workflows/test_gcf.yaml: -------------------------------------------------------------------------------- 1 | name: Google Cloud Function Notebook Deploy Test 2 | 3 | on: push 4 | 5 | jobs: 6 | deploy: 7 | # turn workflow off 8 | if: 1 ==2 9 | runs-on: ubuntu-latest 10 | steps: 11 | # GCP: https://cloud.google.com/sdk/gcloud/reference/beta/notebooks 12 | # Azure: https://docs.microsoft.com/en-us/azure/container-instances/container-instances-gpu 13 | # AWS: sagemaker? 14 | - uses: exelban/gcloud@master 15 | env: 16 | PROJECT_ID: ${{ secrets.GOOGLE_PROJECT_ID }} 17 | APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }} 18 | with: 19 | args: --quiet beta run deploy notebook-serve-action --allow-unauthenticated --platform managed --region us-west1 --image hamelsmu/repo2docker-test:d28ad6b9fa6a 20 | -------------------------------------------------------------------------------- /.github/workflows/binder.yaml: -------------------------------------------------------------------------------- 1 | name: Binder 2 | on: 3 | pull_request: 4 | types: [opened, reopened] 5 | 6 | jobs: 7 | Create-Binder-Badge: 8 | runs-on: ubuntu-latest 9 | steps: 10 | 11 | - name: comment on PR with Binder link 12 | if: github.event == 'pull_request' 13 | uses: actions/github-script@v1 14 | with: 15 | github-token: ${{secrets.GITHUB_TOKEN}} 16 | script: | 17 | var BRANCH_NAME = process.env.BRANCH_NAME; 18 | github.issues.createComment({ 19 | issue_number: context.issue.number, 20 | owner: context.repo.owner, 21 | repo: context.repo.repo, 22 | body: `[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/${context.repo.owner}/${context.repo.repo}/${BRANCH_NAME}) :point_left: Launch a binder notebook on this branch` 23 | }) 24 | env: 25 | BRANCH_NAME: ${{ github.event.pull_request.head.ref }} 26 | -------------------------------------------------------------------------------- /.github/workflows/release-updates.yaml: -------------------------------------------------------------------------------- 1 | # Automatically updates "vX" branches based on GitHub releases. To cut a new 2 | # release, use the GitHub UI where you enter a tag name and release name of 3 | # "vX.Y.Z". See https://github.com/jupyterhub/repo2docker-action/releases. 4 | --- 5 | name: Release updates 6 | 7 | on: 8 | release: 9 | types: [published, edited] 10 | 11 | jobs: 12 | actions-tagger: 13 | runs-on: windows-latest 14 | permissions: 15 | contents: write 16 | steps: 17 | # Action reference: https://github.com/Actions-R-Us/actions-tagger 18 | - uses: Actions-R-Us/actions-tagger@release/v2 19 | with: 20 | # By using branches as identifiers it is still possible to backtrack 21 | # some patch, but not if we use tags. 22 | prefer_branch_releases: true 23 | token: "${{ github.token }}" 24 | -------------------------------------------------------------------------------- /.github/workflows/test.yaml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: 4 | pull_request: 5 | paths-ignore: 6 | - ".github/workflows/*.yaml" 7 | - "!.github/workflows/test.yaml" 8 | push: 9 | paths-ignore: 10 | - ".github/workflows/*.yaml" 11 | - "!.github/workflows/test.yaml" 12 | branches-ignore: 13 | - "dependabot/**" 14 | - "pre-commit-ci-update-config" 15 | tags: ["**"] 16 | schedule: 17 | # Run at 05:00 every day, ref: https://crontab.guru/#0_5_*_*_* 18 | - cron: "0 5 * * *" 19 | workflow_dispatch: 20 | 21 | jobs: 22 | test-registry: 23 | runs-on: ubuntu-latest 24 | strategy: 25 | matrix: 26 | image_name: ['repo2docker-test', ''] 27 | tag: ['test-tag', ''] 28 | no_push: [true, ''] 29 | latest_off: [true, ''] 30 | services: 31 | local-registry: 32 | image: registry:2 33 | ports: 34 | - 5000:5000 35 | steps: 36 | - uses: actions/checkout@v4 37 | - name: test action 38 | uses: ./ 39 | with: 40 | IMAGE_NAME: ${{ matrix.image_name }} 41 | ADDITIONAL_TAG: ${{ matrix.tag }} 42 | NO_PUSH: ${{ matrix.push }} 43 | LATEST_TAG_OFF: ${{ matrix.latest_off }} 44 | DOCKER_REGISTRY: "localhost:5000" 45 | DOCKER_USERNAME: 'foo' 46 | DOCKER_PASSWORD: 'foo' 47 | 48 | mybinder: 49 | runs-on: ubuntu-latest 50 | steps: 51 | - uses: actions/checkout@v4 52 | 53 | - name: mybinder 54 | uses: ./ 55 | with: 56 | NO_PUSH: true 57 | MYBINDERORG_TAG: ${{ github.sha }} 58 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | This project inherits and adopts the [Project Jupyter Code of Conduct](https://jupyter.org/governance/conduct/code_of_conduct.html). 4 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guide 2 | 3 | ## Project Jupyter Contributing Guidelines 4 | 5 | This project is also governed by the [Project Jupyter Contributing Guidelines](https://jupyter.readthedocs.io/en/latest/contributing/content-contributor.html). In the case of any conflicts between what is written here and the Jupyter Contributing Guidelines the Jupyter guidelines will control. 6 | 7 | _shamlessly borrowed many of these guidelines from [repo2docker](https://repo2docker.readthedocs.io/en/latest/contributing/contributing.html#types-of-contribution)_ 8 | 9 | 10 | 11 | - [Process for making a contribution](#process-for-making-a-contribution) 12 | - [Guidelines to getting a Pull Request merged](#guidelines-to-getting-a-pull-request-merged) 13 | - [Setting up for Local Development](#setting-up-for-local-development) 14 | - [Resources For Getting Started With Actions](#resources-for-getting-started-with-actions) 15 | 16 | 17 | 18 | # Process for making a contribution 19 | 20 | - Update the documentation. If you’re reading a page or docstring and it doesn’t make sense (or doesn’t exist!), please let us know by opening a bug report. It’s even more amazing if you can give us a suggested change. 21 | 22 | - Fix bugs or add requested features. Have a look through the issue tracker and see if there are any tagged as “help wanted”. As the label suggests, we’d love your help! 23 | 24 | - Report a bug. If repo2docker-action isn’t doing what you thought it would do then open a bug report. That issue template will ask you a few questions described in more detail below. 25 | 26 | - Suggest a new feature. We know that there are lots of ways to extend the repo2docker-action! If you’re interested in adding a feature then please open a feature request. That issue template will ask you a few questions described in detail below. 27 | 28 | - Review someone’s Pull Request. Whenever somebody proposes changes to the repo2docker-action codebase, the community reviews the changes, and provides feedback, edits, and suggestions. Check out the open pull requests and provide feedback that helps improve the PR and get it merged. Please keep your feedback positive and constructive! 29 | 30 | - Tell people about the repo2docker-action. As we said above, repo2docker-action is built by and for its community. If you know anyone who would like to use repo2docker-action, please tell them about the project! You could give a talk about it, or run a demonstration. 31 | 32 | # Process for making a contribution 33 | 34 | This outlines the process for getting changes to the repo2docker-action project merged. 35 | 36 | 1. Identify the correct issue template: bug report or feature request. 37 | 38 | Bug reports (examples, new issue) will ask you for a description of the problem, the expected behaviour, the actual behaviour, how to reproduce the problem, and your personal set up. Bugs can include problems with the documentation, or code not running as expected. 39 | 40 | It is really important that you make it easy for the maintainers to reproduce the problem you’re having. This guide on creating a minimal, complete and verifiable example is a great place to start. 41 | 42 | Feature requests (examples, new issue) will ask you for the proposed change, any alternatives that you have considered, a description of who would use this feature, and a best-guess of how much work it will take and what skills are required to accomplish. 43 | 44 | Very easy feature requests might be updates to the documentation to clarify steps for new users. Harder feature requests may be to add new functionality to the project and will need more in depth discussion about who can complete and maintain the work. 45 | 46 | Feature requests are a great opportunity for you to advocate for the use case you’re suggesting. They help others understand how much effort it would be to integrate the work,and - if you’re successful at convincing them that this effort is worth it - make it more likely that they to choose to work on it with you. 47 | 48 | 2. Open an issue. Getting consensus with the community is a great way to save time later. 49 | 50 | 3. Make edits in your fork of the repo2docker-action repository. 51 | 52 | 4. Make a pull request. Read the next section for guidelines for both reviewers and contributors on merging a PR. 53 | 54 | 5. Edit the changelog by appending your feature / bug fix to the development version. 55 | 56 | 5. Wait for a community member to merge your changes. Remember that someone else must merge your pull request. That goes for new contributors and long term maintainers alike. 57 | 58 | 59 | # Guidelines to getting a Pull Request merged 60 | 61 | These are suggestions to help complete your contribution as smoothly as possible. 62 | 63 | - Create a PR as early as possible, marking it with [WIP] while you work on it. This avoids duplicated work, lets you get high level feedback on functionality or API changes, and/or helps find collaborators to work with you. 64 | 65 | - Keep your PR focused. The best PRs solve one problem. If you end up changing multiple things, please open separate PRs for the different conceptual changes. 66 | 67 | - Add tests to your code. PRs will not be merged if Travis is failing. 68 | 69 | - Use merge commits instead of merge-by-squashing/-rebasing. This makes it easier to find all changes since the last deployment git log --merges --pretty=format:"%h %<(10,trunc)%an %<(15)%ar %s" .. and your PR easier to review. 70 | 71 | - Make it clear when your PR is ready for review. Prefix the title of your pull request (PR) with [MRG] if the contribution is complete and should be subjected to a detailed review. 72 | 73 | - Use commit messages to describe why you are proposing the changes you are proposing. 74 | 75 | Try to not rush changes (the definition of rush depends on how big your changes are). Remember that everyone in the repo2docker-action team is a volunteer and we can not (nor would we want to) control their time or interests. Wait patiently for a reviewer to merge the PR. (Remember that someone else must merge your PR, even if you have the admin rights to do so.) 76 | 77 | # Setting up for Local Development 78 | 79 | To develop & test repo2docker-action locally, you need: 80 | 81 | 1. Familiarity with using a command line terminal 82 | 2. Familiary with [GitHub Actions](https://docs.github.com/en/actions) 83 | 2. A computer running macOS / Linux 84 | 3. Some knowledge of git 85 | 4. A recent version of Docker Community Edition, and familiarity with Docker 86 | 87 | You can run the Action locally by editing and running [bootstrap.sh](./bootstrap.sh). You will have to change and set environment variables to supply the various inputs to this Action. Note that the various input parameters described in the [API Reference Section of the README](https://github.com/jupyterhub/repo2docker-action#api-reference), must be prepended by `INPUT_` as an environment variable for the local docker container. For example, to supply the input `NOTEBOOK_USER` you would pass the environment variable `INPUT_NOTEBOOK_USER` as an environment variable into the container at runtime. This is to emulate what happens in GitHub Actions. 88 | 89 | Per the [Actions docs](https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#inputs): 90 | 91 | > When you specify an input to an action in a workflow file or use a default input value, GitHub creates an environment variable for the input with the name INPUT_. The environment variable created converts input names to uppercase letters and replaces spaces with _ characters. 92 | 93 | Finally, you cannot completely replicate GitHub Actions locally and it might be helpful to interactively debug Actions in the context that are created and run. Forking the repo and using [this debugging action](https://github.com/marketplace/actions/debugging-with-tmate) can be very useful for this purposes. 94 | 95 | # Resources For Getting Started With GitHub Actions 96 | 97 | - [Creating GitHub Actions - Official Documentation](https://docs.github.com/en/actions/creating-actions) 98 | - [Live Demo: Actions For Data Science](https://youtu.be/S-kn4mmlxFU) 99 | - [Blog Post re:Actions For Data Scientists](https://fastpages.fast.ai/actions/markdown/2020/03/06/fastpages-actions.html) 100 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM quay.io/jupyterhub/repo2docker:main 2 | 3 | RUN apk add --no-cache curl build-base python3 python3-dev py3-pip 4 | 5 | RUN python3 -m pip install --upgrade wheel setuptools 6 | 7 | # Manually downgrade version of docker-py 8 | # Until a fix for https://github.com/docker/docker-py/issues/3240 9 | # is released, we want to use an older version of docker-py 10 | RUN pip install 'docker!=7.0.0' 11 | 12 | # https://stackoverflow.com/a/41651363/1695486 13 | RUN apk add --no-cache curl curl-dev 14 | COPY create_docker_image.sh /create_docker_image.sh 15 | COPY binder_cache.py /binder_cache.py 16 | COPY trigger_binder.sh /trigger_binder.sh 17 | 18 | ENTRYPOINT ["/bin/bash", "/create_docker_image.sh"] 19 | 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 ML Apps 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![](https://github.com/jupyterhub/repo2docker-action/workflows/Test/badge.svg) [![MLOps](https://img.shields.io/badge/MLOps-black.svg?logo=github&?logoColor=blue)](https://mlops-github.com) 2 | 3 | 4 | # repo2docker GitHub Action 5 | 6 | 7 | 8 | 9 | - [What Can I Do With This Action?](#what-can-i-do-with-this-action) 10 | - [API Reference](#api-reference) 11 | - [Mandatory Inputs](#mandatory-inputs) 12 | - [Optional Inputs](#optional-inputs) 13 | - [Outputs](#outputs) 14 | - [Testing the built image](#testing-the-built-image) 15 | - [Examples](#examples) 16 | - [mybinder.org](#mybinderorg) 17 | - [Cache builds on mybinder.org](#cache-builds-on-mybinderorg) 18 | - [Cache Builds On mybinder.org And Provide A Link](#cache-builds-on-mybinderorg-and-provide-a-link) 19 | - [Use GitHub Actions To Cache The Build For BinderHub](#use-github-actions-to-cache-the-build-for-binderhub) 20 | - [Push Repo2Docker Image To DockerHub](#push-repo2docker-image-to-dockerhub) 21 | - [Push Repo2Docker Image To quay.io](#push-repo2docker-image-to-quayio) 22 | - [Push Repo2Docker Image To Amazon ECR](#push-repo2docker-image-to-amazon-ecr) 23 | - [Push Repo2Docker Image To Google Container Registry](#push-repo2docker-image-to-google-container-registry) 24 | - [Push Repo2Docker Image To Google Artifact Registry](#push-repo2docker-image-to-google-artifact-registry) 25 | - [Push Repo2Docker Image To GitHub Package Registry](#push-repo2docker-image-to-github-package-registry) 26 | - [Push Repo2Docker Image To Azure Container Registry](#push-repo2docker-image-to-azure-container-registry) 27 | - [Push Repo2Docker Image To Other Registries](#push-repo2docker-image-to-other-registries) 28 | - [Change Image Name](#change-image-name) 29 | - [Test Image Build](#test-image-build) 30 | - [Contributing](#contributing-to-repo2docker-action) 31 | 32 | 33 | 34 | 35 | Trigger [repo2docker](https://github.com/jupyter/repo2docker) to build a Jupyter enabled Docker image from your GitHub repository and push this image to a Docker registry of your choice. This will automatically attempt to build an environment from configuration files found in your repository in the [manner described here](https://repo2docker.readthedocs.io/en/latest/usage.html#where-to-put-configuration-files). 36 | 37 | Read the full docs on repo2docker for more information: https://repo2docker.readthedocs.io 38 | 39 | Images generated by this action are automatically tagged with both `latest` and `` corresponding to the relevant [commit SHA on GitHub](https://help.github.com/en/github/getting-started-with-github/github-glossary#commit). Both tags are pushed to the Docker registry specified by the user. If an existing image with the `latest` tag already exists in your registry, this Action attempts to pull that image as a cache to reduce uncessary build steps. 40 | 41 | # What Can I Do With This Action? 42 | 43 | - Use repo2docker to pre-cache images for your own [BinderHub cluster](https://binderhub.readthedocs.io/en/latest/zero-to-binderhub/setup-binderhub.html), or for [mybinder.org](https://mybinder.org/). 44 | - You can use this Action to pre-cache Docker images to a Docker registry that you can reference in your repo. For example if you have the file `Dockerfile` in the `binder/` directory relative to the root of your repository with the following contents, this will allow Binder to start quickly by pulling an image you have already built: 45 | 46 | ```dockerfile 47 | # This is the image that is built and pushed by this Action (replace this with your image name) 48 | FROM myorg/myimage:latest 49 | ... 50 | ``` 51 | - Provide a way to Dockerize data science repositories with Jupyter server enabled that you can deploy to VMs, [serverless computing](https://en.wikipedia.org/wiki/Serverless_computing) or other services that can serve Docker containers as-a-service. 52 | - Maximize reproducibility by allowing authors, without any prior knowledge of Docker, to build and share containers. 53 | - Run tests after the image has been built, to make sure package changes don't break your code. 54 | 55 | # API Reference 56 | 57 | See the [examples](#examples) section is very helpful for understanding the inputs and outputs of this Action. 58 | 59 | ## Optional Inputs 60 | 61 | - **`DOCKER_USERNAME`**: 62 | description: Docker registry username. If not supplied, credentials must be setup ahead of time. 63 | - **`DOCKER_PASSWORD`**: 64 | description: Docker registry password or [access token (recommended)](https://docs.docker.com/docker-hub/access-tokens/). If not supplied, credentials must be setup ahead of time. 65 | - **`DOCKER_REGISTRY`**: 66 | description: domain name of the docker registry. If not supplied, this defaults to [DockerHub](https://hub.docker.com/) 67 | - **`IMAGE_NAME`**: 68 | name of the image. Example - myusername/myContainer. If not supplied, this defaults to `/` or `/`. 69 | - **`NOTEBOOK_USER`**: 70 | description: username of the primary user in the image. If this is not specified, this is set to `joyvan`. **NOTE**: This value is also overriden with `jovyan` if the parameters `BINDER_CACHE` or `MYBINDERORG_TAG` are provided. 71 | - **`REPO_DIR`**: 72 | Path inside the image where contents of the repositories are copied to, and where all the build operations (such as postBuild) happen. Defaults to `/home/` if not set. 73 | - **`APPENDIX_FILE`**: 74 | Path to file containing Dockerfile commands to run at the end of the build. Can be used to customize the resulting image after all standard build steps finish. 75 | - **`LATEST_TAG_OFF`**: 76 | Setting this variable to any value will prevent your image from being tagged with `latest`. Note that your image is always tagged with the [GitHub commit SHA](https://help.github.com/en/github/getting-started-with-github/github-glossary#commit). 77 | - **`ADDITIONAL_TAG`**: 78 | An optional string that specifies the name of an additional tag you would like to apply to the image. Images are already tagged with the relevant [GitHub commit SHA](https://help.github.com/en/github/getting-started-with-github/github-glossary#commit). 79 | - **`NO_PUSH`**: 80 | If "true". this variable will prevent any images from being pushed to a registry. Furthermore, verbose logging will be enabled in this mode. Default value is "false". 81 | - **`BINDER_CACHE`**: 82 | Setting this variable to any value will add the file `binder/Dockerfile` that references the docker image that was pushed to the registry by this Action. You cannot use this option if the parameter `NO_PUSH` is set. This is disabled by default. 83 | - Note: This Action assumes you are not explicitly using Binder to build your dependencies (You are using this Action to build your dependencies). If a directory `binder` with other files other than `Dockerfile` or a directory named `.binder/` is detected, this step will be aborted. This Action does not support caching images for Binder where dependencies are defined in `binder/Dockerfile` (if you are defining your dependencies this way, you probably don't need this Action). 84 | 85 | When this parameter is supplied, this Action will add/override `binder/Dockerfile` in the branch checked out in the Actions runner: 86 | ```dockerfile 87 | ### DO NOT EDIT THIS FILE! This Is Automatically Generated And Will Be Overwritten ### 88 | FROM 89 | ``` 90 | - **`COMMIT_MSG`**: 91 | The commit message associated with specifying the `BINDER_CACHE` flag. If no value is specified, the default commit message of `Update image tag` will be entered. 92 | - **`MYBINDERORG_TAG`**: 93 | This the Git branch, tag, or commit that you want [mybinder.org](https://mybinder.org/) to proactively build from your repo. This is useful if you wish to reduce startup time on mybinder.org. **Your repository must be public for this work, as mybinder.org only works with public repositories**. 94 | - **`PUBLIC_REGISTRY_CHECK`**: 95 | Setting this variable to any value will validate that the image pushed to the registry is publicly visible. 96 | - **`REPO2DOCKER_EXTRA_ARGS`**: 97 | Any extra commandline parameters to be passed to the repo2docker build command 98 | - **`FORCE_REPO2DOCKER_VERSION`**: 99 | Force a specific version of repo2docker to be installed. Either in the form of `repo2docker==` for install from pypi, or `git+https://@ [!WARNING] 121 | > If you are using a Dockerfile to configure your environment, then include `COPY --chown=${NB_USER}:${NB_USER} image-tests ${REPO_DIR}/image-tests` in your Dockerfile to ensure the correct ownership of this folder within the image. 122 | 123 | To use automatic image testing, follow these steps: 124 | 125 | 1. Create a directory named `image-tests/` in your GitHub repository. 126 | 2. Any `.py` files you add inside this directory will be discovered 127 | and run with `pytest` inside the built image after the image has 128 | successfully built. 129 | 3. Any Jupyter Notebook (`.ipynb`) files inside this directory will 130 | be run with [`pytest-notebook`](https://pytest-notebook.readthedocs.io/en/latest/), and the notebook is considered to 131 | have *failed* if the outputs of the code execution do not match 132 | the outputs already in the notebook. A nice diff of the outputs 133 | is shown if they differ. See the [pytest-notebook docs](https://pytest-notebook.readthedocs.io/en/latest/) 134 | for more information. 135 | 4. Optionally, a `requirements.txt` file inside the `image-tests/` 136 | directory can list additional libraries installed just for the 137 | test. 138 | 139 | For example, look at the following image environment repository structure: 140 | 141 | ``` 142 | my-image/ 143 | ├── environment.yml 144 | └── image-tests 145 | ├── mytestnotebook.ipynb 146 | └── mytest.py 147 | ``` 148 | 149 | This defines three things: 150 | 151 | - **`environment.yml`** is a repo2docker environment file, which defines the packages for the user image 152 | - **`image-tests/mytestnotebook.ipynb`** is a Jupyter notebook that is already executed so its outputs are included in the `ipynb` file. When the image is built, this notebook will be re-executed, and the outputs compared against the version stored with the repository. 153 | - **`image-tests/mytest.py`** is a Python file that will be run with Pytest, and any failures will be reported. 154 | # Examples 155 | 156 | ## mybinder.org 157 | 158 | A very popular use case for this Action is to cache builds for [mybinder.org](https://mybinder.org/). If you desire to cache builds for mybinder.org, you must specify the argument `MYBINDERORG_TAG`. Some examples of doing this are below: 159 | 160 | ### Cache builds on mybinder.org 161 | 162 | Proactively build your environment on mybinder.org for any branch. Alternatively, you can use [using GitHub Actions to build an image for BindHub generally](https://github.com/jupyterhub/repo2docker-action#use-github-actions-to-cache-the-build-for-binderhub), including mybinder.org. 163 | 164 | ```yaml 165 | name: Binder 166 | on: [push] 167 | 168 | jobs: 169 | Create-MyBinderOrg-Cache: 170 | runs-on: ubuntu-latest 171 | steps: 172 | - name: cache binder build on mybinder.org 173 | uses: jupyterhub/repo2docker-action@master 174 | with: 175 | NO_PUSH: true 176 | MYBINDERORG_TAG: ${{ github.event.ref }} # This builds the container on mybinder.org with the branch that was pushed on. 177 | ``` 178 | 179 | ### Cache Builds On mybinder.org And Provide A Link 180 | 181 | Same example as above, but also comment on a PR with a link to the binder environment. Commenting on the PR is optional, and is included here for informational purposes only. In this example the image will only be cached when the pull request is opened but not if the pull request is updated with subsequent commits. 182 | 183 | In this example the image will only be cached when the pull request is opened but not if the pull request is updated with subsequent commits. 184 | 185 | ```yaml 186 | name: Binder 187 | on: 188 | pull_request: 189 | types: [opened, reopened] 190 | 191 | jobs: 192 | Create-Binder-Badge: 193 | runs-on: ubuntu-latest 194 | steps: 195 | - name: cache binder build on mybinder.org 196 | uses: jupyterhub/repo2docker-action@master 197 | with: 198 | NO_PUSH: true 199 | MYBINDERORG_TAG: ${{ github.event.pull_request.head.ref }} 200 | 201 | - name: comment on PR with Binder link 202 | uses: actions/github-script@v1 203 | with: 204 | github-token: ${{secrets.GITHUB_TOKEN}} 205 | script: | 206 | var BRANCH_NAME = process.env.BRANCH_NAME; 207 | github.issues.createComment({ 208 | issue_number: context.issue.number, 209 | owner: context.repo.owner, 210 | repo: context.repo.repo, 211 | body: `[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/${context.repo.owner}/${context.repo.repo}/${BRANCH_NAME}) :point_left: Launch a binder notebook on this branch` 212 | }) 213 | env: 214 | BRANCH_NAME: ${{ github.event.pull_request.head.ref }} 215 | ``` 216 | 217 | ### Use GitHub Actions To Cache The Build For BinderHub 218 | 219 | Instead of forcing mybinder.org to cache your builds, you can optionally build a Docker image with GitHub Actions and push that to a Docker registry, so that any [BinderHub](https://binderhub.readthedocs.io/en/latest/) instance, including mybinder.org only has to pull the image. This might give you more control than triggering a build directly on mybinder.org like the method illustrated above. In this example, you must supply the [secrets](https://help.github.com/en/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets) `DOCKER_USERNAME` and `DOCKER_PASSWORD` so that Actions can push to DockerHub. Note that, instead of your actual password, you can use an [access token](https://docs.docker.com/docker-hub/access-tokens/) — which may be a more secure option. 220 | 221 | In this case, we set `BINDER_CACHE` to `true` to enable this option. See the documentation for the parameter `BINDER_CACHE` in the [Optional Inputs](#optional-inputs) section for more information. 222 | 223 | ```yaml 224 | name: Test 225 | on: push 226 | 227 | jobs: 228 | binder: 229 | runs-on: ubuntu-latest 230 | steps: 231 | - name: Checkout Code 232 | uses: actions/checkout@v2 233 | with: 234 | ref: ${{ github.event.pull_request.head.sha }} 235 | 236 | - name: update jupyter dependencies with repo2docker 237 | uses: jupyterhub/repo2docker-action@master 238 | with: 239 | DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} 240 | DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} 241 | BINDER_CACHE: true 242 | PUBLIC_REGISTRY_CHECK: true 243 | ``` 244 | 245 | ## Push Repo2Docker Image To DockerHub 246 | 247 | We recommend creating a [personal access token](https://docs.docker.com/docker-hub/access-tokens/) 248 | and use that as `DOCKER_PASSWORD` instead of using your dockerhub password. 249 | 250 | ```yaml 251 | name: Build Notebook Container 252 | on: [push] # You may want to trigger this Action on other things than a push. 253 | jobs: 254 | build: 255 | runs-on: ubuntu-latest 256 | steps: 257 | 258 | - name: checkout files in repo 259 | uses: actions/checkout@main 260 | 261 | - name: update jupyter dependencies with repo2docker 262 | uses: jupyterhub/repo2docker-action@master 263 | with: 264 | DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} 265 | DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} 266 | ``` 267 | 268 | ## Push Repo2Docker Image To quay.io 269 | 270 | DockerHub now has some [pretty strong rate limits](https://docs.docker.com/docker-hub/download-rate-limit/), 271 | so you might want to push to a different docker repository. 272 | [quay.io](https://quay.io/) is a popular place, and isn't tied 273 | to any particular cloud vendor. 274 | 275 | 1. Login to [quay.io](https://quay.io) 276 | 2. Create a new [repository](https://quay.io/new/). This will determine 277 | the name of your image, and you will push / pull from it. Your image 278 | name will be `quay.io//`. 279 | 3. Go to your account settings (under your name in the top right), and 280 | select the 'Robot Accounts' option on the left menu. 281 | 4. Click 'Create Robot account', give it a memorable name (such as 282 | `_image_builder`) and click 'Create' 283 | 5. In the next screen, select the repository you just created in step (2), 284 | and give the robot account `Write` permission to the repository. 285 | 6. Once done, click the name of the robot account again. This will give you 286 | its username and password. 287 | 7. Create these [GitHub secrets](https://docs.github.com/en/actions/reference/encrypted-secrets) 288 | for your repository with the credentials from the robot account: 289 | 1. `QUAY_USERNAME`: user name of the robot account 290 | 2. `QUAY_PASSWORD`: password of the robot account 291 | 292 | 8. Use the following config for your github action. 293 | ```yaml 294 | name: Build container image 295 | 296 | on: [push] 297 | 298 | jobs: 299 | build: 300 | runs-on: ubuntu-latest 301 | steps: 302 | 303 | - name: checkout files in repo 304 | uses: actions/checkout@main 305 | 306 | - name: update jupyter dependencies with repo2docker 307 | uses: jupyterhub/repo2docker-action@master 308 | with: # make sure username & password/token matches your registry 309 | DOCKER_USERNAME: ${{ secrets.QUAY_USERNAME }} 310 | DOCKER_PASSWORD: ${{ secrets.QUAY_PASSWORD }} 311 | DOCKER_REGISTRY: "quay.io" 312 | IMAGE_NAME: "/" 313 | 314 | ``` 315 | 316 | ## Push Repo2Docker Image To Amazon ECR 317 | 318 | 1. Login to [Amazon AWS Console](https://console.aws.amazon.com/) 319 | 2. [Create an individual IAM user](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#create-iam-users) who's access key will be used by the GitHub Actions. Make sure the user has permissions to make calls to the Amazon ECR APIs and to push/pull images to the repositories you need. 320 | Checkout and follow [Amazon IAM best practices](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html) for the AWS credentials used in GitHub Actions workflows. 321 | 3. Create a new private [repository](https://us-east-2.console.aws.amazon.com/ecr/create-repository). This will determine the name of your image, and you will push / pull from it. Your image name will be `.dkr.ecr..amazonaws.com//`. 322 | 4. Go to the IAM dashboard, ['Users' section](https://console.aws.amazon.com/iamv2/home#/users) and click on the username created at `Step 2`. 323 | Click on 'Security credentials' tab, right below the 'Summary' section. In the 'Access keys' section, click on the 'Create access key' button. 324 | Once done, it will give you an 'Access key ID' and the 'Secret access key'. 325 | 5. Create these [GitHub secrets](https://docs.github.com/en/actions/reference/encrypted-secrets) 326 | for your repository with the credentials from the robot account: 327 | 1. `AWS_ACCESS_KEY_ID`: access key id of the IAM user 328 | 2. `AWS_SECRET_ACCESS_KEY`: secret access key of the IAM user 329 | 330 | 6. Use the following config for your github action. 331 | ```yaml 332 | name: Build container image 333 | 334 | on: [push] 335 | 336 | jobs: 337 | build: 338 | runs-on: ubuntu-latest 339 | env: 340 | DOCKER_CONFIG: $HOME/.docker 341 | steps: 342 | - name: checkout files in repo 343 | uses: actions/checkout@main 344 | 345 | - name: Configure AWS Credentials 346 | uses: aws-actions/configure-aws-credentials@v1 347 | with: 348 | aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} 349 | aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} 350 | aws-region: 351 | 352 | - name: Login to Amazon ECR 353 | id: login-ecr 354 | uses: aws-actions/amazon-ecr-login@v1 355 | 356 | 357 | - name: Update jupyter dependencies with repo2docker 358 | uses: jupyterhub/repo2docker-action@master 359 | with: 360 | DOCKER_REGISTRY: ${{ steps.login-ecr.outputs.registry }} 361 | IMAGE_NAME: "/" 362 | 363 | ``` 364 | 365 | ## Push Repo2Docker Image To Google Container Registry 366 | 367 | 1. Login to [Google Cloud Console](https://console.cloud.google.com) 368 | 2. Create (or use an existing) Google Cloud Project with the billing activated. This will be the place where the registry hosting the repo2docker image will live. 369 | 3. Make sure [`Container Registry API`](https://console.cloud.google.com/apis/library/containerregistry.googleapis.com) is enabled for this project. 370 | 4. The repository will be created automatically once the first image is pushed. Your image name will be `grc.io//`. 371 | 5. Create a Service Account to authenticate the calls made by GitHub Actions to our GCP project: 372 | - In the Cloud Console, go to the [Service Accounts page](https://console.cloud.google.com/iam-admin/serviceaccounts). 373 | - Make sure the right project is selected in the drop-down menu above. 374 | - Click on [`Create Service Account`](https://console.cloud.google.com/iam-admin/serviceaccounts/create) 375 | - Enter a service account name — give it a memorable name (such as `_image_builder`). 376 | - Grant this service account access to project. As a best practice, grant it only the minimum permissions: `Cloud Run Admin`, `Service Account User`, and `Storage Admin`. 377 | 6. Click on the service account's name you just created and select the `Keys` tab. Click on the `ADD KEY` button, select `Create new key`, then create a JSON key type. The private key will be saved to your computer. Make sure to store it somewhere secure! 378 | 7. Create these [GitHub secrets](https://docs.github.com/en/actions/reference/encrypted-secrets) 379 | for your repository with the credentials from the robot account: 380 | 1. `GCP_SA_KEY`: the private key of the service account created in the previous step 381 | 2. `GCP_PROJECT_ID`: the id of the Google Cloud Project 382 | 383 | 8. Use the following config for your github action. 384 | ```yaml 385 | name: Build container image 386 | 387 | on: [push] 388 | 389 | jobs: 390 | build: 391 | runs-on: ubuntu-latest 392 | env: 393 | DOCKER_CONFIG: $HOME/.docker 394 | 395 | steps: 396 | - name: checkout files in repo 397 | uses: actions/checkout@main 398 | 399 | - name: Login to GCR 400 | uses: docker/login-action@v1 401 | with: 402 | registry: gcr.io 403 | username: _json_key 404 | password: ${{ secrets.GCP_SA_KEY }} 405 | 406 | - name: Update jupyter dependencies with repo2docker 407 | uses: jupyterhub/repo2docker-action@master 408 | with: 409 | DOCKER_REGISTRY: gcr.io 410 | IMAGE_NAME: ${{ secrets.GCP_PROJECT_ID }}/ 411 | ``` 412 | 413 | ## Push Repo2Docker Image To Google Artifact Registry 414 | 415 | 1. Login to [Google Cloud Console](https://console.cloud.google.com) 416 | 2. Create (or use an existing) Google Cloud Project with the billing activated. This will be the place where the registry hosting the repo2docker image will live. 417 | 3. Make sure [`Artifact Registry API`](https://console.cloud.google.com/apis/library/artifactregistry.googleapis.com) is enabled for this project. 418 | 4. Create a new [artifact repository](https://console.cloud.google.com/artifacts/create-repo). This will determine the name and location of your image. Your image name will be `-docker.pkg.dev//` 419 | 5. Create a Service Account to authenticate the calls made by GitHub Actions to our GCP project: 420 | - In the Cloud Console, go to the [Service Accounts page](https://console.cloud.google.com/iam-admin/serviceaccounts). 421 | - Make sure the right project is selected in the drop-down menu above. 422 | - Click on [`Create Service Account`](https://console.cloud.google.com/iam-admin/serviceaccounts/create) 423 | - Enter a service account name — give it a memorable name (such as `_image_builder`). 424 | - Grant this service account access to project. As a best practice, grant it only the minimum permissions: `Cloud Run Admin`, `Service Account User`, `Storage Admin`, `Artifact Registry Repository Administrator`. 425 | 6. Click on the service account's name you just created and select the `Keys` tab. Click on the `ADD KEY` button, select `Create new key`, then create a JSON key type. The private key will be saved to your computer. Make sure to store it somewhere secure! 426 | 7. Create these [GitHub secrets](https://docs.github.com/en/actions/reference/encrypted-secrets) 427 | for your repository with the credentials from the robot account: 428 | 1. `GCP_SA_KEY`: the private key of the service account created in the previous step 429 | 2. `GCP_PROJECT_ID`: the id of the Google Cloud Project 430 | 431 | 8. Use the following config for your github action. 432 | ```yaml 433 | name: Build container image 434 | 435 | on: [push] 436 | 437 | jobs: 438 | build: 439 | runs-on: ubuntu-latest 440 | env: 441 | DOCKER_CONFIG: $HOME/.docker 442 | 443 | steps: 444 | - name: checkout files in repo 445 | uses: actions/checkout@main 446 | 447 | - name: Login to GAR 448 | uses: docker/login-action@v1 449 | with: 450 | registry: -docker.pkg.dev 451 | username: _json_key 452 | password: ${{ secrets.GCP_SA_KEY }} 453 | 454 | - name: Update jupyter dependencies with repo2docker 455 | uses: jupyterhub/repo2docker-action@master 456 | with: 457 | DOCKER_REGISTRY: -docker.pkg.dev 458 | IMAGE_NAME: ${{ secrets.GCP_PROJECT_ID }}/ 459 | 460 | ``` 461 | 462 | ## Push Repo2Docker Image To Azure Container Registry 463 | 464 | 1. Login to [Azure Portal](https://portal.azure.com/) 465 | 2. Create a new [container registry](https://portal.azure.com/#create/Microsoft.ContainerRegistry). This will determine the name of your image, and you will push / pull from it. Your image name will be `.azurecr.io/`. 466 | 3. Go to `Access Keys` option on the left menu. 467 | 4. Enable `Admin user` so you can use the registry name as username and admin user access key as password to docker login to your container registry. 468 | 5. Create these [GitHub secrets](https://docs.github.com/en/actions/reference/encrypted-secrets) 469 | for your repository with the credentials from the robot account: 470 | 1. `ACR_USERNAME`: the registry name 471 | 2. `ACR_PASSWORD`: the access key of the admin user 472 | 473 | 6. Use the following config for your github action. 474 | ```yaml 475 | name: Build container image 476 | 477 | on: [push] 478 | 479 | jobs: 480 | build: 481 | runs-on: ubuntu-latest 482 | 483 | steps: 484 | - name: checkout files in repo 485 | uses: actions/checkout@main 486 | 487 | - name: Update jupyter dependencies with repo2docker 488 | uses: jupyterhub/repo2docker-action@master 489 | with: 490 | DOCKER_USERNAME: ${{ secrets.ACR_USERNAME }} 491 | DOCKER_PASSWORD: ${{ secrets.ACR_PASSWORD }} 492 | DOCKER_REGISTRY: .azurecr.io 493 | IMAGE_NAME: 494 | 495 | ``` 496 | 497 | ## Push Repo2Docker Image To GitHub Package Registry 498 | 499 | You can push the image to the package registry associated with the GitHub Repository that the repo2docker files are in. No set-up is necessary. 500 | 501 | 1. Use the following config for your github action. 502 | ```yaml 503 | name: Build container image 504 | 505 | on: [push] 506 | 507 | jobs: 508 | build: 509 | runs-on: ubuntu-latest 510 | steps: 511 | 512 | - name: checkout files in repo 513 | uses: actions/checkout@main 514 | 515 | - name: update jupyter dependencies with repo2docker 516 | uses: jupyterhub/repo2docker-action@master 517 | with: 518 | DOCKER_USERNAME: ${{github.actor}} 519 | DOCKER_PASSWORD: ${{secrets.GITHUB_TOKEN}} 520 | DOCKER_REGISTRY: "ghcr.io" 521 | IMAGE_NAME: "/" 522 | ``` 523 | 524 | The image url will be `ghcr.io//` and appear in "packages" in the right side of the repository window. 525 | 526 | ## Push Repo2Docker Image To Other Registries 527 | 528 | If the docker registry accepts a credentials to be passed as a username and password string, you can do it like this. 529 | 530 | ```yaml 531 | name: Build Notebook Container 532 | on: [push] 533 | jobs: 534 | build: 535 | runs-on: ubuntu-latest 536 | steps: 537 | 538 | - name: checkout files in repo 539 | uses: actions/checkout@main 540 | 541 | - name: update jupyter dependencies with repo2docker 542 | uses: jupyterhub/repo2docker-action@master 543 | with: # make sure username & password/token matches your registry 544 | DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} 545 | DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} 546 | DOCKER_REGISTRY: "gcr.io" 547 | ``` 548 | 549 | If the docker registry doesn't credentials to be passed as a username and password strong, or if you want to do it in another way, you can configure credentials to the docker registry ahead of time instead. Below is an incomplete example doing that. 550 | 551 | ```yaml 552 | name: Build Notebook Container 553 | on: [push] 554 | jobs: 555 | build: 556 | runs-on: ubuntu-latest 557 | steps: 558 | 559 | - name: checkout files in repo 560 | uses: actions/checkout@main 561 | 562 | # TODO: add a step here to setup credentials to push to your 563 | # docker registry before running the repo2docker-action 564 | 565 | - name: update jupyter dependencies with repo2docker 566 | uses: jupyterhub/repo2docker-action@master 567 | with: 568 | DOCKER_REGISTRY: your-registry.example.org 569 | IMAGE_NAME: your-image-name 570 | ``` 571 | 572 | ## Change Image Name 573 | 574 | When you do not provide an image name your image name defaults to `DOCKER_USERNAME/GITHUB_REPOSITORY_NAME`. For example if the user [`hamelsmu`](http://www.github.com/hamelsmu) tried to run this Action from this repo, it would be named `hamelsmu/repo2docker-action`. However, sometimes you may want a different image name, you can accomplish by providing the `IMAGE_NAME` parameter as illustrated below: 575 | 576 | ```yaml 577 | name: Build Notebook Container 578 | on: [push] 579 | jobs: 580 | build: 581 | runs-on: ubuntu-latest 582 | steps: 583 | 584 | - name: checkout files in repo 585 | uses: actions/checkout@main 586 | 587 | - name: update jupyter dependencies with repo2docker 588 | uses: jupyterhub/repo2docker-action@master 589 | with: 590 | DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} 591 | DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} 592 | IMAGE_NAME: "hamelsmu/my-awesome-image" # this overrides the image name 593 | ``` 594 | 595 | ## Test Image Build 596 | 597 | You might want to only test the image build withtout pushing to a registry, for example to test a pull request. You can do this by setting the `NO_PUSH` parameter to 'true': 598 | 599 | ```yaml 600 | name: Build Notebook Container 601 | on: [pull_request] 602 | jobs: 603 | build-image-without-pushing: 604 | runs-on: ubuntu-latest 605 | steps: 606 | - name: Checkout PR 607 | uses: actions/checkout@v2 608 | with: 609 | ref: ${{ github.event.pull_request.head.sha }} 610 | 611 | - name: test build 612 | uses: jupyterhub/repo2docker-action@master 613 | with: 614 | NO_PUSH: 'true' 615 | IMAGE_NAME: "hamelsmu/repo2docker-test" 616 | ``` 617 | 618 | _When you specify a value for the `NO_PUSH` parameter, you can omit the otherwhise mandatory parameters `DOCKER_USERNAME` and `DOCKER_PASSWORD`._ 619 | 620 | # Contributing To repo2docker-action 621 | 622 | See the [Contributing Guide](./CONTRIBUTING.md). 623 | -------------------------------------------------------------------------------- /RELEASE.md: -------------------------------------------------------------------------------- 1 | # Making a release 2 | 3 | Releases are automated through 4 | [.github/workflows/release-updates.yaml](https://github.com/jupyterhub/repo2docker-action/blob/HEAD/.github/workflows/release-updates.yaml). 5 | 6 | To cut a release, visit the projects [releases 7 | page](https://github.com/jupyterhub/repo2docker-action/releases) where 8 | you create a new GitHub release. Enter a _tag name_ and _release name_ of 9 | "vX.Y.Z". Doing so will automatically update the "vX" branch allowing users to 10 | reference this action with `jupyterhub/repo2docker-action@vX`. 11 | 12 | If you are to cut a major release, make sure to also update references to the 13 | `@vX` branch to the `@vX+1` branch. 14 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: 'repo2docker Action' 2 | description: 'Creates a docker image of your repository to view the collection of notebooks' 3 | inputs: 4 | DOCKER_USERNAME: 5 | description: Docker registry username. If not supplied, credentials must be setup ahead of time. 6 | require: false 7 | DOCKER_PASSWORD: 8 | description: Docker registry password. If not supplied, credentials must be setup ahead of time. 9 | required: false 10 | DOCKER_REGISTRY: 11 | description: domain name of the docker registry. If not supplied, this defaults to registry.hub.docker.com. 12 | require: false 13 | IMAGE_NAME: 14 | description: name of the image. Example - myusername/myContainer. If not supplied, this defaults to $DOCKER_USERNAME/$GITHUB_REPOSITORY_NAME or $GITHUB_ACTOR/$GITHUB_REPOSITORY_NAME. 15 | require: false 16 | NOTEBOOK_USER: 17 | description: username of the primary user in the image 18 | require: false 19 | REPO_DIR: 20 | description: path inside the image where contents of the repositories are copied to 21 | require: false 22 | APPENDIX_FILE: 23 | description: Appendix of Dockerfile commands to run at the end of the build. Can be used to customize the resulting image after all standard build steps finish. 24 | require: false 25 | LATEST_TAG_OFF: 26 | description: Setting this variable to any value will prevent your image from being tagged with `latest`, in additiona to the GitHub commit SHA. This is enabled by default. 27 | require: false 28 | ADDITIONAL_TAG: 29 | description: An optional string that specifies the name of an additional tag you would like to apply to the image. Images are already tagged with the relevant GitHub SHA. 30 | require: false 31 | NO_PUSH: 32 | description: Setting this variable to any value will turn debug mode on. When debug mode is on, images will not be pushed to the registry. Furthermore, verbose logging will be enabled. 33 | require: false 34 | BINDER_CACHE: 35 | description: Setting this variable to any value will add the file binder/Dockerfile that references the docker image that was pushed to the registry by this Action. You cannot use this option if the parameter NO_PUSH is set. This is disabled by default. 36 | require: false 37 | COMMIT_MSG: 38 | description: The commit message associated with specifying the `BINDER_CACHE` flag. 39 | require: false 40 | default: Update image tag 41 | MYBINDERORG_TAG: 42 | description: This the Git branch, tag, or commit that you want mybinder.org to proactively build from your repo. This is useful if you wish to avoid startup time on mybinder.org. Your repository must be public for this work, as mybinder.org only works on public repositories. 43 | require: false 44 | PUBLIC_REGISTRY_CHECK: 45 | description: Setting this variable to any value will validate that the image pushed to the registry is publicly visible. 46 | require: false 47 | NO_GIT_PUSH: 48 | description: This is a private variable that is used by the maintainers of this Action for debugging. Setting this value to true will prevent any changes from being saved to your repository. 49 | require: false 50 | REPO2DOCKER_EXTRA_ARGS: 51 | description: Extra commandline arguments to be passed to repo2docker 52 | FORCE_REPO2DOCKER_VERSION: 53 | description: Force a specific version of repo2docker to be installed. Either in the form of `repo2docker==` for install from pypi, or `git+https://@ /dev/null || true 65 | echo "::endgroup::" 66 | 67 | # Print variables for debugging 68 | echo "::group::Show Variables" 69 | echo "DOCKER_REGISTRY": ${INPUT_DOCKER_REGISTRY} 70 | echo "INPUT_ADDITIONAL_TAG: ${INPUT_ADDITIONAL_TAG}" 71 | echo "INPUT_APPENDIX_FILE: ${INPUT_APPENDIX_FILE}" 72 | echo "INPUT_BINDER_CACHE: ${INPUT_BINDER_CACHE}" 73 | echo "INPUT_IMAGE_NAME: ${INPUT_IMAGE_NAME}" 74 | echo "INPUT_IMAGE_NAME: ${INPUT_IMAGE_NAME}" 75 | echo "INPUT_MYBINDERORG_TAG: ${INPUT_MYBINDERORG_TAG}" 76 | echo "INPUT_MYBINDERORG_TAG: ${INPUT_MYBINDERORG_TAG}" 77 | echo "INPUT_NOTEBOOK_USER: ${INPUT_NOTEBOOK_USER}" 78 | echo "INPUT_NO_PUSH: ${INPUT_NO_PUSH}" 79 | echo "INPUT_PUBLIC_REGISTRY_CHECK: ${INPUT_PUBLIC_REGISTRY_CHECK}" 80 | echo "INPUT_FORCE_REPO2DOCKER_VERSION: ${INPUT_FORCE_REPO2DOCKER_VERSION}" 81 | echo "INPUT_REPO_DIR: ${INPUT_REPO_DIR}" 82 | echo "NB_USER: ${NB_USER}" 83 | echo "PWD: ${PWD}" 84 | echo "SHA_NAME: ${SHA_NAME}" 85 | echo "::endgroup::" 86 | 87 | echo "IMAGE_SHA_NAME=${SHA_NAME}" >> $GITHUB_OUTPUT 88 | echo "IMAGE_SHA_TAG=${shortSHA}" >> $GITHUB_OUTPUT 89 | 90 | 91 | echo "::group::Build ${SHA_NAME}" 92 | # Install specific version of repo2docker if required 93 | if [ ! -z "${INPUT_FORCE_REPO2DOCKER_VERSION}" ]; then 94 | python3 -m pip install --upgrade --force ${INPUT_FORCE_REPO2DOCKER_VERSION} 95 | fi 96 | 97 | 98 | # If BINDER_CACHE flag is specified, validate user intent by checking for the presence of .binder and binder directories. 99 | if [ "$INPUT_BINDER_CACHE" ]; then 100 | GENERIC_MSG="This Action assumes you are not explicitly using Binder to build your dependencies." 101 | 102 | # Exit if .binder directory is present 103 | if [ -d ".binder" ]; then 104 | echo "Found directory .binder ${GENERIC_MSG} The presence of a directory named .binder indicates otherwise. Aborting this step."; 105 | exit 1; 106 | fi 107 | 108 | # Delete binder directory if it exists and only contains Dockerfile, so repo2docker can do a fresh build. 109 | if [ -d "binder" ]; then 110 | # if /binder has files other than Dockerfile, exit with status code 1, else remove the binder folder. 111 | num_files=`ls binder | grep -v 'Dockerfile' | wc -l` 112 | if [[ "$num" -gt 0 ]]; 113 | then 114 | echo "Files other than Dockerfile are present in your binder/ directory. ${GENERIC_MSG} This directory is used by this Action to point to an existing Docker image that Binder can pull."; 115 | exit 1; 116 | else 117 | rm -rf binder 118 | fi 119 | fi 120 | fi 121 | 122 | # Just build the image, do not push it 123 | # Don't quote ${INPUT_REPO2DOCKER_EXTRA_ARGS}, as it *should* be interpreted as arbitrary 124 | # arguments to be passed to repo2docker. 125 | # Explicitly specify repo and ref labels, as repo2docker only knows it is building something 126 | # local. 127 | jupyter-repo2docker --no-run --user-id 1000 --user-name ${NB_USER} \ 128 | --target-repo-dir ${REPO_DIR} --image-name ${SHA_NAME} --cache-from ${INPUT_IMAGE_NAME} \ 129 | --label "repo2docker.repo=https://github.com/${GITHUB_REPOSITORY}" \ 130 | --label "repo2docker.ref=${GITHUB_REF}" \ 131 | --appendix "$APPENDIX" ${INPUT_REPO2DOCKER_EXTRA_ARGS} ${PWD} 132 | 133 | if [ -z "$INPUT_LATEST_TAG_OFF" ]; then 134 | docker tag ${SHA_NAME} ${INPUT_IMAGE_NAME}:latest 135 | fi 136 | if [ "$INPUT_ADDITIONAL_TAG" ]; then 137 | docker tag ${SHA_NAME} ${INPUT_IMAGE_NAME}:$INPUT_ADDITIONAL_TAG 138 | fi 139 | echo "::endgroup::" 140 | 141 | # If a directory named image-tests exists, run tests on the built image 142 | if [ -d "${PWD}/image-tests" ]; then 143 | echo "::group::Run tests found in image-tests/" 144 | # We pass in bash that is run inside the built container, so watch out for quoting. 145 | docker run -u 1000 -w ${REPO_DIR} \ 146 | ${SHA_NAME} /bin/bash -c ' 147 | export PYTEST_FLAGS=""; 148 | 149 | # If there is a requirements.txt file inside image-tests, install it. 150 | # Useful if you want to install a bunch of pytest packages. 151 | [ -f image-tests/requirements.txt ] && \ 152 | echo "Installing from image-tests/requirements.txt..." && \ 153 | python3 -m pip install --no-cache -r image-tests/requirements.txt; 154 | 155 | # If pytest is not already installed in the image, install it. 156 | which py.test > /dev/null || \ 157 | echo "Installing pytest inside the image..." && \ 158 | python3 -m pip install --no-cache pytest > /dev/null; 159 | 160 | # If there are any .ipynb files in image-tests, install pytest-notebook 161 | # if necessary, and set PYTEST_FLAGS so notebook tests are run. 162 | ls image-tests/*.ipynb > /dev/null && \ 163 | echo "Found notebooks, using pytest-notebook to run them..." && \ 164 | export PYTEST_FLAGS="--nb-test-files ${PYTEST_FLAGS}" && \ 165 | python3 -c "import pytest_notebook" 2> /dev/null || \ 166 | python3 -m pip install --no-cache pytest-notebook > /dev/null; 167 | 168 | py.test ${PYTEST_FLAGS} image-tests/ 169 | ' 170 | echo "::endgroup::" 171 | fi 172 | 173 | if [ "$INPUT_NO_PUSH" = "false" ]; then 174 | echo "::group::Pushing ${SHA_NAME}" 175 | 176 | docker push ${SHA_NAME} 177 | 178 | if [ -z "$INPUT_LATEST_TAG_OFF" ]; then 179 | docker push ${INPUT_IMAGE_NAME}:latest 180 | fi 181 | if [ "$INPUT_ADDITIONAL_TAG" ]; then 182 | docker push ${INPUT_IMAGE_NAME}:$INPUT_ADDITIONAL_TAG 183 | fi 184 | 185 | echo "::endgroup::" 186 | 187 | echo "PUSH_STATUS=true" >> $GITHUB_OUTPUT 188 | 189 | if [ "$INPUT_PUBLIC_REGISTRY_CHECK" ]; then 190 | echo "::group::Verify That Image Is Public" 191 | docker logout 192 | if docker pull $SHA_NAME; then 193 | echo "Verified that $SHA_NAME is publicly visible." 194 | else 195 | echo "Could not pull docker image: $SHA_NAME. Make sure this image is public before proceeding." 196 | exit 1 197 | fi 198 | echo "::endgroup::" 199 | fi 200 | 201 | else 202 | if [ "$INPUT_NO_PUSH" != "true" ]; then 203 | echo "Error: invalid value for NO_PUSH: $INPUT_NO_PUSH. Valid values are true or false." 204 | exit 1 205 | fi 206 | 207 | echo "PUSH_STATUS=false" >> $GITHUB_OUTPUT 208 | fi 209 | 210 | if [ "$INPUT_BINDER_CACHE" ]; then 211 | echo "::group::Commit Local Dockerfile For Binder Cache" 212 | python /binder_cache.py "$SHA_NAME" 213 | git config --global --add safe.directory /github/workspace 214 | git config --global user.email "github-actions[bot]@users.noreply.github.com" 215 | git config --global user.name "github-actions[bot]" 216 | git add binder/Dockerfile 217 | if [ "$INPUT_COMMIT_MSG" ]; then 218 | git commit -m"${INPUT_COMMIT_MSG}" 219 | else 220 | git commit -m'Update image tag' 221 | fi 222 | if [ ! "$INPUT_NO_GIT_PUSH" ]; then 223 | git push -f 224 | fi 225 | echo "::endgroup::" 226 | fi 227 | 228 | 229 | if [ "$INPUT_MYBINDERORG_TAG" ]; then 230 | echo "::group::Triggering Image Build on mybinder.org" 231 | /trigger_binder.sh "https://gke.mybinder.org/build/gh/$GITHUB_REPOSITORY/$INPUT_MYBINDERORG_TAG" 232 | echo "::endgroup::" 233 | fi 234 | -------------------------------------------------------------------------------- /notebooks/Hello World.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# This is a test notebook" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "![](https://octodex.github.com/images/daftpunktocat-thomas.gif)" 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": 5, 20 | "metadata": {}, 21 | "outputs": [ 22 | { 23 | "name": "stdout", 24 | "output_type": "stream", 25 | "text": [ 26 | "Hello World\n" 27 | ] 28 | } 29 | ], 30 | "source": [ 31 | "print('Hello World')" 32 | ] 33 | }, 34 | { 35 | "cell_type": "markdown", 36 | "metadata": {}, 37 | "source": [] 38 | } 39 | ], 40 | "metadata": { 41 | "kernelspec": { 42 | "display_name": "Python 3", 43 | "language": "python", 44 | "name": "python3" 45 | }, 46 | "language_info": { 47 | "codemirror_mode": { 48 | "name": "ipython", 49 | "version": 3 50 | }, 51 | "file_extension": ".py", 52 | "mimetype": "text/x-python", 53 | "name": "python", 54 | "nbconvert_exporter": "python", 55 | "pygments_lexer": "ipython3", 56 | "version": "3.6.7" 57 | } 58 | }, 59 | "nbformat": 4, 60 | "nbformat_minor": 2 61 | } 62 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | flask -------------------------------------------------------------------------------- /trigger_binder.sh: -------------------------------------------------------------------------------- 1 | 2 | #!/usr/bin/env bash 3 | # from https://github.com/scikit-hep/pyhf/blob/master/binder/trigger_binder.sh 4 | 5 | function trigger_binder() { 6 | local URL="${1}" 7 | 8 | curl -L --connect-timeout 20 --max-time 900 "${URL}" 9 | curl_return=$? 10 | 11 | # Return code 28 is when the --max-time is reached 12 | if [ "${curl_return}" -eq 0 ] || [ "${curl_return}" -eq 28 ]; then 13 | if [[ "${curl_return}" -eq 28 ]]; then 14 | printf "\nBinder build started.\nCheck back soon.\n" 15 | fi 16 | else 17 | return "${curl_return}" 18 | fi 19 | 20 | return 0 21 | } 22 | 23 | function main() { 24 | # 1: the Binder build API URL to curl 25 | trigger_binder $1 26 | } 27 | 28 | main "$@" || exit 1 29 | --------------------------------------------------------------------------------