├── .devcontainer ├── Dockerfile ├── devcontainer.json └── docker-compose.yml ├── .github └── workflows │ └── snaplet-restore.yml ├── .gitignore ├── README.md └── action.yml /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | # Update the VARIANT arg in docker-compose.yml to pick a Node version: 10, 12, 14 2 | ARG VARIANT=12 3 | FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:0-${VARIANT} 4 | 5 | # Update args in docker-compose.yaml to set the UID/GID of the "node" user. 6 | ARG USER_UID=1000 7 | ARG USER_GID=$USER_UID 8 | RUN if [ "$USER_GID" != "1000" ] || [ "$USER_UID" != "1000" ]; then groupmod --gid $USER_GID node && usermod --uid $USER_UID --gid $USER_GID node; fi 9 | 10 | RUN wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add - \ 11 | && echo "deb http://apt.postgresql.org/pub/repos/apt/ `lsb_release -cs`-pgdg main" |sudo tee /etc/apt/sources.list.d/pgdg.list 12 | 13 | # [Optional] Uncomment this section to install additional OS packages. 14 | RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ 15 | && apt-get -y install --no-install-recommends postgresql-client-13 tmux neovim brotli awscli \ 16 | && curl -sL https://app.snaplet.dev/get-cli/ | bash 17 | 18 | # Docker from docker setup 19 | 20 | RUN apt-get update \ 21 | && apt-get install -y apt-transport-https ca-certificates curl gnupg2 lsb-release \ 22 | && curl -fsSL https://download.docker.com/linux/$(lsb_release -is | tr '[:upper:]' '[:lower:]')/gpg | apt-key add - 2>/dev/null \ 23 | && echo "deb [arch=amd64] https://download.docker.com/linux/$(lsb_release -is | tr '[:upper:]' '[:lower:]') $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list \ 24 | && apt-get update \ 25 | && apt-get install -y docker-ce-cli 26 | 27 | # Install Docker Compose 28 | RUN LATEST_COMPOSE_VERSION=$(curl -sSL "https://api.github.com/repos/docker/compose/releases/latest" | grep -o -P '(?<="tag_name": ").+(?=")') \ 29 | && curl -sSL "https://github.com/docker/compose/releases/download/${LATEST_COMPOSE_VERSION}/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose \ 30 | && chmod +x /usr/local/bin/docker-compose 31 | 32 | ARG NONROOT_USER=node 33 | 34 | RUN echo "#!/bin/sh\n\ 35 | sudoIf() { if [ \"\$(id -u)\" -ne 0 ]; then sudo \"\$@\"; else \"\$@\"; fi }\n\ 36 | SOCKET_GID=\$(stat -c '%g' /var/run/docker.sock) \n\ 37 | if [ \"${SOCKET_GID}\" != '0' ]; then\n\ 38 | if [ \"\$(cat /etc/group | grep :\${SOCKET_GID}:)\" = '' ]; then sudoIf groupadd --gid \${SOCKET_GID} docker-host; fi \n\ 39 | if [ \"\$(id ${NONROOT_USER} | grep -E \"groups=.*(=|,)\${SOCKET_GID}\(\")\" = '' ]; then sudoIf usermod -aG \${SOCKET_GID} ${NONROOT_USER}; fi\n\ 40 | fi\n\ 41 | exec \"\$@\"" > /usr/local/share/docker-init.sh \ 42 | && chmod +x /usr/local/share/docker-init.sh 43 | 44 | # SSH setup - start 45 | 46 | RUN wget https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip && unzip ngrok-stable-linux-amd64.zip && mv ./ngrok /usr/bin/ngrok 47 | RUN curl -sSL https://raw.githubusercontent.com/microsoft/vscode-dev-containers/master/script-library/sshd-debian.sh | sudo bash -s -- 2222 $(whoami) true random 48 | 49 | # [Optional] Uncomment if you want to install an additional version of node using nvm 50 | # ARG EXTRA_NODE_VERSION=10 51 | # RUN su node -c "source /usr/local/share/nvm/nvm.sh && nvm install ${EXTRA_NODE_VERSION}" 52 | 53 | # [Optional] Uncomment if you want to install more global node modules 54 | # RUN su node -c "npm install -g " 55 | 56 | # Setting the ENTRYPOINT to docker-init.sh will configure non-root access 57 | # to the Docker socket. The script will also execute CMD as needed. 58 | ENTRYPOINT [ "/usr/local/share/docker-init.sh" ] 59 | CMD [ "sleep", "infinity" ] -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: 2 | // https://github.com/microsoft/vscode-dev-containers/tree/v0.187.0/containers/javascript-node-postgres 3 | // Update the VARIANT arg in docker-compose.yml to pick a Node.js version: 10, 12, 14 4 | { 5 | "name": "Node.js & PostgreSQL (Community)", 6 | "dockerComposeFile": "docker-compose.yml", 7 | "service": "app", 8 | "workspaceFolder": "/workspace", 9 | 10 | // Set *default* container specific settings.json values on container create. 11 | "settings": { 12 | "sqltools.connections": [ 13 | { 14 | "name": "Videolet", 15 | "driver": "PostgreSQL", 16 | "previewLimit": 50, 17 | "server": "localhost", 18 | "port": 5432, 19 | "username": "postgres", 20 | "password": "postgres", 21 | "database": "videolet" 22 | } 23 | ] 24 | }, 25 | 26 | // Add the IDs of extensions you want installed when the container is created. 27 | "extensions": [ 28 | "dbaeumer.vscode-eslint", 29 | "mtxr.sqltools", 30 | "mtxr.sqltools-driver-pg" 31 | ], 32 | 33 | // Use 'forwardPorts' to make a list of ports inside the container available locally. 34 | // ssh -p 2222 node@localhost when the codespace is running 35 | "forwardPorts": [5432, 2222], 36 | 37 | // Use 'postCreateCommand' to run commands after the container is created. 38 | // "postCreateCommand": "yarn install", 39 | 40 | // Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. 41 | "remoteUser": "node" 42 | } 43 | -------------------------------------------------------------------------------- /.devcontainer/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | services: 4 | app: 5 | build: 6 | context: . 7 | dockerfile: Dockerfile 8 | args: 9 | # [Choice] Node.js version: 14, 12, 10 10 | VARIANT: 14 11 | # On Linux, you may need to update USER_UID and USER_GID below if not your local UID is not 1000. 12 | USER_UID: 1000 13 | USER_GID: 1000 14 | 15 | volumes: 16 | - /var/run/docker.sock:/var/run/docker.sock 17 | - ..:/workspace:cached 18 | 19 | # Overrides default command so things don't shut down after the process ends. 20 | command: sleep infinity 21 | 22 | # Runs app on the same network as the database container, allows "forwardPorts" in devcontainer.json function. 23 | network_mode: service:db 24 | 25 | # Uncomment the next line to use a non-root user for all processes. 26 | # user: node 27 | 28 | # Use "forwardPorts" in **devcontainer.json** to forward an app port locally. 29 | # (Adding the "ports" property to this file will not forward from a Codespace.) 30 | 31 | db: 32 | # image: postgres:latest 33 | image: ghcr.io/snaplet/publish-postgres-with-data-docker-action_database 34 | restart: unless-stopped 35 | volumes: 36 | - postgres-data:/var/lib/postgresql/data 37 | environment: 38 | POSTGRES_PASSWORD: postgres 39 | POSTGRES_USER: postgres 40 | POSTGRES_DB: videolet 41 | 42 | # Add "forwardPorts": ["5432"] to **devcontainer.json** to forward PostgreSQL locally. 43 | # (Adding the "ports" property to this file will not forward from a Codespace.) 44 | 45 | volumes: 46 | postgres-data: 47 | -------------------------------------------------------------------------------- /.github/workflows/snaplet-restore.yml: -------------------------------------------------------------------------------- 1 | name: Snaplet Restore 2 | on: 3 | push: 4 | workflow_dispatch: 5 | schedule: 6 | - cron: '0 5 * * *' # 5 AM everyday 7 | 8 | jobs: 9 | # Label of the runner job 10 | snaplet-restore: 11 | name: Snaplet Restore 12 | timeout-minutes: 10 13 | runs-on: ubuntu-latest 14 | 15 | services: 16 | postgres: 17 | image: postgres:latest # Must match the database where snapshot was taken 18 | env: 19 | PGDATA: /data # Important: data location has to be changed as default is defined as a volume, so snapshot won't persist 20 | POSTGRES_PASSWORD: postgres 21 | POSTGRES_USER: postgres 22 | POSTGRES_DB: snapshot 23 | options: >- 24 | --health-cmd pg_isready 25 | --health-interval 10s 26 | --health-timeout 5s 27 | --health-retries 5 28 | --name snapshot 29 | ports: 30 | - 5432:5432 31 | 32 | steps: 33 | - name: Checkout Repository Code 34 | uses: actions/checkout@v2 35 | 36 | - name: Login to Docker Hub 37 | uses: docker/login-action@v1 38 | with: 39 | registry: ${{ secrets.GHCR_CONTAINER_REGISTRY_SERVER }} 40 | username: ${{ secrets.GHCR_CONTAINER_REGISTRY_USER }} 41 | password: ${{ secrets.GHCR_CONTAINER_REGISTRY_PASSWORD }} 42 | 43 | - name: Snaplet Restore 44 | uses: ./ 45 | with: 46 | docker-container-name: snapshot 47 | docker-image-tag: ghcr.io/snaplet/publish-postgres-with-data-docker-action_database 48 | snaplet-database-url: postgres://postgres:postgres@localhost:5432/snapshot 49 | env: 50 | SNAPLET_ACCESS_TOKEN: ${{ secrets.SNAPLET_ACCESS_TOKEN }} 51 | SNAPLET_PROJECT_ID: ${{ secrets.SNAPLET_PROJECT_ID }} 52 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .gitignore 3 | .snaplet/ 4 | data/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | This action lets your restore a Snaplet snapshot into a Docker container and push it to your registry for later use. 4 | To use it you need to create a workflow with a service container running a database. This container will be populated with data and pushed to a registry. 5 | 6 | # Inputs 7 | 8 | ## `docker-container-name` 9 | 10 | **required** Name of the docker container running the database. 11 | 12 | ## `docker-image-tag` 13 | 14 | **required** A tag to apply and push the image with. Must be fully qualified including registry URL e.g. `ghcr.io/snaplet/snaplet-snapshot:latest`. 15 | 16 | ## `snaplet-database-url` 17 | 18 | **required** A connection string to use to restore a snapshot. 19 | 20 | ## `snaplet-restore-command` 21 | 22 | A command to run to restore a snapshot. Default `snaplet snapshot restore --latest`. 23 | 24 | ## Example usage 25 | 26 | Apart from inputs this action expects standard Snaplet environment variables to authenticate the CLI. See example workflow in `.github/workflows/snaplet-restore.yml`. 27 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: Postgres Docker image with "baked-in" data 2 | author: Snaplet, Inc. 3 | description: Creates a Postgres Docker Image, with data from a Snaplet snapshot, for restoration in Codespaces, development environments. 4 | inputs: 5 | docker-container-name: 6 | description: Name of docker database container 7 | required: true 8 | type: string 9 | docker-image-tag: 10 | description: Tag for docker image 11 | required: true 12 | type: string 13 | snaplet-database-url: 14 | description: Connection string to restore a snapshot 15 | required: true 16 | type: string 17 | snaplet-restore-command: 18 | description: Command used to restore a snapshot 19 | required: false 20 | type: string 21 | default: snaplet snapshot restore --latest 22 | runs: 23 | using: "composite" 24 | steps: 25 | - name: Install Snaplet 26 | run: | 27 | curl -sS "https://app.snaplet.dev/get-cli/" | bash &> "/dev/null" 28 | echo "$HOME/.local/bin" >> "$GITHUB_PATH" 29 | shell: bash 30 | 31 | - name: Restore snapshot 32 | run: ${{ inputs.snaplet-restore-command }} 33 | shell: bash 34 | env: 35 | SNAPLET_TARGET_DATABASE_URL: ${{ inputs.snaplet-database-url }} 36 | 37 | - name: Commit and push Docker image 38 | run: | 39 | docker commit ${{ inputs.docker-container-name }} ${{ inputs.docker-image-tag }} 40 | docker push ${{ inputs.docker-image-tag }} 41 | shell: bash 42 | --------------------------------------------------------------------------------