0
Fork 0
mirror of https://github.com/verdaccio/verdaccio.git synced 2024-12-16 21:56:25 -05:00

feat: keep_readmes option when publishing packages (#4961)

This commit is contained in:
Marc Bernard 2024-11-28 05:54:51 -05:00 committed by GitHub
parent 3967a5280a
commit 538bb8f3a6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 101 additions and 14 deletions

View file

@ -0,0 +1,6 @@
---
'@verdaccio/types': patch
'@verdaccio/store': patch
---
feat: keep_readmes option when publishing packages

View file

@ -202,8 +202,11 @@ export interface Security {
api: APITokenOptions; api: APITokenOptions;
} }
export type ReadmeOptions = 'latest' | 'tagged' | 'all' | undefined;
export interface PublishOptions { export interface PublishOptions {
allow_offline: boolean; allow_offline: boolean;
keep_readmes: ReadmeOptions;
check_owners: boolean; check_owners: boolean;
} }

View file

@ -3,7 +3,14 @@ import semver from 'semver';
import { errorUtils, pkgUtils, searchUtils, validatioUtils } from '@verdaccio/core'; import { errorUtils, pkgUtils, searchUtils, validatioUtils } from '@verdaccio/core';
import { API_ERROR, DIST_TAGS, HTTP_STATUS, MAINTAINERS, USERS } from '@verdaccio/core'; import { API_ERROR, DIST_TAGS, HTTP_STATUS, MAINTAINERS, USERS } from '@verdaccio/core';
import { AttachMents, Manifest, Version, Versions } from '@verdaccio/types'; import {
AttachMents,
GenericBody,
Manifest,
ReadmeOptions,
Version,
Versions,
} from '@verdaccio/types';
import { generateRandomHexString, isNil, isObject } from '@verdaccio/utils'; import { generateRandomHexString, isNil, isObject } from '@verdaccio/utils';
import { sortVersionsAndFilterInvalid } from './versions-utils'; import { sortVersionsAndFilterInvalid } from './versions-utils';
@ -92,10 +99,28 @@ export function getLatestReadme(pkg: Manifest): string {
return readme; return readme;
} }
// FIXME: type any due this /**
export function cleanUpReadme(version: any): Version { * Cleanup readme from package version
*
* By default, we don't keep readmes for package versions, only one readme per package.
* Using publish.keep_readmes you can override this behavior and keep all readmes
* or only readmes for tagged versions.
*/
export function cleanUpReadme(
version: Version,
distTags?: GenericBody,
keepReadmes?: ReadmeOptions
): Version {
if (keepReadmes === 'all') {
return version;
} else if (keepReadmes === 'tagged') {
if (distTags && Object.values(distTags).includes(version.version)) {
return version;
}
}
if (isNil(version) === false) { if (isNil(version) === false) {
delete version.readme; version.readme = '';
} }
return version; return version;

View file

@ -1404,11 +1404,11 @@ class Storage {
): Promise<void> { ): Promise<void> {
debug(`add version %s package for %s`, version, name); debug(`add version %s package for %s`, version, name);
await this.updatePackage(name, async (data: Manifest): Promise<Manifest> => { await this.updatePackage(name, async (data: Manifest): Promise<Manifest> => {
// keep only one readme per package // keep latest readme in manifest (on root level)
data.readme = metadata.readme; data.readme = metadata.readme;
debug('%s readme mutated', name); debug('%s readme mutated', name);
// TODO: lodash remove // removing other readmes depends on config
metadata = cleanUpReadme(metadata); metadata = cleanUpReadme(metadata, metadata[DIST_TAGS], this.config?.publish?.keep_readmes);
metadata.contributors = normalizeContributors(metadata.contributors as Author[]); metadata.contributors = normalizeContributors(metadata.contributors as Author[]);
debug('%s contributors normalized', name); debug('%s contributors normalized', name);
@ -1966,10 +1966,12 @@ class Storage {
debug('new version from upstream %o', versionId); debug('new version from upstream %o', versionId);
let version = remoteManifest.versions[versionId]; let version = remoteManifest.versions[versionId];
// we don't keep readme for package versions, // removing readmes depends on config
// only one readme per package version = cleanUpReadme(
// TODO: readme clean up could be saved in configured eventually version,
version = cleanUpReadme(version); remoteManifest[DIST_TAGS],
this.config?.publish?.keep_readmes
);
debug('clean up readme for %o', versionId); debug('clean up readme for %o', versionId);
version.contributors = normalizeContributors(version.contributors as Author[]); version.contributors = normalizeContributors(version.contributors as Author[]);

View file

@ -1,11 +1,12 @@
import { describe, expect, test } from 'vitest'; import { describe, expect, test } from 'vitest';
import { DIST_TAGS } from '@verdaccio/core'; import { DIST_TAGS } from '@verdaccio/core';
import { generatePackageMetadata } from '@verdaccio/test-helper';
import { Manifest } from '@verdaccio/types'; import { Manifest } from '@verdaccio/types';
import { generatePackageMetadata } from '../../api/node_modules/@verdaccio/test-helper/build';
import { import {
STORAGE, STORAGE,
cleanUpReadme,
hasInvalidPublishBody, hasInvalidPublishBody,
isDeprecatedManifest, isDeprecatedManifest,
isDifferentThanOne, isDifferentThanOne,
@ -356,4 +357,54 @@ describe('Storage Utils', () => {
).toBeTruthy(); ).toBeTruthy();
}); });
}); });
describe('cleanUpReadme', () => {
describe('should keep only latest readme', () => {
test('should clean up readme (no dist-tags)', () => {
const manifest = generatePackageMetadata('foo');
const version = manifest.versions['1.0.0'];
const cleanup = cleanUpReadme(version);
expect(cleanup.readme).toEqual('');
});
test('should clean up readme (latest in dist-tag)', () => {
const manifest = generatePackageMetadata('foo');
const version = manifest.versions['1.0.0'];
const cleanup = cleanUpReadme(version, manifest[DIST_TAGS]);
expect(cleanup.readme).toEqual('');
});
});
describe('should keep only tagged readme', () => {
test('should clean up readme (no dist-tags)', () => {
const manifest = generatePackageMetadata('foo');
const version = manifest.versions['1.0.0'];
const cleanup = cleanUpReadme(version, undefined, 'tagged');
expect(cleanup.readme).toEqual('');
});
test('should keep readme (version in dist-tag)', () => {
const manifest = generatePackageMetadata('foo');
const version = manifest.versions['1.0.0'];
const cleanup = cleanUpReadme(version, manifest[DIST_TAGS], 'tagged');
expect(cleanup.readme).toEqual('# test');
});
});
describe('should keep all readmes', () => {
test('should keep readme (no dist-tags)', () => {
const manifest = generatePackageMetadata('foo');
const version = manifest.versions['1.0.0'];
const cleanup = cleanUpReadme(version, undefined, 'all');
expect(cleanup.readme).toEqual('# test');
});
test('should keep readme (version in dist-tag)', () => {
const manifest = generatePackageMetadata('foo');
const version = manifest.versions['1.0.0'];
const cleanup = cleanUpReadme(version, manifest[DIST_TAGS], 'all');
expect(cleanup.readme).toEqual('# test');
});
});
});
}); });

