From 74d4232424b7c1f446b72307803284fe1bf0a5e2 Mon Sep 17 00:00:00 2001 From: Erick Hitter <git-contrib@ethitter.com> Date: Sat, 13 Apr 2019 18:09:37 -0700 Subject: [PATCH] Initial commit --- .gitignore | 0 .gitlab-ci.yml | 7 +++ README.md | 39 ++++++++++++++++- scripts/deploy.sh | 107 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 152 insertions(+), 1 deletion(-) create mode 100644 .gitignore create mode 100644 .gitlab-ci.yml create mode 100644 scripts/deploy.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..d30de7d --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,7 @@ +lint:shell-scripts: + stage: test + image: koalaman/shellcheck-alpine:latest + before_script: + - shellcheck -V + script: + - find scripts -name "*.sh" -exec shellcheck {} \; diff --git a/README.md b/README.md index d776dfc..afb1d26 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,39 @@ -# Deploy plugin to WP.org +# WP.org Plugin Deploy +Deploy plugin updates to WordPress.org's plugin SVN. Modeled on [10up's GitHub action](https://github.com/10up/actions-wordpress/blob/598b1572d5024340f09d7efc083a65ebff3bcdef/dotorg-plugin-deploy/entrypoint.sh) of the same intent. + +## Configuration + +### `.gitlab-ci.yml` + +Add the following to the plugin's `.gitlab-ci.yml`: + +```yaml +PluginSVN: + stage: deploy + image: containers.ethitter.com:443/docker/images/php:7.3 + before_script: + - apt-get update + - apt-get install -y rsync + script: ./bin/deploy.sh + when: on_success +``` + +While unnecessary, if you'd rather save the time of testing the deploy, append the following to the CI job's configuration: + +```yaml +only: + - master +``` + +The above is a time-save only; the build script exits before the `svn commit` stage if the merge isn't into `master`. + +### CI Environment Variables + +Set the following environment variables in the GitLab project's configuration: + +* `WP_ORG_PASSWORD` +* `WP_ORG_PASSWORD` +* `PLUGIN_SLUG` - plugin's name on WordPress.org +* `PLUGIN_VERSION` - version to tag +* `WP_ORG_RELEASE_REF` - commit ref (branch or tag) to use for release diff --git a/scripts/deploy.sh b/scripts/deploy.sh new file mode 100644 index 0000000..41b276e --- /dev/null +++ b/scripts/deploy.sh @@ -0,0 +1,107 @@ +#!/usr/bin/env bash + +# Note that this does not use pipefail +# because if the grep later doesn't match any deleted files, +# which is likely the majority case, +# it does not exit with a 0, and I only care about the final exit. +set -eo + +# Ensure SVN username and password are set +# IMPORTANT: while secrets are encrypted and not viewable in the GitHub UI, +# they are by necessity provided as plaintext in the context of the Action, +# so do not echo or use debug mode unless you want your secrets exposed! +if [[ -z "$CI" ]]; then + echo "Script is only to be run by GitLab CI" 1>&2 + exit 1 +fi + +if [[ -z "$WP_ORG_USERNAME" ]]; then + echo "WordPress.org username not set" 1>&2 + exit 1 +fi + +if [[ -z "$WP_ORG_PASSWORD" ]]; then + echo "WordPress.org password not set" 1>&2 + exit 1 +fi + +if [[ -z "$PLUGIN_SLUG" ]]; then + echo "Plugin's SVN slug is not set" 1>&2 + exit 1 +fi + +if [[ -z "$PLUGIN_VERSION" ]]; then + echo "Plugin's version is not set" 1>&2 + exit 1 +fi + +echo "ℹ︎ PLUGIN_SLUG is $PLUGIN_SLUG" +echo "ℹ︎ PLUGIN_VERSION is $PLUGIN_VERSION" + +SVN_URL="https://plugins.svn.wordpress.org/${PLUGIN_SLUG}/" +SVN_DIR="$CI_BUILDS_DIR/svn-${PLUGIN_SLUG}" +TMP_DIR="$CI_BUILDS_DIR/git-archive" + +# Checkout just trunk for efficiency +# Tagging will be handled on the SVN level +echo "➤ Checking out .org repository..." +svn checkout --depth immediates "$SVN_URL" "$SVN_DIR" +cd "$SVN_DIR" +svn update --set-depth infinity trunk + +# Ensure we are in the $CI_PROJECT_DIR directory, just in case +echo "➤ Copying files..." +cd "$CI_PROJECT_DIR" + +git config --global user.email "git-contrib+ci@ethitter.com" +git config --global user.name "Erick Hitter (GitLab CI)" + +# If there's no .gitattributes file, write a default one into place +if [[ ! -e "$CI_PROJECT_DIR/.gitattributes" ]]; then + cat > "$CI_PROJECT_DIR/.gitattributes" <<-EOL + /.gitattributes export-ignore + /.gitignore export-ignore + /.github export-ignore + EOL + + # The .gitattributes file has to be committed to be used + # Just don't push it to the origin repo :) + git add .gitattributes && git commit -m "Add .gitattributes file" +fi + +# This will exclude everything in the .gitattributes file with the export-ignore flag +mkdir "$TMP_DIR" +git archive HEAD | tar x --directory="$TMP_DIR" + +cd "$SVN_DIR" + +# Copy from clean copy to /trunk +# The --delete flag will delete anything in destination that no longer exists in source +rsync -r "$TMP_DIR/" trunk/ --delete + +# Add everything and commit to SVN +# The force flag ensures we recurse into subdirectories even if they are already added +# Suppress stdout in favor of svn status later for readability +echo "➤ Preparing files..." +svn add . --force > /dev/null + +# SVN delete all deleted files +# Also suppress stdout here +svn status | grep '^\!' | sed 's/! *//' | xargs -I% svn rm % > /dev/null + +# Copy tag locally to make this a single commit +echo "➤ Copying tag..." +svn cp "trunk" "tags/$PLUGIN_VERSION" + +svn status + +# Stop here unless this is a merge into master. +if [[ -z "$CI_COMMIT_REF_NAME" || -z "$WP_ORG_RELEASE_REF" || "$CI_COMMIT_REF_NAME" != "$WP_ORG_RELEASE_REF" ]]; then + echo "ð˜…︎ EXITING before commit step as this is the '${CI_COMMIT_REF_NAME}' ref, not the '${WP_ORG_RELEASE_TAG}' ref." 1>&2 + exit 0 +fi + +echo "➤ Committing files..." +svn commit -m "Update to version ${PLUGIN_VERSION} from GitLab (${CI_PROJECT_URL}; ${CI_JOB_URL})" --no-auth-cache --non-interactive --username "$WP_ORG_USERNAME" --password "$WP_ORG_PASSWORD" + +echo "✓ Plugin deployed!" -- GitLab