diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml new file mode 100644 index 0000000..fce47a0 --- /dev/null +++ b/.github/workflows/lint.yaml @@ -0,0 +1,35 @@ +name: "Lint" + +on: + workflow_dispatch: + pull_request: + push: + branches: [master] + +jobs: + lint: + name: "Lint" + runs-on: ubuntu-latest + timeout-minutes: 5 + + steps: + - name: "Checkout" + uses: actions/checkout@v4 + + #- name: "Debug event.json" + # run: | + # cat "${GITHUB_EVENT_PATH}" + + - name: "ShellCheck" + if: ${{ always() }} + uses: ludeeus/action-shellcheck@master + env: + SHELLCHECK_OPTS: -x + with: + scandir: src + + - name: "Prettier" + if: ${{ always() }} + run: | + npm install prettier + npx prettier --check . diff --git a/.github/workflows/mirror.yaml b/.github/workflows/mirror.yaml index aa7372a..550f4dc 100644 --- a/.github/workflows/mirror.yaml +++ b/.github/workflows/mirror.yaml @@ -2,8 +2,6 @@ name: "Mirror" on: workflow_dispatch: - release: - types: ["published"] push: branches: ["**"] tags: ["**"] @@ -21,7 +19,7 @@ jobs: fetch-depth: 0 - name: "Mirror to Codeberg" - uses: cssnr/mirror-repository-action@master + uses: cssnr/mirror-repository-action@v1 with: host: https://codeberg.org create: true diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 0000000..9f47abb --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,17 @@ +name: "Release" + +on: + release: + types: [published] + +jobs: + release: + name: "Release" + runs-on: ubuntu-latest + timeout-minutes: 5 + permissions: + contents: write + + steps: + - name: "Update Tags" + uses: cssnr/update-version-tags-action@v1 diff --git a/.github/workflows/tags.yaml b/.github/workflows/tags.yaml index c235835..9539e5e 100644 --- a/.github/workflows/tags.yaml +++ b/.github/workflows/tags.yaml @@ -1,17 +1,23 @@ name: "Tags" on: - release: - types: [published] + workflow_dispatch: + inputs: + tag: + description: "Target Tag" + required: true jobs: tags: name: "Tags" runs-on: ubuntu-latest timeout-minutes: 5 + permissions: + contents: write steps: - name: "Update Tags" uses: cssnr/update-version-tags-action@v1 with: - token: ${{ secrets.GITHUB_TOKEN }} + tag: ${{ inputs.tag }} + token: ${{ secrets.GH_PAT }} diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index c9114e5..6109824 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -2,9 +2,14 @@ name: "Test" on: workflow_dispatch: - pull_request: + schedule: + - cron: "23 23 * * 4" push: - branches: [master] + paths: + - "src/**" + - ".github/workflows/test.yaml" + - "Dockerfile" + - "action.yaml" env: PRIVATE_IMAGE: "smashedr/alpine-private:latest" # amd64/arm64 @@ -12,20 +17,30 @@ env: jobs: test: name: "Test" + if: ${{ !contains(github.event.head_commit.message, '#notest') }} runs-on: ubuntu-latest timeout-minutes: 5 + concurrency: + group: test + cancel-in-progress: true steps: - name: "Checkout" uses: actions/checkout@v4 - - name: "Write YAML Basic" + #- name: "Debug event.json" + # run: | + # cat "${GITHUB_EVENT_PATH}" + + - name: "1: Write YAML" + if: ${{ always() }} uses: teunmooij/yaml@v1 with: data: '{"version":"3.8","services":{"alpine":{"image":"alpine:latest","command":"tail -f /dev/null"}}}' to-file: "docker-compose.yaml" - - name: "Test Action Basic" + - name: "1: Test Password" + if: ${{ always() }} id: test1 uses: ./ with: @@ -34,16 +49,18 @@ jobs: host: ${{ secrets.DOCKER_HOST }} port: ${{ secrets.DOCKER_PORT }} user: ${{ secrets.DOCKER_USER }} - #pass: ${{ secrets.DOCKER_PASS }} - ssh_key: "${{ secrets.DOCKER_SSH_KEY }}" + pass: ${{ secrets.DOCKER_PASS }} + #ssh_key: "${{ secrets.DOCKER_SSH_KEY }}" - - name: "Write YAML Private" + - name: "2: Write YAML" + if: ${{ always() && !github.event.act }} 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" + - name: "2: Test SSH and Auth" + if: ${{ always() && !github.event.act }} id: test2 uses: ./ with: @@ -54,20 +71,6 @@ jobs: 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" - runs-on: ubuntu-latest - timeout-minutes: 5 - - steps: - - name: "Checkout" - uses: actions/checkout@v4 - - - name: "ShellCheck" - uses: ludeeus/action-shellcheck@master - with: - scandir: src + summary: false diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..c199942 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,8 @@ +# IDE +.idea/ +.vscode/ + +# Tools +.ruff_cache/ +.mypy_cache/ +.pytest_cache/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..394da11 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,51 @@ +# Contributing + +> [!WARNING] +> This guide is a work in progress and may not be complete. + +This is a basic contributing guide and is a work in progress. + +## Workflow + +1. Fork the repository. +2. Create a branch in your fork! +3. Make your changes. +4. [Test](#Testing) your changes. +5. Commit and push your changes. +6. Create a PR to this repository. +7. Verify the tests pass, otherwise resolve. +8. Make sure to keep your branch up-to-date. + +## Testing + +GitHub is easier to set up, but you have to push your commits to test. +Running locally is harder to set up, but it is much easier to test; and by far recommended! + +### GitHub + +Add your secrets to GitHub Actions Secrets. + +When you push your branch to your repository, the [test.yaml](.github/workflows/test.yaml) should run... + +### Locally + +To run actions locally you need to install act: https://nektosact.com/installation/index.html + +1. Create a `.secrets` file with all your secrets in .env file format. +2. Run: `act -j test` + +To test the private image you must create a `.env` file with, or use --env `PRIVATE_IMAGE=yourimage` + +To skip the private image test run with `-e event.json`. + +To print your secrets in plan text (insecure) use `--insecure-secrets` + +To see all available jobs run `act -l` and see `act --help` + +```shell +act -j test --insecure-secrets -e event.json +act -j test --insecure-secrets --env PRIVATE_IMAGE=your/private-image:latest +act -j lint +``` + +For more information see the documentation: https://nektosact.com/usage/index.html diff --git a/Dockerfile b/Dockerfile index 94261c2..0b84446 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ -FROM docker:24-dind +FROM docker:28-dind RUN apk add --update --no-cache bash sshpass -COPY src/main.sh /main.sh +COPY src/ /src -ENTRYPOINT ["bash", "/main.sh"] +ENTRYPOINT ["bash", "/src/main.sh"] diff --git a/README.md b/README.md index c123cf4..a89012f 100644 --- a/README.md +++ b/README.md @@ -1,53 +1,82 @@ -[![Tags](https://img.shields.io/github/actions/workflow/status/cssnr/stack-deploy-action/tags.yaml?logo=github&logoColor=white&label=tags)](https://github.com/cssnr/stack-deploy-action/actions/workflows/tags.yaml) +[![Release](https://img.shields.io/github/actions/workflow/status/cssnr/stack-deploy-action/release.yaml?logo=github&logoColor=white&label=release)](https://github.com/cssnr/stack-deploy-action/actions/workflows/release.yaml) [![Test](https://img.shields.io/github/actions/workflow/status/cssnr/stack-deploy-action/test.yaml?logo=github&logoColor=white&label=test)](https://github.com/cssnr/stack-deploy-action/actions/workflows/test.yaml) +[![Lint](https://img.shields.io/github/actions/workflow/status/cssnr/stack-deploy-action/lint.yaml?logo=github&logoColor=white&label=lint)](https://github.com/cssnr/stack-deploy-action/actions/workflows/lint.yaml) [![GitHub Release Version](https://img.shields.io/github/v/release/cssnr/stack-deploy-action?logo=github)](https://github.com/cssnr/stack-deploy-action/releases/latest) [![GitHub Last Commit](https://img.shields.io/github/last-commit/cssnr/parse-issue-form-action?logo=github&logoColor=white&label=updated)](https://github.com/cssnr/parse-issue-form-action/graphs/commit-activity) [![Codeberg Last Commit](https://img.shields.io/gitea/last-commit/cssnr/parse-issue-form-action/master?gitea_url=https%3A%2F%2Fcodeberg.org%2F&logo=codeberg&logoColor=white&label=updated)](https://codeberg.org/cssnr/parse-issue-form-action) [![GitHub Top Language](https://img.shields.io/github/languages/top/cssnr/stack-deploy-action?logo=htmx&logoColor=white)](https://github.com/cssnr/stack-deploy-action) -[![GitHub Org Stars](https://img.shields.io/github/stars/cssnr?style=flat&logo=github&logoColor=white)](https://cssnr.github.io/) +[![GitHub Forks](https://img.shields.io/github/forks/cssnr/stack-deploy-action?style=flat&logo=github)](https://github.com/cssnr/stack-deploy-action/forks) +[![GitHub Repo Stars](https://img.shields.io/github/stars/cssnr/stack-deploy-action?style=flat&logo=github&logoColor=white)](https://github.com/cssnr/stack-deploy-action/stargazers) +[![GitHub Org Stars](https://img.shields.io/github/stars/cssnr?style=flat&logo=github&logoColor=white&label=org%20stars)](https://cssnr.github.io/) [![Discord](https://img.shields.io/discord/899171661457293343?logo=discord&logoColor=white&label=discord&color=7289da)](https://discord.gg/wXy6m2X8wY) # Docker Stack Deploy Action +- [Inputs](#Inputs) +- [Examples](#Examples) +- [Support](#Support) +- [Contributing](#Contributing) + 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) +**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) -- [Contributing](#Contributing) +> [!NOTE] +> Please submit a [Feature Request](https://github.com/cssnr/stack-deploy-action/discussions/categories/feature-requests) +> for new features or [Open an Issue](https://github.com/cssnr/stack-deploy-action/issues) +> if you find any bugs... ## Inputs -| 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 \* | +| input | required | default | description | +| ------------- | :----------: | --------------------- | --------------------------------- | +| host | **Yes** | - | Remote Docker hostname | +| port | - | `22` | Remote Docker port | +| user | **Yes** | - | Remote Docker username | +| pass | or `ssh_key` | - | Remote Docker password \* | +| ssh_key | or `pass` | - | Remote SSH Key file \* | +| name | **Yes** | - | Docker Stack name | +| file | - | `docker-compose.yaml` | Docker Compose file | +| env_file | - | - | Docker Environment file | +| registry_auth | - | - | Enable Registry Authentication \* | +| registry_host | - | - | Registry Authentication Host \* | +| registry_user | - | - | Registry Authentication User \* | +| registry_pass | - | - | Registry Authentication Pass \* | +| summary | - | `true` | Add Job Summary \* | + +**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` -**pass/ssh_key** - You must provide either a `pass` or `ssh_key` +**registry_user/registry_pass** - Required to run `docker login` before stack deploy. -**registry_auth** - Set to `true` to deploy with `--with-registry-auth` +**summary** - Write a Summary for the job. To disable this set to `false`. -**registry_host** - To run `docker login` on another registry, example: `ghcr.io` +
๐Ÿ‘€ View Example Job Summary -**registry_user/registry_pass** - Required to run `docker login` before stack deploy +--- + +๐ŸŽ‰ Stack `test-stack` Successfully Deployed. + +
Results + +```text +Updating service test-stack_alpine (id: ewi9ck5hcdmmvaj8ms0te4t8r) +``` + +
+ +--- + +
```yaml -- name: 'Docker Stack Deploy' +- name: 'Stack Deploy' uses: cssnr/stack-deploy-action@v1 with: name: 'stack-name' @@ -61,7 +90,7 @@ _Portainer Users_: You can deploy directly to Portainer with: [cssnr/portainer-s Use `docker login` and enable `--with-registry-auth` ```yaml -- name: 'Docker Stack Deploy' +- name: 'Stack Deploy' uses: cssnr/stack-deploy-action@v1 with: name: 'stack-name' @@ -80,7 +109,7 @@ Use `docker login` and enable `--with-registry-auth` Simple Example ```yaml -name: 'Test Docker Stack Deploy' +name: 'Stack Deploy Action' on: push: @@ -95,7 +124,7 @@ jobs: - name: 'Checkout' uses: actions/checkout@v4 - - name: 'Docker Stack Deploy' + - name: 'Stack Deploy' uses: cssnr/stack-deploy-action@v1 with: name: 'stack-name' @@ -109,7 +138,7 @@ jobs: Full Example ```yaml -name: 'Test Docker Stack Deploy' +name: 'Stack Deploy Action' on: workflow_dispatch: @@ -123,43 +152,56 @@ env: REGISTRY: 'ghcr.io' jobs: + build: + name: 'Build' + runs-on: ubuntu-latest + timeout-minutes: 5 + permissions: + packages: write + + steps: + - name: 'Checkout' + uses: actions/checkout@v4 + + - name: 'Setup Buildx' + uses: docker/setup-buildx-action@v2 + with: + platforms: linux/amd64,linux/arm64 + + - name: 'Docker Login' + uses: docker/login-action@v3 + with: + registry: $${{ env.REGISTRY }} + username: ${{ secrets.GHCR_USER }} + password: ${{ secrets.GHCR_PASS }} + + - name: 'Generate Tags' + id: tags + uses: smashedr/docker-tags-action@v1 + with: + images: '$${{ env.REGISTRY }}/${{ github.repository }}' + tags: ${{ inputs.tags }} + + - name: 'Build and Push' + uses: docker/build-push-action@v6 + with: + context: . + platforms: linux/amd64,linux/arm64 + push: true + tags: ${{ steps.tags.outputs.tags }} + labels: ${{ steps.tags.outputs.labels }} + deploy: name: 'Deploy' runs-on: ubuntu-latest timeout-minutes: 5 + needs: [build] steps: - name: 'Checkout' uses: actions/checkout@v4 - - name: 'Generate Tags' - id: tags - uses: smashedr/docker-tags-action@master - with: - images: '$${{ env.REGISTRY }}/${{ github.repository }}' - extra: ${{ inputs.tags }} - - - name: 'Setup Buildx' - uses: docker/setup-buildx-action@v2 - with: - platforms: linux/amd64,linux/arm64 - - - name: 'Docker Login' - 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@v6 - with: - context: . - platforms: linux/amd64,linux/arm64 - push: true - tags: ${{ steps.tags.outputs.tags }} - - - name: 'Docker Stack Deploy' + - name: 'Stack Deploy' uses: cssnr/stack-deploy-action@v1 with: name: 'stack-name' @@ -181,22 +223,25 @@ If you are experiencing an issue/bug or getting unexpected results you can: - Report an Issue: https://github.com/cssnr/stack-deploy-action/issues - Chat with us on Discord: https://discord.gg/wXy6m2X8wY -- Provide General - Feedback: [https://cssnr.github.io/feedback/](https://cssnr.github.io/feedback/?app=Stack%20Deploy) +- Provide General Feedback: [https://cssnr.github.io/feedback/](https://cssnr.github.io/feedback/?app=Stack%20Deploy) # Contributing Currently, the best way to contribute to this project is to star this project on GitHub. +If you would like to submit a PR, please review the [CONTRIBUTING.md](CONTRIBUTING.md). + Additionally, you can support other GitHub Actions I have published: -- [VirusTotal Action](https://github.com/cssnr/virustotal-action) -- [Update Version Tags Action](https://github.com/cssnr/update-version-tags-action) -- [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) +- [Stack Deploy Action](https://github.com/cssnr/stack-deploy-action?tab=readme-ov-file#readme) +- [Portainer Stack Deploy](https://github.com/cssnr/portainer-stack-deploy-action?tab=readme-ov-file#readme) +- [VirusTotal Action](https://github.com/cssnr/virustotal-action?tab=readme-ov-file#readme) +- [Mirror Repository Action](https://github.com/cssnr/mirror-repository-action?tab=readme-ov-file#readme) +- [Update Version Tags Action](https://github.com/cssnr/update-version-tags-action?tab=readme-ov-file#readme) +- [Update JSON Value Action](https://github.com/cssnr/update-json-value-action?tab=readme-ov-file#readme) +- [Parse Issue Form Action](https://github.com/cssnr/parse-issue-form-action?tab=readme-ov-file#readme) +- [Cloudflare Purge Cache Action](https://github.com/cssnr/cloudflare-purge-cache-action?tab=readme-ov-file#readme) +- [Mozilla Addon Update Action](https://github.com/cssnr/mozilla-addon-update-action?tab=readme-ov-file#readme) +- [Docker Tags Action](https://github.com/cssnr/docker-tags-action?tab=readme-ov-file#readme) For a full list of current projects to support visit: [https://cssnr.github.io/](https://cssnr.github.io/) diff --git a/action.yaml b/action.yaml index 787724a..1a8df2a 100644 --- a/action.yaml +++ b/action.yaml @@ -22,13 +22,13 @@ inputs: ssh_key: description: "SSH Key File" required: false - file: - description: "Docker Compose File" - default: "docker-compose.yaml" - required: false name: description: "Docker Stack Name" required: true + file: + description: "Docker Compose File" + required: false + default: "docker-compose.yaml" env_file: description: "Environment File" required: false @@ -44,6 +44,10 @@ inputs: registry_pass: description: "Registry Auth Password" required: false + summary: + description: "Add Summary to Job" + required: false + default: "true" runs: using: "docker" diff --git a/event.json b/event.json new file mode 100644 index 0000000..176cfa8 --- /dev/null +++ b/event.json @@ -0,0 +1,3 @@ +{ + "act": true +} diff --git a/src/main.sh b/src/main.sh index 63e2705..f71ed24 100644 --- a/src/main.sh +++ b/src/main.sh @@ -1,79 +1,99 @@ #!/usr/bin/env bash +# https://github.com/cssnr/stack-deploy-action set -e -echo "Running: ${0} as: $(whoami) in: $(pwd)" - function cleanup_trap() { _ST="$?" if [[ "${_ST}" != "0" ]]; then - echo -e "\u001b[31;1mScript Exited with Error: ${_ST}" + echo -e "โ›” \u001b[31;1mFailed to deploy stack ${INPUT_NAME}" + echo "::error::Failed to deploy stack ${INPUT_NAME}. See logs for details..." fi if [ -z "${INPUT_SSH_KEY}" ];then - echo -e "\u001b[35mCleaning Up authorized_keys on: ${INPUT_HOST}" - ssh -p "${INPUT_PORT}" "${INPUT_USER}@${INPUT_HOST}" \ + echo -e "๐Ÿงน Cleaning Up authorized_keys" + ssh -o BatchMode=yes -o ConnectTimeout=30 -p "${INPUT_PORT}" "${INPUT_USER}@${INPUT_HOST}" \ "sed -i '/docker-stack-deploy-action/d' ~/.ssh/authorized_keys" fi if [[ "${_ST}" == "0" ]]; then - echo -e "\u001b[32;1mFinished Success." + echo -e "โœ… \u001b[32;1mFinished Success" fi exit "${_ST}" } -mkdir -p /root/.ssh -chmod 0700 /root/.ssh -ssh-keyscan -p "${INPUT_PORT}" -H "${INPUT_HOST}" >> /root/.ssh/known_hosts +SSH_DIR="/root/.ssh" + +echo "::group::Starting Stack Deploy Action" +echo "User: $(whoami)" +echo "Script: ${0}" +echo "Current Directory: $(pwd)" +echo "Home Directory: ${HOME}" +echo "SSH Directory: ${SSH_DIR}" +mkdir -p "${SSH_DIR}" ~/.ssh +chmod 0700 "${SSH_DIR}" ~/.ssh +ssh-keyscan -p "${INPUT_PORT}" -H "${INPUT_HOST}" >> "${SSH_DIR}/known_hosts" +echo "::endgroup::" if [ -z "${INPUT_SSH_KEY}" ];then - echo -e "\u001b[36mCreating and Copying SSH Key to: ${INPUT_HOST}" - ssh-keygen -q -f /root/.ssh/id_rsa -N "" -C "docker-stack-deploy-action" + echo -e "::group::Copying SSH Key to Remote Host" + ssh-keygen -q -f "${SSH_DIR}/id_rsa" -N "" -C "docker-stack-deploy-action" eval "$(ssh-agent -s)" - ssh-add /root/.ssh/id_rsa - - sshpass -p "${INPUT_PASS}" \ - ssh-copy-id -p "${INPUT_PORT}" -i /root/.ssh/id_rsa \ - "${INPUT_USER}@${INPUT_HOST}" + ssh-add "${SSH_DIR}/id_rsa" + sshpass -eINPUT_PASS \ + ssh-copy-id -i "${SSH_DIR}/id_rsa" -o ConnectTimeout=30 \ + -p "${INPUT_PORT}" "${INPUT_USER}@${INPUT_HOST}" else - echo -e "\u001b[36mAdding SSH Key to SSH Agent" - echo "${INPUT_SSH_KEY}" > /root/.ssh/id_rsa - chmod 0600 /root/.ssh/id_rsa + echo "::group::Adding SSH Key to SSH Agent" + echo "${INPUT_SSH_KEY}" > "${SSH_DIR}/id_rsa" + chmod 0600 "${SSH_DIR}/id_rsa" eval "$(ssh-agent -s)" - ssh-add /root/.ssh/id_rsa + ssh-add "${SSH_DIR}/id_rsa" fi +echo "::endgroup::" 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 - +echo "::group::Verifying Remote Docker Context" +ssh -o BatchMode=yes -o ConnectTimeout=30 -p "${INPUT_PORT}" \ + "${INPUT_USER}@${INPUT_HOST}" "docker info" > /dev/null 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 +echo "::endgroup::" if [ -n "${INPUT_ENV_FILE}" ];then - echo -e "\u001b[36mSourcing Environment File: \u001b[37;1m${INPUT_ENV_FILE}" + echo -e "::group::Sourcing Environment File: \u001b[36;1m${INPUT_ENV_FILE}" stat "${INPUT_ENV_FILE}" set -a # shellcheck disable=SC1090 source "${INPUT_ENV_FILE}" - # echo TRAEFIK_HOST: "${TRAEFIK_HOST}" - # export ENV_FILE="${INPUT_ENV_FILE}" +echo "::endgroup::" 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 -e "::group::Logging in to Registry: \u001b[36;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" + echo "::endgroup::" fi +echo -e "::group::Deploying Stack: \u001b[36;1m${INPUT_NAME}" EXTRA_ARGS=() if [[ -n "${INPUT_REGISTRY_AUTH}" ]];then - echo -e "Adding extra arg: --with-registry-auth" + echo -e "Adding: --with-registry-auth" EXTRA_ARGS+=("--with-registry-auth") fi +# shellcheck disable=SC2034 +STACK_RESULTS=$(docker stack deploy -c "${INPUT_FILE}" "${INPUT_NAME}" "${EXTRA_ARGS[@]}") +echo "::endgroup::" + +echo "${STACK_RESULTS}" -echo -e "\u001b[36mDeploying Stack: \u001b[37;1m${INPUT_NAME}" -docker stack deploy -c "${INPUT_FILE}" "${INPUT_NAME}" "${EXTRA_ARGS[@]}" +if [[ "${INPUT_SUMMARY}" == "true" ]];then + echo "๐Ÿ“ Writing Job Summary" + # shellcheck source=/src/summary.sh + source /src/summary.sh >> "${GITHUB_STEP_SUMMARY}" ||\ + echo "::error::Failed to Write Job Summary!" +fi diff --git a/src/summary.sh b/src/summary.sh new file mode 100644 index 0000000..b9e1ba5 --- /dev/null +++ b/src/summary.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +cat << EOM +## Stack Deploy Action + +๐ŸŽ‰ Stack \`${INPUT_NAME}\` Successfully Deployed. + +
Results + +\`\`\`text +${STACK_RESULTS} +\`\`\` + +
+ +[Report an issue or request a feature](https://github.com/cssnr/stack-deploy-action?tab=readme-ov-file#readme) +EOM