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

feat: show version-specific readmes in web ui

This commit is contained in:
Marc Bernard 2024-12-04 11:30:10 -05:00
parent 4af6b86094
commit 30dd6653e7
4 changed files with 88 additions and 2 deletions

View file

@ -0,0 +1,5 @@
---
'@verdaccio/web': patch
---
feat: show version-specific readmes in web ui

View file

@ -2,11 +2,12 @@ import buildDebug from 'debug';
import { Router } from 'express'; import { Router } from 'express';
import { Auth } from '@verdaccio/auth'; import { Auth } from '@verdaccio/auth';
import { HEADERS, HEADER_TYPE } from '@verdaccio/core'; import { DIST_TAGS, HEADERS, HEADER_TYPE } from '@verdaccio/core';
import { logger } from '@verdaccio/logger'; import { logger } from '@verdaccio/logger';
import { $NextFunctionVer, $RequestExtend, $ResponseExtend, allow } from '@verdaccio/middleware'; import { $NextFunctionVer, $RequestExtend, $ResponseExtend, allow } from '@verdaccio/middleware';
import { Storage } from '@verdaccio/store'; import { Storage } from '@verdaccio/store';
import { Manifest } from '@verdaccio/types'; import { Manifest } from '@verdaccio/types';
import { isVersionValid } from '@verdaccio/utils';
import { AuthorAvatar, addScope } from '../web-utils'; import { AuthorAvatar, addScope } from '../web-utils';
@ -16,6 +17,7 @@ export { $RequestExtend, $ResponseExtend, $NextFunctionVer }; // Was required by
export type PackageExt = Manifest & { author: AuthorAvatar; dist?: { tarball: string } }; export type PackageExt = Manifest & { author: AuthorAvatar; dist?: { tarball: string } };
export const NOT_README_FOUND = 'ERROR: No README data found!'; export const NOT_README_FOUND = 'ERROR: No README data found!';
const debug = buildDebug('verdaccio:web:api:readme'); const debug = buildDebug('verdaccio:web:api:readme');
const getReadme = (readme) => { const getReadme = (readme) => {
if (typeof readme === 'string' && readme.length === 0) { if (typeof readme === 'string' && readme.length === 0) {
return NOT_README_FOUND; return NOT_README_FOUND;
@ -27,6 +29,25 @@ const getReadme = (readme) => {
} }
}; };
const getReadmeFromManifest = (manifest: Manifest, v?: any): string | undefined => {
let id;
let readme;
if (typeof v === 'string' && isVersionValid(manifest, v)) {
id = 'version';
readme = manifest.versions[v].readme;
}
if (!readme && isVersionValid(manifest, manifest[DIST_TAGS]?.latest)) {
id = 'latest';
readme = manifest.versions[manifest[DIST_TAGS].latest].readme;
}
if (!readme && manifest.readme) {
id = 'root';
readme = manifest.readme;
}
debug('readme: %o %o', v, id);
return readme;
};
function addReadmeWebApi(storage: Storage, auth: Auth): Router { function addReadmeWebApi(storage: Storage, auth: Auth): Router {
debug('initialized readme web api'); debug('initialized readme web api');
const can = allow(auth, { const can = allow(auth, {
@ -64,7 +85,9 @@ function addReadmeWebApi(storage: Storage, auth: Auth): Router {
})) as Manifest; })) as Manifest;
debug('readme pkg %o', manifest?.name); debug('readme pkg %o', manifest?.name);
res.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.TEXT_PLAIN_UTF8); res.set(HEADER_TYPE.CONTENT_TYPE, HEADERS.TEXT_PLAIN_UTF8);
next(getReadme(manifest.readme)); const { v } = req.query;
const readme = getReadmeFromManifest(manifest, v);
next(getReadme(readme));
} catch (err) { } catch (err) {
next(err); next(err);
} }

View file

@ -73,4 +73,33 @@ describe('readme api', () => {
.expect(HTTP_STATUS.OK); .expect(HTTP_STATUS.OK);
expect(response.text).toMatch(NOT_README_FOUND); expect(response.text).toMatch(NOT_README_FOUND);
}); });
test('should fetch readme with keeping all readmes (latest)', async () => {
const app = await initializeServer('keep-all-readmes.yaml');
await publishVersion(app, 'pk1-test', '1.0.0', { readme: 'my readme' });
const response = await supertest(app)
.get('/-/verdaccio/data/package/readme/pk1-test')
.set('Accept', HEADERS.TEXT_PLAIN)
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.TEXT_PLAIN_UTF8)
.expect(HTTP_STATUS.OK);
expect(response.text).toMatch('my readme');
});
test('should fetch readme with keeping all readmes (version)', async () => {
const app = await initializeServer('keep-all-readmes.yaml');
await publishVersion(app, 'pk1-test', '1.0.0', { readme: 'my readme' });
await publishVersion(app, 'pk1-test', '1.2.0', { readme: 'my new readme' });
const response = await supertest(app)
.get('/-/verdaccio/data/package/readme/pk1-test')
.set('Accept', HEADERS.TEXT_PLAIN)
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.TEXT_PLAIN_UTF8)
.expect(HTTP_STATUS.OK);
expect(response.text).toMatch('my new readme');
const response2 = await supertest(app)
.get('/-/verdaccio/data/package/readme/pk1-test?v=1.0.0')
.set('Accept', HEADERS.TEXT_PLAIN)
.expect(HEADER_TYPE.CONTENT_TYPE, HEADERS.TEXT_PLAIN_UTF8)
.expect(HTTP_STATUS.OK);
expect(response2.text).toMatch('my readme');
});
}); });

View file

@ -0,0 +1,29 @@
auth:
auth-memory:
users:
test:
name: test
password: test
web:
title: verdaccio
publish:
allow_offline: false
keep_readmes: all
uplinks:
log: { type: stdout, format: pretty, level: trace }
packages:
'@*/*':
access: $anonymous
publish: $anonymous
'**':
access: $anonymous
publish: $anonymous
_debug: true
flags:
changePassword: true