mirror of
https://github.com/payloadcms/payload.git
synced 2026-09-14 20:07:19 +08:00
chore: skip workspace/catalog/link payload deps in upgrade rewrite
This commit is contained in:
@@ -14,7 +14,11 @@ import { loadProject } from '../utils/project.js'
|
||||
import { detectPackageManager } from './detectPackageManager.js'
|
||||
import { renderReport } from './report.js'
|
||||
import { resolveVersions } from './resolveVersions.js'
|
||||
import { isPayloadEslintPackage, rewritePackageJson } from './rewritePackageJson.js'
|
||||
import {
|
||||
isPayloadEslintPackage,
|
||||
isPlaceholderSpec,
|
||||
rewritePackageJson,
|
||||
} from './rewritePackageJson.js'
|
||||
import { runInstall } from './runInstall.js'
|
||||
import { RUNBOOK_RELATIVE_PATH } from './types.js'
|
||||
|
||||
@@ -140,6 +144,7 @@ export async function runUpgrade(
|
||||
floorsWritten: summary.floorsWritten,
|
||||
nextTarget: resolved.nextTarget,
|
||||
overridesRemoved: summary.overridesRemoved,
|
||||
placeholdersSkipped: summary.placeholdersSkipped,
|
||||
runbookPath: resolve(dirname(fileURLToPath(import.meta.url)), '..', RUNBOOK_RELATIVE_PATH),
|
||||
transforms: results,
|
||||
versions,
|
||||
@@ -175,6 +180,11 @@ function verifyResolution(
|
||||
if (isPayloadEslintPackage(name)) {
|
||||
continue
|
||||
}
|
||||
// Workspace/catalog/link specs were left unpinned, so there is no exact
|
||||
// version to verify against.
|
||||
if (isPlaceholderSpec(deps[name])) {
|
||||
continue
|
||||
}
|
||||
const installed = readInstalledVersion(projectPath, name)
|
||||
rows.push({
|
||||
name,
|
||||
|
||||
@@ -8,6 +8,7 @@ describe('renderReport', () => {
|
||||
floorsWritten: ['typescript', '@types/node', 'engines.node'],
|
||||
nextTarget: '16.9.3',
|
||||
overridesRemoved: ['pnpm.overrides.payload'],
|
||||
placeholdersSkipped: ['@payloadcms/ui'],
|
||||
runbookPath: '/x/dist/runbook/payload-v4-upgrade.md',
|
||||
transforms: [
|
||||
{ filesChanged: ['a.ts'], name: 'migrate-versions-default', notes: ['review X'] },
|
||||
@@ -26,6 +27,8 @@ describe('renderReport', () => {
|
||||
expect(out).toContain('payload-v4-upgrade.md')
|
||||
expect(out).toContain('Floors written')
|
||||
expect(out).toContain('typescript')
|
||||
expect(out).toContain('Left as-is')
|
||||
expect(out).toContain('@payloadcms/ui')
|
||||
})
|
||||
|
||||
it('flags a resolution mismatch as not confirmed v4', () => {
|
||||
@@ -33,6 +36,7 @@ describe('renderReport', () => {
|
||||
floorsWritten: [],
|
||||
nextTarget: null,
|
||||
overridesRemoved: [],
|
||||
placeholdersSkipped: [],
|
||||
runbookPath: '/x/runbook.md',
|
||||
transforms: [],
|
||||
versions: [{ name: 'payload', ok: false, resolved: '3.40.0', wrote: '4.0.0-canary.20' }],
|
||||
@@ -48,6 +52,7 @@ describe('renderReport', () => {
|
||||
floorsWritten: [],
|
||||
nextTarget: null,
|
||||
overridesRemoved: [],
|
||||
placeholdersSkipped: [],
|
||||
runbookPath: '/x/runbook.md',
|
||||
transforms: [{ error: new Error('boom'), filesChanged: [], name: 'broken-transform' }],
|
||||
versions: [],
|
||||
|
||||
@@ -11,6 +11,7 @@ export type ReportModel = {
|
||||
floorsWritten: string[]
|
||||
nextTarget: null | string
|
||||
overridesRemoved: string[]
|
||||
placeholdersSkipped: string[]
|
||||
runbookPath: string
|
||||
transforms: TransformRunResult[]
|
||||
versions: VersionReportRow[]
|
||||
@@ -36,6 +37,13 @@ export function renderReport(model: ReportModel): string {
|
||||
lines.push(`Overrides removed: ${model.overridesRemoved.join(', ')}`, '')
|
||||
}
|
||||
|
||||
if (model.placeholdersSkipped.length > 0) {
|
||||
lines.push(
|
||||
`Left as-is (workspace/catalog/link specs): ${model.placeholdersSkipped.join(', ')}`,
|
||||
'',
|
||||
)
|
||||
}
|
||||
|
||||
if (model.floorsWritten.length > 0) {
|
||||
lines.push(`Floors written: ${model.floorsWritten.join(', ')}`, '')
|
||||
}
|
||||
|
||||
@@ -63,6 +63,42 @@ describe('rewritePackageJson', () => {
|
||||
expect(summary.pinnedPayload).not.toContain('@payloadcms/eslint-config')
|
||||
})
|
||||
|
||||
it('leaves workspace/catalog/link specs untouched and reports them as skipped', () => {
|
||||
const data: Record<string, unknown> = {
|
||||
dependencies: {
|
||||
'@payloadcms/next': 'catalog:',
|
||||
'@payloadcms/richtext-lexical': 'link:../lexical',
|
||||
payload: 'workspace:*',
|
||||
},
|
||||
devDependencies: {
|
||||
'@payloadcms/eslint-config': 'workspace:^',
|
||||
'@payloadcms/ui': '^3.0.0',
|
||||
},
|
||||
}
|
||||
|
||||
const summary = rewritePackageJson({ data, resolved })
|
||||
|
||||
expect(data.dependencies).toEqual({
|
||||
'@payloadcms/next': 'catalog:',
|
||||
'@payloadcms/richtext-lexical': 'link:../lexical',
|
||||
payload: 'workspace:*',
|
||||
})
|
||||
// The non-placeholder eslint dep still moves to latest; the workspace one does not.
|
||||
expect(data.devDependencies).toMatchObject({
|
||||
'@payloadcms/eslint-config': 'workspace:^',
|
||||
'@payloadcms/ui': '4.0.0-canary.20',
|
||||
})
|
||||
expect(summary.placeholdersSkipped.sort()).toEqual(
|
||||
[
|
||||
'@payloadcms/eslint-config',
|
||||
'@payloadcms/next',
|
||||
'@payloadcms/richtext-lexical',
|
||||
'payload',
|
||||
].sort(),
|
||||
)
|
||||
expect(summary.pinnedPayload).toEqual(['@payloadcms/ui'])
|
||||
})
|
||||
|
||||
it('adds floors to devDependencies when absent', () => {
|
||||
const data: Record<string, unknown> = { dependencies: { payload: '^3.0.0' } }
|
||||
|
||||
|
||||
@@ -9,10 +9,14 @@ export type RewriteSummary = {
|
||||
floorsWritten: string[]
|
||||
overridesRemoved: string[]
|
||||
pinnedPayload: string[]
|
||||
placeholdersSkipped: string[]
|
||||
}
|
||||
|
||||
const DEP_FIELDS = ['dependencies', 'devDependencies'] as const
|
||||
|
||||
/** Any protocol-prefixed specifier (`workspace:*`, `catalog:`, `link:`, `file:`, `npm:`, a URL). */
|
||||
const PLACEHOLDER_SPEC = /^[a-z][a-z0-9+.-]*:/i
|
||||
|
||||
export const isPayloadPackage = (name: string): boolean =>
|
||||
name === 'payload' || name.startsWith('@payloadcms/')
|
||||
|
||||
@@ -23,6 +27,14 @@ export const isPayloadPackage = (name: string): boolean =>
|
||||
export const isPayloadEslintPackage = (name: string): boolean =>
|
||||
name.startsWith('@payloadcms/eslint')
|
||||
|
||||
/**
|
||||
* A dependency whose version is resolved by the package manager, not a semver
|
||||
* range: `workspace:*`, `catalog:`, `link:`, `file:`, `npm:` aliases, URLs.
|
||||
* Overwriting one with an exact version would break the link, so it is left as-is.
|
||||
*/
|
||||
export const isPlaceholderSpec = (spec: unknown): boolean =>
|
||||
typeof spec === 'string' && PLACEHOLDER_SPEC.test(spec)
|
||||
|
||||
/**
|
||||
* Mutate `data` in place for a v4 upgrade: exact-pin payload packages, drop
|
||||
* payload dependency overrides, and write the toolchain floors. Never touches
|
||||
@@ -30,31 +42,41 @@ export const isPayloadEslintPackage = (name: string): boolean =>
|
||||
* Returns a summary for the report. Idempotent.
|
||||
*/
|
||||
export function rewritePackageJson({ data, resolved }: RewriteArgs): RewriteSummary {
|
||||
const pinnedPayload = pinPayloadPackages(data, resolved.payloadVersion)
|
||||
const { pinnedPayload, placeholdersSkipped } = pinPayloadPackages(data, resolved.payloadVersion)
|
||||
const overridesRemoved = removePayloadOverrides(data)
|
||||
const floorsWritten = writeFloors(data, resolved)
|
||||
return { floorsWritten, overridesRemoved, pinnedPayload }
|
||||
return { floorsWritten, overridesRemoved, pinnedPayload, placeholdersSkipped }
|
||||
}
|
||||
|
||||
function pinPayloadPackages(data: Record<string, unknown>, version: string): string[] {
|
||||
function pinPayloadPackages(
|
||||
data: Record<string, unknown>,
|
||||
version: string,
|
||||
): { pinnedPayload: string[]; placeholdersSkipped: string[] } {
|
||||
const pinned: string[] = []
|
||||
const skipped: string[] = []
|
||||
for (const field of DEP_FIELDS) {
|
||||
const deps = data[field]
|
||||
if (!isRecord(deps)) {
|
||||
continue
|
||||
}
|
||||
for (const name of Object.keys(deps)) {
|
||||
if (!isPayloadPackage(name)) {
|
||||
continue
|
||||
}
|
||||
// A workspace/catalog/link spec resolves itself; pinning it breaks the link.
|
||||
if (isPlaceholderSpec(deps[name])) {
|
||||
skipped.push(name)
|
||||
continue
|
||||
}
|
||||
if (isPayloadEslintPackage(name)) {
|
||||
deps[name] = 'latest'
|
||||
continue
|
||||
}
|
||||
if (isPayloadPackage(name)) {
|
||||
deps[name] = version
|
||||
pinned.push(name)
|
||||
}
|
||||
deps[name] = version
|
||||
pinned.push(name)
|
||||
}
|
||||
}
|
||||
return pinned
|
||||
return { pinnedPayload: pinned, placeholdersSkipped: skipped }
|
||||
}
|
||||
|
||||
function removePayloadOverrides(data: Record<string, unknown>): string[] {
|
||||
|
||||
Reference in New Issue
Block a user