Upgrade script for MediaWiki website with one external addon (wave 1) I have a MediaWiki 1.33.0 website with only one external addon installed (external extension), which is ContactPage.
I have created the following script with that logic:


  if there is an upgrade to either MediaWiki core OR ContactPage these will be upgraded respectively;
  else, the script keeps the original state (that is, the state before the upgrade attempt). Successful upgrading might
  require further manual changes although I didn't have a case of
  needing to make manual changes.


I tested the script and it seems to work as expected; if no new version was released, the current ones are kept.

The script:

# Declare MediaWiki download variables (ensure latest versions are downloaded because as of 08/10/19 there aren't version-agnostic download links):

latest_mediawiki_core="https://releases.wikimedia.org/mediawiki/1.33/mediawiki-1.33.0.tar.gz"
latest_contactpage_extension="https://extdist.wmflabs.org/dist/extensions/ContactPage-REL1_33-abdcab9.tar.gz"

# Declare other important variables:

current_date="$(date +%Y-%m-%d-%H-%M-%S)"
war="$HOME/public_html" # Web Application Root # Change to your Web Application Root if needed
domain="example.com" # Change to relevant domain
db-username_and_db-name="DB_CREDENTIALS" # Change to relevant DB credentials

# Create backup directories:

mkdir -p "${war}/mediawiki_general_backups"
mkdir -p "${war}/mediawiki_specific_backups"

# General backups:

zip -r "${war}/mediawiki_general_backups/${domain}-directory-backup-${current_date}.zip" "${war}/${domain}"
mysqldump \
-u "${db-username_and_db-name}" \
-p "${db-username_and_db-name}" \
&gt; "${war}/mediawiki_general_backups/${db-username_and_db-name}-${current_date}.sql"

# Specific backups:

rm "${war}"/mediawiki_specific_backups/*
rm "${war}"/mediawiki_specific_backups/.* # If I won't run this, a specific backup of .htaccess, in that directory, won't get deleted;

cp "${war}/${domain}"/.htaccess*                  "${war}/mediawiki_specific_backups"/.htaccess*
cp "${war}/${domain}"/LocalSettings.php           "${war}/mediawiki_specific_backups"/LocalSettings.php
cp "${war}/${domain}"/robots.txt                  "${war}/mediawiki_specific_backups"/robots.txt
cp "${war}/${domain}"/${domain}.png               "${war}/mediawiki_specific_backups"/${domain}.png
cp "${war}/${domain}"/googlec69e044fede13fdc.html "${war}/mediawiki_specific_backups"/googlec69e044fede13fdc.html

# Downloads and configurations:

rm -rf "${war}/${domain}"
mkdir "${war}/${domain}"
wget "${latest_mediawiki_core}" -O - | tar -xzv --strip-components 1 -C "${war}/${domain}"
wget "${latest_contactpage_extension}" -O - | tar -xzv -C "${war}/${domain}"/extensions/
cp -a "${war}/mediawiki_specific_backups"/* "${war}/${domain}"

# Create a new sitemap:

mkdir -p "${war}/${domain}/sitemap"
php "${war}/${domain}"/maintenance/generateSitemap.php \
--memory-limit=50M \
--fspath=/"${war}/${domain}/sitemap" \
--identifier="${domain}" \
--urlpath=/sitemap/  \
--server=https://"${domain}" \
--compress=yes

# Update DB (One might need to change LocalSettings.php before doing so):
php "${war}/${domain}"/maintenance/update.php
Make the process approach atomic

The script first wipes out ${war}/${domain},
then populates it with content from wget commands,
and restores content from backup.

The wget commands are a serious risk here.
If any of the source sites is down or experiencing instability at the time the script runs,
your site can end up in an inconsistent state.

At the minimum, it would be better to fetch all external resources before you start rewriting your content.

An even better way would be to try to make the process as atomic as possible:
build up the new content in a dedicated directory isolated from production,
but on the same partition,
and when all is ready, make the switch in fast directory rename operations.

Separate your backups from your production environment

The $war directory looks clearly in the heart of the production environment.
In that directory, you create backup directories side by side with the $domain directory.
I suggest to create the backups elsewhere.
Ideally on a different filesystem partition.

Closely related to this, the backup directories are somewhere in $war/...,
and the original content is also somewhere in $war/....
I think this invites mistakes.
If you had distinct variable name prefixes such as $backup_... and $content,
that would reduce the risk of mistakes.

Syntax error

I don't understand what this is doing in a Bash script:


db-username_and_db-name="DB_CREDENTIALS"



This is an invalid statement in all Bash versions that I know.

Bash scripts should have a shebang

The posted code has no shebang.
Since the question is tagged bash,
maybe it's implied it's really there in your version,
but just for the record, every Bash script should start with a shebang.

Watch out for things that may go wrong

Toby already mentioned this in his review,
but I think it deserves to be stressed.
Many things can go wrong in this script:


If mysqldump fails for some reason, the script will keep going without a backup created. That can lead to data loss, and it's to be avoided.
If any of the wget commands fail for some reason, the script will keep going and update the sitemap and the DB. That can lead to inconsistent state of your site that's difficult to debug.


My suggestion is similar to Toby's:
put set -euo pipefail near the top of the script,
to make it stop executing when something goes wrong unexpectedly.

Double-quote variables used in command arguments

You did that correctly for the most part,
you missed just one here:


cp "${war}/${domain}"/${domain}.png               "${war}/mediawiki_specific_backups"/${domain}.png



Use more variables

The term ${war}/mediawiki_general_backups comes up repeatedly.
It would be better if it was in a variable.
Editors with Bash support will make it possible to rename, see, find easily all occurrences.

Make long pipelines easier to read and understand

Take for example this:


wget "${latest_mediawiki_core}" -O - | tar -xzv --strip-components 1 -C "${war}/${domain}"



I think it's better to write flags before arguments.
The text closer to the left is naturally easier to read.
And the flags pack a lot of important details in little space,
and the URL argument is long and not very interesting to read.

Secondly, it's easier to understand code when there is a single statement per line.
A good way to achieve that is by splitting the line at each command in the pipeline.

That is, I suggest writing like this:

wget -O- "${latest_mediawiki_core}" \
| tar -xzv --strip-components 1 -C "${war}/${domain}"


Simplify

Instead of this:


rm "${war}"/mediawiki_specific_backups/*
rm "${war}"/mediawiki_specific_backups/.* # If I won't run this, a specific backup of .htaccess, in that directory, won't get deleted;



Why not simply:

rm -r "${war}"/mediawiki_specific_backups