From 62477d8c65385dcbcc8c0da759b1105bcc1d28a2 Mon Sep 17 00:00:00 2001
From: Dirk Hohndel <dirk@hohndel.org>
Date: Thu, 4 Jan 2024 20:44:31 -0800
Subject: [PATCH] Complete redesign of Subsurface version numbers

- for now all versions start with v6.0
- CICD builds use the monolithic build number as patch level, e.g. v6.0.12345
- local builds use the following algorithm
  - find the newest commit with a CICD build number that is included in the
    working tree
  - count the number of commits in the working tree since that commit
  - if there are no commits since the last CICD build, the local build version
    will be v6.0.12345-local
  - if there are N commits since the last CICD build, it will be
    v6.0.12345-N-local
- test builds in the CICD that don't create artifacts simply use a dummy release
  in order to not incorrectly increment the build number and also not to waste
  time and resources by manually checking out the nightly-build repo for each of
  these builds.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
---
 .github/workflows/android.yml                 |  21 +--
 .github/workflows/coverity-scan.yml           |   2 +-
 .github/workflows/fedora-copr-build.yml       |  21 ++-
 .github/workflows/ios.yml                     |   9 ++
 .../workflows/linux-bionic-5.9.yml.disabled   |   5 +
 .github/workflows/linux-fedora-qt6.yml        |   5 +
 .github/workflows/linux-focal-5.12.yml        |   5 +
 .github/workflows/linux-jammy-5.15.yml        |   5 +
 .github/workflows/linux-snap.yml              |  26 ++++
 .github/workflows/linux-trusty-5.12.yml       |  57 ++++++++
 .github/workflows/mac.yml                     |  22 +--
 .../scripts/linux-in-container-build.sh       |   2 +-
 .github/workflows/ubuntu-launchpad-build.yml  |  19 +++
 .github/workflows/windows.yml                 |  21 +--
 CMakeLists.txt                                |   2 +-
 cmake/Modules/HandleVersionGeneration.cmake   |   4 +-
 cmake/Modules/version.cmake                   |  19 ++-
 core/version.c                                |   3 +-
 packaging/android/qmake-build.sh              |   6 +-
 packaging/ios/build.sh                        |   8 +-
 packaging/macosx/make-package.sh              |   2 +-
 packaging/windows/create-win-installer.sh     |   2 +-
 scripts/get-version                           | 136 +++++++++---------
 smtk-import/cmake/Modules/version.cmake       |  19 +--
 24 files changed, 295 insertions(+), 126 deletions(-)

diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml
index a5c3dc857..bc2862e6f 100644
--- a/.github/workflows/android.yml
+++ b/.github/workflows/android.yml
@@ -18,7 +18,7 @@ jobs:
       uses: actions/checkout@v1
 
     - name: atomically create or retrieve the build number
-      id: build_nr
+      id: version_number
       if: github.event_name == 'push'
       run: |
         cd .. # check out parallel to subsurface sources
@@ -31,6 +31,16 @@ jobs:
         git push origin main
         cd ..
         bash -x subsurface/scripts/get-or-create-build-nr.sh ${{ github.sha }}
+        cp nightly-builds/latest-subsurface-buildnumber subsurface
+        echo "CICD-release" > subsurface/latest-subsurface-buildnumber-extension
+        version=$(bash subsurface/scripts/get-version)
+        echo "version=$version" >> $GITHUB_OUTPUT
+
+    - name: store dummy version and build number for pull request
+      if: github.event_name == 'pull_request'
+      run: |
+        echo "100" > latest-subsurface-buildnumber
+        echo "CICD-pull-request" > latest-subsurface-buildnumber-extension
 
     - name: run build
       id: build
@@ -59,15 +69,6 @@ jobs:
         curl -q https://raw.githubusercontent.com/subsurface/nightly-builds/main/latest-subsurface-buildnumber > buildnr.dat
         OUTPUT_DIR=$GITHUB_WORKSPACE bash -x ./subsurface/packaging/android/qmake-build.sh
 
-    - name: create version number
-      id: version_number
-      if: github.event_name == 'push'
-      run: |
-        gitversion=$(bash scripts/get-version win)
-        latest=$(cat ../nightly-builds/latest-subsurface-buildnumber)
-        version="$gitversion-$latest"
-        echo "version=$version" >> $GITHUB_OUTPUT
-
     # only publish a 'release' on push events (those include merging a PR)
     - name: upload binaries
       if: github.event_name == 'push'
diff --git a/.github/workflows/coverity-scan.yml b/.github/workflows/coverity-scan.yml
index c0236d998..788af6313 100644
--- a/.github/workflows/coverity-scan.yml
+++ b/.github/workflows/coverity-scan.yml
@@ -44,5 +44,5 @@ jobs:
         email: glance@acc.umu.se
         command: subsurface/scripts/build.sh -desktop -build-with-webkit
         working-directory: ${{ github.workspace }}/..
-        version: $(/scripts/get-version linux)
+        version: $(/scripts/get-version)
         description: Automatic scan on github actions
