Skip to content

Commit

Permalink
Merge pull request #4 from valicm/3-improve-script-usability
Browse files Browse the repository at this point in the history
Improvements
  • Loading branch information
valicm committed Nov 1, 2023
2 parents 1fe6bfc + 4f7c372 commit 1596e4d
Show file tree
Hide file tree
Showing 3 changed files with 186 additions and 33 deletions.
29 changes: 29 additions & 0 deletions .github/workflows/shellcheck.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: ShellCheck
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

permissions:
contents: read

jobs:
lint:
runs-on: ubuntu-latest

permissions:
security-events: write

steps:
- name: Repository checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

- id: ShellCheck
name: Differential ShellCheck
uses: redhat-plumbers-in-action/differential-shellcheck@v5
with:
severity: warning
token: ${{ secrets.GITHUB_TOKEN }}
12 changes: 11 additions & 1 deletion action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,22 @@ branding:
inputs:
update_type:
description: 'Are we doing minor or major updates. Allowed values are semver-safe-update or all'
required: true
required: false
update_core:
description: 'Skip checking for Drupal core updates. Default false'
required: false
update_exclude:
description: 'Modules excluded from checks. Use comma separated list: token,redirect,pathauto'
required: false
runs:
using: "composite"
steps:
- run: echo "INPUT_UPDATE_TYPE=${{ inputs.update_type }}" >> $GITHUB_ENV
shell: bash
- run: echo "INPUT_UPDATE_CORE=${{ inputs.update_core }}" >> $GITHUB_ENV
shell: bash
- run: echo "INPUT_UPDATE_EXCLUDE=${{ inputs.update_exclude }}" >> $GITHUB_ENV
shell: bash
- run: chmod +x ${{ github.action_path }}/drupal-update.sh
shell: bash
- run: $GITHUB_ACTION_PATH/drupal-update.sh
Expand Down
178 changes: 146 additions & 32 deletions drupal-update.sh
Original file line number Diff line number Diff line change
@@ -1,34 +1,81 @@
#!/bin/bash
# GNU General Public License v3.0
#
# Copyright (c) 2023 Valentino Međimorec
#
set -e

###############################################################################
# GNU General Public License v3.0 #
# Copyright (c) 2023 Valentino Međimorec #
# #
# Simplistic script to use with GitHub Actions or standalone #
# to perform composer updates. #
# to perform composer updates of Drupal projects. #
# #
# Standalone usage #
# Run minor updates -> bash drupal-update.sh #
# Run all updates -> bash drupal-update.sh all # #
# Predefined options #
# #
# Type of update to perform #
# - semver-safe-update (only perform minor changes in versions) #
# - all (perform all possible upgrades, includes minor) #
# #
# Run minor updates -> bash drupal-update.sh #
# Run all updates -> bash drupal-update.sh -t all #
# Run updates, except core -> bash drupal-update.sh -t all -c false # #
###############################################################################

set -e

# Function to display script usage.
usage() {
echo "Usage: $0 [OPTIONS]"
echo "Options:"
echo " -h, --help Display this help message"
echo " -t, --type Options: semver-safe-update or all. Default is semver-safe-update: minor and security upgrades."
echo " -o, --output Specify an output file to save summary. Default is none."
echo " -c, --core Flag to enable or disable Drupal core upgrades check. Default is true."
echo " -e, --exclude Exclude certain modules from updates check. Use comma separated list: token,redirect,pathauto"
}

# Exit with error.
exit_error() {
usage
exit 1
}

# Validate options passed by GitHub or by standalone usage with flags.
validate_options() {
UPDATE_TYPE=$1
UPDATE_CORE=$2
UPDATE_EXCLUDE=$3
SUMMARY_FILE=$4

if [ -n "$UPDATE_TYPE" ] && [ "$UPDATE_TYPE" != "semver-safe-update" ] && [ "$UPDATE_TYPE" != "all" ]; then
echo "Error: Update type can be either semver-safe-update or all"
exit_error
fi

if [ -n "$UPDATE_CORE" ] && [ "$UPDATE_CORE" != true ] && [ "$UPDATE_CORE" != false ]; then
echo "Error: Core flag must be either true or false. Default if empty is false"
exit_error
fi
}

