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.

🛟 Updated. 28d5985 · on main · k33g · 2h ago
02-release.publish.sh · 175 lines · 5.2 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
167
168
169
170
171
172
173
174
175
#!/bin/bash
: <<'COMMENT'
Create the release page on Codeberg for a tag 01-release.tag.sh already pushed.

  ./02-release.publish.sh              create it
  ./02-release.publish.sh --dry-run    show what would be sent, send nothing

This does NOT publish the module. A Go module is published by its tag being
reachable, and `go get codeberg.org/turbo-editors/turbo-core@TAG` already works
the moment 01 has run. What this adds is the page a person reads: the notes, and
somewhere to link to.

There is deliberately no 03 or 04 here. Those build and attach binaries, and a
library has none — its artefact is the tag.
COMMENT

# `set -e` is safe here, unlike in the editors' own 02, which uses the
# `read -r -d '' DATA` idiom — that always exits non-zero by design, so adding
# -e there kills the script on its first line. The JSON below is built with jq
# instead, which both avoids that trap and escapes the values properly.
set -euo pipefail

dry_run=false
case "${1:-}" in
--dry-run) dry_run=true ;;
"") ;;
*)
	echo "usage: $0 [--dry-run]"
	exit 1
	;;
esac

for tool in curl jq; do
	if ! command -v "${tool}" >/dev/null; then
		echo "${tool} is needed and is not installed"
		exit 1
	fi
done

if [ ! -f release.env ]; then
	echo "❌ release.env is missing"
	echo "💡 It holds the version and the repository:"
	echo '     TAG="v0.1.0"'
	echo '     ABOUT="The Turbo editor library"'
	echo '     OWNER="turbo-editors"'
	echo '     REPO="turbo-core"'
	exit 1
fi

set -o allexport
# shellcheck source=/dev/null
source release.env
# The token lives in its own file so that release.env can be pasted into an
# issue without leaking it. Both are gitignored by *.env.
if [ -f turbo-core.token.env ]; then
	# shellcheck source=/dev/null
	source turbo-core.token.env
fi
set +o allexport

: "${TAG:?TAG is not set in release.env}"
: "${OWNER:?OWNER is not set in release.env}"
: "${REPO:?REPO is not set in release.env}"
ABOUT="${ABOUT:-${TAG}}"

if [ -z "${TOKEN:-}" ]; then
	echo "❌ TOKEN is not set"
	echo "💡 Put it in turbo-core.token.env (gitignored):"
	echo '     TOKEN=your-codeberg-application-token'
	echo "   Codeberg → Settings → Applications → Generate token, scope: repository"
	exit 1
fi

# A release page for a tag the remote has never seen is a page nobody can use:
# the download links 404 and `go get` fails. Ask origin rather than trusting the
# local ref, which is exactly the state 01 exists to get out of.
# "Not there" and "could not ask" are different answers and must not be
# conflated: ls-remote exits 2 when the ref is absent and 128 when it cannot
# reach the remote at all. Treating the second as the first refuses a perfectly
# good release from any machine with no key loaded.
set +e
git ls-remote --exit-code --tags origin "refs/tags/${TAG}" >/dev/null 2>&1
lookup=$?
set -e

case ${lookup} in
0) ;;
2)
	echo "${TAG} is not on origin"
	echo "💡 Run ./01-release.tag.sh first — it pushes the branch, then the tag."
	exit 1
	;;
*)
	echo "⚠️  cannot reach origin to check that ${TAG} is pushed; carrying on."
	echo "   If it is not, Codeberg will refuse the release below."
	;;
esac

# The body is the notes plus the two lines a reader actually needs. A library's
# release page whose only content is its own version number tells nobody how to
# use it.
#
# The links are absolute: a release page is not inside the repository tree, so a
# relative path from it 404s.
module="$(go list -m)"
repo_url="https://codeberg.org/${OWNER}/${REPO}"
body="$(
	cat <<-EOM
		${ABOUT}

		\`\`\`bash
		go get ${module}@${TAG}
		\`\`\`

		Documentation: [English](${repo_url}/src/tag/${TAG}/docs/en/README.md) · [Français](${repo_url}/src/tag/${TAG}/docs/fr/README.md)
	EOM
)"

# jq builds the JSON, so a quote, a newline or a backtick in ABOUT cannot break
# the request — which hand-written JSON in a heredoc does silently.
payload="$(jq -n \
	--arg tag "${TAG}" \
	--arg name "${TAG}" \
	--arg body "${body}" \
	'{tag_name: $tag, name: $name, body: $body, draft: false, prerelease: false}')"

url="https://codeberg.org/api/v1/repos/${OWNER}/${REPO}/releases"

if ${dry_run}; then
	echo "POST ${url}"
	echo "${payload}"
	echo "✅ dry run: nothing was sent"
	exit 0
fi

echo "Creating the release page for ${TAG} on ${OWNER}/${REPO}"

# The status is separated from the body so the script can say which failure this
# is. A bare curl prints the API's JSON and leaves the reader to guess.
response="$(mktemp)"
trap 'rm -f "${response}"' EXIT
status="$(curl -sS -o "${response}" -w '%{http_code}' \
	-X POST \
	-H "Authorization: token ${TOKEN}" \
	-H "Content-Type: application/json" \
	"${url}" \
	-d "${payload}")"

case "${status}" in
201)
	echo "${TAG} published: $(jq -r '.html_url' "${response}")"
	;;
409)
	echo "❌ a release for ${TAG} already exists"
	echo "💡 Delete it on Codeberg, or bump TAG in release.env. A published"
	echo "   version is not worth moving: consumers pin it and the module proxy"
	echo "   caches what it fetched."
	exit 1
	;;
401 | 403)
	echo "${status}: the token was refused"
	echo "💡 Check TOKEN in turbo-core.token.env, and that its scope covers this repository."
	exit 1
	;;
404)
	echo "❌ 404: no repository ${OWNER}/${REPO}"
	echo "💡 Check OWNER and REPO in release.env."
	exit 1
	;;
*)
	echo "${status} from Codeberg:"
	cat "${response}"
	exit 1
	;;
esac