turbo-editors/turbo-corepublic Fork 0
28d59854361aeda8541d853093e732126f3d7bff
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.

02-release.publish.sh · 175 lines · 5.2 KBBash Blame HistoryRaw
🛟 Updated. 28d5985 k33g 12h ago1#!/bin/bash
2: <<'COMMENT'
3Create the release page on Codeberg for a tag 01-release.tag.sh already pushed.
4
5 ./02-release.publish.sh create it
6 ./02-release.publish.sh --dry-run show what would be sent, send nothing
7
8This does NOT publish the module. A Go module is published by its tag being
9reachable, and `go get codeberg.org/turbo-editors/turbo-core@TAG` already works
10the moment 01 has run. What this adds is the page a person reads: the notes, and
11somewhere to link to.
12
13There is deliberately no 03 or 04 here. Those build and attach binaries, and a
14library has none — its artefact is the tag.
15COMMENT
16
17# `set -e` is safe here, unlike in the editors' own 02, which uses the
18# `read -r -d '' DATA` idiom — that always exits non-zero by design, so adding
19# -e there kills the script on its first line. The JSON below is built with jq
20# instead, which both avoids that trap and escapes the values properly.
21set -euo pipefail
22
23dry_run=false
24case "${1:-}" in
25--dry-run) dry_run=true ;;
26"") ;;
27*)
28 echo "usage: $0 [--dry-run]"
29 exit 1
30 ;;
31esac
32
33for tool in curl jq; do
34 if ! command -v "${tool}" >/dev/null; then
35 echo "${tool} is needed and is not installed"
36 exit 1
37 fi
38done
39
40if [ ! -f release.env ]; then
41 echo "❌ release.env is missing"
42 echo "💡 It holds the version and the repository:"
43 echo ' TAG="v0.1.0"'
44 echo ' ABOUT="The Turbo editor library"'
45 echo ' OWNER="turbo-editors"'
46 echo ' REPO="turbo-core"'
47 exit 1
48fi
49
50set -o allexport
51# shellcheck source=/dev/null
52source release.env
53# The token lives in its own file so that release.env can be pasted into an
54# issue without leaking it. Both are gitignored by *.env.
55if [ -f turbo-core.token.env ]; then
56 # shellcheck source=/dev/null
57 source turbo-core.token.env
58fi
59set +o allexport
60
61: "${TAG:?TAG is not set in release.env}"
62: "${OWNER:?OWNER is not set in release.env}"
63: "${REPO:?REPO is not set in release.env}"
64ABOUT="${ABOUT:-${TAG}}"
65
66if [ -z "${TOKEN:-}" ]; then
67 echo "❌ TOKEN is not set"
68 echo "💡 Put it in turbo-core.token.env (gitignored):"
69 echo ' TOKEN=your-codeberg-application-token'
70 echo " Codeberg → Settings → Applications → Generate token, scope: repository"
71 exit 1
72fi
73
74# A release page for a tag the remote has never seen is a page nobody can use:
75# the download links 404 and `go get` fails. Ask origin rather than trusting the
76# local ref, which is exactly the state 01 exists to get out of.
77# "Not there" and "could not ask" are different answers and must not be
78# conflated: ls-remote exits 2 when the ref is absent and 128 when it cannot
79# reach the remote at all. Treating the second as the first refuses a perfectly
80# good release from any machine with no key loaded.
81set +e
82git ls-remote --exit-code --tags origin "refs/tags/${TAG}" >/dev/null 2>&1
83lookup=$?
84set -e
85
86case ${lookup} in
870) ;;
882)
89 echo "${TAG} is not on origin"
90 echo "💡 Run ./01-release.tag.sh first — it pushes the branch, then the tag."
91 exit 1
92 ;;
93*)
94 echo "⚠️ cannot reach origin to check that ${TAG} is pushed; carrying on."
95 echo " If it is not, Codeberg will refuse the release below."
96 ;;
97esac
98
99# The body is the notes plus the two lines a reader actually needs. A library's
100# release page whose only content is its own version number tells nobody how to
101# use it.
102#
103# The links are absolute: a release page is not inside the repository tree, so a
104# relative path from it 404s.
105module="$(go list -m)"
106repo_url="https://codeberg.org/${OWNER}/${REPO}"
107body="$(
108 cat <<-EOM
109 ${ABOUT}
110
111 \`\`\`bash
112 go get ${module}@${TAG}
113 \`\`\`
114
115 Documentation: [English](${repo_url}/src/tag/${TAG}/docs/en/README.md) · [Français](${repo_url}/src/tag/${TAG}/docs/fr/README.md)
116 EOM
117)"
118
119# jq builds the JSON, so a quote, a newline or a backtick in ABOUT cannot break
120# the request — which hand-written JSON in a heredoc does silently.
121payload="$(jq -n \
122 --arg tag "${TAG}" \
123 --arg name "${TAG}" \
124 --arg body "${body}" \
125 '{tag_name: $tag, name: $name, body: $body, draft: false, prerelease: false}')"
126
127url="https://codeberg.org/api/v1/repos/${OWNER}/${REPO}/releases"
128
129if ${dry_run}; then
130 echo "POST ${url}"
131 echo "${payload}"
132 echo "✅ dry run: nothing was sent"
133 exit 0
134fi
135
136echo "Creating the release page for ${TAG} on ${OWNER}/${REPO}"
137
138# The status is separated from the body so the script can say which failure this
139# is. A bare curl prints the API's JSON and leaves the reader to guess.
140response="$(mktemp)"
141trap 'rm -f "${response}"' EXIT
142status="$(curl -sS -o "${response}" -w '%{http_code}' \
143 -X POST \
144 -H "Authorization: token ${TOKEN}" \
145 -H "Content-Type: application/json" \
146 "${url}" \
147 -d "${payload}")"
148
149case "${status}" in
150201)
151 echo "${TAG} published: $(jq -r '.html_url' "${response}")"
152 ;;
153409)
154 echo "❌ a release for ${TAG} already exists"
155 echo "💡 Delete it on Codeberg, or bump TAG in release.env. A published"
156 echo " version is not worth moving: consumers pin it and the module proxy"
157 echo " caches what it fetched."
158 exit 1
159 ;;
160401 | 403)
161 echo "${status}: the token was refused"
162 echo "💡 Check TOKEN in turbo-core.token.env, and that its scope covers this repository."
163 exit 1
164 ;;
165404)
166 echo "❌ 404: no repository ${OWNER}/${REPO}"
167 echo "💡 Check OWNER and REPO in release.env."
168 exit 1
169 ;;
170*)
171 echo "${status} from Codeberg:"
172 cat "${response}"
173 exit 1
174 ;;
175esac