Files
element-x-android/tools/release/releaseV2.sh
T
Benoit Marty 5b09fdf13f Replace git flow with regular git commands in the release script V2
The script was relying on the external git-flow tool and on a local
`git config gitflow.*` initialisation, which made its behaviour depend on
the machine setup and hid what was actually done to the branches.

The release branch is now created with `git checkout -b`, and the release
is finished with explicit merge, tag, back-merge and branch deletion
commands. The merge and tag messages are provided explicitly so that the
generated history stays identical to the previous releases. Each step now
aborts the script with a clear message when it fails, instead of letting
the script continue.

Note that tools/release/release.sh (V1) still uses git flow.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 16:57:01 +02:00

560 lines
24 KiB
Bash
Executable File

#!/usr/bin/env bash
# Copyright (c) 2026 Element Creations Ltd.
#
# SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
# Please see LICENSE files in the repository root for full details.
# do not exit when any command fails, failures are handled explicitly by the script
set +e
printf "\n================================================================================\n"
printf "| Welcome to the release script (V2)! |\n"
printf "================================================================================\n"
printf "Checking environment...\n"
envError=0
# Check that bundletool is installed
if ! command -v bundletool &> /dev/null
then
printf "Fatal: bundletool is not installed. You can install it running \`brew install bundletool\`\n"
envError=1
fi
# Check that the GitHub CLI is installed. It is expected to be already authenticated, see `gh auth login`.
if ! command -v gh &> /dev/null
then
printf "Fatal: gh (the GitHub CLI) is not installed. You can install it running \`brew install gh\`\n"
envError=1
fi
# Path of the key store (it's a file)
keyStorePath="${ELEMENT_X_KEYSTORE_PATH}"
if [[ -z "${keyStorePath}" ]]; then
printf "Fatal: ELEMENT_X_KEYSTORE_PATH is not defined in the environment.\n"
envError=1
fi
# Keystore password
keyStorePassword="${ELEMENT_X_KEYSTORE_PASSWORD}"
if [[ -z "${keyStorePassword}" ]]; then
printf "Fatal: ELEMENT_X_KEYSTORE_PASSWORD is not defined in the environment.\n"
envError=1
fi
# Key password
keyPassword="${ELEMENT_X_KEY_PASSWORD}"
if [[ -z "${keyPassword}" ]]; then
printf "Fatal: ELEMENT_X_KEY_PASSWORD is not defined in the environment.\n"
envError=1
fi
# Android home
androidHome="${ANDROID_HOME}"
if [[ -z "${androidHome}" ]]; then
printf "Fatal: ANDROID_HOME is not defined in the environment.\n"
envError=1
fi
# @elementbot:matrix.org matrix token / Not mandatory
elementBotToken="${ELEMENT_BOT_MATRIX_TOKEN}"
if [[ -z "${elementBotToken}" ]]; then
printf "Warning: ELEMENT_BOT_MATRIX_TOKEN is not defined in the environment.\n"
fi
if [ ${envError} == 1 ]; then
exit 1
fi
# Abort the script with an error message.
fail() {
printf "\nFatal: %s\n" "$1"
exit 1
}
# Handle the result of a version check. ${checkError} must be set to 1 when a check has failed.
checkVersionResult() {
if [[ ${checkError} -ne 0 ]]; then
printf "\nThe check above has failed, this is not expected.\n"
read -r -p "Do you want to continue anyway (yes/no) default to no? " doContinue
doContinue=${doContinue:-no}
if [ "${doContinue}" != "yes" ]; then
exit 1
fi
else
printf "The versions are correct.\n"
fi
}
# Read minSdkVersion from file plugins/src/main/kotlin/Versions.kt
minSdkVersion=$(grep "MIN_SDK_FOSS =" ./plugins/src/main/kotlin/Versions.kt |cut -d '=' -f 2 |xargs)
# Read buildToolsVersion from file plugins/src/main/kotlin/Versions.kt
buildToolsVersion=$(grep "BUILD_TOOLS_VERSION =" ./plugins/src/main/kotlin/Versions.kt |cut -d '=' -f 2 |xargs)
buildToolsPath="${androidHome}/build-tools/${buildToolsVersion}"
if [[ ! -d ${buildToolsPath} ]]; then
printf "Fatal: %s folder not found, ensure that you have installed the SDK version %s.\n" "${buildToolsPath}" "${buildToolsVersion}"
exit 1
fi
# Check that there is no unmerged PR with the label "Z-NextRelease", else exit
unmergedPrs=$(gh pr list --repo element-hq/element-x-android --label "Z-NextRelease" --state open --json title,url -q '.[] | "\(.url): \(.title)"')
if [[ ${unmergedPrs} != "" ]]; then
printf "Fatal: There are unmerged PRs with the label Z-NextRelease:\n%s" "${unmergedPrs}"
printf "\n"
exit 1
fi
printf "OK\n"
printf "\n================================================================================\n"
printf "Ensuring main and develop branches are up to date...\n"
git checkout main
git pull
git checkout develop
git pull
printf "\n================================================================================\n"
# Guessing version to propose a default version
versionsFile="./plugins/src/main/kotlin/Versions.kt"
# The version of the release must match the date of next monday, where the release is supposed to go live
# The command below gets the date of next monday
nextMondayDateCommand="date -v +1w -v -monday"
# Get release year on 2 digits
versionYearCandidate=$(${nextMondayDateCommand} +%y)
currentVersionMonth=$(grep "val versionMonth" ${versionsFile} | cut -d " " -f6)
# Get release month on 2 digits
versionMonthCandidate=$(${nextMondayDateCommand} +%m)
versionMonthCandidateNoLeadingZero=${versionMonthCandidate/#0/}
currentVersionReleaseNumber=$(grep "val versionReleaseNumber" ${versionsFile} | cut -d " " -f6)
# if the release month is the same as the current version, we increment the release number, else we reset it to 0
if [[ ${currentVersionMonth} -eq ${versionMonthCandidateNoLeadingZero} ]]; then
versionReleaseNumberCandidate=$((currentVersionReleaseNumber + 1))
else
versionReleaseNumberCandidate=0
fi
versionCandidate="${versionYearCandidate}.${versionMonthCandidate}.${versionReleaseNumberCandidate}"
read -r -p "Please enter the release version (example: ${versionCandidate}). Format must be 'YY.MM.x' or 'YY.MM.xy', with year and month matching next Monday. Just press enter if ${versionCandidate} is correct. " version
version=${version:-${versionCandidate}}
# extract year, month and release number for future use
versionYear=$(echo "${version}" | cut -d "." -f1)
versionMonth=$(echo "${version}" | cut -d "." -f2)
versionMonthNoLeadingZero=${versionMonth/#0/}
versionReleaseNumber=$(echo "${version}" | cut -d "." -f3)
printf "\n================================================================================\n"
printf "Starting the release %s\n" "${version}"
git checkout -b "release/${version}" develop
# Note: in case the release is already started and the script is started again, checkout the release branch again.
ret=$?
if [[ $ret -ne 0 ]]; then
printf "Mmh, it seems that the release is already started. I'm displaying the changes now:\n"
git diff --stat "release/${version}" origin/main
printf "Do you want to continue the release using its contents?\n\n"
read -r -p "Continue (yes/no) default to yes? " doContinue
doContinue=${doContinue:-yes}
if [ "${doContinue}" == "no" ]; then
printf "OK, exiting, you can start the release again with the command 'git checkout -b release/%s develop'\n" "${version}"
exit 1
fi
git checkout "release/${version}"
fi
# Ensure version is OK
versionsFileBak="${versionsFile}.bak"
cp ${versionsFile} ${versionsFileBak}
sed "s/private const val versionYear = .*/private const val versionYear = ${versionYear}/" ${versionsFileBak} > ${versionsFile}
sed "s/private const val versionMonth = .*/private const val versionMonth = ${versionMonthNoLeadingZero}/" ${versionsFile} > ${versionsFileBak}
sed "s/private const val versionReleaseNumber = .*/private const val versionReleaseNumber = ${versionReleaseNumber}/" ${versionsFileBak} > ${versionsFile}
rm ${versionsFileBak}
printf -v versionReleaseNumber2Digits "%02d" "${versionReleaseNumber}"
versionCode="20${versionYear}${versionMonth}${versionReleaseNumber2Digits}0"
# Update the file aaptDump.txt with the new version
aaptDumpFile="./tools/manifest/gplay/release/aaptDump.txt"
sed "s/versionCode='[0-9]*'/versionCode='${versionCode}'/" ${aaptDumpFile} > ${aaptDumpFile}.bak
sed "s/versionName='[0-9]*\.[0-9]*\.[0-9]*'/versionName='${version}'/" ${aaptDumpFile}.bak > ${aaptDumpFile}
rm ${aaptDumpFile}.bak
git commit -a -m "Setting version for the release ${version}"
printf "\n================================================================================\n"
printf "Creating fastlane file...\n"
fastlaneFile="${versionCode}.txt"
fastlanePathFile="./fastlane/metadata/android/en-US/changelogs/${fastlaneFile}"
printf "Main changes in this version: bug fixes and improvements.\nFull changelog: https://github.com/element-hq/element-x-android/releases" > "${fastlanePathFile}"
read -r -p "I have created the file ${fastlanePathFile}, please edit it and press enter to continue. "
git add "${fastlanePathFile}"
git commit -a -m "Adding fastlane file for version ${version}"
printf "\n================================================================================\n"
printf "OK, finishing the release...\n"
# Merge the release branch into main, tag it, then merge the tag back into develop and delete the
# release branch. The merge messages are provided explicitly to keep the history consistent with
# the previous releases.
git checkout main || fail "unable to checkout main."
git merge --no-ff --no-edit -m "Merge branch 'release/${version}'" "release/${version}" \
|| fail "unable to merge the branch release/${version} into main. Please fix the conflicts and finish the release manually."
git tag -a "v${version}" -m "Release v${version}" || fail "unable to create the tag v${version}."
git checkout develop || fail "unable to checkout develop."
git merge --no-ff --no-edit -m "Merge tag 'v${version}' into develop" "v${version}" \
|| fail "unable to merge the tag v${version} into develop. Please fix the conflicts and finish the release manually."
git branch -d "release/${version}" || fail "unable to delete the branch release/${version}."
printf "\n================================================================================\n"
read -r -p "Done, push the branch 'main' and the new tag (yes/no) default to yes? " doPush
doPush=${doPush:-yes}
if [ "${doPush}" == "yes" ]; then
printf "Pushing branch 'main' and tag 'v%s'...\n" "${version}"
git push origin main
git push origin "v${version}"
else
printf "Not pushing, do not forget to push manually!\n"
fi
printf "\n================================================================================\n"
printf "Checking out develop...\n"
git checkout develop
printf "\n================================================================================\n"
printf "Downloading the artifacts...\n"
targetPath="./tmp/Element/${version}"
fdroidTargetPath="${targetPath}/fdroid"
gplayTargetPath="${targetPath}/gplay"
releaseCommit=$(git rev-parse --verify --quiet "v${version}^{commit}")
if [[ -z "${releaseCommit}" ]]; then
# Without a commit, `gh run list` would return the latest run of the workflow, which may be another one.
printf "Fatal: the tag v%s cannot be resolved.\n" "${version}"
exit 1
fi
printf "Looking for the run of the workflow release.yml for the commit %s...\n" "${releaseCommit}"
runId=""
# The run can take a few seconds to appear after the push, so retry for a couple of minutes.
for _ in $(seq 1 12); do
runId=$(gh run list --repo element-hq/element-x-android --workflow release.yml --commit "${releaseCommit}" --limit 1 --json databaseId -q '.[0].databaseId' 2> /dev/null)
if [[ -n "${runId}" ]]; then
break
fi
printf "No run found yet, waiting...\n"
sleep 10
done
if [[ -z "${runId}" ]]; then
printf "Fatal: no run of the workflow release.yml found for the commit %s.\n" "${releaseCommit}"
exit 1
fi
printf "Found the run https://github.com/element-hq/element-x-android/actions/runs/%s\n" "${runId}"
printf "Waiting for the run to complete...\n"
gh run watch "${runId}" --repo element-hq/element-x-android --compact --exit-status
ret=1
while [[ $ret -ne 0 ]]; do
gh run download "${runId}" --repo element-hq/element-x-android \
--dir "${gplayTargetPath}" \
--name elementx-app-gplay-bundle-unsigned
ret=$?
if [[ $ret -eq 0 ]]; then
gh run download "${runId}" --repo element-hq/element-x-android \
--dir "${fdroidTargetPath}" \
--name elementx-app-fdroid-apks-unsigned
ret=$?
fi
if [[ $ret -ne 0 ]]; then
read -r -p "Error while downloading the artifacts. You may want to fix the issue and retry. Retry (yes/no) default to yes? " doRetry
doRetry=${doRetry:-yes}
if [ "${doRetry}" == "no" ]; then
exit 1
fi
fi
done
printf "\n================================================================================\n"
printf "Signing the FDroid APKs...\n"
cp "${fdroidTargetPath}"/app-fdroid-arm64-v8a-release.apk \
"${fdroidTargetPath}"/app-fdroid-arm64-v8a-release-signed.apk
"${buildToolsPath}"/apksigner sign \
-v \
--alignment-preserved true \
--ks "${keyStorePath}" \
--ks-pass pass:"${keyStorePassword}" \
--ks-key-alias elementx \
--key-pass pass:"${keyPassword}" \
--min-sdk-version "${minSdkVersion}" \
"${fdroidTargetPath}"/app-fdroid-arm64-v8a-release-signed.apk
cp "${fdroidTargetPath}"/app-fdroid-armeabi-v7a-release.apk \
"${fdroidTargetPath}"/app-fdroid-armeabi-v7a-release-signed.apk
"${buildToolsPath}"/apksigner sign \
-v \
--alignment-preserved true \
--ks "${keyStorePath}" \
--ks-pass pass:"${keyStorePassword}" \
--ks-key-alias elementx \
--key-pass pass:"${keyPassword}" \
--min-sdk-version "${minSdkVersion}" \
"${fdroidTargetPath}"/app-fdroid-armeabi-v7a-release-signed.apk
cp "${fdroidTargetPath}"/app-fdroid-x86-release.apk \
"${fdroidTargetPath}"/app-fdroid-x86-release-signed.apk
"${buildToolsPath}"/apksigner sign \
-v \
--alignment-preserved true \
--ks "${keyStorePath}" \
--ks-pass pass:"${keyStorePassword}" \
--ks-key-alias elementx \
--key-pass pass:"${keyPassword}" \
--min-sdk-version "${minSdkVersion}" \
"${fdroidTargetPath}"/app-fdroid-x86-release-signed.apk
cp "${fdroidTargetPath}"/app-fdroid-x86_64-release.apk \
"${fdroidTargetPath}"/app-fdroid-x86_64-release-signed.apk
"${buildToolsPath}"/apksigner sign \
-v \
--alignment-preserved true \
--ks "${keyStorePath}" \
--ks-pass pass:"${keyStorePassword}" \
--ks-key-alias elementx \
--key-pass pass:"${keyPassword}" \
--min-sdk-version "${minSdkVersion}" \
"${fdroidTargetPath}"/app-fdroid-x86_64-release-signed.apk
printf "\n================================================================================\n"
printf "Checking the signed APKs...\n"
checkError=0
# Each APK gets the version code of the app bundle, plus the code of its ABI.
# Must be kept in sync with the abiVersionCodes map in app/build.gradle.kts.
fdroidAbis="armeabi-v7a:1 arm64-v8a:2 x86:3 x86_64:4"
for abiEntry in ${fdroidAbis}; do
abi="${abiEntry%%:*}"
abiCode="${abiEntry##*:}"
expectedApkVersionCode=$((versionCode + abiCode))
apkFile="${fdroidTargetPath}/app-fdroid-${abi}-release-signed.apk"
apkBadging=$("${buildToolsPath}"/aapt dump badging "${apkFile}" | grep -m 1 "^package")
apkVersionCode=$(printf "%s" "${apkBadging}" | sed -n "s/.*versionCode='\([0-9]*\)'.*/\1/p")
apkVersionName=$(printf "%s" "${apkBadging}" | sed -n "s/.*versionName='\([^']*\)'.*/\1/p")
printf "File app-fdroid-%s-release-signed.apk: version code %s, version name %s\n" "${abi}" "${apkVersionCode}" "${apkVersionName}"
if [[ "${apkVersionCode}" != "${expectedApkVersionCode}" ]]; then
printf "Warning: was expecting the version code %s, but got %s.\n" "${expectedApkVersionCode}" "${apkVersionCode}"
checkError=1
fi
if [[ "${apkVersionName}" != "${version}" ]]; then
printf "Warning: was expecting the version name %s, but got %s.\n" "${version}" "${apkVersionName}"
checkError=1
fi
done
checkVersionResult
printf "\n================================================================================\n"
printf "The APKs in %s have been signed!\n" "${fdroidTargetPath}"
unsignedBundlePath="${gplayTargetPath}/app-gplay-release.aab"
signedBundlePath="${gplayTargetPath}/app-gplay-release-signed.aab"
# The universal APK is downloaded manually from the GooglePlay console, and is named after the version code.
universalApkPath="${gplayTargetPath}/${versionCode}.apk"
printf "\n================================================================================\n"
printf "Signing file %s with build-tools version %s for min SDK version %s...\n" "${unsignedBundlePath}" "${buildToolsVersion}" "${minSdkVersion}"
cp "${unsignedBundlePath}" "${signedBundlePath}"
"${buildToolsPath}"/apksigner sign \
-v \
--ks "${keyStorePath}" \
--ks-pass pass:"${keyStorePassword}" \
--ks-key-alias elementx \
--key-pass pass:"${keyPassword}" \
--min-sdk-version "${minSdkVersion}" \
"${signedBundlePath}"
printf "\n================================================================================\n"
printf "Checking the signed app bundle...\n"
checkError=0
bundleVersionCode=$(bundletool dump manifest --bundle="${signedBundlePath}" --xpath=/manifest/@android:versionCode)
bundleVersionName=$(bundletool dump manifest --bundle="${signedBundlePath}" --xpath=/manifest/@android:versionName)
printf "File %s: version code %s, version name %s\n" "$(basename "${signedBundlePath}")" "${bundleVersionCode}" "${bundleVersionName}"
if [[ "${bundleVersionCode}" != "${versionCode}" ]]; then
printf "Warning: was expecting the version code %s, but got %s.\n" "${versionCode}" "${bundleVersionCode}"
checkError=1
fi
if [[ "${bundleVersionName}" != "${version}" ]]; then
printf "Warning: was expecting the version name %s, but got %s.\n" "${version}" "${bundleVersionName}"
checkError=1
fi
checkVersionResult
printf "\n================================================================================\n"
printf "The file %s has been signed and can be uploaded to the PlayStore!\n" "${signedBundlePath}"
printf "\n================================================================================\n"
read -r -p "Do you want to build the APKs from the app bundle? You need to do this step if you want to install the application to your device. (yes/no) default to no " doBuildApks
doBuildApks=${doBuildApks:-no}
if [ "${doBuildApks}" == "yes" ]; then
printf "Building apks...\n"
bundletool build-apks --bundle="${signedBundlePath}" --output="${gplayTargetPath}"/elementx.apks \
--ks=./app/signature/debug.keystore --ks-pass=pass:android --ks-key-alias=androiddebugkey --key-pass=pass:android \
--overwrite
read -r -p "Do you want to install the application to your device? Make sure there is one (and only one!) connected device first. (yes/no) default to yes " doDeploy
doDeploy=${doDeploy:-yes}
if [ "${doDeploy}" == "yes" ]; then
printf "Installing apk for your device...\n"
bundletool install-apks --apks="${gplayTargetPath}"/elementx.apks
read -r -p "Please run the application on your phone to check that the upgrade went well. Press enter to continue. "
else
printf "APK will not be deployed!\n"
fi
else
printf "APKs will not be generated!\n"
fi
printf "\n================================================================================\n"
printf "Create the open testing release on GooglePlay.\n"
printf "On GooglePlay console, go the the open testing section and click on \"Create new release\" button, then:\n"
printf " - upload the file %s.\n" "${signedBundlePath}"
printf " - copy the release note from the fastlane file.\n"
printf " - download the universal APK, to be able to provide it to the GitHub release: click on the right arrow next to the \"App bundle\", then click on the \"Download\" tab, and download the \"Signed, universal APK\". Save it, without renaming it, to the folder %s. The expected final path is %s\n" "${gplayTargetPath}" "${universalApkPath}"
printf " - submit the release.\n"
read -r -p "Press enter to continue. "
printf "You can then go to \"Publishing overview\" and send the new release for a review by Google.\n"
read -r -p "Press enter to continue. "
printf "\n================================================================================\n"
printf "Creating the release on GitHub.\n"
releaseAssets=(
"${signedBundlePath}"
"${universalApkPath}"
"${fdroidTargetPath}/app-fdroid-arm64-v8a-release-signed.apk"
"${fdroidTargetPath}/app-fdroid-armeabi-v7a-release-signed.apk"
"${fdroidTargetPath}/app-fdroid-x86-release-signed.apk"
"${fdroidTargetPath}/app-fdroid-x86_64-release-signed.apk"
)
# Set this variable to something other than 0 to enter the loop, and reset it to 0 when all files are found.
missingAsset=-1
while [[ ${missingAsset} -ne 0 ]]; do
missingAsset=0
for releaseAsset in "${releaseAssets[@]}"; do
if [[ ! -f "${releaseAsset}" ]]; then
printf "Error: the file %s does not exist.\n" "${releaseAsset}"
missingAsset=1
fi
done
if [[ ${missingAsset} -ne 0 ]]; then
read -r -p "Some files are missing, please fix the issue and press enter to retry. Press Ctrl+C to exit. "
fi
done
printf "Creating the pre-release v%s and uploading the %d files, this can take a while...\n" "${version}" "${#releaseAssets[@]}"
gh release create "v${version}" \
--repo element-hq/element-x-android \
--title "Element X Android v${version}" \
--generate-notes \
--prerelease \
--verify-tag \
"${releaseAssets[@]}"
if [[ $? -ne 0 ]]; then
printf "Fatal: error while creating the GitHub release.\n"
exit 1
fi
printf "The pre-release has been created: https://github.com/element-hq/element-x-android/releases/tag/v%s\n" "${version}"
printf "Please check the generated release notes, and optionally reorder items and fix typos.\n"
read -r -p "Press enter to continue. "
printf "\n================================================================================\n"
printf "Update the project release notes:\n\n"
printf "Getting the release notes from GitHub...\n"
releaseNotes=$(gh release view "v${version}" --repo element-hq/element-x-android --json body -q .body)
if [[ $? -ne 0 || -z "${releaseNotes}" ]]; then
printf "Fatal: error while getting the release notes from GitHub.\n"
exit 1
fi
# GitHub returns the release notes with CRLF line endings, remove the CR.
releaseNotes="${releaseNotes//$'\r'/}"
changesTitle="Changes in Element X v${version}"
# Underline the title with as many '=' as there are characters in the title.
changesUnderline="${changesTitle//?/=}"
changesFile="./CHANGES.md"
changesFileBak="${changesFile}.bak"
mv "${changesFile}" "${changesFileBak}"
{
printf "%s\n%s\n\n" "${changesTitle}" "${changesUnderline}"
printf "%s\n\n" "${releaseNotes}"
cat "${changesFileBak}"
} > "${changesFile}"
rm "${changesFileBak}"
printf "The file CHANGES.md has been updated.\n"
read -r -p "Please check the change and press enter to commit it. "
printf "\n================================================================================\n"
printf "Committing...\n"
git commit -a -m "Changelog for version ${version}"
printf "\n================================================================================\n"
read -r -p "Done, push the branch 'develop' (yes/no) default to yes? (A rebase may be necessary in case develop got new commits) " doPush
doPush=${doPush:-yes}
if [ "${doPush}" == "yes" ]; then
printf "Pushing branch 'develop'...\n"
git push origin develop
else
printf "Not pushing, do not forget to push manually!\n"
fi
printf "\n================================================================================\n"
printf "Message for the Android internal room:\n\n"
message="@room Element X Android ${version} is ready to be tested. You can get it from https://github.com/element-hq/element-x-android/releases/tag/v${version}. You can install the universal APK. If you want to install the application from the app bundle, you can follow instructions [here](https://github.com/element-hq/element-x-android/blob/develop/docs/install_from_github_release.md). Please report any feedback. Thanks!"
printf "%s\n\n" "${message}"
if [[ -z "${elementBotToken}" ]]; then
read -r -p "ELEMENT_BOT_MATRIX_TOKEN is not defined in the environment. Cannot send the message for you. Please send it manually, and press enter to continue. "
else
read -r -p "Send this message to the room (yes/no) default to yes? " doSend
doSend=${doSend:-yes}
if [ "${doSend}" == "yes" ]; then
printf "Sending message...\n"
transactionId=$(openssl rand -hex 16)
# Element Android internal
matrixRoomId="!LiSLXinTDCsepePiYW:matrix.org"
curl -X PUT --data "{\"msgtype\":\"m.text\",\"body\":\"${message}\"}" -H "Authorization: Bearer ${elementBotToken}" https://matrix-client.matrix.org/_matrix/client/r0/rooms/${matrixRoomId}/send/m.room.message/\$local."${transactionId}"
else
printf "Message not sent, please send it manually!\n"
fi
fi
printf "\n================================================================================\n"
printf "Congratulation! Kudos for using this script! Have a nice day!\n"
printf "================================================================================\n"