# Validate if all requirements are present.
# Check existence of composer.json/lock file, composer, sed and jq binaries.
validate_requirements() {
if [ ! -f composer.json ] || [ ! -f composer.lock ]; then
echo "Error: composer.json or composer.lock are missing"
exit 1
fi

BINARIES="php composer sed jq";
for BINARY in $BINARIES
do
if ! [ -x "$(command -v "$BINARY")" ]; then
echo "Error: $BINARY is not installed."
exit 1
fi
done

}

# Update project based on composer update status.
# Mark dev versions as success, because we don't have specific version.
update_project() {
PROJECT_NAME=$1
CURRENT_VERSION=$2
LATEST_VERSION=$3
UPDATE_STATUS=$4
if [ "$UPDATE_STATUS" == "update-possible" ]
then
if [ "$UPDATE_STATUS" == "update-possible" ]; then
composer require "$PROJECT_NAME":"$LATEST_VERSION" -W -q --ignore-platform-reqs
else
composer update "$PROJECT_NAME" -W -q --ignore-platform-reqs
Expand All @@ -43,21 +90,58 @@ update_project() {
fi
}

# Set default values.
SUMMARY_FILE=
UPDATE_TYPE="semver-safe-update"
UPDATE_EXCLUDE=
UPDATE_CORE=true

# Determine if we're running inside GitHub actions.
GITHUB_RUNNING_ACTION=$GITHUB_ACTIONS

# For GitHub actions use inputs.
if [ "$GITHUB_RUNNING_ACTION" == true ]
then
UPDATE_TYPE=${INPUT_UPDATE_TYPE}
else
UPDATE_TYPE=$1
UPDATE_CORE=${INPUT_UPDATE_CORE}
UPDATE_EXCLUDE=${INPUT_UPDATE_EXCLUDE}
fi

# Fallback to minor updates.
if [ "$UPDATE_TYPE" != "semver-safe-update" ] && [ "$UPDATE_TYPE" != "all" ]
then
UPDATE_TYPE="semver-safe-update"
# Go through any flags available.
while getopts "h:t:c:e:o:" options; do
case "${options}" in
h)
echo usage
exit
;;
t)
UPDATE_TYPE=${OPTARG}
;;
c)
UPDATE_CORE=${OPTARG}
;;
e)
UPDATE_EXCLUDE=${OPTARG}
;;
o)
SUMMARY_FILE=${OPTARG}
;;
:)
echo "Error: -${OPTARG} requires an argument."
;;
*)
exit_error
;;
esac
done

# Perform validations of shell scripts arguments and requirements to run script.
validate_options "$UPDATE_TYPE" "$UPDATE_CORE" "$UPDATE_EXCLUDE" "$SUMMARY_FILE"
validate_requirements

# If we have list of exclude modules, convert it to loop list.
if [ -n "$UPDATE_EXCLUDE" ]; then
UPDATE_EXCLUDE="${UPDATE_EXCLUDE//,/ }"
fi