diff --git a/.github/workflows/fedora-copr-build.yml b/.github/workflows/fedora-copr-build.yml
index d5f813098..749b68dc6 100644
--- a/.github/workflows/fedora-copr-build.yml
+++ b/.github/workflows/fedora-copr-build.yml
@@ -15,6 +15,25 @@ jobs:
     - name: Check out sources
       uses: actions/checkout@v1
 
+    - name: atomically create or retrieve the build number
+      id: version_number
+      if: github.event_name == 'push'
+      run: |
+        cd .. # check out parallel to subsurface sources
+        url="https://subsurface:${{ secrets.NIGHTLY_BUILDS }}@github.com/subsurface/nightly-builds"
+        # the clone followed by the pointless push should verify that the password is stored in the config
+        # that way the script doesn't need the password
+        git clone -b main https://github.com/subsurface/nightly-builds
+        cd nightly-builds
+        git remote set-url origin "$url"
+        git push origin main
+        cd ..
+        bash -x subsurface/scripts/get-or-create-build-nr.sh ${{ github.sha }}
+        cp nightly-builds/latest-subsurface-buildnumber subsurface
+        echo "CICD-release" > subsurface/latest-subsurface-buildnumber-extension
+        version=$(bash subsurface/scripts/get-version)
+        echo "version=$version" >> $GITHUB_OUTPUT
+
     - name: Setup API token for copr-cli
       env:
         API_TOKEN: ${{ secrets.COPR_TOKEN }}
@@ -43,4 +62,4 @@ jobs:
       run: |
         cd ..
         bash -x subsurface/packaging/copr/make-package.sh post
-          
+
diff --git a/.github/workflows/ios.yml b/.github/workflows/ios.yml
index 4c1019452..dc2af03fa 100644
--- a/.github/workflows/ios.yml
+++ b/.github/workflows/ios.yml
@@ -13,16 +13,25 @@ jobs:
     steps:
     - name: switch to Xcode 11
       run: sudo xcode-select -s "/Applications/Xcode_11.7.app"
+
     - name: checkout sources
       uses: actions/checkout@v1
+
     - name: setup Homebrew
       run: brew install autoconf automake libtool pkg-config
+
     - name: set our Qt build
       run: |
         env
         curl -L --output Qt-5.14.1-ios.tar.xz https://f002.backblazeb2.com/file/Subsurface-Travis/Qt-5.14.1-ios.tar.xz
         mkdir -p $HOME/Qt
         xzcat Qt-5.14.1-ios.tar.xz | tar -x -C $HOME/Qt -f -
+
+    - name: store dummy version and build number for test build
+      run: |
+        echo "100" > latest-subsurface-buildnumber
+        echo "CICD-test-build" > latest-subsurface-buildnumber-extension
+
     - name: build Subsurface-mobile for iOS
       env:
          SUBSURFACE_REPO_PATH: ${{ github.workspace }}
diff --git a/.github/workflows/linux-bionic-5.9.yml.disabled b/.github/workflows/linux-bionic-5.9.yml.disabled
index e8dca3a3c..702cc7f7d 100644
--- a/.github/workflows/linux-bionic-5.9.yml.disabled
+++ b/.github/workflows/linux-bionic-5.9.yml.disabled
@@ -31,6 +31,11 @@ jobs:
         qtpositioning5-dev qtscript5-dev qttools5-dev qttools5-dev-tools \
         qtquickcontrols2-5-dev xvfb libbluetooth-dev libmtp-dev
 
+    - name: store dummy version and build number for pull request
+      if: github.event_name == 'pull_request'
+      run: |
+        echo "6.0.100" > latest-subsurface-buildnumber
+
     - name: build Subsurface
       env:
          SUBSURFACE_REPO_PATH: ${{ github.workspace }}
diff --git a/.github/workflows/linux-fedora-qt6.yml b/.github/workflows/linux-fedora-qt6.yml
index 5b8d10820..a17e90e49 100644
--- a/.github/workflows/linux-fedora-qt6.yml
+++ b/.github/workflows/linux-fedora-qt6.yml
@@ -33,6 +33,11 @@ jobs:
         bluez-libs-devel libgit2-devel libzip-devel libmtp-devel \
         xorg-x11-server-Xvfb
 
+    - name: store dummy version and build number for test build
+      run: |
+        echo "100" > latest-subsurface-buildnumber
+        echo "CICD-test-build" > latest-subsurface-buildnumber-extension
+
     - name: build Subsurface
       env:
          SUBSURFACE_REPO_PATH: ${{ github.workspace }}
diff --git a/.github/workflows/linux-focal-5.12.yml b/.github/workflows/linux-focal-5.12.yml
index 8676b50d4..0ff14b896 100644
--- a/.github/workflows/linux-focal-5.12.yml
+++ b/.github/workflows/linux-focal-5.12.yml
@@ -35,6 +35,11 @@ jobs:
         qtpositioning5-dev qtscript5-dev qttools5-dev qttools5-dev-tools \
         qtquickcontrols2-5-dev xvfb libbluetooth-dev libmtp-dev
 
+    - name: store dummy version and build number for test build
+      run: |
+        echo "100" > latest-subsurface-buildnumber
+        echo "CICD-test-build" > latest-subsurface-buildnumber-extension
+
     - name: build Subsurface-mobile
       env:
          SUBSURFACE_REPO_PATH: ${{ github.workspace }}
