diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 1e4a764..c9114e5 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -2,7 +2,12 @@ name: "Test" on: workflow_dispatch: + pull_request: push: + branches: [master] + +env: + PRIVATE_IMAGE: "smashedr/alpine-private:latest" # amd64/arm64 jobs: test: @@ -14,24 +19,44 @@ jobs: - name: "Checkout" uses: actions/checkout@v4 - - name: "Write YAML" - id: yaml-action + - name: "Write YAML Basic" uses: teunmooij/yaml@v1 with: - data: '{"version":"3.8","services":{"alpine":{"image":"alpine","command":"tail -f /dev/null"}}}' + data: '{"version":"3.8","services":{"alpine":{"image":"alpine:latest","command":"tail -f /dev/null"}}}' to-file: "docker-compose.yaml" - - name: "Test Local Action" - id: test + - name: "Test Action Basic" + id: test1 uses: ./ with: + name: "test-stack" + file: "docker-compose.yaml" host: ${{ secrets.DOCKER_HOST }} port: ${{ secrets.DOCKER_PORT }} user: ${{ secrets.DOCKER_USER }} #pass: ${{ secrets.DOCKER_PASS }} ssh_key: "${{ secrets.DOCKER_SSH_KEY }}" - file: "docker-compose.yaml" + + - name: "Write YAML Private" + uses: teunmooij/yaml@v1 + with: + data: '{"version":"3.8","services":{"alpine":{"image":"${{ env.PRIVATE_IMAGE }}","command":"tail -f /dev/null"}}}' + to-file: "docker-compose.yaml" + + - name: "Test Action Private" + id: test2 + uses: ./ + with: name: "test-stack" + file: "docker-compose.yaml" + host: ${{ secrets.DOCKER_HOST }} + port: ${{ secrets.DOCKER_PORT }} + user: ${{ secrets.DOCKER_USER }} + #pass: ${{ secrets.DOCKER_PASS }} + ssh_key: "${{ secrets.DOCKER_SSH_KEY }}" + #registry_host: "ghcr.io" + registry_user: ${{ vars.DOCKER_HUB_USER }} + registry_pass: ${{ secrets.DOCKER_HUB_PASS }} lint: name: "Lint" diff --git a/.prettierrc.json b/.prettierrc.json index 9872391..34dae84 100644 --- a/.prettierrc.json +++ b/.prettierrc.json @@ -4,15 +4,15 @@ "singleQuote": true, "overrides": [ { - "files": ["**/*.json", "**/*.yaml", "**/*.yml"], + "files": ["**/*.html", "**/*.yaml", "**/*.yml"], "options": { "singleQuote": false } }, { - "files": ["**/*.json", "**/*.yaml", "**/*.yml"], + "files": ["**/*.js", "**/*.css", "**/*.scss"], "options": { - "tabWidth": 2 + "tabWidth": 4 } } ] diff --git a/README.md b/README.md index 05664a3..c123cf4 100644 --- a/README.md +++ b/README.md @@ -10,9 +10,12 @@ # Docker Stack Deploy Action This action deploys a docker stack from a compose file to a remote docker host using SSH Password or Key File Authentication. +You can also optionally authenticate against a private registry using a username and password. For more details see [action.yaml](action.yaml) and [src/main.sh](src/main.sh). +_Portainer Users_: You can deploy directly to Portainer with: [cssnr/portainer-stack-deploy-action](https://github.com/cssnr/portainer-stack-deploy-action) + - [Inputs](#Inputs) - [Examples](#Examples) - [Support](#Support) @@ -20,29 +23,56 @@ For more details see [action.yaml](action.yaml) and [src/main.sh](src/main.sh). ## Inputs -| input | required | default | description | -| -------- | -------- | --------------------- | ------------------------- | -| host | **Yes** | - | Remote Docker hostname | -| port | No | `22` | Remote Docker port | -| user | **Yes** | - | Remote Docker username | -| pass | No | - | Remote Docker password \* | -| ssh_key | No | - | Remote SSH Key file \* | -| file | No | `docker-compose.yaml` | Docker Compose file | -| name | **Yes** | - | Docker Stack name | -| env_file | No | - | Docker Environment file | +| input | required | default | description | +| ------------- | ---------------- | --------------------- | --------------------------------- | +| host | **Yes** | - | Remote Docker hostname | +| port | No | `22` | Remote Docker port | +| user | **Yes** | - | Remote Docker username | +| pass | Not w/ `ssh_key` | - | Remote Docker password \* | +| ssh_key | Not w/ `pass` | - | Remote SSH Key file \* | +| file | No | `docker-compose.yaml` | Docker Compose file | +| name | **Yes** | - | Docker Stack name | +| env_file | No | - | Docker Environment file | +| registry_auth | No | - | Enable Registry Authentication \* | +| registry_host | No | - | Registry Authentication Host \* | +| registry_user | No | - | Registry Authentication User \* | +| registry_pass | No | - | Registry Authentication Pass \* | **pass/ssh_key** - You must provide either a `pass` or `ssh_key` +**registry_auth** - Set to `true` to deploy with `--with-registry-auth` + +**registry_host** - To run `docker login` on another registry, example: `ghcr.io` + +**registry_user/registry_pass** - Required to run `docker login` before stack deploy + ```yaml - name: 'Docker Stack Deploy' uses: cssnr/stack-deploy-action@v1 with: + name: 'stack-name' + file: 'docker-compose-swarm.yaml' host: ${{ secrets.DOCKER_HOST }} port: ${{ secrets.DOCKER_PORT }} user: ${{ secrets.DOCKER_USER }} pass: ${{ secrets.DOCKER_PASS }} - file: 'docker-compose-swarm.yaml' +``` + +Use `docker login` and enable `--with-registry-auth` + +```yaml +- name: 'Docker Stack Deploy' + uses: cssnr/stack-deploy-action@v1 + with: name: 'stack-name' + file: 'docker-compose-swarm.yaml' + host: ${{ secrets.DOCKER_HOST }} + port: ${{ secrets.DOCKER_PORT }} + user: ${{ secrets.DOCKER_USER }} + pass: ${{ secrets.DOCKER_PASS }} + registry_host: 'ghcr.io' + registry_user: ${{ vars.GHCR_USER }} + registry_pass: ${{ secrets.GHCR_PASS }} ``` ## Examples @@ -68,12 +98,12 @@ jobs: - name: 'Docker Stack Deploy' uses: cssnr/stack-deploy-action@v1 with: + name: 'stack-name' + file: 'docker-compose-swarm.yaml' host: ${{ secrets.DOCKER_HOST }} port: ${{ secrets.DOCKER_PORT }} user: ${{ secrets.DOCKER_USER }} pass: ${{ secrets.DOCKER_PASS }} - file: 'docker-compose-swarm.yaml' - name: 'stack-name' ``` Full Example @@ -115,14 +145,14 @@ jobs: platforms: linux/amd64,linux/arm64 - name: 'Docker Login' - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: $${{ env.REGISTRY }} username: ${{ secrets.GHCR_USER }} password: ${{ secrets.GHCR_PASS }} - name: 'Build and Push' - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v6 with: context: . platforms: linux/amd64,linux/arm64 @@ -132,12 +162,12 @@ jobs: - name: 'Docker Stack Deploy' uses: cssnr/stack-deploy-action@v1 with: + name: 'stack-name' + file: 'docker-compose-swarm.yaml' host: ${{ secrets.DOCKER_HOST }} port: ${{ secrets.DOCKER_PORT }} user: ${{ secrets.DOCKER_USER }} ssh_key: '${{ secrets.DOCKER_SSH_KEY }}' - file: 'docker-compose-swarm.yaml' - name: 'stack-name' ``` # Support @@ -165,6 +195,7 @@ Additionally, you can support other GitHub Actions I have published: - [Update JSON Value Action](https://github.com/cssnr/update-json-value-action) - [Parse Issue Form Action](https://github.com/cssnr/parse-issue-form-action) - [Mirror Repository Action](https://github.com/cssnr/mirror-repository-action) +- [Stack Deploy Action](https://github.com/cssnr/stack-deploy-action) - [Portainer Stack Deploy](https://github.com/cssnr/portainer-stack-deploy-action) - [Mozilla Addon Update Action](https://github.com/cssnr/mozilla-addon-update-action) diff --git a/action.yaml b/action.yaml index 2fe36ad..787724a 100644 --- a/action.yaml +++ b/action.yaml @@ -1,5 +1,5 @@ name: "Docker Stack Deploy" -description: "Deploy a Docker Stack" +description: "Deploy a Docker Stack to a Remote Host over SSH w/ Optional Registry Authentication" author: "Shane" branding: icon: "layers" @@ -32,6 +32,18 @@ inputs: env_file: description: "Environment File" required: false + registry_auth: + description: "Enable Registry Auth" + required: false + registry_host: + description: "Registry Auth Hostname" + required: false + registry_user: + description: "Registry Auth Username" + required: false + registry_pass: + description: "Registry Auth Password" + required: false runs: using: "docker" diff --git a/src/main.sh b/src/main.sh index 32aa0df..63e2705 100644 --- a/src/main.sh +++ b/src/main.sh @@ -46,12 +46,14 @@ trap cleanup_trap EXIT HUP INT QUIT PIPE TERM echo -e "\u001b[36mVerifying Docker and Setting Context." ssh -p "${INPUT_PORT}" "${INPUT_USER}@${INPUT_HOST}" "docker info" > /dev/null -docker context create remote --docker "host=ssh://${INPUT_USER}@${INPUT_HOST}:${INPUT_PORT}" -docker context ls +if ! docker context inspect remote >/dev/null 2>&1;then + docker context create remote --docker "host=ssh://${INPUT_USER}@${INPUT_HOST}:${INPUT_PORT}" +fi docker context use remote +docker context ls if [ -n "${INPUT_ENV_FILE}" ];then - echo -e "\u001b[36mSourcing Environment File: ${INPUT_ENV_FILE}" + echo -e "\u001b[36mSourcing Environment File: \u001b[37;1m${INPUT_ENV_FILE}" stat "${INPUT_ENV_FILE}" set -a # shellcheck disable=SC1090 @@ -60,5 +62,18 @@ if [ -n "${INPUT_ENV_FILE}" ];then # export ENV_FILE="${INPUT_ENV_FILE}" fi +if [[ -n "${INPUT_REGISTRY_USER}" && -n "${INPUT_REGISTRY_PASS}" ]];then + echo -e "\u001b[36mLogging in to Registry: \u001b[37;1m${INPUT_REGISTRY_HOST:-Docker Hub}" + echo "${INPUT_REGISTRY_PASS}" | + docker login --username "${INPUT_REGISTRY_USER}" --password-stdin "${INPUT_REGISTRY_HOST}" + INPUT_REGISTRY_AUTH="true" +fi + +EXTRA_ARGS=() +if [[ -n "${INPUT_REGISTRY_AUTH}" ]];then + echo -e "Adding extra arg: --with-registry-auth" + EXTRA_ARGS+=("--with-registry-auth") +fi + echo -e "\u001b[36mDeploying Stack: \u001b[37;1m${INPUT_NAME}" -docker stack deploy -c "${INPUT_FILE}" "${INPUT_NAME}" +docker stack deploy -c "${INPUT_FILE}" "${INPUT_NAME}" "${EXTRA_ARGS[@]}"