diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c54a78814..18dfaa291 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,7 +11,7 @@ jobs: name: Library — lint / test / build runs-on: ubuntu-latest env: - LIBS: chat,langgraph,ag-ui,render,a2ui,partial-json,licensing + LIBS: chat,langgraph,ag-ui,render,a2ui,licensing,telemetry steps: - uses: actions/checkout@v6.0.2 - uses: actions/setup-node@v6.3.0 @@ -22,6 +22,7 @@ jobs: - run: npx nx run-many -t lint --projects=$LIBS - run: npx nx run-many -t test --projects=$LIBS --coverage - run: npx nx run-many -t build --projects=$LIBS --configuration=production + - run: node scripts/verify-release-versions.mjs website: name: Website — lint / build diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 958417cd2..4dcc1eca5 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -18,7 +18,7 @@ jobs: contents: read id-token: write # required for npm trusted publishing + provenance env: - NPM_PUBLISHABLE_PROJECTS: chat,langgraph,ag-ui,render,a2ui,partial-json,licensing + NPM_PUBLISHABLE_PROJECTS: chat,langgraph,ag-ui,render,a2ui,licensing,telemetry steps: - uses: actions/checkout@v6.0.2 # Node 24 ships npm 11+ which fully implements npm trusted publishing @@ -43,6 +43,9 @@ jobs: - name: Lint, test, build publishable projects run: npx nx run-many -t lint,test,build --projects=$NPM_PUBLISHABLE_PROJECTS --skip-nx-cache + - name: Patch install telemetry into publishable manifests + run: node libs/telemetry/scripts/apply-install-telemetry.mjs dist/libs/chat dist/libs/langgraph dist/libs/ag-ui dist/libs/render dist/libs/a2ui dist/libs/licensing + - name: Verify atomic release versions run: node scripts/verify-release-versions.mjs --tag "$RELEASE_TAG" env: diff --git a/libs/chat/package.json b/libs/chat/package.json index fb77d1b62..93e562c40 100644 --- a/libs/chat/package.json +++ b/libs/chat/package.json @@ -1,6 +1,6 @@ { "name": "@ngaf/chat", - "version": "0.0.32", + "version": "0.0.29", "exports": { ".": { "types": "./index.d.ts", diff --git a/libs/telemetry/package.json b/libs/telemetry/package.json index 8bbd6c520..dcadba47b 100644 --- a/libs/telemetry/package.json +++ b/libs/telemetry/package.json @@ -1,6 +1,6 @@ { "name": "@ngaf/telemetry", - "version": "0.0.0", + "version": "0.0.29", "license": "MIT", "repository": { "type": "git", diff --git a/libs/telemetry/project.json b/libs/telemetry/project.json index ac61e14e5..430e3c1f7 100644 --- a/libs/telemetry/project.json +++ b/libs/telemetry/project.json @@ -36,6 +36,11 @@ "command": "node libs/telemetry/scripts/assemble-dist.mjs" } }, + "nx-release-publish": { + "options": { + "packageRoot": "dist/{projectRoot}" + } + }, "test": { "executor": "@nx/vitest:test", "options": { diff --git a/libs/telemetry/src/node/client.spec.ts b/libs/telemetry/src/node/client.spec.ts index 3410043b5..ea155064e 100644 --- a/libs/telemetry/src/node/client.spec.ts +++ b/libs/telemetry/src/node/client.spec.ts @@ -14,7 +14,13 @@ describe('node client', () => { _resetDisableForTesting(); delete process.env.DO_NOT_TRACK; delete process.env.NGAF_TELEMETRY_DISABLED; + delete process.env.npm_config_do_not_track; + delete process.env.NPM_CONFIG_DO_NOT_TRACK; delete process.env.CI; + delete process.env.GITHUB_ACTIONS; + delete process.env.CONTINUOUS_INTEGRATION; + delete process.env.BUILDKITE; + delete process.env.CIRCLECI; delete process.env.NGAF_TELEMETRY_SAMPLE_RATE; delete process.env.npm_config_user_agent; process.env.NGAF_TELEMETRY_INGEST_URL = 'https://test.example/api/ingest'; diff --git a/libs/telemetry/src/node/postinstall.spec.ts b/libs/telemetry/src/node/postinstall.spec.ts index 2eff4a9af..40811d25f 100644 --- a/libs/telemetry/src/node/postinstall.spec.ts +++ b/libs/telemetry/src/node/postinstall.spec.ts @@ -18,8 +18,15 @@ describe('postinstall script', () => { beforeEach(() => { vi.mocked(capturePostinstall).mockClear(); delete process.env.CI; + delete process.env.GITHUB_ACTIONS; + delete process.env.CONTINUOUS_INTEGRATION; + delete process.env.BUILDKITE; + delete process.env.CIRCLECI; delete process.env.DO_NOT_TRACK; + delete process.env.npm_config_do_not_track; + delete process.env.NPM_CONFIG_DO_NOT_TRACK; delete process.env.DEBUG; + delete process.env.NGAF_TELEMETRY_DISABLED; }); test('calls capturePostinstall with the package name + version', async () => { diff --git a/package-lock.json b/package-lock.json index d479afbc8..624942641 100644 --- a/package-lock.json +++ b/package-lock.json @@ -188,7 +188,7 @@ }, "libs/chat": { "name": "@ngaf/chat", - "version": "0.0.32", + "version": "0.0.29", "license": "MIT", "dependencies": { "@cacheplane/partial-json": ">=0.1.1 <0.3.0", @@ -291,7 +291,7 @@ }, "libs/telemetry": { "name": "@ngaf/telemetry", - "version": "0.0.0", + "version": "0.0.29", "license": "MIT", "bin": { "ngaf-telemetry-postinstall": "node/postinstall.js" diff --git a/scripts/verify-release-versions.mjs b/scripts/verify-release-versions.mjs index 975054e73..e770d7e7b 100644 --- a/scripts/verify-release-versions.mjs +++ b/scripts/verify-release-versions.mjs @@ -144,6 +144,14 @@ export async function verifyReleaseVersions({ } const packageInfo = await getPackageForProject(workspaceRoot, project); + const publishRoot = + project.targets['nx-release-publish']?.options?.packageRoot; + + if (publishRoot !== 'dist/{projectRoot}') { + throw new Error( + `Release project "${projectName}" must publish from dist/{projectRoot}.` + ); + } if (packageInfo.packageJson.private === true) { throw new Error( diff --git a/scripts/verify-release-versions.spec.mjs b/scripts/verify-release-versions.spec.mjs index c3d269d2e..076a57ef4 100644 --- a/scripts/verify-release-versions.spec.mjs +++ b/scripts/verify-release-versions.spec.mjs @@ -30,6 +30,13 @@ async function createWorkspace(projectVersions) { await mkdir(projectRoot, { recursive: true }); await writeJson(join(projectRoot, 'project.json'), { name: projectName, + targets: { + 'nx-release-publish': { + options: { + packageRoot: 'dist/{projectRoot}', + }, + }, + }, }); await writeJson(join(projectRoot, 'package.json'), { name: `@ngaf/${projectName}`, @@ -110,4 +117,23 @@ describe('verifyReleaseVersions', () => { 'Public package @ngaf/render is not included in release group "publishable".' ); }); + + it('rejects release projects without an explicit dist publish root', async () => { + const workspaceRoot = await createWorkspace({ + chat: '0.0.13', + telemetry: '0.0.13', + }); + await writeJson(join(workspaceRoot, 'libs', 'telemetry', 'project.json'), { + name: 'telemetry', + targets: { + 'nx-release-publish': { + options: {}, + }, + }, + }); + + await expect(verifyReleaseVersions({ workspaceRoot })).rejects.toThrow( + 'Release project "telemetry" must publish from dist/{projectRoot}.' + ); + }); });