View file

@ -176,7 +176,7 @@ describe('storage', () => {
}); });
expect(manifest[DIST_TAGS]).toEqual({ latest: '1.0.0' }); expect(manifest[DIST_TAGS]).toEqual({ latest: '1.0.0' });
// verdaccio keeps latest version of readme on manifest level but not by version // verdaccio keeps latest version of readme on manifest level but not by version
expect(manifest.versions['1.0.0'].readme).not.toBeDefined(); expect(manifest.versions['1.0.0'].readme).toEqual('');
expect(manifest.readme).toEqual('# test'); expect(manifest.readme).toEqual('# test');
expect(manifest._attachments).toEqual({}); expect(manifest._attachments).toEqual({});
expect(typeof manifest._rev).toBeTruthy(); expect(typeof manifest._rev).toBeTruthy();
@ -388,7 +388,7 @@ describe('storage', () => {
})) as Manifest; })) as Manifest;
// verdaccio keeps latest version of readme on manifest level but not by version // verdaccio keeps latest version of readme on manifest level but not by version
expect(manifest.versions['1.0.0'].readme).not.toBeDefined(); expect(manifest.versions['1.0.0'].readme).toEqual('');
expect(manifest.readme).toEqual('# test'); expect(manifest.readme).toEqual('# test');
}); });
}); });