diff --git a/.github/workflows/linux-jammy-5.15.yml b/.github/workflows/linux-jammy-5.15.yml
index 4091fc13a..140e40b61 100644
--- a/.github/workflows/linux-jammy-5.15.yml
+++ b/.github/workflows/linux-jammy-5.15.yml
@@ -35,6 +35,11 @@ jobs:
         qtpositioning5-dev qtscript5-dev qttools5-dev qttools5-dev-tools \
         qtquickcontrols2-5-dev xvfb libbluetooth-dev libmtp-dev
 
+    - name: store dummy version and build number for test build
+      run: |
+        echo "100" > latest-subsurface-buildnumber
+        echo "CICD-test-build" > latest-subsurface-buildnumber-extension
+
     - name: build Subsurface-mobile
       env:
          SUBSURFACE_REPO_PATH: ${{ github.workspace }}
diff --git a/.github/workflows/linux-snap.yml b/.github/workflows/linux-snap.yml
index 95fa8c98b..badd89d44 100644
--- a/.github/workflows/linux-snap.yml
+++ b/.github/workflows/linux-snap.yml
@@ -20,6 +20,31 @@ jobs:
         # Needed for version determination to work
         fetch-depth: 0
 
+    - name: atomically create or retrieve the build number
+      id: version_number
+      if: github.event_name == 'push'
+      run: |
+        cd .. # check out parallel to subsurface sources
+        url="https://subsurface:${{ secrets.NIGHTLY_BUILDS }}@github.com/subsurface/nightly-builds"
+        # the clone followed by the pointless push should verify that the password is stored in the config
+        # that way the script doesn't need the password
+        git clone -b main https://github.com/subsurface/nightly-builds
+        cd nightly-builds
+        git remote set-url origin "$url"
+        git push origin main
+        cd ..
+        bash -x subsurface/scripts/get-or-create-build-nr.sh ${{ github.sha }}
+        cp nightly-builds/latest-subsurface-buildnumber subsurface
+        echo "CICD-release" > subsurface/latest-subsurface-buildnumber-extension
+        version=$(bash subsurface/scripts/get-version)
+        echo "version=$version" >> $GITHUB_OUTPUT
+
+    - name: store dummy version and build number for pull request
+      if: github.event_name == 'pull_request'
+      run: |
+        echo "100" > latest-subsurface-buildnumber
+        echo "CICD-pull-request" > latest-subsurface-buildnumber-extension
+
     - name: Set up LXD
       uses: canonical/setup-lxd@main
 
@@ -56,6 +81,7 @@ jobs:
       run: ccache --show-stats --zero-stats
 
     - name: Upload the snap
+      if: github.event_name == 'push'
       uses: actions/upload-artifact@v2
       with:
         name: ${{ steps.build-snap.outputs.snap-name }}
diff --git a/.github/workflows/linux-trusty-5.12.yml b/.github/workflows/linux-trusty-5.12.yml
index 4c2eea091..f0148054d 100644
--- a/.github/workflows/linux-trusty-5.12.yml
+++ b/.github/workflows/linux-trusty-5.12.yml
@@ -17,6 +17,31 @@ jobs:
     - name: checkout sources
       uses: actions/checkout@v1
 
+    - name: atomically create or retrieve the build number
+      id: version_number
+      if: github.event_name == 'push'
+      run: |
+        cd .. # check out parallel to subsurface sources
+        url="https://subsurface:${{ secrets.NIGHTLY_BUILDS }}@github.com/subsurface/nightly-builds"
+        # the clone followed by the pointless push should verify that the password is stored in the config
+        # that way the script doesn't need the password
+        git clone -b main https://github.com/subsurface/nightly-builds
+        cd nightly-builds
+        git remote set-url origin "$url"
+        git push origin main
+        cd ..
+        bash -x subsurface/scripts/get-or-create-build-nr.sh ${{ github.sha }}
+        cp nightly-builds/latest-subsurface-buildnumber subsurface
+        echo "CICD-release" > subsurface/latest-subsurface-buildnumber-extension
+        version=$(bash subsurface/scripts/get-version)
+        echo "version=$version" >> $GITHUB_OUTPUT
+
+    - name: store dummy version and build number for pull request
+      if: github.event_name == 'pull_request'
+      run: |
+        echo "100" > latest-subsurface-buildnumber
+        echo "CICD-pull-request" > latest-subsurface-buildnumber-extension
+
     - name: run build
       env:
          SUBSURFACE_REPO_PATH: ${{ github.workspace }}
@@ -39,3 +64,35 @@ jobs:
       with:
         name: Linux-artifacts
         path: Linux-artifacts