# Get full composer content for later usage.
Expand All @@ -72,33 +156,56 @@ UPDATES=$(composer outdated "drupal/*" -f json -D --locked --ignore-platform-req
for UPDATE in $(echo "${UPDATES}" | jq -c '.locked[]'); do
PROJECT_NAME=$(echo "${UPDATE}" | jq '."name"' | sed "s/\"//g")
PROJECT_URL=$(echo "${UPDATE}" | jq '."homepage"' | sed "s/\"//g")
if [ -n "$PROJECT_URL" ]; then
PROJECT_URL="https://www.drupal.org/project/drupal"
fi
CURRENT_VERSION=$(echo "${UPDATE}" | jq '."version"' | sed "s/\"//g")
LATEST_VERSION=$(echo "${UPDATE}" | jq '."latest"' | sed "s/\"//g")
UPDATE_STATUS=$(echo "${UPDATE}" | jq '."latest-status"' | sed "s/\"//g")
ABANDONED=$(echo "${UPDATE}" | jq '."abandoned"' | sed "s/\"//g")
PATCHES=$(echo "$COMPOSER_CONTENTS" | jq '.extra.patches."'"$PROJECT_NAME"'" | length')

PROJECT_RELEASE_URL=$PROJECT_URL
if [[ $LATEST_VERSION != dev-* ]]; then
PROJECT_RELEASE_URL=$PROJECT_URL"/releases/"$LATEST_VERSION
fi

RESULT="skipped"

if [ "$UPDATE_TYPE" == 'all' ]
then
# Go through excluded packages and skip them.
if [ -n "$UPDATE_EXCLUDE" ]; then
for EXCLUDE in $UPDATE_EXCLUDE
do
if [ "$PROJECT_NAME" = "drupal/$EXCLUDE" ]; then
continue
fi
done
fi

# If we need to skip Drupal core updates.
# Still write latest version for summary table.
if [ "$UPDATE_CORE" == false ]; then
if [[ "$PROJECT_NAME" =~ drupal/core-* ]] || [ "$PROJECT_NAME" = "drupal/core" ]; then
SUMMARY_OUTPUT_TABLE+="| [${PROJECT_NAME}](${PROJECT_URL}) | ${CURRENT_VERSION} | [${LATEST_VERSION}]($PROJECT_RELEASE_URL) | skipped | $PATCHES | $ABANDONED |\n"
continue
fi
fi

if [ "$UPDATE_TYPE" == 'major' ]; then
echo "Update $PROJECT_NAME from $CURRENT_VERSION to $LATEST_VERSION"
RESULT=$(update_project "$PROJECT_NAME" "$CURRENT_VERSION" "$LATEST_VERSION" "$UPDATE_STATUS")
else
if [ "$UPDATE_STATUS" == "$UPDATE_TYPE" ]
then
if [ "$UPDATE_STATUS" == "$UPDATE_TYPE" ]; then
echo "Update $PROJECT_NAME from $CURRENT_VERSION to $LATEST_VERSION"
RESULT=$(update_project "$PROJECT_NAME" "$CURRENT_VERSION" "$LATEST_VERSION" "$UPDATE_STATUS")
fi
fi

SUMMARY_OUTPUT_TABLE+="| [${PROJECT_NAME}](${PROJECT_URL}) | ${CURRENT_VERSION} | ${LATEST_VERSION} | $RESULT | $PATCHES | $ABANDONED |\n"

SUMMARY_OUTPUT_TABLE+="| [${PROJECT_NAME}](${PROJECT_URL}) | ${CURRENT_VERSION} | [${LATEST_VERSION}]($PROJECT_RELEASE_URL) | $RESULT | $PATCHES | $ABANDONED |\n"
done

# For GitHub actions use inputs.
if [ "$GITHUB_RUNNING_ACTION" == true ]
then
# For GitHub actions use GitHub step summary and environment variable DRUPAL_UPDATES_TABLE.
if [ "$GITHUB_RUNNING_ACTION" == true ]; then
echo -e "$SUMMARY_OUTPUT_TABLE" >> "$GITHUB_STEP_SUMMARY"
{
echo 'DRUPAL_UPDATES_TABLE<<EOF'
Expand All @@ -109,3 +216,10 @@ else
echo -e "$SUMMARY_OUTPUT_TABLE"
fi

# If we have summary file.
if [ -n "$SUMMARY_FILE" ]; then
if [ ! -f "$SUMMARY_FILE" ]; then
touch "$SUMMARY_FILE"
fi
echo -e "$SUMMARY_OUTPUT_TABLE" > "$SUMMARY_FILE"
fi

0 comments on commit 1596e4d

Please sign in to comment.