|
| 1 | +"use strict"; |
| 2 | +const fs = require("fs"); |
| 3 | + |
| 4 | +const segmenter = new Intl.Segmenter("en", { granularity: "grapheme" }); |
| 5 | + |
| 6 | +function graphemes(str) { |
| 7 | + return Array.from(segmenter.segment(str), s => s.segment); |
| 8 | +} |
| 9 | + |
| 10 | +// Hard-cap to `limit` graphemes. When `ellipsis` is true, reserve 3 graphemes |
| 11 | +// for a trailing "..." (matches the legacy Play Store preparer). Assumes |
| 12 | +// limit >= 4 when ellipsis is true. |
| 13 | +function capGraphemes(str, limit, { ellipsis = false } = {}) { |
| 14 | + const chars = graphemes(str); |
| 15 | + if (chars.length <= limit) return str; |
| 16 | + if (ellipsis) return chars.slice(0, limit - 3).join("") + "..."; |
| 17 | + return chars.slice(0, limit).join(""); |
| 18 | +} |
| 19 | + |
| 20 | +function formatPrChangelog({ title, number, commits }) { |
| 21 | + const header = `${title} (#${number})`; |
| 22 | + // Reverse to newest-first; gh pr view --json commits returns oldest-first |
| 23 | + const rows = [...commits].reverse().map(c => `${c.oid.slice(0, 7)} ${c.messageHeadline}`); |
| 24 | + |
| 25 | + const build = rs => (rs.length > 0 ? [header, "", ...rs] : [header]).join("\n"); |
| 26 | + |
| 27 | + let output = build(rows); |
| 28 | + if (graphemes(output).length <= 500) return output; |
| 29 | + |
| 30 | + // Drop oldest rows (end of newest-first list) until within limit |
| 31 | + while (rows.length > 0) { |
| 32 | + rows.pop(); |
| 33 | + output = build(rows); |
| 34 | + if (graphemes(output).length <= 500) return output; |
| 35 | + } |
| 36 | + |
| 37 | + // Header alone exceeds 500: hard-slice, no ellipsis |
| 38 | + return capGraphemes(output, 500); |
| 39 | +} |
| 40 | + |
| 41 | +module.exports = { formatPrChangelog, capGraphemes, graphemes }; |
| 42 | + |
| 43 | +if (require.main === module) { |
| 44 | + const mode = process.argv[2]; |
| 45 | + |
| 46 | + if (mode === "pr") { |
| 47 | + const pr = JSON.parse(fs.readFileSync("pr.json", "utf8")); |
| 48 | + fs.writeFileSync("changelog.txt", formatPrChangelog(pr), "utf8"); |
| 49 | + } else if (mode === "cap") { |
| 50 | + const buildVersion = process.env.BUILD_VERSION; |
| 51 | + const input = fs.readFileSync("changelog.txt", "utf8"); |
| 52 | + fs.writeFileSync( |
| 53 | + `android/fastlane/metadata/android/en-US/changelogs/${buildVersion}.txt`, |
| 54 | + capGraphemes(input, 500, { ellipsis: true }), |
| 55 | + "utf8" |
| 56 | + ); |
| 57 | + } else { |
| 58 | + console.error(`Unknown mode "${mode}". Usage: node changelog.js <pr|cap>`); |
| 59 | + process.exit(1); |
| 60 | + } |
| 61 | +} |
0 commit comments