diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ec7ec7ee8787..4b528c7f268d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1215,6 +1215,9 @@ importers: '@types/socket.io-client': specifier: 1.4.35 version: 1.4.35 + '@types/ssri': + specifier: ^7.1.5 + version: 7.1.5 '@types/testing-library__jest-dom': specifier: 5.9.5 version: 5.9.5 @@ -23190,6 +23193,9 @@ importers: '@types/mocha': specifier: 9.1.0 version: 9.1.0 + '@types/ssri': + specifier: ^7.1.5 + version: 7.1.5 chai: specifier: 4.3.0 version: 4.3.0 @@ -26296,9 +26302,15 @@ importers: '@types/react-dom': specifier: ^17.0.21 version: 17.0.25 + assert: + specifier: ^2.1.0 + version: 2.1.0 browserify-zlib: specifier: 0.2.0 version: 0.2.0 + buffer: + specifier: 6.0.3 + version: 6.0.3 camelcase: specifier: 6.2.0 version: 6.2.0 @@ -26353,6 +26365,9 @@ importers: process: specifier: 0.11.10 version: 0.11.10 + punycode: + specifier: ^2.3.1 + version: 2.3.1 querystring-es3: specifier: 0.2.1 version: 0.2.1 @@ -26374,12 +26389,21 @@ importers: stream-http: specifier: 3.2.0 version: 3.2.0 + string_decoder: + specifier: ^1.3.0 + version: 1.3.0 timers-browserify: specifier: 2.0.12 version: 2.0.12 tty-browserify: specifier: 0.0.1 version: 0.0.1 + url: + specifier: ^0.11.3 + version: 0.11.3 + util: + specifier: ^0.12.5 + version: 0.12.5 vm-browserify: specifier: 1.1.2 version: 1.1.2 @@ -47333,7 +47357,6 @@ packages: resolution: {integrity: sha512-odD/56S3B51liILSk5aXJlnYt99S6Rt9EFDDqGtJM26rKHApHcwyU/UoYHrzKkdkHMAIquGWCuHtQTbes+FRQw==} dependencies: '@types/node': 20.2.5 - dev: false /@types/stack-utils@2.0.3: resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} @@ -48513,7 +48536,7 @@ packages: '@types/semver': 7.3.4 '@types/treeify': 1.0.3 '@yarnpkg/fslib': 3.0.2 - '@yarnpkg/libzip': 3.0.1(@yarnpkg/fslib@3.0.2) + '@yarnpkg/libzip': 3.0.1 '@yarnpkg/parsers': 3.0.0 '@yarnpkg/shell': 4.0.0 camelcase: 5.3.1 @@ -48544,7 +48567,7 @@ packages: '@types/semver': 7.3.4 '@types/treeify': 1.0.3 '@yarnpkg/fslib': 3.0.2 - '@yarnpkg/libzip': 3.0.1(@yarnpkg/fslib@3.0.2) + '@yarnpkg/libzip': 3.0.1 '@yarnpkg/parsers': 3.0.0 '@yarnpkg/shell': 4.0.0 camelcase: 5.3.1 @@ -48625,11 +48648,9 @@ packages: tslib: 1.14.1 dev: false - /@yarnpkg/libzip@3.0.1(@yarnpkg/fslib@3.0.2): + /@yarnpkg/libzip@3.0.1: resolution: {integrity: sha512-fiqRLk2fyd2r34/Qc7HlP8fKIo1CK5CZpLNObJwnbFmZQN2hVanovFlG++3oH3qYJymEmjPl5EGsygcEJZl4Pg==} engines: {node: '>=18.12.0'} - peerDependencies: - '@yarnpkg/fslib': ^3.0.2 dependencies: '@types/emscripten': 1.39.10 '@yarnpkg/fslib': 3.0.2 diff --git a/scopes/pkg/pkg/publisher.ts b/scopes/pkg/pkg/publisher.ts index e86eb340b7f2..eb7f1d72dc23 100644 --- a/scopes/pkg/pkg/publisher.ts +++ b/scopes/pkg/pkg/publisher.ts @@ -10,6 +10,7 @@ import { Scope } from '@teambit/legacy/dist/scope'; import fsx from 'fs-extra'; import mapSeries from 'p-map-series'; import { join } from 'path'; +import ssri from 'ssri'; import execa from 'execa'; import { PkgAspect } from './pkg.aspect'; import { PkgExtensionConfig } from './pkg.main.runtime'; @@ -68,7 +69,7 @@ export class Publisher { publishParams.push(...extraArgsSplit); } const publishParamsStr = publishParams.join(' '); - + const getPkgJson = async () => fsx.readJSON(`${capsule.path}/package.json`); const componentIdStr = capsule.id.toString(); const errors: string[] = []; try { @@ -82,7 +83,23 @@ export class Publisher { const errorDetails = typeof err === 'object' && err && 'message' in err ? err.message : err; const errorMsg = `failed running ${this.packageManager} ${publishParamsStr} at ${cwd}: ${errorDetails}`; this.logger.error(`${componentIdStr}, ${errorMsg}`); - errors.push(errorMsg); + let isPublished = false; + if (typeof errorDetails === 'string' && errorDetails.includes('EPERM') && tarPath) { + const pkgJson = await getPkgJson(); + // sleep 5 seconds + await new Promise((resolve) => setTimeout(resolve, Number(process.env.NPM_WAKE_UP || 5000))); + const integrityOnNpm = await this.getIntegrityOnNpm(pkgJson.name, pkgJson.version); + if (integrityOnNpm && tarPath) { + const tarData = fsx.readFileSync(join(tarFolderPath, tarPath)); + // If the integrity of the tarball in the registry matches the local one, + // we consider the package published + isPublished = ssri.checkData(tarData, integrityOnNpm) !== false; + this.logger.debug( + `${componentIdStr}, package ${pkgJson.name} is already on npm with version ${pkgJson.version}` + ); + } + } + if (!isPublished) errors.push(errorMsg); } let metadata: TaskMetadata = {}; if (errors.length === 0 && !this.options.dryRun) { @@ -93,6 +110,17 @@ export class Publisher { return { component, metadata, errors, startTime, endTime: Date.now() }; } + private async getIntegrityOnNpm(pkgName: string, pkgVersion: string): Promise { + const args = ['view', `${pkgName}@${pkgVersion}`, 'dist.integrity']; + try { + const results = await execa(this.packageManager, args); + return results.stdout; + } catch (err: unknown) { + this.logger.error(`failed running ${this.packageManager} ${args.join(' ')}: ${err}`, err); + return undefined; + } + } + private getTagFlagForPreRelease(id: ComponentID): string[] { const preReleaseData = id.getVersionPreReleaseData(); if (!preReleaseData) return []; diff --git a/workspace.jsonc b/workspace.jsonc index d33644e9f7c6..a9aa9b707070 100644 --- a/workspace.jsonc +++ b/workspace.jsonc @@ -346,6 +346,7 @@ "@types/react-syntax-highlighter": "15.5.10", "@types/react-tabs": "2.3.2", "@types/socket.io-client": "1.4.35", + "@types/ssri": "^7.1.5", "@types/testing-library__jest-dom": "5.9.5", "@types/ua-parser-js": "0.7.35", "@types/url-join": "4.0.0",