Refuse to release until the fastlane changelog for this version code matches CHANGELOG.md
This commit is contained in:
parent
4e607dd5a2
commit
e78359746b
6 changed files with 58 additions and 7 deletions
|
|
@ -197,7 +197,8 @@ rolling out on Play and submitting for review.
|
|||
```sh
|
||||
pnpm bump minor # or patch, major, or an explicit x.y.z
|
||||
# write the CHANGELOG.md section for the new version
|
||||
git commit -am "Bump version"
|
||||
pnpm release:changelog # copies it to fastlane/ for F-Droid, which reads it from the tag
|
||||
git add -A && git commit -m "Bump version"
|
||||
git tag 1.12.0 && git push origin dev 1.12.0
|
||||
pnpm release:local
|
||||
```
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
"build:server": "vite build --config vite.config.server.ts",
|
||||
"start": "node server.js",
|
||||
"release:check": "node scripts/release/local.mjs --check && node scripts/release/ci.mjs --check",
|
||||
"release:changelog": "node scripts/release/changelog.mjs",
|
||||
"release:local": "node scripts/release/local.mjs",
|
||||
"release:ci": "node scripts/release/ci.mjs",
|
||||
"bump": "node scripts/release/bump.mjs",
|
||||
|
|
|
|||
14
scripts/release/changelog.mjs
Normal file
14
scripts/release/changelog.mjs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
#!/usr/bin/env node
|
||||
import {mkdir, writeFile} from "node:fs/promises"
|
||||
import {dirname, relative} from "node:path"
|
||||
import {fastlaneChangelog, notes, root, shortNotes, version} from "./lib/context.mjs"
|
||||
import {fail} from "./lib/shell.mjs"
|
||||
|
||||
if (!notes) {
|
||||
fail(`CHANGELOG.md has no "# ${version}" section`)
|
||||
}
|
||||
|
||||
await mkdir(dirname(fastlaneChangelog), {recursive: true})
|
||||
await writeFile(fastlaneChangelog, `${shortNotes}\n`)
|
||||
|
||||
console.log(`Wrote ${relative(root, fastlaneChangelog)}`)
|
||||
|
|
@ -11,6 +11,7 @@ config({path: join(root, ".env.local")})
|
|||
export const {name, version} = JSON.parse(await readFile(join(root, "package.json"), "utf-8"))
|
||||
|
||||
const changelog = await readFile(join(root, "CHANGELOG.md"), "utf-8")
|
||||
const gradleConfig = await readFile(join(root, "android/app/build.gradle"), "utf-8")
|
||||
const zapstore = await readFile(join(root, "zapstore.yaml"), "utf-8")
|
||||
|
||||
const zapstoreField = key => {
|
||||
|
|
@ -35,6 +36,22 @@ export const notes = (nextHeading < 0 ? remainder : remainder.slice(0, nextHeadi
|
|||
.join("\n")
|
||||
.trim()
|
||||
|
||||
export const versionCode = Number(gradleConfig.match(/versionCode (\d+)/)[1])
|
||||
|
||||
// Play and F-Droid both cap release notes at 500 characters, so cut at the last whole line under it
|
||||
const noteLines = notes.split("\n")
|
||||
|
||||
while (noteLines.join("\n").length > 500) {
|
||||
noteLines.pop()
|
||||
}
|
||||
|
||||
export const shortNotes = noteLines.join("\n")
|
||||
|
||||
export const fastlaneChangelog = join(
|
||||
root,
|
||||
`fastlane/metadata/android/en-US/changelogs/${versionCode}.txt`,
|
||||
)
|
||||
|
||||
export const git = (...gitArgs) => {
|
||||
try {
|
||||
return output("git", gitArgs, {cwd: root, stdio: ["ignore", "pipe", "ignore"]})
|
||||
|
|
|
|||
|
|
@ -1,7 +1,17 @@
|
|||
import {existsSync, readFileSync} from "node:fs"
|
||||
import {join} from "node:path"
|
||||
import {join, relative} from "node:path"
|
||||
import {parseArgs} from "node:util"
|
||||
import {followUps, git, name, notes, repository, root, version} from "./context.mjs"
|
||||
import {
|
||||
fastlaneChangelog,
|
||||
followUps,
|
||||
git,
|
||||
name,
|
||||
notes,
|
||||
repository,
|
||||
root,
|
||||
shortNotes,
|
||||
version,
|
||||
} from "./context.mjs"
|
||||
import {ask, bold, dim, fail, green, red, yellow} from "./shell.mjs"
|
||||
|
||||
export const release = async (command, steps) => {
|
||||
|
|
@ -46,6 +56,16 @@ export const release = async (command, steps) => {
|
|||
|
||||
if (!notes) {
|
||||
problems.push({missing: [`CHANGELOG.md has no "# ${version}" section`]})
|
||||
} else if (
|
||||
!existsSync(fastlaneChangelog) ||
|
||||
readFileSync(fastlaneChangelog, "utf-8") !== `${shortNotes}\n`
|
||||
) {
|
||||
// F-Droid reads it from the tag, so it has to be committed before tagging
|
||||
problems.push({
|
||||
missing: [
|
||||
`${relative(root, fastlaneChangelog)} doesn't match CHANGELOG.md: pnpm release:changelog`,
|
||||
],
|
||||
})
|
||||
}
|
||||
|
||||
if (git("rev-parse", `refs/tags/${version}`)) {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import {readFile} from "node:fs/promises"
|
|||
import {join, resolve} from "node:path"
|
||||
import {spec} from "@welshman/lib"
|
||||
import {gradle, keystoreEnv} from "../lib/android.mjs"
|
||||
import {followUps, missingEnv, notes, root, version} from "../lib/context.mjs"
|
||||
import {followUps, missingEnv, root, shortNotes, version, versionCode} from "../lib/context.mjs"
|
||||
import {play} from "../lib/play.mjs"
|
||||
|
||||
const aab = join(root, "android/app/build/outputs/bundle/release/app-release.aab")
|
||||
|
|
@ -30,7 +30,6 @@ export default {
|
|||
],
|
||||
run: async () => {
|
||||
const gradleConfig = await readFile(join(root, "android/app/build.gradle"), "utf-8")
|
||||
const versionCode = Number(gradleConfig.match(/versionCode (\d+)/)[1])
|
||||
const track = process.env.PLAY_TRACK ?? "production"
|
||||
const status = process.env.PLAY_STATUS ?? "draft"
|
||||
const api = await play({
|
||||
|
|
@ -68,8 +67,7 @@ export default {
|
|||
versionCode,
|
||||
track,
|
||||
status,
|
||||
// Play rejects release notes over 500 characters
|
||||
notes: notes.slice(0, 500),
|
||||
notes: shortNotes,
|
||||
})
|
||||
|
||||
followUps.push(
|
||||
|
|
|
|||
Loading…
Reference in a new issue