Skip to content

Instantly share code, notes, and snippets.

@lcatlett
Last active May 31, 2024 21:19
Show Gist options
  • Save lcatlett/b583d520408cfd70bd7734ef65f3ad94 to your computer and use it in GitHub Desktop.
Save lcatlett/b583d520408cfd70bd7734ef65f3ad94 to your computer and use it in GitHub Desktop.
Codeserver known host modificcation
name: 'Reusable: Deploy code to configurable Pantheon environment'
on:
workflow_call:
inputs:
environment:
required: true
type: string
site_id:
type: string
clone:
type: boolean
backup:
type: boolean
secrets:
PANTHEON_DEVOPS_TOKEN:
required: true
DEVOPS_DRUPAL_USER:
required: true
DEVOPS_DRUPAL_PASSWORD:
required: true
CI_SSH_PRIVATE_KEY:
required: true
# Cancel previous runs of this same WF.
concurrency:
group: ci-deployment-${{ inputs.environment }}
cancel-in-progress: true
env:
# Need to set the secrets to env variables so we can interpolate the git string.
DEVOPS_DRUPAL_USER: ${{ secrets.DEVOPS_DRUPAL_USER }}
DEVOPS_DRUPAL_PASSWORD: ${{ secrets.DEVOPS_DRUPAL_PASSWORD }}
CI_SSH_PRIVATE_KEY: ${{ secrets.CI_SSH_PRIVATE_KEY }}
jobs:
environment_approval:
name: 'Acquire environment approval, if necessary'
# @todo How to handle if an environment passed is not defined?
environment: ${{ inputs.environment }}
runs-on: ubuntu-latest
steps: [run: echo 'Approved']
publish_code:
name: 'Publish artifact to environment branch'
needs: [environment_approval]
runs-on: ubuntu-latest
outputs:
git: ${{ steps.blt_config.outputs.git }}
steps:
- uses: actions/checkout@v3
with:
# @todo Is this always right?
ref: ${{ github.event.pull_request.head.sha }}
- name: Use Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
- name: 'Setup'
run: |
composer install -vvv
- name: 'Publish artifact to environment branch'
if: ${{ !contains(fromJson('["dev", "test", "live", "sync"]'), inputs.environment) }}
run: |
./vendor/bin/blt artifact:deploy --ignore-dirty --commit-msg "Automated commit (latest $GITHUB_REF_NAME) by Github for build $GITHUB_RUN_ID." --branch ${{ inputs.environment }} --no-interaction --verbose
- name: 'Get upstream git string'
id: blt_config
run : |
BLT_GIT_REMOTE=$(./vendor/bin/blt config:get git.remotes.0)
echo "git=$BLT_GIT_REMOTE" >> $GITHUB_OUTPUT
define_site_matrix:
uses: ./.github/workflows/call-matrix.yml
needs: [environment_approval]
secrets: inherit
with:
site_id: ${{ inputs.site_id }}
deploy_to_pantheon:
name: 'Deploy'
runs-on: ubuntu-latest
needs:
- publish_code
- define_site_matrix
strategy:
matrix: ${{ fromJson(needs.define_site_matrix.outputs.sites) }}
# Ensure all jobs get a chance to run.
fail-fast: false
env:
SITE_ID: ${{ matrix.site }}
CI_SSH_PRIVATE_KEY: ${{ secrets.CI_SSH_PRIVATE_KEY }}
steps:
- name: Install Terminus
uses: pantheon-systems/terminus-github-actions@v1
with:
pantheon-machine-token: ${{ secrets.PANTHEON_DEVOPS_TOKEN }}
- name: 'Terminus authentication caching'
id: terminus-credentials-cache
uses: actions/cache/restore@v3
with:
path: ~/.terminus
key: terminus-credentials-cache-${{ github.sha }}
- name: 'Terminus login'
if: steps.terminus-credentials-cache.outputs.cache-hit != 'true'
run: terminus auth:login --machine-token=${{ secrets.PANTHEON_DEVOPS_TOKEN }}
- name: Setup SSH
uses: webfactory/ssh-agent@v0.7.0
with:
ssh-private-key: ${{ secrets.CI_SSH_PRIVATE_KEY }}
- name: 'Push code to Pantheon'
env:
ENV_ID: ${{ inputs.environment }}
TASK_CLONE: ${{ inputs.clone }}
TASK_BACKUP: ${{ inputs.backup }}
UPSTREAM_GIT_URL: ${{ needs.publish_code.outputs.git }}
shell: bash
run: |
# Show commands run in output.
set -x
# Early exit?
if [[ -n $SITE_ID ]] && [[ -z $(terminus env:list $SITE_ID --field=id --filter='id='$ENV_ID) ]]; then
echo "::warning::Skipping $SITE_ID, no environment named $ENV_ID..."
exit 0;
fi
function push_code {
BRANCH=$ENV_ID
COMMIT_MSG="Automated commit (latest $GITHUB_REF_NAME) by Github for build $GITHUB_RUN_ID."
echo "Setting up SSH host keys for Pantheon site..."
# Default ENV_ID to dev
if [[ -z $ENV_ID ]]; then
ENV_ID="dev"
fi
SITE_UUID=$(terminus site:lookup "$SITE_ID")
ssh-keyscan -t rsa -p 2222 "appserver.${ENV_ID}.${SITE_UUID}.drush.in" >>~/.ssh/known_hosts
ssh-keyscan -t rsa -p 2222 "codeserver.dev.${SITE_UUID}.drush.in" >>~/.ssh/known_hosts
# Clone the artifact.
mkdir $RUNNER_TEMP/upstream
cd $RUNNER_TEMP/upstream
git clone --branch $ENV_ID --depth 2 ${{ env.UPSTREAM_GIT_URL }} .
SITE_GIT_URL=$(terminus connection:info $SITE_ID.$ENV_ID --field=git_url)
mkdir $RUNNER_TEMP/$SITE_ID
cd $RUNNER_TEMP/$SITE_ID
# Initialize git.
git init --quiet
git config --local user.name "Github Actions CI"
git config --local user.email "DL-DrupalCI@voya.com"
# @todo Below 2 directives needed?
git config --local core.excludesfile false
git config --local core.fileMode true
git remote add pantheon $SITE_GIT_URL
git checkout -b $BRANCH
# If the branch exists, merge it.
# NOTE: This is a fuzzy match. So "master" matches "master" and "test/master".
if git ls-remote pantheon $ENV_ID | wc -l > /dev/null; then
echo 'Pulling existing branch...'
GIT_SSH_COMMAND="ssh -vvv" git fetch pantheon $BRANCH --depth=1 -vv
git merge pantheon/$BRANCH -vv
fi
# Rsync files from the artifact, delete any files not present in the artifact, but dont send .git/ or .github/ folders, and protect the destination .git/ folder.
rsync -a --no-g --delete --delete-excluded --exclude='.git/' --exclude='.github/' --filter 'protect /.git/' $RUNNER_TEMP/upstream/ ./
# This is what BLT DeployCommand is doing.
git rm -r --cached --ignore-unmatch --quiet .
git add -A
git commit -m "$COMMIT_MSG" --quiet --allow-empty
echo "Pushing artifact to Pantheon $ENV_ID"
git push pantheon $BRANCH -vv
}
function pull_code {
if [[ "$ENV_ID" =~ ^(dev|sync)$ ]]; then
# Pull code updates from custom upstream master branch.
terminus upstream:updates:apply --accept-upstream --yes -- $SITE_ID.$ENV_ID
elif [[ "$ENV_ID" =~ ^(test|live)$ ]]; then
terminus env:deploy --yes -- $SITE_ID.$ENV_ID
else
echo "::warning::Function pull_code called, but for an invalid environment..."
fi
}
function code_update {
# Wait while code gets deployed to Pantheon servers.
terminus workflow:wait $SITE_ID.$ENV_ID -vvv
# Testing additional wait...
sleep 30
terminus drush $SITE_ID.$ENV_ID -- updatedb -n -vvv
terminus drush $SITE_ID.$ENV_ID -- cache:rebuild -vvv
}
# Wake the environment up, if it's needed...
terminus env:wake $SITE_ID.$ENV_ID -vvv
# @todo This currently doesn't work, but we need to wait for it.
# Only wait 20 seconds max for the environment to wake up.
terminus workflow:wait --max=20 $SITE_ID.$ENV_ID -vvv
if [ "$TASK_CLONE" = true ]; then
# Check if LIVE environment exists.
if [[ -n $(terminus env:list $SITE_ID --field=id --filter='id=live') ]]; then
terminus env:clone-content --yes -- $SITE_ID.live $ENV_ID
else
echo "::warning::Site $SITE_ID not cloned, no LIVE environment..."
fi
fi
if [ "$TASK_BACKUP" = true ]; then
terminus backup:create -- $SITE_ID.$ENV_ID
fi
if [[ "$ENV_ID" =~ ^(dev|test|live|sync)$ ]]; then
# Pantheon pipeline. Expects custom upstream `master` is up to date.
pull_code
else
# Multidev. Must push code.
push_code
fi
code_update
- name: 'Terminus logout'
if: always()
run: terminus auth:logout
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment