File indexing completed on 2025-02-16 05:12:26

0001 #!/usr/bin/env bash
0002 # This script is part of the release procedure of the SOCI library based
0003 # on current state of given release branch or master (see RELEASING.md).
0004 #
0005 # Copyright (c) 2019 Mateusz Loskot <mateusz@loskot.net>
0006 #
0007 # This script performs the following steps:
0008 # 1. If given release/X.Y exists
0009 #    - on remote as origin/release/X.Y, check it out;
0010 #    - locally, then pass option --use-local-branch to check it out;
0011 #    and use it as ready for packaging.
0012 # 3. Determine the full release version number from `SOCI_LIB_VERSION` value in include/soci/version.h.
0013 # 4. Build HTML documentation
0014 # 4.1. Create Python virtual environment
0015 # 4.2. Install MkDocs
0016 # 4.3. Build documentation
0017 # 5. Filter unwanted content
0018 #    - Website files
0019 #    - Markdown documentation and configuration files
0020 #    - CI configuration files
0021 #    - Development auxiliary files
0022 #    - Git auxiliary files
0023 # 6. Create archives (.zip, .tar.gz)
0024 #
0025 usage()
0026 {
0027     echo "Usage: `realpath $0` [OPTIONS] <release/X.Y branch>"
0028     echo "  --rc <N>            N is number of release candidate (e.g. from 1 to 9)"
0029     echo "  --use-local-branch  Use existing local release/X.Y branch instead of checking out origin/release/X.Y"
0030     echo "  --help, -h          Displays this message"
0031     exit 1
0032 }
0033 ME=`basename "$0"`
0034 MSG_TAG="| $ME"
0035 
0036 UNAME_S="$(uname -s)"
0037 case "${UNAME_S}" in
0038     Linux*)     THIS_SYS=Linux;;
0039     Darwin*)    THIS_SYS=Mac;;
0040     CYGWIN*)    THIS_SYS=Cygwin;;
0041     MINGW*)     THIS_SYS=MinGW;;
0042     *)          THIS_SYS="UNKNOWN:${UNAME_S}"
0043 esac
0044 if [[ "$THIS_SYS" != "Linux" ]]; then
0045     echo "${MSG_TAG} ERROR: This script requires Linux. Yours is '$THIS_SYS'. Aborting."
0046     exit 1
0047 fi
0048 if [[ ! -d "$PWD/.git" ]] || [[ ! -r "$PWD/include/soci/version.h" ]]; then
0049     echo "${MSG_TAG} ERROR: Directory '$PWD' is not Git repository. Aborting."
0050     exit 1
0051 fi
0052 
0053 OPT_USE_LOCAL_RELEASE_BRANCH=0
0054 OPT_GIT_RELEASE_BRANCH=""
0055 OPT_RC_NUMBER=""
0056 while [[ $# -gt 0 ]];
0057 do
0058     case $1 in
0059         --rc) test ! -z $2 && OPT_RC_NUMBER=$2; shift; echo "${MSG_TAG} INFO: Setting --rc=$OPT_RC_NUMBER, building release candidate archive";;
0060         --use-local-branch) OPT_USE_LOCAL_RELEASE_BRANCH=1; echo "${MSG_TAG} INFO: Setting --use-local-branch on, using existing local release/X.Y branch";;
0061         -h|--help) usage;;
0062         *) OPT_GIT_RELEASE_BRANCH=$1;;
0063     esac;
0064     shift
0065 done
0066 
0067 if [[ -n "$OPT_RC_NUMBER" ]] && [[ ! "$OPT_RC_NUMBER" =~ ^[1-9]+$ ]]; then
0068     echo "${MSG_TAG} ERROR: Release candidate must be single digit integer from 1 to 9, not '$OPT_RC_NUMBER'. Aborting."
0069     exit 1
0070 fi
0071 
0072 GIT_RELEASE_BRANCH=$OPT_GIT_RELEASE_BRANCH
0073 if [[ -z "$GIT_RELEASE_BRANCH" ]] || [[ ! "$GIT_RELEASE_BRANCH" =~ ^release/[3-9]\.[0-9]$ ]]; then
0074     echo "${MSG_TAG} ERROR: Missing valid 'release/X.Y' branch name i.e. release/3.0 or later"
0075     usage
0076     exit 1
0077 fi
0078 
0079 GIT_CURRENT_BRANCH=$(git branch | grep \* | cut -d ' ' -f2)
0080 echo "${MSG_TAG} INFO: Current branch is $GIT_CURRENT_BRANCH"
0081 echo "${MSG_TAG} INFO: Releasing branch $GIT_RELEASE_BRANCH"
0082 
0083 echo "${MSG_TAG} INFO: Fetching branches from origin"
0084 git fetch origin
0085 
0086 # Checkout branch release/X.Y
0087 GIT_LOCAL_RELEASE_BRANCH=$(git branch -a | grep -Po "(\*?\s+)\K$GIT_RELEASE_BRANCH")
0088 if [[ $OPT_USE_LOCAL_RELEASE_BRANCH -eq 1 ]]; then
0089     if [[ -n "$GIT_LOCAL_RELEASE_BRANCH" ]]; then
0090         echo "${MSG_TAG} INFO: Checking out branch '$GIT_RELEASE_BRANCH'"
0091         git checkout $GIT_RELEASE_BRANCH || exit 1
0092         echo "${MSG_TAG} INFO: Updating branch '$GIT_RELEASE_BRANCH' from origin"
0093         git pull --ff-only origin $GIT_RELEASE_BRANCH || exit 1
0094     else
0095         echo "${MSG_TAG} ERROR: Local release branch '$GIT_LOCAL_RELEASE_BRANCH' does not exists. Aborting."
0096         exit 1
0097     fi
0098 else
0099     if [[ -n "$GIT_LOCAL_RELEASE_BRANCH" ]]; then
0100         echo "${MSG_TAG} ERROR: Local release branch '$GIT_LOCAL_RELEASE_BRANCH' already exists. Aborting."
0101         echo "${MSG_TAG} INFO: Delete the local branch and run again to checkout 'origin/$GIT_RELEASE_BRANCH'."
0102         exit 1
0103     fi
0104 fi
0105 
0106 # Checkout branch origin/release/X.Y as release/X.Y
0107 if [[ $OPT_USE_LOCAL_RELEASE_BRANCH -eq 0 ]]; then
0108     GIT_REMOTE_RELEASE_BRANCH=$(git branch -a | grep -Po "(\*?\s+)\Kremotes/origin/$GIT_RELEASE_BRANCH")
0109     if [[ -n "$GIT_REMOTE_RELEASE_BRANCH" ]]; then
0110         echo "${MSG_TAG} INFO: Release branch 'origin/$GIT_RELEASE_BRANCH' does exist. Checking it out."
0111         git checkout -b $GIT_RELEASE_BRANCH --no-track origin/$GIT_RELEASE_BRANCH || exit 1
0112         git pull --ff-only origin $GIT_RELEASE_BRANCH || exit 1
0113     else
0114         echo "${MSG_TAG} ERROR: Release branch 'origin/$GIT_RELEASE_BRANCH' does not exist. Aborting"
0115         echo "${MSG_TAG} INFO: Create release branch 'origin/$GIT_RELEASE_BRANCH' and run again."
0116         exit 1
0117     fi
0118 fi
0119 
0120 GIT_CURRENT_RELEASE_BRANCH=$(git branch -a | grep -Po "(\*\s+)\K$GIT_RELEASE_BRANCH")
0121 if [[ "$GIT_CURRENT_RELEASE_BRANCH" != "$GIT_RELEASE_BRANCH" ]]; then
0122     echo "${MSG_TAG} ERROR: Current branch is not '$GIT_RELEASE_BRANCH' but '$GIT_CURRENT_RELEASE_BRANCH'. Aborting."
0123     exit 1
0124 fi
0125 
0126 SOCI_VERSION=$(cat "$PWD/include/soci/version.h" | grep -Po "(.*#define\s+SOCI_LIB_VERSION\s+.+)\K([3-9]_[0-9]_[0-9])" | sed "s/_/\./g")
0127 if [[ ! "$SOCI_VERSION" =~ ^[4-9]\.[0-9]\.[0-9]$ ]]; then
0128     echo "${MSG_TAG} ERROR: Invalid format of SOCI version '$SOCI_VERSION'. Aborting."
0129     exit 1
0130 else
0131     echo "${MSG_TAG} INFO: Releasing version $SOCI_VERSION"
0132 fi
0133 
0134 SOCI_FULL_VERSION=$SOCI_VERSION
0135 if [[ -n $OPT_RC_NUMBER ]];then
0136     SOCI_FULL_VERSION=$SOCI_VERSION-rc$OPT_RC_NUMBER
0137 fi
0138 SOCI_ARCHIVE=soci-$SOCI_FULL_VERSION
0139 
0140 if [[ -d "$SOCI_ARCHIVE" ]]; then
0141     echo "${MSG_TAG} ERROR: Directory '$SOCI_ARCHIVE' already exists. Aborting."
0142     echo "${MSG_TAG} INFO: Delete it and run again."
0143     exit 1
0144 fi
0145 if [[ -f "${SOCI_ARCHIVE}.zip" ]]; then
0146     echo "${MSG_TAG} ERROR: Archive '${SOCI_ARCHIVE}.zip' already exists. Aborting."
0147     echo "${MSG_TAG} INFO: Delete it and run again."
0148     exit 1
0149 fi
0150 if [[ -f "${SOCI_ARCHIVE}.tar.gz" ]]; then
0151     echo "${MSG_TAG} ERROR: Archive '${SOCI_ARCHIVE}.tar.gz' already exists. Aborting."
0152     echo "${MSG_TAG} INFO: Delete it and run again."
0153     exit 1
0154 fi
0155 
0156 if [[ -d $PWD/.venv ]] && [[ ! -f $PWD/.venv/bin/activate ]]; then
0157     echo "${MSG_TAG} ERROR: Directory '$PWD/.venv' already exists. Can not create Python environment. Aborting."
0158     exit 1
0159 fi
0160 
0161 if [[ ! -f $PWD/.venv/bin/activate ]]; then
0162     MASTER_PY=""
0163     if command -v python3 &>/dev/null; then
0164         MASTER_PY=$(which python3)
0165     fi
0166     if [[ -z "$MASTER_PY" ]] && command -v python &>/dev/null; then
0167         MASTER_PY=$(which python)
0168     fi
0169     if [[ -z "$MASTER_PY" ]] || [[ ! $($MASTER_PY --version) =~ ^Python.+3 ]]; then
0170         echo "${MSG_TAG} ERROR: Python 3 not found. Aborting."
0171         exit 1
0172     else
0173         echo "${MSG_TAG} INFO: Creating Python virtual environment using $MASTER_PY (`$MASTER_PY --version`)"
0174     fi
0175     $MASTER_PY -m venv $PWD/.venv || exit 1
0176 fi
0177 
0178 if [[ ! -f $PWD/.venv/bin/activate ]]; then
0179     echo "${MSG_TAG} ERROR: Python virtual environment script '$PWD/.venv/bin/activate' not found. Aborting."
0180     exit 1
0181 fi
0182 source $PWD/.venv/bin/activate
0183 echo "${MSG_TAG} INFO: Using Python from `which python` (`python --version`)"
0184 python -m pip --quiet install --upgrade pip
0185 python -m pip --quiet install --upgrade mkdocs
0186 
0187 echo "${MSG_TAG} INFO: Building documentation with `mkdocs --version`"
0188 mkdocs build --clean
0189 
0190 echo "${MSG_TAG} INFO: Exiting Python virtual environment"
0191 deactivate
0192 
0193 echo "${MSG_TAG} INFO: Preparing release archive in '$SOCI_ARCHIVE'"
0194 mkdir $SOCI_ARCHIVE
0195 cp -a cmake $SOCI_ARCHIVE
0196 cp -a include $SOCI_ARCHIVE
0197 cp -a languages $SOCI_ARCHIVE
0198 cp -a src $SOCI_ARCHIVE
0199 cp -a tests $SOCI_ARCHIVE
0200 cp -a AUTHORS CMakeLists.txt LICENSE_1_0.txt README.md Vagrantfile $SOCI_ARCHIVE/
0201 mv site $SOCI_ARCHIVE/docs
0202 
0203 # Add git SHA-1 to version in CHANGES file
0204 RELEASE_BRANCH_SHA1=$(git show-ref --hash=8 origin/$GIT_RELEASE_BRANCH)
0205 echo "${MSG_TAG} INFO: Appending '$RELEASE_BRANCH_SHA1' hash to version in '$SOCI_ARCHIVE/CHANGES'"
0206 cat CHANGES | sed "s/Version $SOCI_VERSION.*differs/Version $SOCI_FULL_VERSION ($RELEASE_BRANCH_SHA1) differs/" > $SOCI_ARCHIVE/CHANGES
0207 
0208 echo "${MSG_TAG} INFO: Building release archive '$SOCI_ARCHIVE.zip'"
0209 zip -q -r $SOCI_ARCHIVE.zip $SOCI_ARCHIVE
0210 if [[ $? -ne 0 ]]; then
0211     echo "${MSG_TAG} ERROR: zip failed. Aborting."
0212     exit 1
0213 fi
0214 
0215 echo "${MSG_TAG} INFO: Building release archive '$SOCI_ARCHIVE.tar.gz'"
0216 tar -czf $SOCI_ARCHIVE.tar.gz $SOCI_ARCHIVE
0217 if [[ $? -ne 0 ]]; then
0218     echo "${MSG_TAG} ERROR: tar failed. Aborting."
0219     exit 1
0220 fi
0221 
0222 echo "${MSG_TAG} INFO: Cleaning up"
0223 rm -rf "${SOCI_ARCHIVE}"
0224 git checkout $GIT_CURRENT_BRANCH
0225 
0226 if [[ $OPT_USE_LOCAL_RELEASE_BRANCH -eq 0 ]]; then
0227     echo "${MSG_TAG} INFO: Deleting '$GIT_RELEASE_BRANCH' checked out from 'origin/$GIT_RELEASE_BRANCH'."
0228     git branch -D $GIT_RELEASE_BRANCH
0229 fi
0230 
0231 echo "${MSG_TAG} INFO: Done"