turbo-editors/turbo-jspublic Fork 0
v1.0.0
Commits
Clone
git clone https://git.rickub.com/turbo-editors/turbo-js.git
git clone ssh://git@rickub.com/turbo-editors/turbo-js.git

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

02-build-releases.sh · 209 lines · 7.2 KBBash Blame HistoryRaw
📦 Turbo JS 91999d1 k33g 12h ago1#!/bin/bash
2: <<'COMMENT'
3Build the release binaries and stage them under release/${TAG}/
4
5Usage:
6 ./02-build-releases.sh # TAG and ABOUT come from release.env
7 ./02-build-releases.sh v1.0.0 # override the tag for this run (what CI does)
8
9This is the script the Release workflow runs when ./01-release.tag.sh pushes a
10tag; the workflow then attaches everything staged here to the release page.
11Nothing here publishes anything, so it is also the way to see what a release
12will contain before cutting it, or to build the binaries by hand.
13
14Only the Go toolchain and git are needed. The same command works on a laptop
15and in a Rickub CI job.
16
17What ends up in release/${TAG}/:
18 turbo-js-<version>-<os>-<arch>[.exe] one binary per platform in PLATFORMS
19 SHA256SUMS checksums of every binary
20 README.md the downloads, how to run and verify them
21COMMENT
22
23set -euo pipefail
24
25# release.env carries TAG ("v1.0.0") and ABOUT (the one-line description). It
26# is git-ignored (*.env), so a CI job does not have it: there the tag comes
27# from the command line and ABOUT from the environment, or defaults to the
28# tag. A tag given on the command line always wins, so a test build never
29# edits the file.
30if [ -f release.env ]; then
31 # shellcheck source=/dev/null
32 source release.env
33fi
34TAG="${1:-${TAG:-}}"
35ABOUT="${ABOUT:-Turbo JS ${TAG}}"
36
37# A tag that is not vMAJOR.MINOR.PATCH[-prerelease] is a typo — and for a Go
38# module it is worse than a typo: the proxy will not serve a tag it cannot read
39# as a version, so `go install` would fail on a release that built perfectly.
40if ! [[ "${TAG}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then
41 echo "❌ TAG must look like v1.2.3 or v1.2.3-rc.1, got '${TAG}' (check release.env)"
42 exit 1
43fi
44
45# 01 refuses this too, but CI runs *this* script on a tag that is already
46# pushed, without ever running 01. The proxy serves go.mod as written, so a
47# published editor carrying a replace tells `go install` to look for turbo-core
48# in a directory that does not exist on the installer's machine.
49if grep -qE '^[[:space:]]*replace[[:space:]]' go.mod; then
50 echo "❌ go.mod has a replace directive, which a published module must not"
51 grep -nE '^[[:space:]]*replace[[:space:]]' go.mod
52 exit 1
53fi
54
55# The platforms a release is built for. Add or remove a line and everything
56# below follows: the builds, the checksums and the README.
57PLATFORMS=(
58 "darwin/arm64"
59 "linux/amd64"
60 "linux/arm64"
61 "windows/amd64"
62 "windows/arm64"
63)
64
65echo "🚀 Building Turbo JS ${TAG}${ABOUT}"
66echo "🐹 $(go version)"
67
68RELEASES_DIR="release/${TAG}"
69
70# The tag is "v1.0.0"; the assets carry the bare version, "1.0.0".
71VERSION="${TAG#v}"
72
73# Where the Makefile puts the binary for this machine.
74BUILT="bin/turbo-js"
75
76# The release is ${TAG}, so ${TAG} is what every binary here reports. The
77# Makefile's own default comes from `git describe`, which answers a different
78# question — where HEAD is — and disagrees the moment you commit after tagging.
79# Overriding VERSION keeps the -X paths defined in one place all the same.
80LDFLAGS="$(make --no-print-directory ldflags VERSION="${TAG}")"
81
82# A fresh directory, so a binary left by an earlier run for a platform since
83# removed from PLATFORMS cannot end up on the release page.
84rm -rf "${RELEASES_DIR}"
85mkdir -p "${RELEASES_DIR}"
86
87# The host build comes first: it is the quickest way to find a compile error,
88# before spending five cross-compiles on it.
89make build VERSION="${TAG}"
90
91if [ ! -f "${BUILT}" ]; then
92 echo "❌ make build produced no ${BUILT}"
93 exit 1
94fi
95
96# assetName returns what the binary for a platform is called once staged.
97# Windows executables carry .exe, or Windows will not run them.
98assetName() {
99 local goos=$1 goarch=$2
100 local name="turbo-js-${VERSION}-${goos}-${goarch}"
101
102 if [ "${goos}" = "windows" ]; then
103 name="${name}.exe"
104 fi
105 printf '%s\n' "${name}"
106}
107
108echo ""
109echo "🔨 Cross-compiling for ${#PLATFORMS[@]} platforms..."
110
111for platform in "${PLATFORMS[@]}"; do
112 goos="${platform%/*}"
113 goarch="${platform#*/}"
114 asset="$(assetName "${goos}" "${goarch}")"
115
116 # CGO_ENABLED=0 because there is nothing to link against on the other side
117 # of a cross-compile, and this project needs no C at all: tcell and toml
118 # are both pure Go.
119 #
120 # -trimpath keeps the paths of this machine out of a binary that goes to
121 # strangers.
122 #
123 # -ldflags is what makes a downloaded binary agree with the release it came
124 # from. Without it the Go build system names the build itself, and every
125 # asset here would report "devel" while the release page says ${TAG}.
126 if ! CGO_ENABLED=0 GOOS="${goos}" GOARCH="${goarch}" \
127 go build -trimpath -ldflags "${LDFLAGS}" -o "${RELEASES_DIR}/${asset}" .; then
128 echo "${platform}"
129 exit 1
130 fi
131 echo "${asset}"
132done
133
134# The staged asset for this machine is the only one that can be run here, and
135# running it is the only proof that what ships carries the version rather than
136# that the flags looked right.
137# The number has to *equal* the tag, not merely appear in the output: "0.2.0"
138# is a substring of "10.2.0" and of a commit hash that happens to contain it,
139# and a stamp that is nearly right is the failure worth catching.
140HOST_ASSET="$(assetName "$(go env GOOS)" "$(go env GOARCH)")"
141if [ -x "${RELEASES_DIR}/${HOST_ASSET}" ]; then
142 if ! reported="$(scripts/check-version.sh "${RELEASES_DIR}/${HOST_ASSET}" "${TAG}")"; then
143 exit 1
144 fi
145 echo "${HOST_ASSET} reports ${reported}"
146fi
147
148# checksum runs whichever of the two tools this machine has: sha256sum on
149# Linux, shasum on macOS.
150checksum() {
151 if command -v sha256sum >/dev/null 2>&1; then
152 sha256sum "$@"
153 else
154 shasum -a 256 "$@"
155 fi
156}
157
158# The workflow attaches SHA256SUMS beside the binaries, so it is written here.
159# One file covers every platform, which is what "sha256sum -c" expects to
160# read, and the names carry no directory so it works next to the downloads.
161(cd "${RELEASES_DIR}" && checksum turbo-js-"${VERSION}"-* >SHA256SUMS)
162echo " ✅ SHA256SUMS"
163
164# downloadTable lists the platforms as a Markdown table, so the README grows
165# and shrinks with PLATFORMS rather than repeating it by hand.
166downloadTable() {
167 printf '| Platform | Download |\n|---|---|\n'
168 for platform in "${PLATFORMS[@]}"; do
169 local goos="${platform%/*}" goarch="${platform#*/}"
170 printf '| %s | `%s` |\n' "${platform}" "$(assetName "${goos}" "${goarch}")"
171 done
172}
173
174cat >"${RELEASES_DIR}/README.md" <<EOM
175# Turbo JS ${TAG}
176
177${ABOUT}
178
179Built with $(go env GOVERSION). No runtime dependencies; \`typescript-language-server\` is optional and
180only completion needs it (\`npm install -g typescript-language-server typescript@6\`).
181
182$(downloadTable)
183
184## Running it
185
186 chmod +x turbo-js-${VERSION}-<platform>
187 ./turbo-js-${VERSION}-<platform> main.js
188
189On macOS, an unsigned download is quarantined until you say otherwise:
190
191 xattr -d com.apple.quarantine turbo-js-${VERSION}-darwin-arm64
192
193## Installing from the module proxy instead
194
195 go install $(go list -m)@${TAG}
196
197## Verifying the download
198
199 sha256sum -c SHA256SUMS --ignore-missing # shasum -a 256 -c on macOS
200
201EOM
202echo " ✅ README.md"
203
204echo ""
205echo "✨ Build complete!"
206ls -lh "${RELEASES_DIR}"
207echo ""
208echo "💡 Nothing was published. The Release workflow runs this same script when"
209echo " ./01-release.tag.sh pushes ${TAG}, and attaches release/${TAG}/ to the release page."