@stacksjs/actions 0.75.257 → 0.75.258

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,79 @@
1
+ import type { CommitInfo } from '@stacksjs/logsmith';
2
+ /**
3
+ * The notes for these commits, grouped the way logsmith groups a changelog.
4
+ * Empty when none of them is something a tester sees.
5
+ */
6
+ export declare function testerNotes(commits: CommitInfo[], options?: TesterNotesOptions): string;
7
+ /**
8
+ * Notes cut to `limit` characters on whole lines, saying how many items were
9
+ * left out ("…and 12 more"). A section heading whose items were all cut goes
10
+ * too; a single line longer than the limit is cut at a word.
11
+ */
12
+ export declare function fitNotes(text: string, limit: number): string;
13
+ /** The newest mobile release tag (`v*-build.*`) at or before `ref`. */
14
+ export declare function previousMobileTag(cwd: string, ref?: string): string | undefined;
15
+ /** The conventional commits in `from..to`, parsed by logsmith. */
16
+ export declare function commitsBetween(cwd: string, from: string | undefined, to?: string): CommitInfo[];
17
+ /**
18
+ * The notes for a release and where they came from: `--notes`/`--notes-file`,
19
+ * then RELEASE_NOTES/RELEASE_NOTES_FILE, then config/mobile.ts, then generated.
20
+ */
21
+ export declare function resolveNotes(options: ResolveNotesOptions): { text: string, source: NotesSource };
22
+ /**
23
+ * App Store locales for the app's languages (`en` → `en-US`, `de` → `de-DE`),
24
+ * always with `en-US` first, the locale an app without localizations uses.
25
+ */
26
+ export declare function appStoreLocales(languages: string[] | undefined): string[];
27
+ /**
28
+ * Write `TestFlight/WhatToTest.<locale>.txt` beside the Xcode project, where
29
+ * Xcode Cloud reads it when it uploads the build to TestFlight. Returns the
30
+ * files written, relative to `root`.
31
+ */
32
+ export declare function writeWhatToTest(root: string, projectDir: string, notes: string, locales: string[]): string[];
33
+ /** The What to Test a tag shipped with, as committed beside its Xcode project. */
34
+ export declare function committedWhatToTest(cwd: string, tag: string, projectDir: string, locale?: string): string | null;
35
+ /** App Store Connect's limit on a build's "What to Test". */
36
+ export declare const TESTFLIGHT_NOTES_LIMIT: 4000;
37
+ /**
38
+ * The cap for `TestFlight/WhatToTest.<locale>.txt`. Apple documents 4000
39
+ * characters for the field, but Xcode Cloud has been seen to log "Found notes"
40
+ * and then show nothing for a file over about 2 KB (developer forums, thread
41
+ * 810627), so the file stays well under that. The App Store Connect API path
42
+ * (`--wait`, `buddy release:notes --testflight`) sets the full 4000.
43
+ */
44
+ export declare const XCODE_CLOUD_NOTES_LIMIT: 1000;
45
+ /** Google Play's limit on a release's "What's new", per language. */
46
+ export declare const PLAY_NOTES_LIMIT: 500;
47
+ /**
48
+ * The commit types a tester notices, in the order bumpx's changelog lists them.
49
+ * @defaultValue `['feat', 'fix', 'perf', 'revert']`
50
+ */
51
+ export declare const DEFAULT_NOTE_TYPES: string[];
52
+ /**
53
+ * Scopes that never describe something a tester sees.
54
+ * @defaultValue `['release', 'ci', 'deps', 'deps-dev', 'test', 'tests', 'docs', 'lint']`
55
+ */
56
+ export declare const DEFAULT_EXCLUDED_SCOPES: string[];
57
+ /** What testers read when nothing since the last build is theirs to see. */
58
+ export declare const NO_VISIBLE_CHANGES: 'Maintenance build: no visible changes since the previous build.';
59
+ /** What `config/mobile.ts` may say about release notes (`MobileConfig.release`). */
60
+ export declare interface ReleaseNotesConfig {
61
+ notes?: string
62
+ notesFile?: string
63
+ noteTypes?: string[]
64
+ excludeScopes?: string[]
65
+ locales?: string[]
66
+ }
67
+ export declare interface TesterNotesOptions {
68
+ types?: string[]
69
+ excludeScopes?: string[]
70
+ markdown?: boolean
71
+ }
72
+ export declare interface ResolveNotesOptions {
73
+ cwd: string
74
+ flags?: { notes?: string, notesFile?: string }
75
+ env?: Record<string, string | undefined>
76
+ config?: ReleaseNotesConfig
77
+ generate: () => string
78
+ }
79
+ export type NotesSource = 'flag' | 'env' | 'config' | 'generated';
@@ -0,0 +1,9 @@
1
+ import{existsSync,mkdirSync,readFileSync,writeFileSync}from"node:fs";import{isAbsolute,join,relative}from"node:path";import{defaultConfig,getCommits,groupCommits}from"@stacksjs/logsmith";export const TESTFLIGHT_NOTES_LIMIT=4000,XCODE_CLOUD_NOTES_LIMIT=1000,PLAY_NOTES_LIMIT=500,DEFAULT_NOTE_TYPES=["feat","fix","perf","revert"],DEFAULT_EXCLUDED_SCOPES=["release","ci","deps","deps-dev","test","tests","docs","lint"];const SECTION_TITLES={feat:"Features",fix:"Fixes",perf:"Performance",refactor:"Changes",revert:"Reverted",style:"Styles",build:"Build",docs:"Documentation"},BANG=/^(\w+)(?:\(([^)]+)\))?!: (.+)$/;function normalized(commit){const bang=commit.type==="misc"?BANG.exec(commit.message):null;return bang?{...commit,type:bang[1],scope:bang[2]||void 0,description:bang[3],breaking:!0}:commit}function line(description,scope){const text=description.replace(/\s*\((?:#\d+(?:,\s*)?)+\)\s*$/,"").replace(/\s+/g," ").trim(),sentence=text.charAt(0).toUpperCase()+text.slice(1),context=scope?.split(",").map((part)=>part.trim()).filter(Boolean).join(", ");return context?`${sentence} (${context})`:sentence}export function testerNotes(commits,options={}){const types=options.types?.length?options.types:DEFAULT_NOTE_TYPES,sections=groupCommits(commits.map(normalized),{...defaultConfig,verbose:!1,includeCommitTypes:types,excludeCommitTypes:[],excludeScopes:options.excludeScopes??DEFAULT_EXCLUDED_SCOPES,includeScopes:[],excludeAuthors:[],includeAuthors:[],excludeMessages:[],groupBreakingChanges:!1,maxCommitsPerSection:0,minCommitsForSection:1,maxDescriptionLength:0}),blocks=[];for(const section of sections){const type=section.commits[0]?.type??"",seen=new Set,lines=section.commits.map((entry)=>line(entry.description,entry.scope)).filter((text)=>text&&!seen.has(text.toLowerCase())&&seen.add(text.toLowerCase())).map((text)=>`- ${text}`);if(!lines.length)continue;const title=SECTION_TITLES[type]??type.charAt(0).toUpperCase()+type.slice(1);blocks.push([options.markdown?`**${title}**`:title,...options.markdown?[""]:[],...lines].join(`
2
+ `))}return blocks.join(`
3
+
4
+ `)}export const NO_VISIBLE_CHANGES="Maintenance build: no visible changes since the previous build.";export function fitNotes(text,limit){const notes=text.trim();if(notes.length<=limit)return notes;const lines=notes.split(`
5
+ `),isItem=(value)=>/^\s*(?:[-*\u2022]|\d+\.)\s/.test(value),suffix=(omitted)=>omitted>0?`
6
+ \u2026and ${omitted} more`:"\u2026",kept=[];let index=0;for(;index<lines.length;index++){const rest=lines.slice(index+1).filter(isItem).length;if([...kept,lines[index]].join(`
7
+ `).length+suffix(rest).length>limit)break;kept.push(lines[index])}const trim=()=>{while(kept.length&&!kept[kept.length-1].trim())kept.pop()};trim();if(kept.length&&!isItem(kept[kept.length-1])&&lines[kept.length]!==void 0&&isItem(lines[kept.length])&&kept.some(isItem)){kept.pop();trim()}const omitted=lines.slice(kept.length).filter(isItem).length;if(!kept.length||omitted===0&&!kept.some(isItem)){const room=limit-1,cut=notes.slice(0,room),word=cut.lastIndexOf(" ");return`${(word>room/2?cut.slice(0,word):cut).trimEnd()}\u2026`}return`${kept.join(`
8
+ `)}${suffix(omitted)}`}function git(cwd,args){const result=Bun.spawnSync(["git",...args],{cwd,stdout:"pipe",stderr:"ignore"});return result.exitCode===0?result.stdout.toString().trim():null}export function previousMobileTag(cwd,ref="HEAD"){return git(cwd,["describe","--tags","--match","v*-build.*","--abbrev=0",ref])||void 0}export function commitsBetween(cwd,from,to="HEAD"){return getCommits(from,to,cwd)}function readNotesFile(cwd,path,origin){const absolute=isAbsolute(path)?path:join(cwd,path);if(!existsSync(absolute))throw Error(`${origin} names ${path}, which does not exist`);return readFileSync(absolute,"utf8")}export function resolveNotes(options){const{cwd,flags={},env=process.env,config={}}=options,pick=(text,file,origin,source)=>{if(text?.trim()&&file?.trim())throw Error(`give either ${origin[0]} or ${origin[1]}, not both`);const value=text?.trim()?text:file?.trim()?readNotesFile(cwd,file.trim(),origin[1]):void 0;return value?.trim()?{text:value.trim(),source}:null},notes=typeof flags.notes==="string"?flags.notes:void 0,notesFile=typeof flags.notesFile==="string"?flags.notesFile:void 0;return pick(notes,notesFile,["--notes","--notes-file"],"flag")??pick(env.RELEASE_NOTES,env.RELEASE_NOTES_FILE,["RELEASE_NOTES","RELEASE_NOTES_FILE"],"env")??pick(config.notes,config.notesFile,["release.notes","release.notesFile"],"config")??{text:options.generate().trim()||NO_VISIBLE_CHANGES,source:"generated"}}const APP_STORE_LOCALES={en:"en-US",de:"de-DE",fr:"fr-FR",es:"es-ES",nl:"nl-NL",pt:"pt-BR",zh:"zh-Hans"};export function appStoreLocales(languages){const locales=(languages??[]).map((language)=>language.trim().replace("_","-")).filter(Boolean).map((language)=>language.includes("-")?language:APP_STORE_LOCALES[language.toLowerCase()]??language.toLowerCase());return[...new Set(["en-US",...locales])]}export function writeWhatToTest(root,projectDir,notes,locales){const dir=join(isAbsolute(projectDir)?projectDir:join(root,projectDir),"TestFlight");mkdirSync(dir,{recursive:!0});const text=`${fitNotes(notes,XCODE_CLOUD_NOTES_LIMIT)}
9
+ `;return locales.map((locale)=>{const path=join(dir,`WhatToTest.${locale}.txt`);writeFileSync(path,text);return relative(root,path)})}export function committedWhatToTest(cwd,tag,projectDir,locale="en-US"){const path=`${projectDir.replace(/\/$/,"")}/TestFlight/WhatToTest.${locale}.txt`;return git(cwd,["show",`${tag}:${path}`])}
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@stacksjs/actions",
3
3
  "type": "module",
4
4
  "sideEffects": false,
5
- "version": "0.75.257",
5
+ "version": "0.75.258",
6
6
  "description": "The Stacks actions.",
7
7
  "author": "Chris Breuer",
8
8
  "contributors": [
@@ -66,54 +66,54 @@
66
66
  "prepublishOnly": "bun run build"
67
67
  },
68
68
  "dependencies": {
69
- "@stacksjs/action-runner": "0.75.257",
70
- "@stacksjs/ai": "0.75.257",
71
- "@stacksjs/analytics": "0.75.257",
72
- "@stacksjs/api": "0.75.257",
73
- "@stacksjs/auth": "0.75.257",
74
- "@stacksjs/build": "0.75.257",
69
+ "@stacksjs/action-runner": "0.75.258",
70
+ "@stacksjs/ai": "0.75.258",
71
+ "@stacksjs/analytics": "0.75.258",
72
+ "@stacksjs/api": "0.75.258",
73
+ "@stacksjs/auth": "0.75.258",
74
+ "@stacksjs/build": "0.75.258",
75
75
  "@stacksjs/bumpx": "^0.2.25",
76
76
  "@stacksjs/bunpress": "^0.2.15",
77
- "@stacksjs/cli": "0.75.257",
78
- "@stacksjs/cloud": "0.75.257",
79
- "@stacksjs/cms": "0.75.257",
77
+ "@stacksjs/cli": "0.75.258",
78
+ "@stacksjs/cloud": "0.75.258",
79
+ "@stacksjs/cms": "0.75.258",
80
80
  "@stacksjs/components": "0.2.644",
81
- "@stacksjs/config": "0.75.257",
82
- "@stacksjs/database": "0.75.257",
83
- "@stacksjs/desktop-build": "0.75.257",
84
- "@stacksjs/dns": "0.75.257",
85
- "@stacksjs/enums": "0.75.257",
86
- "@stacksjs/env": "0.75.257",
87
- "@stacksjs/error-handling": "0.75.257",
88
- "@stacksjs/github": "0.75.257",
81
+ "@stacksjs/config": "0.75.258",
82
+ "@stacksjs/database": "0.75.258",
83
+ "@stacksjs/desktop-build": "0.75.258",
84
+ "@stacksjs/dns": "0.75.258",
85
+ "@stacksjs/enums": "0.75.258",
86
+ "@stacksjs/env": "0.75.258",
87
+ "@stacksjs/error-handling": "0.75.258",
88
+ "@stacksjs/github": "0.75.258",
89
89
  "@stacksjs/gitit": "^0.2.5",
90
- "@stacksjs/i18n": "0.75.257",
91
- "@stacksjs/image": "0.75.257",
92
- "@stacksjs/logging": "0.75.257",
90
+ "@stacksjs/i18n": "0.75.258",
91
+ "@stacksjs/image": "0.75.258",
92
+ "@stacksjs/logging": "0.75.258",
93
93
  "@stacksjs/logsmith": "^0.2.11",
94
- "@stacksjs/mobile": "0.75.257",
95
- "@stacksjs/orm": "0.75.257",
96
- "@stacksjs/path": "0.75.257",
97
- "@stacksjs/payments": "0.75.257",
98
- "@stacksjs/queue": "0.75.257",
99
- "@stacksjs/registry": "0.75.257",
100
- "@stacksjs/router": "0.75.257",
94
+ "@stacksjs/mobile": "0.75.258",
95
+ "@stacksjs/orm": "0.75.258",
96
+ "@stacksjs/path": "0.75.258",
97
+ "@stacksjs/payments": "0.75.258",
98
+ "@stacksjs/queue": "0.75.258",
99
+ "@stacksjs/registry": "0.75.258",
100
+ "@stacksjs/router": "0.75.258",
101
101
  "@stacksjs/rpx": "^0.11.54",
102
- "@stacksjs/scheduler": "0.75.257",
103
- "@stacksjs/search-engine": "0.75.257",
104
- "@stacksjs/security": "0.75.257",
105
- "@stacksjs/server": "0.75.257",
106
- "@stacksjs/sites": "0.75.257",
107
- "@stacksjs/storage": "0.75.257",
108
- "@stacksjs/strings": "0.75.257",
102
+ "@stacksjs/scheduler": "0.75.258",
103
+ "@stacksjs/search-engine": "0.75.258",
104
+ "@stacksjs/security": "0.75.258",
105
+ "@stacksjs/server": "0.75.258",
106
+ "@stacksjs/sites": "0.75.258",
107
+ "@stacksjs/storage": "0.75.258",
108
+ "@stacksjs/strings": "0.75.258",
109
109
  "@stacksjs/stx": "0.2.644",
110
110
  "@stacksjs/tlsx": "^0.13.19",
111
111
  "@stacksjs/ts-cloud": "^0.16.58",
112
112
  "@stacksjs/ts-md": "^0.1.1",
113
- "@stacksjs/tunnel": "0.75.257",
114
- "@stacksjs/types": "0.75.257",
115
- "@stacksjs/utils": "0.75.257",
116
- "@stacksjs/whois": "0.75.257",
113
+ "@stacksjs/tunnel": "0.75.258",
114
+ "@stacksjs/types": "0.75.258",
115
+ "@stacksjs/utils": "0.75.258",
116
+ "@stacksjs/whois": "0.75.258",
117
117
  "bun-plugin-stx": "0.2.644"
118
118
  },
119
119
  "peerDependencies": {
@@ -129,7 +129,7 @@
129
129
  }
130
130
  },
131
131
  "devDependencies": {
132
- "@stacksjs/validation": "0.75.257",
132
+ "@stacksjs/validation": "0.75.258",
133
133
  "better-dx": "^0.2.24"
134
134
  }
135
135
  }