turbo-editors/turbo-corepublic Fork 0
main
Commits
Clone
git clone https://git.rickub.com/turbo-editors/turbo-core.git
git clone ssh://git@rickub.com/turbo-editors/turbo-core.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

📦 Turbo Core d662ceb · on main · k33g · 10h ago
02-build-releases.sh · 166 lines · 5.9 KBBash Blame HistoryRaw
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#!/bin/bash
: <<'COMMENT'
Stage the release artefacts of turbo-core under release/${TAG}/

Usage:
  ./02-build-releases.sh          # TAG and ABOUT come from release.env
  ./02-build-releases.sh v0.2.0   # override the tag for this run (what CI does)

turbo-core is a library, so where an editor's build cross-compiles one binary
per platform this stages the one artefact a Go module has: an archive of the
source the tag is on. `go get` never downloads it — the module proxy serves the
module straight from the tag, which is why 01 alone already publishes it. The
archive is here so a release page has something to verify against, and so the
library can be had by somebody who does not reach the proxy.

Only the Go toolchain and git are needed. The same command works on a laptop
and in a Rickub CI job.

What ends up in release/${TAG}/:
  turbo-core-<version>.tar.gz   the tagged source, under turbo-core-<version>/
  SHA256SUMS                    checksum of the archive
  README.md                     the go get line, the packages, how to verify
COMMENT

set -euo pipefail

# release.env carries TAG ("v0.2.0") and ABOUT (the one-line description). It
# is git-ignored (*.env), so a CI job does not have it: there the tag comes
# from the command line and ABOUT from the environment, or defaults to the
# tag. A tag given on the command line always wins, so a test build never
# edits the file.
if [ -f release.env ]; then
	# shellcheck source=/dev/null
	source release.env
fi
TAG="${1:-${TAG:-}}"
ABOUT="${ABOUT:-Turbo Core ${TAG}}"

# A tag that is not vMAJOR.MINOR.PATCH[-prerelease] is a typo — and for a Go
# module it is worse than a typo: the proxy will not serve a tag it cannot read
# as a version, so `go get` would fail on a release that staged perfectly.
if ! [[ "${TAG}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then
	echo "❌ TAG must look like v1.2.3 or v1.2.3-rc.1, got '${TAG}' (check release.env)"
	exit 1
fi

# 01 refuses this too, but CI runs *this* script on a tag that is already
# pushed, without ever running 01. The proxy serves go.mod as written, so a
# published library carrying a replace tells every consumer to look for
# turbo-core in a directory that does not exist on their machine.
if grep -qE '^[[:space:]]*replace[[:space:]]' go.mod; then
	echo "❌ go.mod has a replace directive, which a published module must not"
	grep -nE '^[[:space:]]*replace[[:space:]]' go.mod
	exit 1
fi

# The tag is "v0.2.0"; the assets carry the bare version, "0.2.0".
VERSION="${TAG#v}"
RELEASES_DIR="release/${TAG}"
ARCHIVE="turbo-core-${VERSION}.tar.gz"
MODULE="$(go list -m)"

echo "🚀 Staging turbo-core ${TAG}${ABOUT}"
echo "🐹 $(go version)"

# The archive comes from HEAD, not from the working directory: git archive
# writes what is committed. A dirty tree is therefore not an error here, but it
# does mean the archive is not what you are looking at — worth saying once.
if ! git diff --quiet HEAD 2>/dev/null; then
	echo "⚠️  the working tree has uncommitted changes; the archive is HEAD, not what is on disk"
fi

rm -rf "${RELEASES_DIR}"
mkdir -p "${RELEASES_DIR}"

echo ""
echo "🔨 Checking what ships..."

# Every package has to compile and pass vet before it is archived. A library
# has no binary whose start proves anything, so this is the equivalent: the
# whole module, built the way a consumer's build will build it.
if ! go build ./...; then
	echo "   ❌ go build ./..."
	exit 1
fi
echo "   ✅ go build ./..."

if ! go vet ./...; then
	echo "   ❌ go vet ./..."
	exit 1
fi
echo "   ✅ go vet ./..."

# The prefix is what the archive unpacks into, so extracting it beside other
# downloads does not scatter a go.mod and eighteen directories into the
# current one.
git archive --format=tar.gz --prefix="turbo-core-${VERSION}/" -o "${RELEASES_DIR}/${ARCHIVE}" HEAD
echo "${ARCHIVE}"

# Extracting the archive and building it is the one proof that what ships
# builds on its own — that nothing needed was left untracked, gitignored, or
# only present in this checkout. The dependencies come from the shared module
# cache, which the build above has just filled.
extracted="$(mktemp -d)"
trap 'rm -rf "${extracted}"' EXIT
tar -xzf "${RELEASES_DIR}/${ARCHIVE}" -C "${extracted}"
if ! (cd "${extracted}/turbo-core-${VERSION}" && go build ./... >/dev/null); then
	echo "   ❌ the extracted archive does not build on its own"
	exit 1
fi
echo "   ✅ the extracted archive builds on its own"

# checksum runs whichever of the two tools this machine has: sha256sum on
# Linux, shasum on macOS.
checksum() {
	if command -v sha256sum >/dev/null 2>&1; then
		sha256sum "$@"
	else
		shasum -a 256 "$@"
	fi
}

# Names only (no directory), which is what `sha256sum -c` expects to read next
# to the downloaded file.
(cd "${RELEASES_DIR}" && checksum "${ARCHIVE}" >SHA256SUMS)
echo "   ✅ SHA256SUMS"

# packageTable lists the library's packages with the first line of each one's
# doc comment, so the README grows and shrinks with the module rather than
# repeating it by hand. Packages with no doc comment — the module root, which
# holds nothing but this tooling's tests — are left out, and a pipe in a
# synopsis is escaped so it cannot break the table.
packageTable() {
	printf '| Package | What it is |\n|---|---|\n'
	go list -f '{{.ImportPath}}|{{.Doc}}' ./... | while IFS='|' read -r path doc; do
		[ -z "${doc}" ] && continue
		printf '| `%s` | %s |\n' "${path#"${MODULE}"/}" "${doc//|/\\|}"
	done
}

cat >"${RELEASES_DIR}/README.md" <<EOM
# Turbo Core ${TAG}

${ABOUT}

The library the Turbo editors are built from. Built and checked with $(go env GOVERSION).

## Using it

    go get ${MODULE}@${TAG}

The module proxy serves this straight from the tag; the archive beside this file is the same source, for verifying against or for working without the proxy.

## What is in it

$(packageTable)

## Verifying the download

    sha256sum -c SHA256SUMS --ignore-missing     # shasum -a 256 -c on macOS
EOM
echo "   ✅ README.md"

echo ""
echo "✨ Staging complete!"
ls -lh "${RELEASES_DIR}"