From 856087c65b9cf295ff48ecab0578de7363c97e37 Mon Sep 17 00:00:00 2001 From: djk01281 Date: Tue, 30 Jun 2026 20:58:36 +0900 Subject: [PATCH] =?UTF-8?q?[#36]=20=F0=9F=90=9B=20fix:=20respect=20changes?= =?UTF-8?q?ets=20fixed=20groups=20in=20canary=20publish?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit protectUnchangedPackages marked every package without a changed file in the PR as private, ignoring the changesets `fixed` group. When a PR touched only one member of a fixed group, the others stayed unpublished and the released package pointed at versions that never shipped. Expand the publish set to include all members of any fixed group it intersects, so protection and version templating cover the whole group. --- canary-publish/dist/index.js | 52 +++++++++++++++++++++++++++-- canary-publish/src/index.ts | 16 ++++++--- canary-publish/src/utils/file.ts | 56 ++++++++++++++++++++++++++++++++ 3 files changed, 117 insertions(+), 7 deletions(-) diff --git a/canary-publish/dist/index.js b/canary-publish/dist/index.js index c7e6ffd..4d93a49 100644 --- a/canary-publish/dist/index.js +++ b/canary-publish/dist/index.js @@ -53319,11 +53319,13 @@ function main() { core.info('No changed packages found.'); return; } + // fixed 그룹 패키지는 함께 배포되어야 하므로 같은 그룹의 형제 패키지를 포함시킵니다. + const packagesToPublish = yield (0, file_1.withFixedGroupSiblings)(changedPackageInfos); yield Promise.all([ // 이번 변경건과 관련없는 모든 .changeset/*.md 파일을 제거한다. (0, file_1.removeChangesetMdFiles)({ changedFiles }), // 변경사항외 다른 패키지들의 배포를 막습니다. - (0, file_1.protectUnchangedPackages)(changedPackageInfos), + (0, file_1.protectUnchangedPackages)(packagesToPublish), ]); // 패키지 변경 버전 반영 yield (0, exec_1.exec)('node', [(0, resolve_from_1.default)(cwd, '@changesets/cli/bin.js'), 'version'], { @@ -53348,8 +53350,8 @@ function main() { fs.writeFileSync(rootPackageJsonPath, JSON.stringify(rootPackageJson, null, 2), 'utf8'); const versionTemplate = core.getInput('version_template'); const packagePathByName = {}; - // 변경된 패키지들의 버전을 강제로 치환합니다 - changedPackageInfos.forEach((packageJsonPath) => { + // 배포 대상 패키지들의 버전을 강제로 치환합니다 + packagesToPublish.forEach((packageJsonPath) => { const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')); const today = new Date(); const pad = (n) => n.toString().padStart(2, '0'); @@ -53463,6 +53465,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.getChangedPackages = getChangedPackages; exports.getAllPackageJSON = getAllPackageJSON; exports.protectUnchangedPackages = protectUnchangedPackages; +exports.withFixedGroupSiblings = withFixedGroupSiblings; exports.removeChangesetMdFiles = removeChangesetMdFiles; const core = __importStar(__nccwpck_require__(6108)); const fast_glob_1 = __importDefault(__nccwpck_require__(6014)); @@ -53511,6 +53514,49 @@ function protectUnchangedPackages(changedPackages) { } }); } +// Members of a changesets `fixed` group are published together, so an untouched +// sibling of a changed package must publish too — not be marked private. +function withFixedGroupSiblings(changedPackages) { + return __awaiter(this, void 0, void 0, function* () { + var _a; + let fixedGroups; + try { + const config = JSON.parse(fs.readFileSync('.changeset/config.json', 'utf8')); + fixedGroups = (_a = config.fixed) !== null && _a !== void 0 ? _a : []; + } + catch (_b) { + return changedPackages; + } + if (fixedGroups.length === 0) { + return changedPackages; + } + const allPackageJSON = yield getAllPackageJSON(); + const pathByName = new Map(); + for (const packageJsonPath of allPackageJSON) { + const { name } = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')); + if (typeof name === 'string') { + pathByName.set(name, packageJsonPath); + } + } + const changedPaths = new Set(changedPackages); + const expanded = new Set(changedPackages); + for (const group of fixedGroups) { + const groupTouchesChange = group.some((name) => { + const packageJsonPath = pathByName.get(name); + return packageJsonPath != null && changedPaths.has(packageJsonPath); + }); + if (groupTouchesChange) { + for (const name of group) { + const packageJsonPath = pathByName.get(name); + if (packageJsonPath != null) { + expanded.add(packageJsonPath); + } + } + } + } + return Array.from(expanded); + }); +} function removeChangesetMdFiles(_a) { return __awaiter(this, arguments, void 0, function* ({ changedFiles, }) { const markdownPaths = yield (0, fast_glob_1.default)('.changeset/*.md'); diff --git a/canary-publish/src/index.ts b/canary-publish/src/index.ts index 9599d32..64128d1 100644 --- a/canary-publish/src/index.ts +++ b/canary-publish/src/index.ts @@ -10,7 +10,12 @@ import resolveFrom from 'resolve-from' import createFetchers from '$actions/apis' import {getChangedAllFiles} from '$actions/utils' -import {getChangedPackages, protectUnchangedPackages, removeChangesetMdFiles} from './utils/file' +import { + getChangedPackages, + protectUnchangedPackages, + removeChangesetMdFiles, + withFixedGroupSiblings, +} from './utils/file' import {setNpmRc} from './utils/npm' import {createReleaseForTags, getPublishedPackageInfos} from './utils/publish' @@ -60,11 +65,14 @@ async function main() { return } + // fixed 그룹 패키지는 함께 배포되어야 하므로 같은 그룹의 형제 패키지를 포함시킵니다. + const packagesToPublish = await withFixedGroupSiblings(changedPackageInfos) + await Promise.all([ // 이번 변경건과 관련없는 모든 .changeset/*.md 파일을 제거한다. removeChangesetMdFiles({changedFiles}), // 변경사항외 다른 패키지들의 배포를 막습니다. - protectUnchangedPackages(changedPackageInfos), + protectUnchangedPackages(packagesToPublish), ]) // 패키지 변경 버전 반영 @@ -95,8 +103,8 @@ async function main() { const packagePathByName: Record = {} - // 변경된 패키지들의 버전을 강제로 치환합니다 - changedPackageInfos.forEach((packageJsonPath) => { + // 배포 대상 패키지들의 버전을 강제로 치환합니다 + packagesToPublish.forEach((packageJsonPath) => { const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')) const today = new Date() diff --git a/canary-publish/src/utils/file.ts b/canary-publish/src/utils/file.ts index 8d621a5..779c1a6 100644 --- a/canary-publish/src/utils/file.ts +++ b/canary-publish/src/utils/file.ts @@ -65,6 +65,62 @@ export async function protectUnchangedPackages(changedPackages: string[]) { } } +interface ChangesetConfig { + fixed?: string[][] +} + +// Members of a changesets `fixed` group are published together, so an untouched +// sibling of a changed package must publish too — not be marked private. +export async function withFixedGroupSiblings(changedPackages: string[]): Promise { + let fixedGroups: string[][] + + try { + const config = JSON.parse(fs.readFileSync('.changeset/config.json', 'utf8')) as ChangesetConfig + + fixedGroups = config.fixed ?? [] + } catch { + return changedPackages + } + + if (fixedGroups.length === 0) { + return changedPackages + } + + const allPackageJSON = await getAllPackageJSON() + const pathByName = new Map() + + for (const packageJsonPath of allPackageJSON) { + const {name} = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')) + + if (typeof name === 'string') { + pathByName.set(name, packageJsonPath) + } + } + + const changedPaths = new Set(changedPackages) + const expanded = new Set(changedPackages) + + for (const group of fixedGroups) { + const groupTouchesChange = group.some((name) => { + const packageJsonPath = pathByName.get(name) + + return packageJsonPath != null && changedPaths.has(packageJsonPath) + }) + + if (groupTouchesChange) { + for (const name of group) { + const packageJsonPath = pathByName.get(name) + + if (packageJsonPath != null) { + expanded.add(packageJsonPath) + } + } + } + } + + return Array.from(expanded) +} + export async function removeChangesetMdFiles({ changedFiles, }: {