| #!/bin/bash |
| |
| # Action will create a folder gh-pages and set that folder to track the gh-pages branch |
| |
| set_value_or_error() { |
| local value="$1" |
| local defaultValue="$2" |
| local variableName="$3" |
| local validValues="${4:-}" # optional argument (if empty, skip validation) |
| |
| if [[ -z "$value" && -z "$defaultValue" ]]; then |
| echo "ERROR: A value for $variableName is required." >&2 |
| exit 1 |
| fi |
| |
| if [[ -n "$value" ]]; then |
| decidedValue="$value" |
| else |
| echo "${variableName}: Using default value: ${defaultValue}" |
| decidedValue="$defaultValue" |
| fi |
| |
| if [[ -n "$validValues" ]]; then |
| local match=false |
| local v |
| for v in $validValues; do |
| if [[ "$decidedValue" == "$v" ]]; then |
| match=true |
| break |
| fi |
| done |
| |
| if ! $match; then |
| echo "ERROR: Invalid value for '$variableName': '$decidedValue'." >&2 |
| echo " Must be one of: $validValues" >&2 |
| return 1 |
| fi |
| fi |
| |
| eval "$variableName=\"\$decidedValue\"" |
| } |
| |
| set_path_value_or_error() { |
| local variableName="$3" |
| set_value_or_error "$@" |
| |
| if [[ "${decidedValue}" == /* || "${decidedValue}" == ./* ]]; then |
| echo "ERROR: ${variableName} must not start with '/' or './'. Got: '${decidedValue}'" |
| exit 1 |
| fi |
| } |
| |
| publish_artifacts() { |
| if [[ -z "${SOURCE_FOLDER}" || -z "${PUBLISH_PATH}" || -z "${BASE_PUBLISH_PATH}" ]]; then |
| echo "ERROR: SOURCE_FOLDER(${SOURCE_FOLDER}), PUBLISH_PATH(${PUBLISH_PATH}), BASE_PUBLISH_PATH(${BASE_PUBLISH_PATH}) must be set." |
| return 1 |
| fi |
| |
| if [[ "${PURGE_EXISTING}" == "true" ]]; then |
| local purgePath |
| if [[ "${PURGE_BY_BASE_PATH}" == "false" ]]; then |
| purgePath="${PUBLISH_PATH}" |
| else |
| purgePath="${BASE_PUBLISH_PATH}" |
| fi |
| |
| if [[ -d "${purgePath}" ]]; then |
| if [[ "$(ls -A "${purgePath}" 2>/dev/null)" ]]; then |
| echo "Removing existing directory at ${purgePath}" |
| git rm -rf "${purgePath}" |
| fi |
| elif [[ -e "${purgePath}" ]]; then |
| echo "Removing existing file at ${purgePath}" |
| git rm -rf "${purgePath}" |
| fi |
| fi |
| |
| echo "Publishing ${SOURCE_FOLDER} to gh-pages:${PUBLISH_PATH}" |
| mkdir -p "${PUBLISH_PATH}" |
| cp -r "../${SOURCE_FOLDER}/." "${PUBLISH_PATH}" |
| git add --verbose "${PUBLISH_PATH}"/* |
| } |
| |
| is_highest_version() { |
| local new_folder="$1" # e.g. "7.0.x" |
| |
| # Strip the trailing ".x" → "7.0", then parse into major/minor |
| local new_major new_minor |
| local folder_no_x="${new_folder%.x}" # "7.0" |
| IFS="." read -r new_major new_minor <<< "$folder_no_x" |
| |
| # Loop over all folders that look like 7.0.x |
| for folder in [0-9]*.x; do |
| [[ -d "$folder" ]] || continue # skip if not a real folder |
| |
| # Use a regex match to parse existing folders into major/minor |
| if [[ "$folder" =~ ^([0-9]+)\.([0-9]+)\.x$ ]]; then |
| local existing_major="${BASH_REMATCH[1]}" |
| local existing_minor="${BASH_REMATCH[2]}" |
| |
| # Compare numeric major/minor |
| if (( existing_major > new_major )); then |
| # Found a folder with a higher major |
| return 1 |
| elif (( existing_major == new_major && existing_minor > new_minor )); then |
| # Found a folder with same major but higher minor |
| return 1 |
| fi |
| fi |
| done |
| |
| return 0 |
| } |
| |
| set -e |
| |
| # GH_TOKEN - the token to access the github repository, can be GITHUB_TOKEN if the same repo and permissions are set correctly |
| set_value_or_error "${GH_TOKEN}" "" "GH_TOKEN" |
| |
| # GITHUB_USER_NAME - the username to commit to gh-pages branch, defaults to GITHUB_ACTOR (assumes permissions are set correctly) |
| set_value_or_error "${GITHUB_USER_NAME}" "${GITHUB_ACTOR}" "GITHUB_USER_NAME" |
| |
| # LAST_RELEASE_FOLDER - when a release is performed, instead of just copying it to a version number, copy it to this static folder name |
| set_value_or_error "${LAST_RELEASE_FOLDER}" "latest" "LAST_RELEASE_FOLDER" |
| |
| # SKIP_RELEASE_FOLDER - if copying to the release folder should be skipped |
| set_value_or_error "${SKIP_RELEASE_FOLDER}" "false" "SKIP_RELEASE_FOLDER" "true false" |
| |
| # LAST_SNAPSHOT_FOLDER - when a snapshot is performed, instead of just copying it a version number, copy it to this static folder name |
| set_path_value_or_error "${LAST_SNAPSHOT_FOLDER}" "snapshot" "LAST_SNAPSHOT_FOLDER" |
| |
| # SKIP_SNAPSHOT_FOLDER - if copying to the snapshot folder should be skipped |
| set_path_value_or_error "${SKIP_SNAPSHOT_FOLDER}" "false" "SKIP_SNAPSHOT_FOLDER" "true false" |
| |
| # GRADLE_PUBLISH_RELEASE - Whether the documents being published is a release or not, expects 'true', 'false' values |
| set_value_or_error "${GRADLE_PUBLISH_RELEASE}" "" "GRADLE_PUBLISH_RELEASE" "true false" |
| |
| # TARGET_REPOSITORY - the document repository to commit to, including owner |
| set_value_or_error "${TARGET_REPOSITORY}" "${GITHUB_REPOSITORY}" "TARGET_REPOSITORY" |
| if [[ ! "$TARGET_REPOSITORY" =~ ^[^/]+/[^/]+$ ]]; then |
| echo "ERROR: TARGET_REPOSITORY must be in the format 'owner/repo'" >&2 |
| exit 1 |
| fi |
| |
| # SOURCE_FOLDER - the relative path of the source documentation folder from the root of the repo |
| set_path_value_or_error "${SOURCE_FOLDER}" "" "SOURCE_FOLDER" |
| |
| # VERSION - the version number of this snapshot or release, v7.0.2 will be `7.0.2`, 7.0.x will be 7.0.x |
| set_value_or_error "${VERSION}" "${GITHUB_REF_NAME}" "VERSION" |
| if [[ ! "$VERSION" =~ ^v?[^.]+\.[^.]+\.[^.]+$ ]]; then |
| echo "ERROR: VERSION must be in the format 'X.X.X' or 'vX.X.X'. Got: '$VERSION'" |
| exit 1 |
| fi |
| if [[ "$VERSION" == v* ]]; then |
| VERSION="${VERSION#v}" |
| else |
| VERSION="$VERSION" |
| fi |
| |
| # TARGET_SUBFOLDER - an optional sub folder to publish to |
| set_path_value_or_error "${TARGET_SUBFOLDER}" "." "TARGET_SUBFOLDER" |
| if [ "${TARGET_SUBFOLDER}" == "." ]; then |
| unset TARGET_SUBFOLDER; |
| fi |
| |
| # PURGE_EXISTING - whether to remove the files before upload |
| set_value_or_error "${PURGE_EXISTING}" "true" "PURGE_EXISTING" "true false" |
| |
| # PURGE_BY_BASE_PATH - sometimes it's useful to purge the base version folder, instead of the targeted nested sub folder |
| set_value_or_error "${PURGE_BY_BASE_PATH}" "false" "PURGE_BY_BASE_PATH" "true false" |
| |
| # GITHUB_WORKSPACE - the safe directory to checkout to |
| set_value_or_error "${GITHUB_WORKSPACE}" "" "GITHUB_WORKSPACE" |
| |
| if [[ "$SKIP_SNAPSHOT_FOLDER" == "true" && "$GRADLE_PUBLISH_RELEASE" == "false" ]]; then |
| echo "Snapshot detected and snapshot publishing is disabled. Skipping documentation deployment." |
| exit 0 |
| fi |
| |
| GIT_REPO_URL="https://${GITHUB_USER_NAME}:${GH_TOKEN}@github.com/${TARGET_REPOSITORY}.git" |
| |
| # Initialize a Git Repository under a separate location from the existing checkout that will be the gh-pages branch |
| cd $GITHUB_WORKSPACE |
| git init |
| git config --global user.email "${GITHUB_USER_NAME}@users.noreply.github.com" |
| git config --global user.name "${GITHUB_USER_NAME}" |
| git config --global http.version HTTP/1.1 |
| git config --global http.postBuffer 157286400 |
| |
| # Create or checkout the documentation branch |
| if git ls-remote --heads "${GIT_REPO_URL}" gh-pages | grep -q "refs/heads/gh-pages"; then |
| echo "gh-pages branch found, cloning" |
| git clone "${GIT_REPO_URL}" gh-pages --branch gh-pages --single-branch |
| cd gh-pages |
| else |
| echo "Creating gh-pages branch as it does not exist" |
| mkdir gh-pages |
| cd gh-pages |
| git init |
| git checkout -b gh-pages |
| git remote add origin "${GIT_REPO_URL}" |
| fi |
| |
| # grails repos have a convention that they create a ghpages.html to replace the root index.html |
| if [[ -f "../${SOURCE_FOLDER}/ghpages.html" ]]; then |
| echo "${SOURCE_FOLDER}/ghpages.html detected, replacing root index.html" |
| cp "../${SOURCE_FOLDER}/ghpages.html" ../index.html |
| git add ../index.html |
| fi |
| |
| # stage the documents |
| if [[ "$GRADLE_PUBLISH_RELEASE" == "false" ]]; then |
| echo "Snapshot detected" |
| |
| # Subfolder support |
| BASE_PUBLISH_PATH="./${LAST_SNAPSHOT_FOLDER}" |
| if [ -n "${TARGET_SUBFOLDER}" ]; then |
| PUBLISH_PATH="./${LAST_SNAPSHOT_FOLDER}/${TARGET_SUBFOLDER}" |
| else |
| PUBLISH_PATH="./${LAST_SNAPSHOT_FOLDER}" |
| fi |
| |
| publish_artifacts |
| else |
| echo "Release detected" |
| |
| versionFolder="${VERSION%.*}" |
| versionFolder="${versionFolder}.x" |
| echo "Version folder will be ${versionFolder}" |
| |
| # Publish to the version folder first |
| BASE_PUBLISH_PATH="./${versionFolder}" |
| if [ -n "${TARGET_SUBFOLDER}" ]; then |
| PUBLISH_PATH="./${versionFolder}/${TARGET_SUBFOLDER}" |
| else |
| PUBLISH_PATH="./${versionFolder}" |
| fi |
| publish_artifacts |
| echo "Published documentation to ${PUBLISH_PATH}" |
| |
| # Publish to the latest release folder if needed |
| if [[ "$SKIP_RELEASE_FOLDER" == "false" ]]; then |
| if is_highest_version "${versionFolder}"; then |
| BASE_PUBLISH_PATH="./${LAST_RELEASE_FOLDER}" |
| if [ -n "${TARGET_SUBFOLDER}" ]; then |
| PUBLISH_PATH="./${LAST_RELEASE_FOLDER}/${TARGET_SUBFOLDER}" |
| else |
| PUBLISH_PATH="./${LAST_RELEASE_FOLDER}" |
| fi |
| publish_artifacts |
| echo "Published a copy of documentation to ${PUBLISH_PATH}" |
| else |
| echo "Skipping documentation copy to '${LAST_RELEASE_FOLDER}' because ${versionFolder} is NOT the highest." |
| fi |
| else |
| echo "Skipping documentation copy to ${LAST_RELEASE_FOLDER}" |
| fi |
| fi |
| |
| echo "Detected the following delta for commit:" |
| git status |
| |
| echo "Committing changes." |
| git commit -m "Deploying to gh-pages - $(date +"%T")" --quiet --allow-empty |
| git push "${GIT_REPO_URL}" gh-pages |
| echo "Deployment successful!" |