+
+    - name: prepare release artifacts
+      if: github.event_name == 'push'
+      run: |
+        mv Subsurface.AppImage Subsurface-v${{ steps.version_number.outputs.version }}.AppImage
+
+    # only publish a 'release' on push events (those include merging a PR)
+    - name: upload binaries
+      if: github.event_name == 'push'
+      uses: softprops/action-gh-release@v1
+      with:
+        tag_name: v${{ steps.version_number.outputs.version }}
+        repository: subsurface/nightly-builds
+        token: ${{ secrets.NIGHTLY_BUILDS }}
+        prerelease: false
+        fail_on_unmatched_files: true
+        files: |
+         ./Subsurface*.AppImage
+        body: |
+          CICD release artifact
+
+          These builds are created on every merge or push into the [Subsurface repo](http://github.com/subsurface/subsurface).
+          This build is based on http://github.com/subsurface/subsurface/commit/${{ github.sha }}
+
+          None of these artifacts are signed.
+          The Android APK can be side-loaded on most Android devices. If you had a previous Subsurface-mobile version installed from the Google Play store, you'll have to uninstall that first.
+          The Windows installer will ask you to confirm installation of an app from an unknown developer.
+          The macOS DMG makes it even harder with a multi-step dance that requires opening the Privacy & Security settings in the System Preferences and explicitly confirming that you are willing to install this app.
+
+          You can find similar Subsurface-Daily builds for [Ubuntu](https://ppa.launchpadcontent.net/subsurface) and Subsurface-test for [Fedora](https://copr.fedorainfracloud.org/coprs/dirkhh/Subsurface-test).
+
+          Please report any issues with these builds in the [Subsurface user forum](https://groups.google.com/g/subsurface-divelog).
diff --git a/.github/workflows/mac.yml b/.github/workflows/mac.yml
index ebe208465..098eef2fb 100644
--- a/.github/workflows/mac.yml
+++ b/.github/workflows/mac.yml
@@ -13,8 +13,9 @@ jobs:
     steps:
     - name: checkout sources
       uses: actions/checkout@v1
+
     - name: atomically create or retrieve the build number
-      id: build_nr
+      id: version_number
       if: github.event_name == 'push'
       run: |
         cd .. # check out parallel to subsurface sources
@@ -27,6 +28,16 @@ jobs:
         git push origin main
         cd ..
         bash -x subsurface/scripts/get-or-create-build-nr.sh ${{ github.sha }}
+        cp nightly-builds/latest-subsurface-buildnumber subsurface
+        echo "CICD-release" > subsurface/latest-subsurface-buildnumber-extension
+        version=$(bash subsurface/scripts/get-version)
+        echo "version=$version" >> $GITHUB_OUTPUT
+
+    - name: store dummy version and build number for pull request
+      if: github.event_name == 'pull_request'
+      run: |
+        echo "100" > latest-subsurface-buildnumber
+        echo "CICD-pull-request" > latest-subsurface-buildnumber-extension
 
     - name: setup Homebrew
       run: brew install hidapi libxslt libjpg libmtp create-dmg confuse
@@ -55,15 +66,6 @@ jobs:
         echo "Created $IMG"
         echo "dmg=$IMG" >> $GITHUB_OUTPUT
 
-    - name: create version number
-      id: version_number
-      if: github.event_name == 'push'
-      run: |
-        gitversion=$(bash scripts/get-version win)
-        latest=$(cat ../nightly-builds/latest-subsurface-buildnumber)
-        version="$gitversion-$latest"
-        echo "version=$version" >> $GITHUB_OUTPUT
-
     # only publish a 'release' on push events (those include merging a PR)
     - name: upload binaries
       if: github.event_name == 'push'
diff --git a/.github/workflows/scripts/linux-in-container-build.sh b/.github/workflows/scripts/linux-in-container-build.sh
index 3921852f4..8e63aacdc 100644
--- a/.github/workflows/scripts/linux-in-container-build.sh
+++ b/.github/workflows/scripts/linux-in-container-build.sh
@@ -49,7 +49,7 @@ unset LD_LIBRARY_PATH
 ./linuxdeployqt*.AppImage --appimage-extract-and-run ./appdir/usr/share/applications/*.desktop -exclude-libs=libdbus-1.so.3 -bundle-non-qt-libs -qmldir=./subsurface/stats -qmldir=./subsurface/map-widget/ -verbose=2
 
 # create the AppImage
-export VERSION=$(cd subsurface/scripts ; ./get-version linux) # linuxdeployqt uses this for naming the file
+export VERSION=$(cd subsurface/scripts ; ./get-version) # linuxdeployqt uses this for naming the file
 ./linuxdeployqt*.AppImage --appimage-extract-and-run ./appdir/usr/share/applications/*.desktop -exclude-libs=libdbus-1.so.3 -appimage -qmldir=./subsurface/stats -qmldir=./subsurface/map-widget/ -verbose=2
 
 # copy AppImage to the calling VM
diff --git a/.github/workflows/ubuntu-launchpad-build.yml b/.github/workflows/ubuntu-launchpad-build.yml
index 700632288..533ab21f5 100644
--- a/.github/workflows/ubuntu-launchpad-build.yml
+++ b/.github/workflows/ubuntu-launchpad-build.yml
@@ -14,6 +14,25 @@ jobs:
     - name: Check out sources
       uses: actions/checkout@v1
 
+    - name: atomically create or retrieve the build number
+      id: version_number
+      if: github.event_name == 'push'
+      run: |
+        cd .. # check out parallel to subsurface sources
+        url="https://subsurface:${{ secrets.NIGHTLY_BUILDS }}@github.com/subsurface/nightly-builds"
+        # the clone followed by the pointless push should verify that the password is stored in the config
+        # that way the script doesn't need the password
+        git clone -b main https://github.com/subsurface/nightly-builds
+        cd nightly-builds
+        git remote set-url origin "$url"
+        git push origin main
+        cd ..
+        bash -x subsurface/scripts/get-or-create-build-nr.sh ${{ github.sha }}
+        cp nightly-builds/latest-subsurface-buildnumber subsurface
+        echo "CICD-release" > subsurface/latest-subsurface-buildnumber-extension
+        version=$(bash subsurface/scripts/get-version)
+        echo "version=$version" >> $GITHUB_OUTPUT
+
     - name: Setup build dependencies
       run: |
         sudo apt-get update
diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml
index ce20f0f07..e3ec8f969 100644
--- a/.github/workflows/windows.yml
+++ b/.github/workflows/windows.yml
@@ -18,7 +18,7 @@ jobs:
       uses: actions/checkout@v1
 
     - name: atomically create or retrieve the build number
-      id: build_nr
+      id: version_number
       if: github.event_name == 'push'
       run: |
         cd .. # check out parallel to subsurface sources
@@ -31,6 +31,16 @@ jobs:
         git push origin main
         cd ..
         bash -x subsurface/scripts/get-or-create-build-nr.sh ${{ github.sha }}
+        cp nightly-builds/latest-subsurface-buildnumber subsurface
+        echo "CICD-release" > subsurface/latest-subsurface-buildnumber-extension
+        version=$(bash subsurface/scripts/get-version)
+        echo "version=$version" >> $GITHUB_OUTPUT
+
+    - name: store dummy version and build number for pull request
+      if: github.event_name == 'pull_request'
+      run: |
+        echo "100" > latest-subsurface-buildnumber
+        echo "CICD-pull-request" > latest-subsurface-buildnumber-extension
 
     - name: get other dependencies
       env:
@@ -49,15 +59,6 @@ jobs:
         bash -x subsurface/.github/workflows/scripts/windows-in-container-build.sh 2>&1 | tee build.log
         grep "Built target installer" build.log
 
-    - name: create version number
-      id: version_number
-      if: github.event_name == 'push'
-      run: |
-        gitversion=$(bash scripts/get-version win)
-        latest=$(cat ../nightly-builds/latest-subsurface-buildnumber)
-        version="$gitversion-$latest"
-        echo "version=$version" >> $GITHUB_OUTPUT
-
     # only publish a 'release' on push events (those include merging a PR)
     - name: upload binaries
       if: github.event_name == 'push'
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3ffd6dd36..cac18e93e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -320,7 +320,7 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
 	endif()
 elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
 	execute_process(
-		COMMAND sh scripts/get-version linux
+		COMMAND bash scripts/get-version
 		WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
 		OUTPUT_VARIABLE SSRF_VERSION_STRING
 		OUTPUT_STRIP_TRAILING_WHITESPACE
diff --git a/cmake/Modules/HandleVersionGeneration.cmake b/cmake/Modules/HandleVersionGeneration.cmake
index 4ef42e71f..25065841c 100644
--- a/cmake/Modules/HandleVersionGeneration.cmake
+++ b/cmake/Modules/HandleVersionGeneration.cmake
@@ -1,7 +1,7 @@
 # Generate the ssrf-config.h every 'make'
 file(WRITE ${CMAKE_BINARY_DIR}/version.h.in
-"#define GIT_VERSION_STRING \"@GIT_VERSION_STRING@\"
-#define CANONICAL_VERSION_STRING \"@CANONICAL_VERSION_STRING@\"
+"#define CANONICAL_VERSION_STRING \"@CANONICAL_VERSION_STRING@\"
+#define CANONICAL_VERSION_STRING_4 \"@CANONICAL_VERSION_STRING_4@\"
 ")
 
 file(COPY cmake/Modules/version.cmake
diff --git a/cmake/Modules/version.cmake b/cmake/Modules/version.cmake
index 2fc011ffd..aa762c128 100644
--- a/cmake/Modules/version.cmake
+++ b/cmake/Modules/version.cmake
@@ -1,11 +1,20 @@
+
 execute_process(
-	COMMAND sh ${CMAKE_TOP_SRC_DIR}/scripts/get-version linux
+	COMMAND bash ${CMAKE_TOP_SRC_DIR}/scripts/get-version 4
 	WORKING_DIRECTORY ${CMAKE_TOP_SRC_DIR}
-	OUTPUT_VARIABLE GIT_VERSION_STRING
+	OUTPUT_VARIABLE CANONICAL_VERSION_STRING_4
 	OUTPUT_STRIP_TRAILING_WHITESPACE
 )
+
 execute_process(
-	COMMAND sh ${CMAKE_TOP_SRC_DIR}/scripts/get-version full
+	COMMAND bash ${CMAKE_TOP_SRC_DIR}/scripts/get-version 3
+	WORKING_DIRECTORY ${CMAKE_TOP_SRC_DIR}
+	OUTPUT_VARIABLE CANONICAL_VERSION_STRING_3
+	OUTPUT_STRIP_TRAILING_WHITESPACE
+)
+
+execute_process(
+	COMMAND bash ${CMAKE_TOP_SRC_DIR}/scripts/get-version
 	WORKING_DIRECTORY ${CMAKE_TOP_SRC_DIR}
 	OUTPUT_VARIABLE CANONICAL_VERSION_STRING
 	OUTPUT_STRIP_TRAILING_WHITESPACE
@@ -15,8 +24,8 @@ configure_file(${SRC} ${DST} @ONLY)
 if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
 	execute_process(
 		COMMAND cat ${CMAKE_TOP_SRC_DIR}/packaging/windows/subsurface.nsi.in
-		COMMAND sed -e "s/VERSIONTOKEN/${GIT_VERSION_STRING}/"
-		COMMAND sed -e "s/PRODVTOKEN/${CANONICAL_VERSION_STRING}/"
+		COMMAND sed -e "s/VERSIONTOKEN/${CANONICAL_VERSION_STRING}/"
+		COMMAND sed -e "s/PRODVTOKEN/${CANONICAL_VERSION_STRING_4}/"
 		OUTPUT_FILE ${CMAKE_BINARY_DIR}/staging/subsurface.nsi
 	)
 endif()
diff --git a/core/version.c b/core/version.c
index 036353b66..9774d7b5f 100644
--- a/core/version.c
+++ b/core/version.c
@@ -1,9 +1,10 @@
 // SPDX-License-Identifier: GPL-2.0
 #include "ssrf-version.h"
 
+// let's leave the two redundant functions in case we change our minds on git SHAs
 const char *subsurface_git_version(void)
 {
-	return GIT_VERSION_STRING;
+	return CANONICAL_VERSION_STRING_4;
 }
 
 const char *subsurface_canonical_version(void)
diff --git a/packaging/android/qmake-build.sh b/packaging/android/qmake-build.sh
index 0170ae181..564c978a7 100755
--- a/packaging/android/qmake-build.sh
+++ b/packaging/android/qmake-build.sh
@@ -84,10 +84,10 @@ mkdir -p "$BUILDROOT"/subsurface-mobile-build
 pushd "$BUILDROOT"/subsurface-mobile-build
 
 # set up the Subsurface versions by hand
-GITVERSION=$(cd "$SUBSURFACE_SOURCE" ; git describe --match "v[0-9]*" --abbrev=12)
-CANONICALVERSION=$(echo "$GITVERSION" | sed -e 's/-g.*$// ; s/^v//' | sed -e 's/-/./')
-echo "#define GIT_VERSION_STRING \"$GITVERSION\"" > ssrf-version.h
+CANONICALVERSION=$("$SUBSURFACE_SOURCE"/scripts/get-version)
 echo "#define CANONICAL_VERSION_STRING \"$CANONICALVERSION\"" >> ssrf-version.h
+CANONICALVERSION_4=$("$SUBSURFACE_SOURCE"/scripts/get-version 4)
+echo "#define CANONICAL_VERSION_STRING_4 \"$CANONICALVERSION_4\"" >> ssrf-version.h
 popd
 
 if [ "$versionOnly" = "1" ] ; then
diff --git a/packaging/ios/build.sh b/packaging/ios/build.sh
index ad54869ab..35fabfd57 100755
--- a/packaging/ios/build.sh
+++ b/packaging/ios/build.sh
@@ -77,10 +77,10 @@ if [[ $QT_VERSION = 5.15* ]] ; then
 fi
 
 # set up the Subsurface versions by hand
-GITVERSION=$(cd "$SUBSURFACE_SOURCE" ; git describe --match "v[0-9]*" --abbrev=12)
-CANONICALVERSION=$(echo "$GITVERSION" | sed -e 's/-g.*$// ; s/^v//' | sed -e 's/-/./')
-echo "#define GIT_VERSION_STRING \"$GITVERSION\"" > "$SUBSURFACE_SOURCE"/ssrf-version.h
+CANONICALVERSION=$("$SUBSURFACE_SOURCE"/scripts/get-version)
 echo "#define CANONICAL_VERSION_STRING \"$CANONICALVERSION\"" >> "$SUBSURFACE_SOURCE"/ssrf-version.h
+CANONICALVERSION_4=$("$SUBSURFACE_SOURCE"/scripts/get-version 4)
+echo "#define CANONICAL_VERSION_STRING_4 \"$CANONICALVERSION_4\"" >> "$SUBSURFACE_SOURCE"/ssrf-version.h
 
 BUNDLE=org.subsurface-divelog.subsurface-mobile
 if [ "${IOS_BUNDLE_PRODUCT_IDENTIFIER}" != "" ] ; then
@@ -264,7 +264,7 @@ if [ "$QUICK" != "1" ] ; then
 	if [ ! "$CURRENT_SHA" = "$PREVIOUS_SHA" ] ; then
 		echo "$CURRENT_SHA" > "${PARENT_DIR}/libdivecomputer-build-${ARCH}/git.SHA"
 		pushd "${PARENT_DIR}/libdivecomputer-build-${ARCH}"
-		"${SUBSURFACE_SOURCE}/libdivecomputer/configure" --host=${BUILDCHAIN} --prefix="$PREFIX" --enable-static --disable-shared --enable-examples=no --without-libusb --without-hidapi 
+		"${SUBSURFACE_SOURCE}/libdivecomputer/configure" --host=${BUILDCHAIN} --prefix="$PREFIX" --enable-static --disable-shared --enable-examples=no --without-libusb --without-hidapi
 		make -j
 		make install
 		popd
diff --git a/packaging/macosx/make-package.sh b/packaging/macosx/make-package.sh
index b533eca95..5c9f8a18d 100755
--- a/packaging/macosx/make-package.sh
+++ b/packaging/macosx/make-package.sh
@@ -11,7 +11,7 @@ DMGCREATE=create-dmg
 
 # same git version magic as in the Makefile
 # for the naming of volume and dmg we want the 3 digits of the full version number
-VERSION=$(cd ${DIR}/subsurface; ./scripts/get-version linux)
+VERSION=$(cd ${DIR}/subsurface; ./scripts/get-version)
 
 # first build and install Subsurface and then clean up the staging area
 # make sure we didn't lose the minimum OS version
diff --git a/packaging/windows/create-win-installer.sh b/packaging/windows/create-win-installer.sh
index 9f18e3b6d..f75d16836 100644
--- a/packaging/windows/create-win-installer.sh
+++ b/packaging/windows/create-win-installer.sh
@@ -7,7 +7,7 @@ cd /__w
 
 # grab the version number
 cd subsurface
-VERSION=$(./scripts/get-version linux)
+VERSION=$(./scripts/get-version)
 cd ..
 
 # prep the container
diff --git a/scripts/get-version b/scripts/get-version
index 99758ade7..a4e80a675 100755
--- a/scripts/get-version
+++ b/scripts/get-version
@@ -1,76 +1,80 @@
-#!/bin/sh
+#!/bin/bash
+# shellcheck disable=SC2164
 
-# $1 - os name {linux|darwin|win}
-# $2 - [optional] raw version string "vX.Y-patchN-sha1". as from `git describe'
-#      (see below)
-
-set -eu
-#set -x
+# consistently name all builds, regardless of OS or desktop/mobile
+#
+# we do need to be able to create three digit (M.m.p) and four digit (M.m.p.c) version strings
+# default is VERSION_EXTENSION version - an argument of '4' or '3' gets you a digits only version string
+#
+# we hardcode a base version - this will rarely change
+# (we actually haven't discussed a situation where it would change...)
+SUBSURFACE_BASE_VERSION=6.0
 
+# little silly helper functions
 croak() {
 	echo "$0: $*" >&2
 	exit 1
 }
+croak_usage() {
+	croak "Usage: $0 [3|4]"
+}
 
-[ $# -ge 1 ] || croak "missing OS argument"
-os=$1
-
-if [ $# -eq 2 ] && [ "$2" ]; then
-	v0=$2
-else
-	cmd="git describe --match "v[0-9]*" --abbrev=12"
-	v0=$($cmd) || v0=$(cat .gitversion) || croak "odd; command '$cmd' failed"
+if [[ $# -gt 1 ]] ; then croak_usage ; fi
+if [[ $# -eq 1 ]] ; then
+	if [[ $1 != "4" && $1 != "3" ]] ; then croak_usage ; fi
+	DIGITS="$1"
 fi
 
-# strip off the 'v' prefix, if any
-v0=${v0#v}
+# figure out where we are in the file system
+cd "$(dirname "$0")/../"
+export SUBSURFACE_SOURCE=$PWD
 
-case $os in
-	linux)
-		v=$v0
-		;;
-	darwin)
-		# just the dots in the version string - this way we can
-		# count them
-		IFS=.
-		set -- $v0		# split $v0 using $IFS separator
-		dots=$(($# - 1))	# use positional argument count
-		# split version string using a '-' separator
-		IFS=-
-		set -- $v0
-		v=$1
-		# do we need to add another digit?
-		# We know there are 1 or 2 dots in $v, so if it's just one
-		# or we are trying to get to 4, add one digit
-		if [ $dots -eq 1 ]; then
-			if [ $# -gt 1 ]; then
-				v=$v.$2
-			else
-				v=$v.0
-			fi
-		fi
-		;;
-	full|win)
-		# just the dots in the version string - this way we can
-		# count them
-		IFS=.
-		set -- $v0		# split $v0 using $IFS separator
-		dots=$(($# - 1))	# use positional argument count
-		# split version string using a '-' separator
-		IFS=-
-		set -- $v0
-		v=$1
-		if [ $dots -eq 1 ]; then
-			v=$v.0
-		fi
-		if [ $# -gt 1 ]; then
-			v=$v.$2
-		else
-			v=$v.0
-		fi
-		;;
-	*)
-		v=git.missing.please.hardcode.version
-		;;
-esac
-printf '%s' $v
+# add the build number to this as 'patch' component
+# if we run in an environment where we are given a build number (e.g. CICD builds)
+# we just grab that - otherwise we have to figure it out on the fly
+if [ ! -f latest-subsurface-buildnumber ] ; then
+	# figure out the most recent build number, given our own git history
+	# this assumes that (a) we are in a checked out git tree and
+	# (b) we have the ability to check out another git repo
+	# in situations where either of these isn't true, it's the caller's
+	# responsibility to ensure that the latest-subsurface-buildnumber file exists
+	if [ ! -d "$SUBSURFACE_SOURCE/nightly-builds" ] ; then
+		git clone https://github.com/subsurface/nightly-builds &> /dev/null || croak "failed to clone nightly-builds repo"
+	fi
+	cd nightly-builds
+	git fetch &> /dev/null
+	LAST_BUILD_BRANCHS=$(git branch -a --sort=-committerdate --list | grep remotes/origin/branch-for | head -50 | cut -d/ -f3)
+	for LAST_BUILD_BRANCH in $LAST_BUILD_BRANCHS "not-found" ; do
+		LAST_BUILD_SHA=$(cut -d- -f 3 <<< "$LAST_BUILD_BRANCH")
+		git -C "$SUBSURFACE_SOURCE" merge-base --is-ancestor "$LAST_BUILD_SHA" HEAD && break
+	done
+	[ "not-found" = "$LAST_BUILD_BRANCH" ] && croak "can't find a build number for the current working tree"
+	git checkout "$LAST_BUILD_BRANCH" &> /dev/null || croak "failed to check out $LAST_BUILD_BRANCH in nightly-builds"
+	BUILDNR=$(<./latest-subsurface-buildnumber)
+	cd "$SUBSURFACE_SOURCE"
+	VERSION_EXTENSION="-"
+	VERSION_EXTENSION+=$(git log --pretty="oneline" "${LAST_BUILD_SHA}...HEAD" | wc -l | tr -d '[:space:]')
+	VERSION_EXTENSION+="-"
+	[ "$VERSION_EXTENSION" = "-0-" ] && VERSION_EXTENSION="-"
+	VERSION_EXTENSION+="local"
+else
+	# use the files included with the sources
+	BUILDNR=$(<"$SUBSURFACE_SOURCE/latest-subsurface-buildnumber")
+	VERSION_EXTENSION=""
+	if [ -f "$SUBSURFACE_SOURCE/latest-subsurface-buildnumber-extension" ] ; then
+		VERSION_EXTENSION="-"
+		VERSION_EXTENSION+=$(<"$SUBSURFACE_SOURCE/latest-subsurface-buildnumber-extension")
+	fi
+fi
+
+COMMITS_SINCE=$(tr -cd "[:digit:]" <<<"$VERSION_EXTENSION")
+[[ -z $COMMITS_SINCE ]] && COMMITS_SINCE="0"
+
+if [[ $DIGITS == "3" ]] ; then
+	VERSION="${SUBSURFACE_BASE_VERSION}.${BUILDNR}"
+elif [[ $DIGITS == "4" ]] ; then
+	VERSION="${SUBSURFACE_BASE_VERSION}.${BUILDNR}.${COMMITS_SINCE}"
+else
+	VERSION="${SUBSURFACE_BASE_VERSION}.${BUILDNR}${VERSION_EXTENSION}"
+fi
+printf '%s' "$VERSION"
diff --git a/smtk-import/cmake/Modules/version.cmake b/smtk-import/cmake/Modules/version.cmake
index 44f3c842c..f875cb563 100644
--- a/smtk-import/cmake/Modules/version.cmake
+++ b/smtk-import/cmake/Modules/version.cmake
@@ -1,23 +1,24 @@
 message(STATUS "processing version.cmake")
 execute_process(
-	COMMAND sh ${CMAKE_TOP_SRC_DIR}/../scripts/get-version linux
-	WORKING_DIRECTORY ${CMAKE_TOP_SRC_DIR}
-	OUTPUT_VARIABLE GIT_VERSION_STRING
-	OUTPUT_STRIP_TRAILING_WHITESPACE
-)
-execute_process(
-	COMMAND sh ${CMAKE_TOP_SRC_DIR}/../scripts/get-version full
+	COMMAND bash ${CMAKE_TOP_SRC_DIR}/../scripts/get-version
 	WORKING_DIRECTORY ${CMAKE_TOP_SRC_DIR}
 	OUTPUT_VARIABLE CANONICAL_VERSION_STRING
 	OUTPUT_STRIP_TRAILING_WHITESPACE
 )
 
+execute_process(
+	COMMAND bash ${CMAKE_TOP_SRC_DIR}/../scripts/get-version 4
+	WORKING_DIRECTORY ${CMAKE_TOP_SRC_DIR}
+	OUTPUT_VARIABLE CANONICAL_VERSION_STRING_4
+	OUTPUT_STRIP_TRAILING_WHITESPACE
+)
+
 configure_file(${SRC} ${DST} @ONLY)
 if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
 	execute_process(
 		COMMAND cat ${CMAKE_TOP_SRC_DIR}/../packaging/windows/smtk-import.nsi.in
-		COMMAND sed -e "s/VERSIONTOKEN/${GIT_VERSION_STRING}/"
-		COMMAND sed -e "s/PRODVTOKEN/${CANONICAL_VERSION_STRING}/"
+		COMMAND sed -e "s/VERSIONTOKEN/${CANONICAL_VERSION_STRING}/"
+		COMMAND sed -e "s/PRODVTOKEN/${CANONICAL_VERSION_STRING_4}/"
 		OUTPUT_FILE ${CMAKE_BINARY_DIR}/staging/smtk-import.nsi
 	)
 endif()