11import { vi } from 'vitest' ;
22import { execFileSync } from 'node:child_process' ;
3- import { mkdtempSync , rmSync , writeFileSync } from 'node:fs' ;
3+ import { mkdirSync , mkdtempSync , rmSync , writeFileSync } from 'node:fs' ;
44import { tmpdir } from 'node:os' ;
55import { join } from 'node:path' ;
66import {
@@ -12,6 +12,7 @@ import {
1212} from '../git' ;
1313import * as loggerModule from '../../logger' ;
1414import type { StatusResult } from 'simple-git' ;
15+ import { setActiveWorkspace } from '../../config' ;
1516
1617describe ( 'getLatestTag' , ( ) => {
1718 it ( 'returns latest tag in the repo by calling `git describe`' , async ( ) => {
@@ -129,6 +130,135 @@ describe('getChangesSince', () => {
129130 rmSync ( dir , { recursive : true , force : true } ) ;
130131 }
131132 } ) ;
133+
134+ it ( 'includes shared and selected workspace changes, with optional related paths' , async ( ) => {
135+ const dir = mkdtempSync ( join ( tmpdir ( ) , 'craft-changelog-workspaces-' ) ) ;
136+ const previousDirectory = process . cwd ( ) ;
137+ const git = ( ...args : string [ ] ) =>
138+ execFileSync ( 'git' , [ '-C' , dir , ...args ] , {
139+ env : {
140+ ...process . env ,
141+ GIT_CONFIG_GLOBAL : '/dev/null' ,
142+ GIT_CONFIG_NOSYSTEM : '1' ,
143+ } ,
144+ } ) ;
145+ const commit = (
146+ file : string ,
147+ title : string ,
148+ additionalFiles : string [ ] = [ ] ,
149+ ) => {
150+ writeFileSync ( join ( dir , file ) , title ) ;
151+ git ( 'add' , '--' , file , ...additionalFiles ) ;
152+ git ( '-c' , 'commit.gpgsign=false' , 'commit' , '--quiet' , '-m' , title ) ;
153+ } ;
154+
155+ try {
156+ git ( 'init' , '--quiet' ) ;
157+ git ( 'config' , 'user.name' , 'Craft Test' ) ;
158+ git ( 'config' , 'user.email' , 'craft-test@example.com' ) ;
159+ for ( const workspace of [
160+ 'packages/cli' ,
161+ 'packages/mcp' ,
162+ 'apps/cli-docs' ,
163+ 'apps/cli-docs-extra' ,
164+ ] ) {
165+ mkdirSync ( join ( dir , workspace ) , { recursive : true } ) ;
166+ writeFileSync (
167+ join ( dir , workspace , 'package.json' ) ,
168+ JSON . stringify ( { name : workspace } ) ,
169+ ) ;
170+ }
171+ mkdirSync ( join ( dir , 'docs' ) ) ;
172+ writeFileSync (
173+ join ( dir , '.craft.yml' ) ,
174+ 'minVersion: 2.29.0\nworkspaces:\n packages/cli:\n changelog:\n policy: auto\n packages/mcp: {}\n' ,
175+ ) ;
176+ writeFileSync (
177+ join ( dir , 'pnpm-workspace.yaml' ) ,
178+ 'packages:\n - packages/*\n - apps/*\n' ,
179+ ) ;
180+ git ( 'add' , '.' ) ;
181+ git ( '-c' , 'commit.gpgsign=false' , 'commit' , '--quiet' , '-m' , 'initial' ) ;
182+ git ( 'tag' , 'cli@0.1.0' ) ;
183+ commit ( 'packages/cli/cli.ts' , 'cli change' ) ;
184+ commit ( 'packages/mcp/mcp.ts' , 'mcp change' ) ;
185+ commit ( 'apps/cli-docs/site.ts' , 'cli docs change' ) ;
186+ commit ( 'apps/cli-docs-extra/site.ts' , 'other docs change' ) ;
187+ commit ( 'docs/readme.md' , 'unowned docs change' ) ;
188+ commit ( 'root.txt' , 'root change' ) ;
189+ writeFileSync ( join ( dir , 'packages/cli/cli.ts' ) , 'shared change' ) ;
190+ commit ( 'packages/mcp/mcp.ts' , 'both change' , [ 'packages/cli/cli.ts' ] ) ;
191+
192+ process . chdir ( dir ) ;
193+ setActiveWorkspace ( 'packages/cli' ) ;
194+ const client = createGitClient ( dir ) ;
195+ const titles = async ( ) =>
196+ ( await getChangesSince ( client , 'cli@0.1.0' ) ) . map ( ( { title } ) => title ) ;
197+
198+ expect ( await titles ( ) ) . toEqual ( [
199+ 'both change' ,
200+ 'root change' ,
201+ 'unowned docs change' ,
202+ 'cli change' ,
203+ ] ) ;
204+ expect (
205+ ( await getChangesSince ( client , '' , 'cli@0.1.0' ) ) . map (
206+ ( { title } ) => title ,
207+ ) ,
208+ ) . toEqual ( [ 'initial' ] ) ;
209+
210+ setActiveWorkspace ( 'packages/mcp' ) ;
211+ expect ( await titles ( ) ) . toEqual ( [
212+ 'both change' ,
213+ 'root change' ,
214+ 'unowned docs change' ,
215+ 'mcp change' ,
216+ ] ) ;
217+ setActiveWorkspace ( 'packages/cli' ) ;
218+
219+ writeFileSync (
220+ join ( dir , '.craft.yml' ) ,
221+ 'minVersion: 2.29.0\nworkspaces:\n packages/cli:\n changelog:\n policy: auto\n includePaths:\n - apps/cli-docs\n packages/mcp: {}\n' ,
222+ ) ;
223+ setActiveWorkspace ( 'packages/cli' ) ;
224+ expect ( await titles ( ) ) . toEqual ( [
225+ 'both change' ,
226+ 'root change' ,
227+ 'unowned docs change' ,
228+ 'cli docs change' ,
229+ 'cli change' ,
230+ ] ) ;
231+
232+ git ( 'mv' , 'packages/cli/cli.ts' , 'packages/mcp/moved.ts' ) ;
233+ git (
234+ '-c' ,
235+ 'commit.gpgsign=false' ,
236+ 'commit' ,
237+ '--quiet' ,
238+ '-m' ,
239+ 'moved across workspaces' ,
240+ ) ;
241+ commit ( 'packages/cli/line\nbreak.ts' , 'newline filename' ) ;
242+ expect ( await titles ( ) ) . toEqual ( [
243+ 'newline filename' ,
244+ 'moved across workspaces' ,
245+ 'both change' ,
246+ 'root change' ,
247+ 'unowned docs change' ,
248+ 'cli docs change' ,
249+ 'cli change' ,
250+ ] ) ;
251+ setActiveWorkspace ( 'packages/mcp' ) ;
252+ expect ( ( await titles ( ) ) . slice ( 0 , 2 ) ) . toEqual ( [
253+ 'moved across workspaces' ,
254+ 'both change' ,
255+ ] ) ;
256+ } finally {
257+ setActiveWorkspace ( undefined ) ;
258+ process . chdir ( previousDirectory ) ;
259+ rmSync ( dir , { recursive : true , force : true } ) ;
260+ }
261+ } ) ;
132262} ) ;
133263
134264describe ( 'isRepoDirty' , ( ) => {
0 commit comments