check-workspace-constraints.spec.ts 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. /** Experimental-package publication and dependency constraints. */
  2. import { readFileSync } from 'node:fs'
  3. import { describe, expect, it } from 'vitest'
  4. import {
  5. checkDshFamilyVersion,
  6. checkWorkspaceManifest,
  7. checkExperimentalDependencyIsolation,
  8. checkExperimentalManifest,
  9. expectedDshPackageFiles,
  10. type WorkspaceManifest,
  11. } from './check-workspace-constraints.ts'
  12. const experimental: WorkspaceManifest = {
  13. dir: 'packages/experimental/prototype',
  14. manifest: { name: '@deepseek-ai/dsh-experimental-prototype', private: true },
  15. }
  16. const publicExperimental: WorkspaceManifest = {
  17. dir: 'packages/experimental/agent-team',
  18. manifest: {
  19. name: '@deepseek-ai/dsh-experimental-agent-team',
  20. publishConfig: { access: 'public' },
  21. },
  22. }
  23. describe('experimental workspace constraints', () => {
  24. it('requires the experimental package-name prefix', () => {
  25. expect(checkExperimentalManifest({
  26. ...experimental,
  27. manifest: { ...experimental.manifest, name: '@deepseek-ai/dsh-prototype' },
  28. })).toEqual([
  29. '@deepseek-ai/dsh-prototype: experimental package name must start with "@deepseek-ai/dsh-experimental-"',
  30. ])
  31. })
  32. it('requires private manifests without publication metadata', () => {
  33. expect(checkExperimentalManifest(experimental)).toEqual([])
  34. expect(checkExperimentalManifest({
  35. ...experimental,
  36. manifest: { ...experimental.manifest, private: false, publishConfig: { access: 'public' } },
  37. })).toEqual([
  38. '@deepseek-ai/dsh-experimental-prototype: experimental package must set "private": true',
  39. '@deepseek-ai/dsh-experimental-prototype: experimental package must omit publishConfig',
  40. ])
  41. })
  42. it('requires public metadata only for the Agent Teams exceptions', () => {
  43. expect(checkExperimentalManifest(publicExperimental)).toEqual([])
  44. expect(checkExperimentalManifest({
  45. ...publicExperimental,
  46. manifest: {
  47. name: '@deepseek-ai/dsh-experimental-agent-team',
  48. private: true,
  49. },
  50. })).toEqual([
  51. '@deepseek-ai/dsh-experimental-agent-team: public experimental package must not set "private": true',
  52. '@deepseek-ai/dsh-experimental-agent-team: public experimental package must set publishConfig.access to "public"',
  53. ])
  54. })
  55. it.each(['dependencies', 'optionalDependencies', 'peerDependencies'] as const)(
  56. 'rejects release %s on an experimental package',
  57. (section) => {
  58. expect(checkExperimentalDependencyIsolation([experimental, {
  59. dir: 'packages/core/consumer',
  60. manifest: {
  61. name: '@deepseek-ai/dsh-consumer',
  62. [section]: { '@deepseek-ai/dsh-experimental-prototype': 'workspace:^' },
  63. },
  64. }])).toEqual([
  65. `@deepseek-ai/dsh-consumer: ${section}.@deepseek-ai/dsh-experimental-prototype must not reference an experimental package`,
  66. ])
  67. },
  68. )
  69. it('allows development and experimental consumers but rejects the Python release runtime', () => {
  70. const manifests: WorkspaceManifest[] = [experimental, {
  71. dir: 'packages/core/test-only',
  72. manifest: {
  73. name: '@deepseek-ai/dsh-test-only',
  74. devDependencies: { '@deepseek-ai/dsh-experimental-prototype': 'workspace:^' },
  75. },
  76. }, {
  77. dir: 'packages/experimental/consumer',
  78. manifest: {
  79. name: '@deepseek-ai/dsh-experimental-consumer',
  80. dependencies: { '@deepseek-ai/dsh-experimental-prototype': 'workspace:^' },
  81. },
  82. }, {
  83. dir: 'python/sdk-runtime',
  84. manifest: {
  85. name: '@deepseek-ai/dsh-python-runtime',
  86. dependencies: { '@deepseek-ai/dsh-experimental-prototype': 'workspace:^' },
  87. },
  88. }]
  89. expect(checkExperimentalDependencyIsolation(manifests)).toEqual([
  90. '@deepseek-ai/dsh-python-runtime: dependencies.@deepseek-ai/dsh-experimental-prototype must not reference an experimental package',
  91. ])
  92. })
  93. })
  94. describe('dsh family version coherence', () => {
  95. it('rejects a package carrying a stale shared version', () => {
  96. expect(checkDshFamilyVersion(
  97. { name: '@deepseek-ai/dsh-http-proxy', version: '0.1.2-alpha.5' },
  98. '0.1.2-rc.1',
  99. )).toBe('@deepseek-ai/dsh-http-proxy: package.json version must match root version 0.1.2-rc.1')
  100. })
  101. it('rejects the root-named CLI app on a stale shared version', () => {
  102. expect(checkDshFamilyVersion(
  103. { name: '@deepseek-ai/dsh', version: '0.1.2-alpha.5' },
  104. '0.1.2-rc.1',
  105. )).toBe('@deepseek-ai/dsh: package.json version must match root version 0.1.2-rc.1')
  106. })
  107. it('accepts a manifest carrying the shared version', () => {
  108. expect(checkDshFamilyVersion(
  109. { name: '@deepseek-ai/dsh-http-proxy', version: '0.1.2-rc.1' },
  110. '0.1.2-rc.1',
  111. )).toBeUndefined()
  112. })
  113. it('leaves other sequences to their own version lines', () => {
  114. expect(checkDshFamilyVersion({ name: '@deepseek-ai/cordis', version: '4.0.1' }, '0.1.2-rc.1')).toBeUndefined()
  115. expect(checkDshFamilyVersion(
  116. { name: '@deepseek-ai/node-addon-system', version: '0.1.1' },
  117. '0.1.2-rc.1',
  118. )).toBeUndefined()
  119. expect(checkDshFamilyVersion({ version: '0.1.2-alpha.5' }, '0.1.2-rc.1')).toBeUndefined()
  120. })
  121. })
  122. describe('package payload constraints', () => {
  123. it('includes a declared profile patch without a package-name allowlist', () => {
  124. expect(expectedDshPackageFiles({
  125. name: '@deepseek-ai/dsh-private-profile',
  126. dsh: { bundle: { patch: './cordis.patch.yml' } },
  127. })).toEqual([
  128. 'lib/index.js',
  129. 'cordis.patch.yml',
  130. 'lib/types/**/*.d.ts',
  131. ])
  132. })
  133. })
  134. it('publishes CLI runtime declarations and rejects a payload that omits them', () => {
  135. const manifest = JSON.parse(readFileSync(new URL('../apps/cli/package.json', import.meta.url), 'utf8')) as WorkspaceManifest['manifest']
  136. expect(checkWorkspaceManifest({ dir: 'apps/cli', manifest })).toEqual([])
  137. expect(checkWorkspaceManifest({ dir: 'apps/cli', manifest: { ...manifest, files: ['lib/*.js'] } }))
  138. .toEqual([expect.stringContaining('@deepseek-ai/dsh: package.json files must be ["lib/*.js","lib/types/*.d.ts"]')])
  139. })