Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#1272] Actions: move deployment to Surge to a secure workflow #1411

Merged
merged 22 commits into from
Jan 22, 2021
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 39 additions & 42 deletions .github/workflows/integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,10 @@ on:
push:
branches-ignore:
- gh-pages
pull_request_target:
pull_request:
branches-ignore:
- gh-pages

env:
ACTION_PULL_REQUEST_NUMBER: ${{ github.event.number }}

jobs:
ubuntu-1604:
name: Ubuntu 16.04 JDK 8
Expand All @@ -21,19 +18,20 @@ jobs:
NODE_VERSION: "lts/*"

steps:
- name: Checkout repository (pull request)
- name: Checkout repository
uses: actions/checkout@v2
if: ${{ github.event_name == 'pull_request_target' }}
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.ref }}
repository: ${{ github.event.pull_request.head.repo.full_name }}

- name: Checkout repository (push)
uses: actions/checkout@v2
if: ${{ github.event_name == 'push' }}
with:
fetch-depth: 0
- name: Update PR checklist for surge.sh as queued (pull request)
dcshzj marked this conversation as resolved.
Show resolved Hide resolved
if: ${{ github.event_name == 'pull_request' }}
env:
fzdy1914 marked this conversation as resolved.
Show resolved Hide resolved
ACTIONS_PULL_REQUEST_HEAD: ${{ github.event.pull_request.head.sha }}
ACTIONS_PULL_REQUEST_NUMBER: ${{ github.event.number }}
GITHUB_TOKEN: ${{ github.token }}
run: |
mkdir -p ./pr
./config/gh-actions/deploy-surge.sh queued

- name: Set up JDK 1.8
uses: actions/setup-java@v1
Expand Down Expand Up @@ -84,19 +82,36 @@ jobs:
if: ${{ success() }}
run: bash <(curl -s https://codecov.io/bash)

- name: Deploy to surge.sh
if: ${{ success() && github.event_name == 'pull_request_target' }}
env:
SURGE_LOGIN: ${{ secrets.SURGE_LOGIN }}
SURGE_TOKEN: ${{ secrets.SURGE_TOKEN }}
ACTIONS_PULL_REQUEST_HEAD: ${{ github.event.pull_request.head.sha }}
GITHUB_TOKEN: ${{ github.token }}
- name: Build preview website (pull request)
if: ${{ success() && github.event_name == 'pull_request' }}
run: |
git fetch --all && git config --global user.email "-" && git config --global user.name "-" && ./gradlew run -Dargs="--since d1"
npm install -g surge
npm install -g markbind-cli
(cd docs && markbind build)
./config/gh-actions/deploy-surge.sh

- name: Save PR number and HEAD commit (pull request)
if: ${{ success() && github.event_name == 'pull_request' }}
run: |
echo ${{ github.event.number }} > ./pr/NUMBER
echo ${{ github.event.pull_request.head.sha }} > ./pr/SHA

- name: Upload artifacts (pull request)
if: ${{ success() && github.event_name == 'pull_request' }}
uses: actions/upload-artifact@v2
with:
name: reposense-report-docs
path: |
./reposense-report
./docs/_site
./pr

- name: Update PR checklist for surge.sh as failure (pull request)
if: ${{ failure() && github.event_name == 'pull_request' }}
env:
ACTIONS_PULL_REQUEST_HEAD: ${{ github.event.pull_request.head.sha }}
ACTIONS_PULL_REQUEST_NUMBER: ${{ github.event.number }}
GITHUB_TOKEN: ${{ github.token }}
run: ./config/gh-actions/deploy-surge.sh failure

macos-1015:
name: macOS 10.15 JDK 8
Expand All @@ -105,17 +120,8 @@ jobs:
HOMEBREW_NO_AUTO_UPDATE: 1 # Prevent time-consuming brew update

steps:
- name: Checkout repository (pull request)
uses: actions/checkout@v2
if: ${{ github.event_name == 'pull_request_target' }}
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.ref }}
repository: ${{ github.event.pull_request.head.repo.full_name }}

- name: Checkout repository (push)
- name: Checkout repository
uses: actions/checkout@v2
if: ${{ github.event_name == 'push' }}
with:
fetch-depth: 0

Expand Down Expand Up @@ -169,17 +175,8 @@ jobs:
runs-on: ubuntu-18.04

steps:
- name: Checkout repository (pull request)
uses: actions/checkout@v2
if: ${{ github.event_name == 'pull_request_target' }}
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.ref }}
repository: ${{ github.event.pull_request.head.repo.full_name }}

