diff --git a/Makefile b/Makefile index a04f215..dd8b75e 100644 --- a/Makefile +++ b/Makefile @@ -8,21 +8,24 @@ APPID=com.tailscale.ipn AAR=android/libs/ipn.aar KEYSTORE=tailscale.jks KEYSTORE_ALIAS=tailscale -GIT_DESCRIBE=$(shell git describe --tags --long) -VERSION_LONG=$(shell ./mkversion.sh long $(GIT_DESCRIBE)) -VERSION_SHORT=$(shell ./mkversion.sh short $(GIT_DESCRIBE)) +TAILSCALE_VERSION=$(shell ./version/tailscale-version.sh) +TAILSCALE_COMMIT=$(lastword $(subst -g, ,$(TAILSCALE_VERSION))) +GIT_DESCRIBE=$(shell git describe --dirty --exclude "*" --always --abbrev=200) +VERSION_LONG=$(shell ./version/mkversion.sh long $(TAILSCALE_VERSION) $(GIT_DESCRIBE)) +VERSION_SHORT=$(shell ./version/mkversion.sh short $(TAILSCALE_VERSION) $(GIT_DESCRIBE)) all: $(APK) -aar: +$(DEBUG_APK): mkdir -p android/libs - go run gioui.org/cmd/gogio -ldflags "-X tailscale.com/version.LONG=$(VERSION_LONG) -X tailscale.com/version.SHORT=$(VERSION_SHORT)" -tags xversion -buildmode archive -target android -appid $(APPID) -o $(AAR) github.com/tailscale/tailscale-android/cmd/tailscale - -$(DEBUG_APK): aar - (cd android && VERSION=$(VERSION_LONG) ./gradlew assembleDebug) + go run gioui.org/cmd/gogio -buildmode archive -target android -appid $(APPID) -o $(AAR) github.com/tailscale/tailscale-android/cmd/tailscale + (cd android && ./gradlew assembleDebug) mv android/build/outputs/apk/debug/android-debug.apk $@ -$(RELEASE_AAB): aar +$(RELEASE_AAB): + mkdir -p android/libs + go run gioui.org/cmd/gogio -ldflags "-X tailscale.com/version.Long=$(VERSION_LONG) -X tailscale.com/version.Short=$(VERSION_SHORT) -X tailscale.com/version.GitCommit=$(TAILSCALE_COMMIT)" -tags xversion -buildmode archive -target android -appid $(APPID) -o $(AAR) github.com/tailscale/tailscale-android/cmd/tailscale + (cd android && VERSION=$(VERSION_LONG) ./gradlew bundleRelease) mv ./android/build/outputs/bundle/release/android-release.aab $@ @@ -39,4 +42,4 @@ dockershell: clean: rm -rf android/build $(RELEASE_AAB) $(DEBUG_APK) $(AAR) -.PHONY: all clean install aar release dockershell +.PHONY: all clean install $(DEBUG_APK) $(RELEASE_AAB) release dockershell diff --git a/mkversion.sh b/mkversion.sh deleted file mode 100755 index 12a5dcb..0000000 --- a/mkversion.sh +++ /dev/null @@ -1,68 +0,0 @@ -#!/bin/sh - -# Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -set -eu - -mode=$1 -describe=$2 - -long() { - ver="${describe#v}" - stem="${ver%%-*}" - case "$stem" in - *.*.*) - # Full SemVer, nothing to do. - semver="${stem}" - ;; - *.*) - # Old style major.minor, add a .0 - semver="${stem}.0" - ;; - *) - echo "Unparseable version $stem" >&2 - exit 1 - ;; - esac - suffix="${ver#$stem}" - case "$suffix" in - -*-*) - # Has a change count in addition to the commit hash. - ;; - -*) - # Missing change count, add one. - suffix="-0${suffix}" - ;; - *) - echo "Unexpected version suffix" >&2 - exit 1 - esac - echo "${semver}${suffix}" -} - -short() { - ver="$(long)" - case "$ver" in - *-*-*) - echo "${ver%-*}" - ;; - *-*) - echo "$ver" - ;; - *) - echo "Long version in invalid format" >&2 - exit 1 - ;; - esac -} - -case "$mode" in - long) - long - ;; - short) - short - ;; -esac diff --git a/version/mkversion.sh b/version/mkversion.sh new file mode 100755 index 0000000..84772bc --- /dev/null +++ b/version/mkversion.sh @@ -0,0 +1,139 @@ +#!/bin/sh + +set -eu + +mode=$1 +describe=$2 +other=$3 + +# Git describe output overall looks like +# MAJOR.MINOR.PATCH-NUMCOMMITS-GITHASH. Depending on the tag being +# described and the state of the repo, ver can be missing PATCH, +# NUMCOMMITS, or both. +# +# Valid values look like: 1.2.3-1234-abcdef, 0.98-1234-abcdef, +# 1.0.0-abcdef, 0.99-abcdef. +ver="${describe#v}" +stem="${ver%%-*}" # Just the semver-ish bit e.g. 1.2.3, 0.98 +suffix="${ver#$stem}" # The rest e.g. -23-abcdef, -abcdef + +# Normalize the stem into a full major.minor.patch semver. We might +# not use all those pieces depending on what kind of version we're +# making, but it's good to have them all on hand. +case "$stem" in + *.*.*) + # Full SemVer, nothing to do + stem="$stem" + ;; + *.*) + # Old style major.minor, add a .0 + stem="${stem}.0" + ;; + *) + echo "Unparseable version $stem" >&2 + exit 1 + ;; +esac +major=$(echo "$stem" | cut -f1 -d.) +minor=$(echo "$stem" | cut -f2 -d.) +patch=$(echo "$stem" | cut -f3 -d.) + +# Extract the change count and git ID from the suffix. +case "$suffix" in + -*-*) + # Has both a change count and a commit hash. + changecount=$(echo "$suffix" | cut -f2 -d-) + githash=$(echo "$suffix" | cut -f3 -d-) + ;; + -*) + # Git hash only, change count is zero. + changecount="0" + githash=$(echo "$suffix" | cut -f2 -d-) + ;; + *) + echo "Unparseable version suffix $suffix" >&2 + exit 1 + ;; +esac + +# The git hash is of the form "gCOMMITHASH". We want to replace the +# 'g' with a 't', for "tailscale", to convey that it's specifically +# the commit hash of the tailscale repo. +if [ -n "$githash" ]; then + # POSIX shell doesn't understand ${foo:1:9} syntax, gaaah. + githash="$(echo $githash | cut -c2-10)" + githash="t${githash}" +fi + +# "other" is a second git commit hash for another repository used to +# build the Tailscale code. In practice it's either the commit hash in +# the Android repository, or the commit hash of Tailscale's +# proprietary repository (which pins a bunch things like build scripts +# used and Go toolchain version). +if [ -n "$other" ]; then + other="$(echo $other | cut -c1-9)" + other="-g${other}" +fi + +# Validate that the version data makes sense. Rules: +# - Odd number minors are unstable. Patch must be 0, and gets +# replaced by changecount. +# - Even number minors are stable. Changecount must be 0, and +# gets removed. +# +# After this section, we only use major/minor/patch, which have been +# tweaked as needed. +if expr "$minor" : "[0-9]*[13579]$" >/dev/null; then + # Unstable + if [ "$patch" != "0" ]; then + # This is a fatal error, because a non-zero patch number + # indicates that we created an unstable git tag in violation + # of our versioning policy, and we want to blow up loudly to + # get that fixed. + echo "Unstable release $describe has a non-zero patch number, which is not allowed" >&2 + exit 1 + fi + patch="$changecount" +else + # Stable + if [ "$changecount" != "0" ]; then + # This is a commit that's sitting between two stable + # releases. We never want to release such a commit to the + # pbulic, but it's useful to be able to build it for + # debugging. Just force the version to 0.0.0, so that we're + # forced to rely on the git commit hash. + major="0" + minor="0" + patch="0" + fi +fi + +if [ "$minor" -eq 1 ]; then + # Hack for 1.1: add 1000 to the patch number, so that builds that + # use the OSS change count order after the builds that used the + # proprietary repo's changecount. Otherwise, the version numbers + # would go backwards and things would be unhappy. + patch=$((patch + 1000)) +fi + +case "$1" in + long) + echo "${major}.${minor}.${patch}-${githash}${other}" + ;; + short) + echo "${major}.${minor}.${patch}" + ;; + xcode) + # CFBundleShortVersionString: the "short name" used in the App + # Store. eg. 0.92.98 + echo "VERSION_NAME = ${major}.${minor}.${patch}" + # CFBundleVersion: the build number. Needs to be 3 numeric + # sections that increment for each release according to SemVer + # rules. + # + # We start counting at 100 because we submitted using raw + # build numbers before, and Apple doesn't let you start over. + # e.g. 0.98.3 -> 100.98.3 + echo "VERSION_ID = $((major + 100)).${minor}.${patch}" + ;; +esac diff --git a/version/tailscale-version.sh b/version/tailscale-version.sh new file mode 100755 index 0000000..0d5fbf3 --- /dev/null +++ b/version/tailscale-version.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env sh + +# Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +# Print the version tailscale repository corresponding +# to the version listed in go.mod. The version is compatible with +# mkversion.sh. + +set -euo pipefail + +go_list=$(go list -m tailscale.com) +# go list outputs `tailscale.com `. Extract the version. +mod_version=${go_list##* } + +if [ -z "$mod_version" ]; then + echo "no version reported by go list -m tailscale.com: $go_list" + exit 1 +fi + +case "$mod_version" in + *-*-*) + # A pseudo-version such as "v1.1.1-0.20201030135043-eab6e9ea4e45" + # includes the commit hash. + commit=${mod_version##*-*-} + version=${mod_version%%-*} + echo "v0.0.0-0-g$commit" + exit 0 + ;; +esac + +# Query git repository for the hash matching the tag. +git_ls_remote=$(git ls-remote --exit-code -t https://github.com/tailscale/tailscale "$mod_version^{}") +# Extract the commit. Note that git ls-remote separates fields with tabs. +commit=${git_ls_remote%%$'\t'*} +echo "$mod_version-0-g$commit"