- name: Checkout repository (push)
- name: Checkout repository
uses: actions/checkout@v2
if: ${{ github.event_name == 'push' }}
with:
fetch-depth: 0

Expand Down
61 changes: 61 additions & 0 deletions .github/workflows/surge.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# This workflow deploys a RepoSense report and the MarkBind documentation
# website to surge.sh in a secure manner for pull requests

name: Surge.sh build preview

on:
workflow_run:
workflows: ["Continuous Integration"]
types:
- completed

jobs:
deploy:
name: Deploy to surge.sh
runs-on: ubuntu-latest
if: ${{ github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success' }}
env:
NODE_VERSION: "lts/*"

steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
fetch-depth: 0

- name: Set up Node.js
uses: actions/setup-node@v1
with:
node-version: '12.x'

- name: Download workflow artifacts
uses: dawidd6/action-download-artifact@v2
with:
workflow: integration.yml
workflow_conclusion: success
name: reposense-report-docs
dcshzj marked this conversation as resolved.
Show resolved Hide resolved
path: .

- name: Update PR checklist for surge.sh as in progress
if: ${{ success() }}
env:
GITHUB_TOKEN: ${{ github.token }}
run: ./config/gh-actions/deploy-surge.sh in_progress

- name: Install surge
if: ${{ success() }}
run: npm install -g surge

- name: Deploy to surge.sh
if: ${{ success() }}
env:
SURGE_LOGIN: ${{ secrets.SURGE_LOGIN }}
SURGE_TOKEN: ${{ secrets.SURGE_TOKEN }}
GITHUB_TOKEN: ${{ github.token }}
run: ./config/gh-actions/deploy-surge.sh success

- name: Update PR checklist for surge.sh as failure
if: ${{ failure() }}
env:
GITHUB_TOKEN: ${{ github.token }}
run: ./config/gh-actions/deploy-surge.sh failure
155 changes: 111 additions & 44 deletions config/gh-actions/deploy-surge.sh
Original file line number Diff line number Diff line change
@@ -1,43 +1,96 @@
#!/bin/bash
# This script automatically deploys RepoSense and documentation to surge.sh
# This is intended to be run for pull_request and workflow_run workflows

# Set to false if unset, ref: http://stackoverflow.com/a/39296583/1320290
CI=${CI:-false}
ACTIONS_STATUS=${1:-false}

if [ "$CI" == "false" ]
then
echo "ERROR: This script is intended to be run on GitHub Actions only!"
exit 1
fi

if [ "$ACTIONS_STATUS" == "false" ]
then
echo "ERROR: This script requires a status supplied as the first parameter"
dcshzj marked this conversation as resolved.
Show resolved Hide resolved
echo "Available values: failure, pending, success"
exit 1
elif [ "$ACTIONS_STATUS" != "failure" ] && [ "$ACTIONS_STATUS" != "in_progress" ] && [ "$ACTIONS_STATUS" != "queued" ] && [ "$ACTIONS_STATUS" != "success" ]
then
echo "ERROR: The status supplied is not a valid status"
echo "Available values: failure, in_progress, queued, success"
exit 1
fi

if [ "$GITHUB_EVENT_NAME" != "workflow_run" ] && [ "$GITHUB_EVENT_NAME" != "pull_request" ]
then
echo "ERROR: This script is intended to be run for either the pull_request or workflow_run workflows only!"
exit 1
fi

# Function to create a deployment via a cURL command, then using Python to
# parse the JSON output to obtain the deployment ID.
# $1: Type of deployment to create (can be dashboard or docs)
# $2: Description of the deployment
# Returns the deployment ID that was created.
create_deployment() {
curl "https://api.github.com/repos/${REPO_OWNER}/${REPO_NAME}/deployments" \
-H "Content-Type: application/json" \
-H "Authorization: token ${GITHUB_TOKEN}" \
-X POST \
-d "{\"ref\": \"${ACTIONS_PULL_REQUEST_HEAD}\",\"auto_merge\": false, \"required_contexts\": [], \"environment\": \"$1\", \"description\": \"$2\"}" | \
python3 -c "import sys, json; print(json.load(sys.stdin)['id'])"
}

# Function to update GitHub deployment status via a cURL command
# $1: The deployment ID to update the status for
# $2: Status (can be failure, in_progress, queued or success)
# $3: Description of the deployment status
# $4: Type of deployment (can be dashboard or docs)
# $5: URL for accessing the deployment (optional)
update_deployment() {
if [ -z "$5" ]
then
ACTIONS_ENVIRONMENT_URL=""
else
ACTIONS_ENVIRONMENT_URL=$5
fi

curl "https://api.github.com/repos/${REPO_OWNER}/${REPO_NAME}/deployments/$1/statuses" \
-H "Content-Type: application/json" \
-H "Authorization: token ${GITHUB_TOKEN}" \
-H "Accept: application/vnd.github.flash-preview+json,application/vnd.github.ant-man-preview+json" \
-X POST \
-d "{\"state\": \"$2\",\"description\": \"$3\", \"log_url\": \"${ACTIONS_WORKFLOW_RUN_URL}\", \"environment\": \"$4\", \"environment_url\": \"$5\"}"
}

# Split on "/", ref: http://stackoverflow.com/a/5257398/689223
REPO_SLUG_ARRAY=(${GITHUB_REPOSITORY//\// })
REPO_OWNER=${REPO_SLUG_ARRAY[0]}
REPO_NAME=${REPO_SLUG_ARRAY[1]}
DASHBOARD_DEPLOY_PATH=./reposense-report
MARKBIND_DEPLOY_PATH=./docs/_site
ACTIONS_DEPLOY="false"
ACTIONS_WORKFLOW_RUN_URL="$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID"

# Set to false if unset, ref: http://stackoverflow.com/a/39296583/1320290
ACTION_IS_PULL_REQUEST=${GITHUB_HEAD_REF:-false}

# Get middle section of refs. Branches are "heads" and tags are "tags"
TEMP_REPO_REFS=${GITHUB_REF#*/}
ACTION_BRANCH_TAG_INDICATOR=${TEMP_REPO_REFS%/*}
# Get the actual branch or tag name
ACTION_BRANCH_TAG=${TEMP_REPO_REFS#*/}

DEPLOY_SUBDOMAIN_UNFORMATTED_LIST=()
if [ "$ACTION_IS_PULL_REQUEST" != "false" ]
if [ "$GITHUB_EVENT_NAME" == "workflow_run" ]
then
DEPLOY_SUBDOMAIN_UNFORMATTED_LIST+=(${ACTION_PULL_REQUEST_NUMBER}-pr)
elif [ "$ACTION_BRANCH_TAG_INDICATOR" == "tags" ]
ACTIONS_DEPLOY="true"
ACTIONS_PULL_REQUEST_HEAD=$(cat ./pr/SHA)
ACTIONS_PULL_REQUEST_NUMBER=$(cat ./pr/NUMBER)
fi

if [ -e "./pr/DASHBOARD_ID" ] && [ -e "./pr/DOCS_ID" ]
then
#sorts the tags and picks the latest
#sort -V does not work on the travis machine
#sort -V ref: http://stackoverflow.com/a/14273595/689223
#sort -t ... ref: http://stackoverflow.com/a/4495368/689223
#reverse with sed ref: http://stackoverflow.com/a/744093/689223
#git tags | ignore release candidates | sort versions | reverse | pick first line
LATEST_TAG=$(git tag | grep -v rc | sort -t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n | sed '1!G;h;$!d' | sed -n 1p)
echo $LATEST_TAG
if [ "$ACTION_BRANCH_TAG" == "$LATEST_TAG" ]
then
DEPLOY_SUBDOMAIN_UNFORMATTED_LIST+=(latest)
fi
DEPLOY_SUBDOMAIN_UNFORMATTED_LIST+=(${ACTION_BRANCH_TAG}-tag)
else
DEPLOY_SUBDOMAIN_UNFORMATTED_LIST+=(${ACTION_BRANCH_TAG}-branch)
ACTIONS_DASHBOARD_ID=$(cat ./pr/DASHBOARD_ID)
ACTIONS_DOCS_ID=$(cat ./pr/DOCS_ID)
fi

DEPLOY_SUBDOMAIN_UNFORMATTED_LIST=()
DEPLOY_SUBDOMAIN_UNFORMATTED_LIST+=(${ACTIONS_PULL_REQUEST_NUMBER}-pr)

for DEPLOY_SUBDOMAIN_UNFORMATTED in "${DEPLOY_SUBDOMAIN_UNFORMATTED_LIST[@]}"
do
# replaces "/" or "." with "-"
Expand All @@ -52,25 +105,39 @@ do
continue
fi

DASHBOARD_DEPLOY_DOMAIN=https://dashboard-${DEPLOY_SUBDOMAIN}-${REPO_NAME}-${REPO_OWNER}.surge.sh
echo "Deploy domain: ${DASHBOARD_DEPLOY_DOMAIN}"
surge --project ${DASHBOARD_DEPLOY_PATH} --domain $DASHBOARD_DEPLOY_DOMAIN;
if [ "$ACTIONS_STATUS" == "failure" ]
then
# Update GitHub status to failed
update_deployment "${ACTIONS_DASHBOARD_ID}" "failure" "Dashboard deploy failed" "dashboard"
update_deployment "${ACTIONS_DOCS_ID}" "failure" "Docs deploy failed" "docs"
elif [ "$ACTIONS_STATUS" == "in_progress" ]
then
# Set GitHub status to in_progress to indicate that deployment is in progress
update_deployment "${ACTIONS_DASHBOARD_ID}" "in_progress" "Dashboard deployment in progress..." "dashboard"
update_deployment "${ACTIONS_DOCS_ID}" "in_progress" "Docs deployment in progress..." "docs"
elif [ "$ACTIONS_STATUS" == "queued" ]
then
# Set GitHub status to queued so that reviewers know that it is part of the checklist
ACTIONS_DASHBOARD_ID=$(create_deployment "dashboard" "RepoSense dashboard preview")
ACTIONS_DOCS_ID=$(create_deployment "docs" "RepoSense documentation preview")

MARKBIND_DEPLOY_DOMAIN=https://docs-${DEPLOY_SUBDOMAIN}-${REPO_NAME}-${REPO_OWNER}.surge.sh
echo "Deploy domain: ${MARKBIND_DEPLOY_DOMAIN}"
surge --project ${MARKBIND_DEPLOY_PATH} --domain $MARKBIND_DEPLOY_DOMAIN;
update_deployment "${ACTIONS_DASHBOARD_ID}" "queued" "Dashboard queued for deployment" "dashboard"
update_deployment "${ACTIONS_DOCS_ID}" "queued" "Docs queued for deployment" "docs"

if [ "$ACTION_IS_PULL_REQUEST" != "false" ] # only create github statuses when it is a PR
echo "$ACTIONS_DASHBOARD_ID" > ./pr/DASHBOARD_ID
echo "$ACTIONS_DOCS_ID" > ./pr/DOCS_ID
elif [ "$ACTIONS_STATUS" == "success" ] && [ "$ACTIONS_DEPLOY" == "true" ]
then
DASHBOARD_DEPLOY_DOMAIN=https://dashboard-${DEPLOY_SUBDOMAIN}-${REPO_NAME}-${REPO_OWNER}.surge.sh
echo "Deploy domain: ${DASHBOARD_DEPLOY_DOMAIN}"
surge --project ${DASHBOARD_DEPLOY_PATH} --domain $DASHBOARD_DEPLOY_DOMAIN;

MARKBIND_DEPLOY_DOMAIN=https://docs-${DEPLOY_SUBDOMAIN}-${REPO_NAME}-${REPO_OWNER}.surge.sh
echo "Deploy domain: ${MARKBIND_DEPLOY_DOMAIN}"
surge --project ${MARKBIND_DEPLOY_PATH} --domain $MARKBIND_DEPLOY_DOMAIN;

# Create github statuses that redirects users to the deployed dashboard and markbind docs
curl "https://api.github.com/repos/${REPO_OWNER}/${REPO_NAME}/statuses/${ACTIONS_PULL_REQUEST_HEAD}?access_token=${GITHUB_TOKEN}" \
-H "Content-Type: application/json" \
-X POST \
-d "{\"state\": \"success\",\"context\": \"dashboard/surge/deploy/${DEPLOY_SUBDOMAIN}\", \"description\": \"Deploy domain: ${DASHBOARD_DEPLOY_DOMAIN}\", \"target_url\": \"${DASHBOARD_DEPLOY_DOMAIN}\"}"

curl "https://api.github.com/repos/${REPO_OWNER}/${REPO_NAME}/statuses/${ACTIONS_PULL_REQUEST_HEAD}?access_token=${GITHUB_TOKEN}" \
-H "Content-Type: application/json" \
-X POST \
-d "{\"state\": \"success\",\"context\": \"docs/surge/deploy/${DEPLOY_SUBDOMAIN}\", \"description\": \"Deploy domain: ${MARKBIND_DEPLOY_DOMAIN}\", \"target_url\": \"${MARKBIND_DEPLOY_DOMAIN}\"}"
update_deployment "${ACTIONS_DASHBOARD_ID}" "success" "Deploy domain: ${DASHBOARD_DEPLOY_DOMAIN}" "dashboard" "${DASHBOARD_DEPLOY_DOMAIN}"
update_deployment "${ACTIONS_DOCS_ID}" "success" "Deploy domain: ${MARKBIND_DEPLOY_DOMAIN}" "docs" "${MARKBIND_DEPLOY_DOMAIN}"
fi
done