1
0
mirror of https://github.com/verdaccio/verdaccio.git synced 2024-11-08 23:25:51 +01:00

chore: re-stablished deprecated support (#3385)

* chore: re-stablished deprecated support

* chore: add e2e

* chore: add more tests

* chore: improve setup

* chore: improve buildcache

* Update e2e-ci.yml

* Update e2e-ci.yml

* Update e2e-ci.yml

* Update e2e-ci.yml

* chore: add more steps

* chore: improve speed

* chore: fix ci

* chore: improve cache

* Update ci.yml

* Update registry.ts

* Update ci.yml

* Update ci.yml
This commit is contained in:
Juan Picado 2022-09-18 21:47:23 +02:00 committed by GitHub
parent 62c24b6321
commit a249ab7b5a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 1288 additions and 361 deletions

@ -24,12 +24,14 @@ jobs:
image: verdaccio/verdaccio:nightly-master
ports:
- 4873:4873
env:
NODE_ENV: production
steps:
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # tag=v3
- name: Use Node 16
- name: Node
uses: actions/setup-node@2fddd8803e2f5c9604345a0b591c3020ee971a93 # tag=v3
with:
node-version: 16
node-version-file: '.nvmrc'
- name: Install pnpm
run: npm i pnpm@6.32.15 -g
- name: set store
@ -51,10 +53,10 @@ jobs:
needs: prepare
steps:
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # tag=v3
- name: Use Node 16
- name: Node
uses: actions/setup-node@2fddd8803e2f5c9604345a0b591c3020ee971a93 # tag=v3
with:
node-version: 16
node-version-file: '.nvmrc'
- name: Install pnpm
run: npm i pnpm@6.32.15 -g
- uses: actions/cache@fd5de65bc895cf536527842281bea11763fefd77 # tag=v3
@ -62,7 +64,7 @@ jobs:
path: ~/.pnpm-store
key: pnpm-${{ hashFiles('pnpm-lock.yaml') }}
- name: Install
run: pnpm recursive install --frozen-lockfile --ignore-scripts
run: pnpm recursive install --offline --frozen-lockfile --reporter=silence --ignore-scripts
- name: Lint
run: pnpm lint
format:
@ -71,10 +73,10 @@ jobs:
needs: prepare
steps:
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # tag=v3
- name: Use Node 16
- name: Use Node
uses: actions/setup-node@2fddd8803e2f5c9604345a0b591c3020ee971a93 # tag=v3
with:
node-version: 16
node-version-file: '.nvmrc'
- name: Install pnpm
run: npm i pnpm@6.32.15 -g
- uses: actions/cache@fd5de65bc895cf536527842281bea11763fefd77 # tag=v3
@ -82,7 +84,7 @@ jobs:
path: ~/.pnpm-store
key: pnpm-${{ hashFiles('pnpm-lock.yaml') }}
- name: Install
run: pnpm recursive install --frozen-lockfile --ignore-scripts
run: pnpm recursive install --offline --frozen-lockfile --reporter=silence --ignore-scripts
- name: Lint
run: pnpm format:check
build:
@ -90,7 +92,7 @@ jobs:
strategy:
fail-fast: true
matrix:
os: [ubuntu-latest, windows-latest]
os: [ubuntu-latest]
node_version: [16, 18]
name: ${{ matrix.os }} / Node ${{ matrix.node_version }}
runs-on: ${{ matrix.os }}
@ -107,7 +109,7 @@ jobs:
path: ~/.pnpm-store
key: pnpm-${{ hashFiles('pnpm-lock.yaml') }}
- name: Install
run: pnpm recursive install --frozen-lockfile --ignore-scripts
run: pnpm recursive install --offline --frozen-lockfile --reporter=silence --ignore-scripts --registry http://localhost:4873
- name: build
run: pnpm build
- name: Test
@ -115,12 +117,12 @@ jobs:
ci-e2e-ui:
needs: [format, lint]
runs-on: ubuntu-latest
name: UI Test E2E Node 16
name: UI Test E2E
steps:
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # tag=v3
- uses: actions/setup-node@2fddd8803e2f5c9604345a0b591c3020ee971a93 # tag=v3
with:
node-version: 16
node-version-file: '.nvmrc'
- name: Install pnpm
run: npm i pnpm@6.32.15 -g
- uses: actions/cache@fd5de65bc895cf536527842281bea11763fefd77 # tag=v3
@ -128,39 +130,15 @@ jobs:
path: ~/.pnpm-store
key: pnpm-${{ hashFiles('pnpm-lock.yaml') }}
- name: Install
run: pnpm recursive install --frozen-lockfile
run: pnpm recursive install --offline --frozen-lockfile --reporter=silence --registry http://localhost:4873
- name: build
run: pnpm build
- name: Test UI
run: pnpm test:e2e:ui
# env:
# DEBUG: verdaccio:e2e*
ci-e2e-cli:
needs: [format, lint]
runs-on: ubuntu-latest
name: CLI Test E2E Node 16
steps:
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # tag=v3
- uses: actions/setup-node@2fddd8803e2f5c9604345a0b591c3020ee971a93 # tag=v3
with:
node-version: 16
- name: Install pnpm
run: npm i pnpm@6.32.15 -g
- uses: actions/cache@fd5de65bc895cf536527842281bea11763fefd77 # tag=v3
with:
path: ~/.pnpm-store
key: pnpm-${{ hashFiles('pnpm-lock.yaml') }}
- name: Install
## we need scripts, pupetter downloads aditional content
run: pnpm recursive install --frozen-lockfile
- name: build
run: pnpm build
- name: Test CLI
run: pnpm test:e2e:cli
# env:
# DEBUG: verdaccio*
sync-translations:
needs: [ci-e2e-cli, ci-e2e-ui]
needs: [ci-e2e-ui]
runs-on: ubuntu-latest
name: synchronize translations
if: (github.event_name == 'push' && github.ref == 'refs/heads/master') || github.event_name == 'workflow_dispatch'
@ -168,7 +146,7 @@ jobs:
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # tag=v3
- uses: actions/setup-node@2fddd8803e2f5c9604345a0b591c3020ee971a93 # tag=v3
with:
node-version: 16
node-version-file: '.nvmrc'
- name: Install pnpm
run: npm i pnpm@6.32.15 -g
- uses: actions/cache@fd5de65bc895cf536527842281bea11763fefd77 # tag=v3
@ -177,7 +155,7 @@ jobs:
key: pnpm-${{ hashFiles('pnpm-lock.yaml') }}
- name: Install
## we need scripts, pupetter downloads aditional content
run: pnpm recursive install --frozen-lockfile
run: pnpm recursive install --frozen-lockfile --registry http://localhost:4873
- name: build
run: pnpm build
- name: generate website translations

113
.github/workflows/e2e-ci.yml vendored Normal file

@ -0,0 +1,113 @@
name: E2E CLI
on:
pull_request:
paths:
- .changeset/**
- .github/workflows/e2e-ci.yml
- 'packages/**'
- 'test/**'
- 'jest/**'
- 'package.json'
- 'pnpm-workspace.yaml'
permissions:
contents: read
jobs:
prepare:
runs-on: ubuntu-latest
name: setup e2e verdaccio
services:
verdaccio:
image: verdaccio/verdaccio:nightly-master
ports:
- 4873:4873
env:
NODE_ENV: production
steps:
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # tag=v3
- name: Use Node 16
uses: actions/setup-node@2fddd8803e2f5c9604345a0b591c3020ee971a93 # tag=v3
with:
node-version: 16
- name: Install pnpm
run: npm i pnpm@6.32.15 -g
- name: set store
run: |
mkdir ~/.pnpm-store
pnpm config set store-dir ~/.pnpm-store
- name: Install
run: pnpm recursive install --frozen-lockfile --reporter=silence --ignore-scripts --registry http://localhost:4873
- name: Cache .pnpm-store
uses: actions/cache@fd5de65bc895cf536527842281bea11763fefd77 # tag=v3
with:
path: ~/.pnpm-store
key: pnpm-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
pnpm-
build:
needs: [prepare]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # tag=v3
- name: Use Node 16
uses: actions/setup-node@2fddd8803e2f5c9604345a0b591c3020ee971a93 # tag=v3
with:
node-version: 16
- name: Install pnpm
run: npm i pnpm@6.32.15 -g
- uses: actions/cache@fd5de65bc895cf536527842281bea11763fefd77 # tag=v3
with:
path: ~/.pnpm-store
key: pnpm-${{ hashFiles('pnpm-lock.yaml') }}
- name: Install
run: pnpm recursive install --offline --frozen-lockfile --reporter=silence --ignore-scripts --registry http://localhost:4873
- name: build
run: pnpm build
- name: Cache packages
uses: actions/cache@fd5de65bc895cf536527842281bea11763fefd77 # tag=v3
id: cache-packages
with:
path: ./packages/
key: pkg-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
packages-
- name: Cache test
uses: actions/cache@fd5de65bc895cf536527842281bea11763fefd77 # tag=v3
id: cache-test
with:
path: ./test/
key: test-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
test-
e2e-cli:
needs: [prepare, build]
strategy:
fail-fast: true
matrix:
pkg: [npm6, npm7, npm8, pnpm6, pnpm7, yarn1, yarn2, yarn3, yarn4]
name: E2E / ${{ matrix.pkg }} / ${{ matrix.os }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # tag=v3
- uses: actions/setup-node@2fddd8803e2f5c9604345a0b591c3020ee971a93 # tag=v3
with:
node-version-file: '.nvmrc'
- name: Install pnpm
run: npm i pnpm@6.32.15 -g
- uses: actions/cache@fd5de65bc895cf536527842281bea11763fefd77 # tag=v3
with:
path: ~/.pnpm-store
key: pnpm-${{ hashFiles('pnpm-lock.yaml') }}
- name: Install
run: pnpm recursive install --offline --frozen-lockfile --reporter=silence --ignore-scripts --registry http://localhost:4873
- uses: actions/cache@fd5de65bc895cf536527842281bea11763fefd77 # tag=v3
with:
path: ./packages/
key: pkg-${{ hashFiles('pnpm-lock.yaml') }}
- uses: actions/cache@fd5de65bc895cf536527842281bea11763fefd77 # tag=v3
with:
path: ./test/
key: test-${{ hashFiles('pnpm-lock.yaml') }}
- name: Test CLI
run: NODE_ENV=production pnpm test --filter ...@verdaccio/e2e-cli-${{matrix.pkg}}

@ -95,22 +95,20 @@ const debug = buildDebug('verdaccio:api:publish');
*/
export default function publish(router: Router, auth: IAuth, storage: Storage): void {
const can = allow(auth);
// publish (update manifest) v6
router.put(
'/:package',
can('publish'),
media(mime.getType('json')),
expectJson,
publishPackageNext(storage)
publishPackage(storage)
);
// unpublish a pacakge v6
router.put(
'/:package/-rev/:revision',
can('unpublish'),
media(mime.getType('json')),
expectJson,
publishPackageNext(storage)
publishPackage(storage)
);
/**
@ -121,7 +119,6 @@ export default function publish(router: Router, auth: IAuth, storage: Storage):
* npm http fetch GET 304 http://localhost:4873/package-name?write=true 1076ms (from cache)
* npm http fetch DELETE 201 http://localhost:4873/package-name/-rev/18-d8ebe3020bd4ac9c 22ms
*/
// v6
router.delete(
'/:package/-rev/:revision',
can('unpublish'),
@ -177,7 +174,7 @@ export default function publish(router: Router, auth: IAuth, storage: Storage):
);
}
export function publishPackageNext(storage: Storage): any {
export function publishPackage(storage: Storage): any {
return async function (
req: $RequestExtend,
_res: $ResponseExtend,

@ -155,7 +155,7 @@ export async function initServer(
process.exitCode = 1;
});
function handleShutdownGracefully() {
logger.warn('received shutdown signal - closing server gracefully...');
logger.info('received shutdown signal - closing server gracefully...');
serverFactory.close(() => {
logger.info('server closed.');
process.exit(0);

@ -4,9 +4,9 @@ module.exports = Object.assign({}, config, {
coverageThreshold: {
global: {
// FIXME: increase to 90
branches: 55,
functions: 81,
lines: 71,
branches: 51,
functions: 69,
lines: 66,
},
},
});

@ -103,11 +103,7 @@ class Storage {
Function changes a package info from local storage and all uplinks with write access./
Used storages: local (write)
*/
public async changePackageNext(
name: string,
metadata: Manifest,
revision: string
): Promise<void> {
public async changePackage(name: string, metadata: Manifest, revision: string): Promise<void> {
debug('change existing package for package %o revision %o', name, revision);
debug(`change manifest tags for %o revision %s`, name, revision);
if (
@ -119,7 +115,7 @@ class Storage {
}
debug(`change manifest udapting manifest for %o`, name);
await this.updatePackageNext(name, async (localData: Manifest): Promise<Manifest> => {
await this.updatePackage(name, async (localData: Manifest): Promise<Manifest> => {
// eslint-disable-next-line guard-for-in
for (const version in localData.versions) {
const incomingVersion = metadata.versions[version];
@ -194,14 +190,11 @@ class Storage {
throw err;
}
const manifest = await this.updatePackageNext(
name,
async (data: Manifest): Promise<Manifest> => {
let newData: Manifest = { ...data };
delete data._attachments[filename];
return newData;
}
);
const manifest = await this.updatePackage(name, async (data: Manifest): Promise<Manifest> => {
let newData: Manifest = { ...data };
delete data._attachments[filename];
return newData;
});
try {
const storage: IPackageStorage = this.getPrivatePackageStorage(name);
@ -879,7 +872,7 @@ class Storage {
* @param tags list of dist-tags
*/
public async mergeTagsNext(name: string, tags: MergeTags): Promise<Manifest> {
return await this.updatePackageNext(name, async (data: Manifest): Promise<Manifest> => {
return await this.updatePackage(name, async (data: Manifest): Promise<Manifest> => {
let newData: Manifest = { ...data };
for (const tag of Object.keys(tags)) {
// this handle dist-tag rm command
@ -922,14 +915,6 @@ class Storage {
return uplink;
}
public async updateLocalMetadata(pkgName: string) {
const storage = this.getPrivatePackageStorage(pkgName);
if (!storage) {
throw errorUtils.getNotFound();
}
}
public async updateManifest(manifest: Manifest, options: UpdateManifestOptions): Promise<void> {
if (isDeprecatedManifest(manifest)) {
// if the manifest is deprecated, we need to update the package.json
@ -968,14 +953,10 @@ class Storage {
}
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
private async deprecate(_body: Manifest, _options: PublishOptions): Promise<void> {
// // const storage: IPackageStorage = this.getPrivatePackageStorage(opname);
// if (typeof storage === 'undefined') {
// throw errorUtils.getNotFound();
// }
throw errorUtils.getInternalError('no implementation ready for npm deprecate');
private async deprecate(manifest: Manifest, options: UpdateManifestOptions): Promise<void> {
const { name } = manifest;
debug('deprecating %s', name);
return this.changePackage(name, manifest, options.revision as string);
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
@ -1253,7 +1234,7 @@ class Storage {
try {
debug('uploaded tarball %o for %o', filename, pkgName);
// update the package metadata
await this.updatePackageNext(pkgName, async (data: Manifest): Promise<Manifest> => {
await this.updatePackage(pkgName, async (data: Manifest): Promise<Manifest> => {
const newData: Manifest = { ...data };
debug('added _attachment for %o', pkgName);
newData._attachments[filename] = {
@ -1301,7 +1282,7 @@ class Storage {
tag: StringValue
): Promise<void> {
debug(`add version %s package for %s`, version, name);
await this.updatePackageNext(name, async (data: Manifest): Promise<Manifest> => {
await this.updatePackage(name, async (data: Manifest): Promise<Manifest> => {
// keep only one readme per package
data.readme = metadata.readme;
debug('%s` readme mutated', name);
@ -1460,13 +1441,15 @@ class Storage {
// this is intended in debug mode we do not want modify the store revision
if (_.isNil(this.config._debug)) {
const prev = json._rev;
json._rev = generateRevision(json._rev);
debug('revision metadata for %s updated from %s to %s', json.name, prev, json._rev);
}
return json;
}
private async writePackageNext(name: string, json: Manifest): Promise<void> {
private async writePackage(name: string, json: Manifest): Promise<void> {
const storage: any = this.getPrivatePackageStorage(name);
if (_.isNil(storage)) {
// TODO: replace here 500 error
@ -1481,7 +1464,7 @@ class Storage {
* @param {*} callback callback that gets invoked after it's all updated
* @return {Function}
*/
private async updatePackageNext(
private async updatePackage(
name: string,
updateHandler: (manifest: Manifest) => Promise<Manifest>
): Promise<Manifest> {
@ -1495,7 +1478,7 @@ class Storage {
const updatedManifest: Manifest = await storage.updatePackage(name, updateHandler);
// after correctly updated write to the storage
try {
await this.writePackageNext(name, normalizePackage(updatedManifest));
await this.writePackage(name, normalizePackage(updatedManifest));
return updatedManifest;
} catch (err: any) {
if (err.code === resourceNotAvailable) {
@ -1913,7 +1896,7 @@ class Storage {
if (change) {
debug('updating package info %o', name);
await this.writePackageNext(name, cacheManifest);
await this.writePackage(name, cacheManifest);
return cacheManifest;
} else {
return cacheManifest;

@ -0,0 +1,15 @@
packages:
'@scope/foo':
access: $all
publish: $authenticated
'@*/*':
access: $all
publish: $all
proxy: ver
'foo':
access: $all
publish: $authenticated
'*':
access: $all
publish: $all
proxy: npmjs

@ -14,8 +14,9 @@ import {
generateLocalPackageMetadata,
generatePackageMetadata,
generateRemotePackageMetadata,
getDeprecatedPackageMetadata,
} from '@verdaccio/test-helper';
import { AbbreviatedManifest, Manifest, Version } from '@verdaccio/types';
import { AbbreviatedManifest, ConfigYaml, Manifest, Version } from '@verdaccio/types';
import { Storage } from '../src';
import manifestFooRemoteNpmjs from './fixtures/manifests/foo-npmjs.json';
@ -34,6 +35,27 @@ const domain = 'https://registry.npmjs.org';
const fakeHost = 'localhost:4873';
const fooManifest = generatePackageMetadata('foo', '1.0.0');
const getConfig = (file, override: Partial<ConfigYaml> = {}): Config => {
const config = new Config(
configExample(
{
...getDefaultConfig(),
storage: generateRandomStorage(),
...override,
},
`./fixtures/config/${file}`,
__dirname
)
);
return config;
};
const defaultRequestOptions = {
host: 'localhost',
protocol: 'http',
headers: {},
};
describe('storage', () => {
beforeEach(() => {
nock.cleanAll();
@ -42,79 +64,95 @@ describe('storage', () => {
});
describe('updateManifest', () => {
test('create private package', async () => {
const mockDate = '2018-01-14T11:17:40.712Z';
MockDate.set(mockDate);
const pkgName = 'upstream';
const requestOptions = {
host: 'localhost',
protocol: 'http',
headers: {},
};
const config = new Config(
configExample(
{
...getDefaultConfig(),
storage: generateRandomStorage(),
},
'./fixtures/config/updateManifest-1.yaml',
__dirname
)
);
const storage = new Storage(config);
await storage.init(config);
const bodyNewManifest = generatePackageMetadata(pkgName, '1.0.0');
await storage.updateManifest(bodyNewManifest, {
signal: new AbortController().signal,
name: pkgName,
uplinksLook: true,
revision: '1',
requestOptions,
});
const manifest = (await storage.getPackageByOptions({
name: pkgName,
uplinksLook: true,
requestOptions,
})) as Manifest;
expect(manifest.name).toEqual(pkgName);
expect(manifest._id).toEqual(pkgName);
expect(Object.keys(manifest.versions)).toEqual(['1.0.0']);
expect(manifest.time).toEqual({
'1.0.0': mockDate,
created: mockDate,
modified: mockDate,
});
expect(manifest[DIST_TAGS]).toEqual({ latest: '1.0.0' });
expect(manifest.readme).toEqual('# test');
expect(manifest._attachments).toEqual({});
expect(typeof manifest._rev).toBeTruthy();
});
// TODO: Review triggerUncaughtException exception on abort
test.skip('abort creating a private package', async () => {
const mockDate = '2018-01-14T11:17:40.712Z';
MockDate.set(mockDate);
const pkgName = 'upstream';
const config = new Config(
configExample(
{
storage: generateRandomStorage(),
},
'./fixtures/config/updateManifest-1.yaml',
__dirname
)
);
const storage = new Storage(config);
await storage.init(config);
const ac = new AbortController();
setTimeout(() => {
ac.abort();
}, 10);
const bodyNewManifest = generatePackageMetadata(pkgName, '1.0.0');
await expect(
storage.updateManifest(bodyNewManifest, {
signal: ac.signal,
describe('publishing', () => {
test('create private package', async () => {
const mockDate = '2018-01-14T11:17:40.712Z';
MockDate.set(mockDate);
const pkgName = 'upstream';
const requestOptions = {
host: 'localhost',
protocol: 'http',
headers: {},
};
const config = new Config(
configExample(
{
...getDefaultConfig(),
storage: generateRandomStorage(),
},
'./fixtures/config/updateManifest-1.yaml',
__dirname
)
);
const storage = new Storage(config);
await storage.init(config);
const bodyNewManifest = generatePackageMetadata(pkgName, '1.0.0');
await storage.updateManifest(bodyNewManifest, {
signal: new AbortController().signal,
name: pkgName,
uplinksLook: true,
revision: '1',
requestOptions,
});
const manifest = (await storage.getPackageByOptions({
name: pkgName,
uplinksLook: true,
requestOptions,
})) as Manifest;
expect(manifest.name).toEqual(pkgName);
expect(manifest._id).toEqual(pkgName);
expect(Object.keys(manifest.versions)).toEqual(['1.0.0']);
expect(manifest.time).toEqual({
'1.0.0': mockDate,
created: mockDate,
modified: mockDate,
});
expect(manifest[DIST_TAGS]).toEqual({ latest: '1.0.0' });
expect(manifest.readme).toEqual('# test');
expect(manifest._attachments).toEqual({});
expect(typeof manifest._rev).toBeTruthy();
});
// TODO: Review triggerUncaughtException exception on abort
test.skip('abort creating a private package', async () => {
const mockDate = '2018-01-14T11:17:40.712Z';
MockDate.set(mockDate);
const pkgName = 'upstream';
const config = new Config(
configExample(
{
storage: generateRandomStorage(),
},
'./fixtures/config/updateManifest-1.yaml',
__dirname
)
);
const storage = new Storage(config);
await storage.init(config);
const ac = new AbortController();
setTimeout(() => {
ac.abort();
}, 10);
const bodyNewManifest = generatePackageMetadata(pkgName, '1.0.0');
await expect(
storage.updateManifest(bodyNewManifest, {
signal: ac.signal,
name: pkgName,
uplinksLook: true,
revision: '1',
requestOptions: {
host: 'localhost',
protocol: 'http',
headers: {},
},
})
).rejects.toThrow('should throw here');
});
test('create private package with multiple consecutive versions', async () => {
const mockDate = '2018-01-14T11:17:40.712Z';
MockDate.set(mockDate);
const settings = {
uplinksLook: true,
revision: '1',
requestOptions: {
@ -122,136 +160,245 @@ describe('storage', () => {
protocol: 'http',
headers: {},
},
})
).rejects.toThrow('should throw here');
});
test('create private package with multiple consecutive versions', async () => {
const mockDate = '2018-01-14T11:17:40.712Z';
MockDate.set(mockDate);
const settings = {
uplinksLook: true,
revision: '1',
requestOptions: {
host: 'localhost',
protocol: 'http',
headers: {},
},
};
const pkgName = 'upstream';
// const storage = generateRandomStorage();
const config = new Config(
configExample(
{
storage: await fileUtils.createTempStorageFolder('storage-test'),
},
'./fixtures/config/updateManifest-1.yaml',
__dirname
)
);
const storage = new Storage(config);
await storage.init(config);
// create a package
const bodyNewManifest1 = generatePackageMetadata(pkgName, '1.0.0');
await storage.updateManifest(bodyNewManifest1, {
signal: new AbortController().signal,
name: pkgName,
...settings,
});
// publish second version
const bodyNewManifest2 = generatePackageMetadata(pkgName, '1.0.1');
await storage.updateManifest(bodyNewManifest2, {
signal: new AbortController().signal,
name: pkgName,
...settings,
});
// retrieve package metadata
const manifest = (await storage.getPackageByOptions({
name: pkgName,
uplinksLook: true,
requestOptions: {
host: 'localhost',
protocol: 'http',
headers: {},
},
})) as Manifest;
expect(manifest.name).toEqual(pkgName);
expect(manifest._id).toEqual(pkgName);
expect(Object.keys(manifest.versions)).toEqual(['1.0.0', '1.0.1']);
expect(manifest.time).toEqual({
'1.0.0': mockDate,
'1.0.1': mockDate,
created: mockDate,
modified: mockDate,
});
expect(manifest[DIST_TAGS]).toEqual({ latest: '1.0.1' });
expect(manifest.readme).toEqual('# test');
expect(manifest._attachments).toEqual({});
expect(typeof manifest._rev).toBeTruthy();
// verify the version structure is correct
const manifestVersion = (await storage.getPackageByOptions({
name: pkgName,
version: '1.0.1',
uplinksLook: true,
requestOptions: {
host: 'localhost',
protocol: 'http',
headers: {},
},
})) as Version;
expect(manifestVersion.name).toEqual(pkgName);
expect(manifestVersion.version).toEqual('1.0.1');
expect(manifestVersion._id).toEqual(`${pkgName}@1.0.1`);
expect(manifestVersion.description).toEqual('package generated');
expect(manifestVersion.dist).toEqual({
integrity:
'sha512-6gHiERpiDgtb3hjqpQH5/i7zRmvYi9pmCjQf2ZMy3QEa9wVk9RgdZaPWUt7ZOnWUPFjcr9cmE6dUBf+XoPoH4g==',
shasum: '2c03764f651a9f016ca0b7620421457b619151b9',
tarball: 'http://localhost:5555/upstream/-/upstream-1.0.1.tgz',
});
expect(manifestVersion.contributors).toEqual([]);
expect(manifestVersion.main).toEqual('index.js');
expect(manifestVersion.author).toEqual({ name: 'User NPM', email: 'user@domain.com' });
expect(manifestVersion.dependencies).toEqual({ verdaccio: '^2.7.2' });
});
test('fails if version already exist', async () => {
const settings = {
uplinksLook: true,
revision: '1',
requestOptions: {
host: 'localhost',
protocol: 'http',
headers: {},
},
};
const pkgName = 'upstream';
const config = new Config(
configExample(
{
storage: generateRandomStorage(),
},
'./fixtures/config/getTarballNext-getupstream.yaml',
__dirname
)
);
const storage = new Storage(config);
await storage.init(config);
const bodyNewManifest1 = generatePackageMetadata(pkgName, '1.0.0');
const bodyNewManifest2 = generatePackageMetadata(pkgName, '1.0.0');
await storage.updateManifest(bodyNewManifest1, {
signal: new AbortController().signal,
name: pkgName,
...settings,
});
await expect(
storage.updateManifest(bodyNewManifest2, {
};
const pkgName = 'upstream';
// const storage = generateRandomStorage();
const config = new Config(
configExample(
{
storage: await fileUtils.createTempStorageFolder('storage-test'),
},
'./fixtures/config/updateManifest-1.yaml',
__dirname
)
);
const storage = new Storage(config);
await storage.init(config);
// create a package
const bodyNewManifest1 = generatePackageMetadata(pkgName, '1.0.0');
await storage.updateManifest(bodyNewManifest1, {
signal: new AbortController().signal,
name: pkgName,
...settings,
})
).rejects.toThrow(API_ERROR.PACKAGE_EXIST);
});
// publish second version
const bodyNewManifest2 = generatePackageMetadata(pkgName, '1.0.1');
await storage.updateManifest(bodyNewManifest2, {
signal: new AbortController().signal,
name: pkgName,
...settings,
});
// retrieve package metadata
const manifest = (await storage.getPackageByOptions({
name: pkgName,
uplinksLook: true,
requestOptions: {
host: 'localhost',
protocol: 'http',
headers: {},
},
})) as Manifest;
expect(manifest.name).toEqual(pkgName);
expect(manifest._id).toEqual(pkgName);
expect(Object.keys(manifest.versions)).toEqual(['1.0.0', '1.0.1']);
expect(manifest.time).toEqual({
'1.0.0': mockDate,
'1.0.1': mockDate,
created: mockDate,
modified: mockDate,
});
expect(manifest[DIST_TAGS]).toEqual({ latest: '1.0.1' });
expect(manifest.readme).toEqual('# test');
expect(manifest._attachments).toEqual({});
expect(typeof manifest._rev).toBeTruthy();
// verify the version structure is correct
const manifestVersion = (await storage.getPackageByOptions({
name: pkgName,
version: '1.0.1',
uplinksLook: true,
requestOptions: {
host: 'localhost',
protocol: 'http',
headers: {},
},
})) as Version;
expect(manifestVersion.name).toEqual(pkgName);
expect(manifestVersion.version).toEqual('1.0.1');
expect(manifestVersion._id).toEqual(`${pkgName}@1.0.1`);
expect(manifestVersion.description).toEqual('package generated');
expect(manifestVersion.dist).toEqual({
integrity:
'sha512-6gHiERpiDgtb3hjqpQH5/i7zRmvYi9pmCjQf2ZMy3QEa9wVk9RgdZaPWUt7ZOnWUPFjcr9cmE6dUBf+XoPoH4g==',
shasum: '2c03764f651a9f016ca0b7620421457b619151b9',
tarball: 'http://localhost:5555/upstream/-/upstream-1.0.1.tgz',
});
expect(manifestVersion.contributors).toEqual([]);
expect(manifestVersion.main).toEqual('index.js');
expect(manifestVersion.author).toEqual({ name: 'User NPM', email: 'user@domain.com' });
expect(manifestVersion.dependencies).toEqual({ verdaccio: '^2.7.2' });
});
test('fails if version already exist', async () => {
const settings = {
uplinksLook: true,
revision: '1',
requestOptions: {
host: 'localhost',
protocol: 'http',
headers: {},
},
};
const pkgName = 'upstream';
const config = new Config(
configExample(
{
storage: generateRandomStorage(),
},
'./fixtures/config/getTarballNext-getupstream.yaml',
__dirname
)
);
const storage = new Storage(config);
await storage.init(config);
const bodyNewManifest1 = generatePackageMetadata(pkgName, '1.0.0');
const bodyNewManifest2 = generatePackageMetadata(pkgName, '1.0.0');
await storage.updateManifest(bodyNewManifest1, {
signal: new AbortController().signal,
name: pkgName,
...settings,
});
await expect(
storage.updateManifest(bodyNewManifest2, {
signal: new AbortController().signal,
name: pkgName,
...settings,
})
).rejects.toThrow(API_ERROR.PACKAGE_EXIST);
});
});
describe('deprecate', () => {
test.each([['foo'], ['@scope/foo']])('deprecate package %s', async (pkgName) => {
const mockDate = '2018-01-14T11:17:40.712Z';
MockDate.set(mockDate);
const config = getConfig('deprecate.yaml');
const storage = new Storage(config);
await storage.init(config);
const bodyNewManifest = generatePackageMetadata(pkgName, '1.0.0');
await storage.updateManifest(bodyNewManifest, {
signal: new AbortController().signal,
name: pkgName,
uplinksLook: true,
revision: '1',
requestOptions: defaultRequestOptions,
});
const manifest1 = (await storage.getPackageByOptions({
name: pkgName,
uplinksLook: true,
requestOptions: defaultRequestOptions,
})) as Manifest;
expect(manifest1.versions['1.0.0'].deprecated).toBeUndefined();
const deprecatedManifest = getDeprecatedPackageMetadata(
pkgName,
'1.0.0',
{
['latest']: '1.0.0',
},
'some deprecation message',
manifest1._rev
);
await storage.updateManifest(deprecatedManifest, {
signal: new AbortController().signal,
name: pkgName,
uplinksLook: true,
revision: '1',
requestOptions: defaultRequestOptions,
});
const manifest = (await storage.getPackageByOptions({
name: pkgName,
uplinksLook: true,
requestOptions: defaultRequestOptions,
})) as Manifest;
expect(manifest.name).toEqual(pkgName);
expect(manifest.versions['1.0.0'].deprecated).toEqual('some deprecation message');
// important revision is updated
expect(manifest._rev !== deprecatedManifest._rev).toBeTruthy();
});
test.each([['foo'], ['@scope/foo']])('undeprecate package %s', async (pkgName) => {
const mockDate = '2018-01-14T11:17:40.712Z';
MockDate.set(mockDate);
const config = getConfig('deprecate.yaml');
const storage = new Storage(config);
await storage.init(config);
// publish new package
const bodyNewManifest = generatePackageMetadata(pkgName, '1.0.0');
await storage.updateManifest(bodyNewManifest, {
signal: new AbortController().signal,
name: pkgName,
uplinksLook: true,
revision: '1',
requestOptions: defaultRequestOptions,
});
// verify not deprecated
const manifest1 = (await storage.getPackageByOptions({
name: pkgName,
uplinksLook: true,
requestOptions: defaultRequestOptions,
})) as Manifest;
expect(manifest1.versions['1.0.0'].deprecated).toBeUndefined();
// deprecate version
const deprecatedManifest = getDeprecatedPackageMetadata(
pkgName,
'1.0.0',
{
['latest']: '1.0.0',
},
'some deprecation message',
manifest1._rev
);
await storage.updateManifest(deprecatedManifest, {
signal: new AbortController().signal,
name: pkgName,
uplinksLook: true,
revision: '1',
requestOptions: defaultRequestOptions,
});
const manifest = (await storage.getPackageByOptions({
name: pkgName,
uplinksLook: true,
requestOptions: defaultRequestOptions,
})) as Manifest;
expect(manifest.name).toEqual(pkgName);
expect(manifest.versions['1.0.0'].deprecated).toEqual('some deprecation message');
// important revision is updated
expect(manifest._rev !== deprecatedManifest._rev).toBeTruthy();
// un deprecated the previous deprecated
const undeprecatedManifest = {
...manifest,
};
undeprecatedManifest.versions['1.0.0'].deprecated = '';
await storage.updateManifest(undeprecatedManifest, {
signal: new AbortController().signal,
name: pkgName,
uplinksLook: true,
revision: '1',
requestOptions: defaultRequestOptions,
});
const manifest3 = (await storage.getPackageByOptions({
name: pkgName,
uplinksLook: true,
requestOptions: defaultRequestOptions,
})) as Manifest;
expect(manifest3.name).toEqual(pkgName);
expect(manifest3.versions['1.0.0'].deprecated).toBeUndefined();
// important revision is updated
expect(manifest3._rev !== deprecatedManifest._rev).toBeTruthy();
});
});
});
@ -724,7 +871,7 @@ describe('storage', () => {
});
});
describe('getLocalDatabaseNext', () => {
describe('getLocalDatabase', () => {
test('should return 0 local packages', async () => {
const config = new Config(
configExample({
@ -902,7 +1049,7 @@ describe('storage', () => {
});
});
describe('get packages getPackageByOptions()', () => {
describe('getPackageByOptions()', () => {
describe('with uplinks', () => {
test('should get 201 and merge from uplink', async () => {
nock(domain).get('/foo').reply(201, fooManifest);

@ -4,7 +4,7 @@ module.exports = Object.assign({}, config, {
coverageThreshold: {
global: {
// FIXME: increase to 90
lines: 48,
lines: 40,
},
},
});

@ -217,6 +217,21 @@ export function generateRemotePackageMetadata(
};
}
export function getDeprecatedPackageMetadata(
pkgName: string,
version = '1.0.0',
distTags: DistTags = { ['latest']: version },
deprecated = 'default deprecated message',
rev = 'rev-foo'
): Manifest {
const manifest = generatePackageMetadata(pkgName, version, distTags);
// deprecated message requires empty attachments
manifest._attachments = {};
manifest._rev = rev;
manifest.versions[version].deprecated = deprecated;
return manifest;
}
export function generatePackageMetadata(
pkgName: string,
version = '1.0.0',

@ -3,6 +3,7 @@ export {
addNewVersion,
generateLocalPackageMetadata,
generateRemotePackageMetadata,
getDeprecatedPackageMetadata,
} from './generatePackageMetadata';
export { generatePublishNewVersionManifest } from './generatePublishNewVersionManifest';
export { initializeServer } from './initializeServer';

@ -7,12 +7,17 @@
### Commands Tested
| cmd | npm6 | npm7 | npm8 | pnpm6 | pnpm7 | yarn1 | yarn2 | yarn3 | yarn4 |
| ------- | ---- | ---- | ---- | ----- | ----- | ----- | ----- | ----- | ----- |
| publish | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ |
| info | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| audit | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
| install | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| cmd | npm6 | npm7 | npm8 | pnpm6 | pnpm7 | yarn1 | yarn2 | yarn3 | yarn4 |
| --------- | ---- | ---- | ---- | ----- | ----- | ----- | ----- | ----- | ----- |
| publish | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ |
| info | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| audit | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
| install | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| deprecate | ✅ | ✅ | ✅ | ✅ | ✅ | ⛔ | ⛔ | ⛔ | ⛔ |
❌ = no tested
✅ = tested
⛔ = no supported
## How it works?

@ -21,7 +21,7 @@ export async function exec(options: SpawnOptions, cmd, args): Promise<ExecOutput
const spawnOptions = {
cwd: options.cwd,
stdio: options.stdio || 'pipe',
...(env ? { env } : {}),
env: process.env,
};
if (process.platform.startsWith('win')) {

@ -12,9 +12,24 @@ export type Setup = {
tempFolder: string;
};
const log =
process.env.NODE_ENV === 'production'
? { type: 'stdout', format: 'json', level: 'warn' }
: { type: 'stdout', format: 'pretty', level: 'warn' };
const defaultConfig = {
...getDefaultConfig(),
log,
};
export async function initialSetup(customConfig?: ConfigYaml): Promise<Setup> {
// @ts-ignore
const { configPath, tempFolder } = await Registry.fromConfigToPath({
...(customConfig ? customConfig : { ...getDefaultConfig(), _debug: true }),
...(customConfig
? customConfig
: {
...defaultConfig,
_debug: true,
}),
});
debug(`configPath %o`, configPath);
debug(`tempFolder %o`, tempFolder);

@ -0,0 +1,137 @@
import { addRegistry, initialSetup, prepareGenericEmptyProject } from '@verdaccio/test-cli-commons';
import { npm } from './utils';
describe('deprecate a package', () => {
jest.setTimeout(15000);
let registry;
async function bumbUp(tempFolder, registry) {
await npm({ cwd: tempFolder }, 'version', 'minor', ...addRegistry(registry.getRegistryUrl()));
}
async function publish(tempFolder, pkgName, registry) {
const resp = await npm(
{ cwd: tempFolder },
'publish',
'--json',
...addRegistry(registry.getRegistryUrl())
);
const parsedBody = JSON.parse(resp.stdout as string);
expect(parsedBody.name).toEqual(pkgName);
}
async function deprecate(tempFolder, packageVersion, registry, message) {
await npm(
{ cwd: tempFolder },
'deprecate',
packageVersion,
message,
'--json',
...addRegistry(registry.getRegistryUrl())
);
}
async function getInfoVersions(pkgName, registry) {
const infoResp = await npm(
{},
'info',
pkgName,
'--json',
...addRegistry(registry.getRegistryUrl())
);
const infoBody = JSON.parse(infoResp.stdout as string);
return infoBody;
}
beforeAll(async () => {
const setup = await initialSetup();
registry = setup.registry;
await registry.init();
});
test.each([['@verdaccio/deprecated-1']])(
'should deprecate a single package %s',
async (pkgName) => {
const message = 'some message';
const { tempFolder } = await prepareGenericEmptyProject(
pkgName,
'1.0.0',
registry.port,
registry.getToken(),
registry.getRegistryUrl()
);
await publish(tempFolder, pkgName, registry);
// deprecate one version
await deprecate(tempFolder, `${pkgName}@1.0.0`, registry, message);
// verify is deprecated
const infoBody = await getInfoVersions(`${pkgName}`, registry);
expect(infoBody.name).toEqual(pkgName);
expect(infoBody.deprecated).toEqual(message);
}
);
test.each([['@verdaccio/deprecated-2']])('should un-deprecate a package %s', async (pkgName) => {
const message = 'some message';
const { tempFolder } = await prepareGenericEmptyProject(
pkgName,
'1.0.0',
registry.port,
registry.getToken(),
registry.getRegistryUrl()
);
await publish(tempFolder, pkgName, registry);
// deprecate one version
await deprecate(tempFolder, `${pkgName}@1.0.0`, registry, message);
// verify is deprecated
const infoBody = await getInfoVersions(`${pkgName}`, registry);
expect(infoBody.deprecated).toEqual(message);
// empty string is same as undeprecate
await deprecate(tempFolder, `${pkgName}@1.0.0`, registry, '');
const infoBody2 = await getInfoVersions(`${pkgName}`, registry);
expect(infoBody2.deprecated).toBeUndefined();
});
test.each([['@verdaccio/deprecated-3']])(
'should deprecate a multiple packages %s',
async (pkgName) => {
const message = 'some message';
const { tempFolder } = await prepareGenericEmptyProject(
pkgName,
'1.0.0',
registry.port,
registry.getToken(),
registry.getRegistryUrl()
);
// publish 1.0.0
await publish(tempFolder, pkgName, registry);
// publish 1.1.0
await bumbUp(tempFolder, registry);
await publish(tempFolder, pkgName, registry);
// publish 1.2.0
await bumbUp(tempFolder, registry);
await publish(tempFolder, pkgName, registry);
// publish 1.3.0
await bumbUp(tempFolder, registry);
await publish(tempFolder, pkgName, registry);
// // deprecate all version
await deprecate(tempFolder, pkgName, registry, message);
// verify is deprecated
for (let v of ['1.0.0', '1.1.0', '1.2.0', '1.3.0']) {
const infoResp = await getInfoVersions(`${pkgName}@${v}`, registry);
expect(infoResp.deprecated).toEqual(message);
}
// publish normal version
// publish 1.4.0
await bumbUp(tempFolder, registry);
await publish(tempFolder, pkgName, registry);
const infoResp = await getInfoVersions(`${pkgName}@1.4.0`, registry);
// must be not deprecated
expect(infoResp.deprecated).toBeUndefined();
}
);
afterAll(async () => {
registry.stop();
});
});

@ -1,6 +1,3 @@
const { defaults } = require('jest-config');
const config = require('../../../jest/config');
const config = require('../jest.config');
module.exports = Object.assign({}, config, {
moduleFileExtensions: [...defaults.moduleFileExtensions, 'ts'],
});
module.exports = { ...config };

@ -2,7 +2,7 @@ import { addRegistry, initialSetup, prepareGenericEmptyProject } from '@verdacci
import { npm } from './utils';
describe('install a package', () => {
describe('publish a package', () => {
jest.setTimeout(10000);
let registry;

@ -0,0 +1,137 @@
import { addRegistry, initialSetup, prepareGenericEmptyProject } from '@verdaccio/test-cli-commons';
import { npm } from './utils';
describe('deprecate a package', () => {
jest.setTimeout(15000);
let registry;
async function bumbUp(tempFolder, registry) {
await npm({ cwd: tempFolder }, 'version', 'minor', ...addRegistry(registry.getRegistryUrl()));
}
async function publish(tempFolder, pkgName, registry) {
const resp = await npm(
{ cwd: tempFolder },
'publish',
'--json',
...addRegistry(registry.getRegistryUrl())
);
const parsedBody = JSON.parse(resp.stdout as string);
expect(parsedBody.name).toEqual(pkgName);
}
async function deprecate(tempFolder, packageVersion, registry, message) {
await npm(
{ cwd: tempFolder },
'deprecate',
packageVersion,
message,
'--json',
...addRegistry(registry.getRegistryUrl())
);
}
async function getInfoVersions(pkgName, registry) {
const infoResp = await npm(
{},
'info',
pkgName,
'--json',
...addRegistry(registry.getRegistryUrl())
);
const infoBody = JSON.parse(infoResp.stdout as string);
return infoBody;
}
beforeAll(async () => {
const setup = await initialSetup();
registry = setup.registry;
await registry.init();
});
test.each([['@verdaccio/deprecated-1']])(
'should deprecate a single package %s',
async (pkgName) => {
const message = 'some message';
const { tempFolder } = await prepareGenericEmptyProject(
pkgName,
'1.0.0',
registry.port,
registry.getToken(),
registry.getRegistryUrl()
);
await publish(tempFolder, pkgName, registry);
// deprecate one version
await deprecate(tempFolder, `${pkgName}@1.0.0`, registry, message);
// verify is deprecated
const infoBody = await getInfoVersions(`${pkgName}`, registry);
expect(infoBody.name).toEqual(pkgName);
expect(infoBody.deprecated).toEqual(message);
}
);
test.each([['@verdaccio/deprecated-2']])('should un-deprecate a package %s', async (pkgName) => {
const message = 'some message';
const { tempFolder } = await prepareGenericEmptyProject(
pkgName,
'1.0.0',
registry.port,
registry.getToken(),
registry.getRegistryUrl()
);
await publish(tempFolder, pkgName, registry);
// deprecate one version
await deprecate(tempFolder, `${pkgName}@1.0.0`, registry, message);
// verify is deprecated
const infoBody = await getInfoVersions(`${pkgName}`, registry);
expect(infoBody.deprecated).toEqual(message);
// empty string is same as undeprecate
await deprecate(tempFolder, `${pkgName}@1.0.0`, registry, '');
const infoBody2 = await getInfoVersions(`${pkgName}`, registry);
expect(infoBody2.deprecated).toBeUndefined();
});
test.each([['@verdaccio/deprecated-3']])(
'should deprecate a multiple packages %s',
async (pkgName) => {
const message = 'some message';
const { tempFolder } = await prepareGenericEmptyProject(
pkgName,
'1.0.0',
registry.port,
registry.getToken(),
registry.getRegistryUrl()
);
// publish 1.0.0
await publish(tempFolder, pkgName, registry);
// publish 1.1.0
await bumbUp(tempFolder, registry);
await publish(tempFolder, pkgName, registry);
// publish 1.2.0
await bumbUp(tempFolder, registry);
await publish(tempFolder, pkgName, registry);
// publish 1.3.0
await bumbUp(tempFolder, registry);
await publish(tempFolder, pkgName, registry);
// // deprecate all version
await deprecate(tempFolder, pkgName, registry, message);
// verify is deprecated
for (let v of ['1.0.0', '1.1.0', '1.2.0', '1.3.0']) {
const infoResp = await getInfoVersions(`${pkgName}@${v}`, registry);
expect(infoResp.deprecated).toEqual(message);
}
// publish normal version
// publish 1.4.0
await bumbUp(tempFolder, registry);
await publish(tempFolder, pkgName, registry);
const infoResp = await getInfoVersions(`${pkgName}@1.4.0`, registry);
// must be not deprecated
expect(infoResp.deprecated).toBeUndefined();
}
);
afterAll(async () => {
registry.stop();
});
});

@ -1,6 +1,3 @@
const { defaults } = require('jest-config');
const config = require('../../../jest/config');
const config = require('../jest.config');
module.exports = Object.assign({}, config, {
moduleFileExtensions: [...defaults.moduleFileExtensions, 'ts'],
});
module.exports = { ...config };

@ -0,0 +1,137 @@
import { addRegistry, initialSetup, prepareGenericEmptyProject } from '@verdaccio/test-cli-commons';
import { npm } from './utils';
describe('deprecate a package', () => {
jest.setTimeout(15000);
let registry;
async function bumbUp(tempFolder, registry) {
await npm({ cwd: tempFolder }, 'version', 'minor', ...addRegistry(registry.getRegistryUrl()));
}
async function publish(tempFolder, pkgName, registry) {
const resp = await npm(
{ cwd: tempFolder },
'publish',
'--json',
...addRegistry(registry.getRegistryUrl())
);
const parsedBody = JSON.parse(resp.stdout as string);
expect(parsedBody.name).toEqual(pkgName);
}
async function deprecate(tempFolder, packageVersion, registry, message) {
await npm(
{ cwd: tempFolder },
'deprecate',
packageVersion,
message,
'--json',
...addRegistry(registry.getRegistryUrl())
);
}
async function getInfoVersions(pkgName, registry) {
const infoResp = await npm(
{},
'info',
pkgName,
'--json',
...addRegistry(registry.getRegistryUrl())
);
const infoBody = JSON.parse(infoResp.stdout as string);
return infoBody;
}
beforeAll(async () => {
const setup = await initialSetup();
registry = setup.registry;
await registry.init();
});
test.each([['@verdaccio/deprecated-1']])(
'should deprecate a single package %s',
async (pkgName) => {
const message = 'some message';
const { tempFolder } = await prepareGenericEmptyProject(
pkgName,
'1.0.0',
registry.port,
registry.getToken(),
registry.getRegistryUrl()
);
await publish(tempFolder, pkgName, registry);
// deprecate one version
await deprecate(tempFolder, `${pkgName}@1.0.0`, registry, message);
// verify is deprecated
const infoBody = await getInfoVersions(`${pkgName}`, registry);
expect(infoBody.name).toEqual(pkgName);
expect(infoBody.deprecated).toEqual(message);
}
);
test.each([['@verdaccio/deprecated-2']])('should un-deprecate a package %s', async (pkgName) => {
const message = 'some message';
const { tempFolder } = await prepareGenericEmptyProject(
pkgName,
'1.0.0',
registry.port,
registry.getToken(),
registry.getRegistryUrl()
);
await publish(tempFolder, pkgName, registry);
// deprecate one version
await deprecate(tempFolder, `${pkgName}@1.0.0`, registry, message);
// verify is deprecated
const infoBody = await getInfoVersions(`${pkgName}`, registry);
expect(infoBody.deprecated).toEqual(message);
// empty string is same as undeprecate
await deprecate(tempFolder, `${pkgName}@1.0.0`, registry, '');
const infoBody2 = await getInfoVersions(`${pkgName}`, registry);
expect(infoBody2.deprecated).toBeUndefined();
});
test.each([['@verdaccio/deprecated-3']])(
'should deprecate a multiple packages %s',
async (pkgName) => {
const message = 'some message';
const { tempFolder } = await prepareGenericEmptyProject(
pkgName,
'1.0.0',
registry.port,
registry.getToken(),
registry.getRegistryUrl()
);
// publish 1.0.0
await publish(tempFolder, pkgName, registry);
// publish 1.1.0
await bumbUp(tempFolder, registry);
await publish(tempFolder, pkgName, registry);
// publish 1.2.0
await bumbUp(tempFolder, registry);
await publish(tempFolder, pkgName, registry);
// publish 1.3.0
await bumbUp(tempFolder, registry);
await publish(tempFolder, pkgName, registry);
// // deprecate all version
await deprecate(tempFolder, pkgName, registry, message);
// verify is deprecated
for (let v of ['1.0.0', '1.1.0', '1.2.0', '1.3.0']) {
const infoResp = await getInfoVersions(`${pkgName}@${v}`, registry);
expect(infoResp.deprecated).toEqual(message);
}
// publish normal version
// publish 1.4.0
await bumbUp(tempFolder, registry);
await publish(tempFolder, pkgName, registry);
const infoResp = await getInfoVersions(`${pkgName}@1.4.0`, registry);
// must be not deprecated
expect(infoResp.deprecated).toBeUndefined();
}
);
afterAll(async () => {
registry.stop();
});
});

@ -1,6 +1,3 @@
const { defaults } = require('jest-config');
const config = require('../../../jest/config');
const config = require('../jest.config');
module.exports = Object.assign({}, config, {
moduleFileExtensions: [...defaults.moduleFileExtensions, 'ts'],
});
module.exports = { ...config };

@ -0,0 +1,137 @@
import { addRegistry, initialSetup, prepareGenericEmptyProject } from '@verdaccio/test-cli-commons';
import { pnpm } from './utils';
describe('deprecate a package', () => {
jest.setTimeout(15000);
let registry;
async function bumbUp(tempFolder, registry) {
await pnpm({ cwd: tempFolder }, 'version', 'minor', ...addRegistry(registry.getRegistryUrl()));
}
async function publish(tempFolder, pkgName, registry) {
const resp = await pnpm(
{ cwd: tempFolder },
'publish',
'--json',
...addRegistry(registry.getRegistryUrl())
);
const parsedBody = JSON.parse(resp.stdout as string);
expect(parsedBody.name).toEqual(pkgName);
}
async function deprecate(tempFolder, packageVersion, registry, message) {
await pnpm(
{ cwd: tempFolder },
'deprecate',
packageVersion,
message,
'--json',
...addRegistry(registry.getRegistryUrl())
);
}
async function getInfoVersions(pkgName, registry) {
const infoResp = await pnpm(
{},
'info',
pkgName,
'--json',
...addRegistry(registry.getRegistryUrl())
);
const infoBody = JSON.parse(infoResp.stdout as string);
return infoBody;
}
beforeAll(async () => {
const setup = await initialSetup();
registry = setup.registry;
await registry.init();
});
test.each([['@verdaccio/deprecated-1']])(
'should deprecate a single package %s',
async (pkgName) => {
const message = 'some message';
const { tempFolder } = await prepareGenericEmptyProject(
pkgName,
'1.0.0',
registry.port,
registry.getToken(),
registry.getRegistryUrl()
);
await publish(tempFolder, pkgName, registry);
// deprecate one version
await deprecate(tempFolder, `${pkgName}@1.0.0`, registry, message);
// verify is deprecated
const infoBody = await getInfoVersions(`${pkgName}`, registry);
expect(infoBody.name).toEqual(pkgName);
expect(infoBody.deprecated).toEqual(message);
}
);
test.each([['@verdaccio/deprecated-2']])('should un-deprecate a package %s', async (pkgName) => {
const message = 'some message';
const { tempFolder } = await prepareGenericEmptyProject(
pkgName,
'1.0.0',
registry.port,
registry.getToken(),
registry.getRegistryUrl()
);
await publish(tempFolder, pkgName, registry);
// deprecate one version
await deprecate(tempFolder, `${pkgName}@1.0.0`, registry, message);
// verify is deprecated
const infoBody = await getInfoVersions(`${pkgName}`, registry);
expect(infoBody.deprecated).toEqual(message);
// empty string is same as undeprecate
await deprecate(tempFolder, `${pkgName}@1.0.0`, registry, '');
const infoBody2 = await getInfoVersions(`${pkgName}`, registry);
expect(infoBody2.deprecated).toBeUndefined();
});
test.each([['@verdaccio/deprecated-3']])(
'should deprecate a multiple packages %s',
async (pkgName) => {
const message = 'some message';
const { tempFolder } = await prepareGenericEmptyProject(
pkgName,
'1.0.0',
registry.port,
registry.getToken(),
registry.getRegistryUrl()
);
// publish 1.0.0
await publish(tempFolder, pkgName, registry);
// publish 1.1.0
await bumbUp(tempFolder, registry);
await publish(tempFolder, pkgName, registry);
// publish 1.2.0
await bumbUp(tempFolder, registry);
await publish(tempFolder, pkgName, registry);
// publish 1.3.0
await bumbUp(tempFolder, registry);
await publish(tempFolder, pkgName, registry);
// // deprecate all version
await deprecate(tempFolder, pkgName, registry, message);
// verify is deprecated
for (let v of ['1.0.0', '1.1.0', '1.2.0', '1.3.0']) {
const infoResp = await getInfoVersions(`${pkgName}@${v}`, registry);
expect(infoResp.deprecated).toEqual(message);
}
// publish normal version
// publish 1.4.0
await bumbUp(tempFolder, registry);
await publish(tempFolder, pkgName, registry);
const infoResp = await getInfoVersions(`${pkgName}@1.4.0`, registry);
// must be not deprecated
expect(infoResp.deprecated).toBeUndefined();
}
);
afterAll(async () => {
registry.stop();
});
});

@ -1,6 +1,3 @@
const { defaults } = require('jest-config');
const config = require('../../../jest/config');
const config = require('../jest.config');
module.exports = Object.assign({}, config, {
moduleFileExtensions: [...defaults.moduleFileExtensions, 'ts'],
});
module.exports = { ...config };

@ -0,0 +1,137 @@
import { addRegistry, initialSetup, prepareGenericEmptyProject } from '@verdaccio/test-cli-commons';
import { pnpm } from './utils';
describe('deprecate a package', () => {
jest.setTimeout(15000);
let registry;
async function bumbUp(tempFolder, registry) {
await pnpm({ cwd: tempFolder }, 'version', 'minor', ...addRegistry(registry.getRegistryUrl()));
}
async function publish(tempFolder, pkgName, registry) {
const resp = await pnpm(
{ cwd: tempFolder },
'publish',
'--json',
...addRegistry(registry.getRegistryUrl())
);
const parsedBody = JSON.parse(resp.stdout as string);
expect(parsedBody.name).toEqual(pkgName);
}
async function deprecate(tempFolder, packageVersion, registry, message) {
await pnpm(
{ cwd: tempFolder },
'deprecate',
packageVersion,
message,
'--json',
...addRegistry(registry.getRegistryUrl())
);
}
async function getInfoVersions(pkgName, registry) {
const infoResp = await pnpm(
{},
'info',
pkgName,
'--json',
...addRegistry(registry.getRegistryUrl())
);
const infoBody = JSON.parse(infoResp.stdout as string);
return infoBody;
}
beforeAll(async () => {
const setup = await initialSetup();
registry = setup.registry;
await registry.init();
});
test.each([['@verdaccio/deprecated-1']])(
'should deprecate a single package %s',
async (pkgName) => {
const message = 'some message';
const { tempFolder } = await prepareGenericEmptyProject(
pkgName,
'1.0.0',
registry.port,
registry.getToken(),
registry.getRegistryUrl()
);
await publish(tempFolder, pkgName, registry);
// deprecate one version
await deprecate(tempFolder, `${pkgName}@1.0.0`, registry, message);
// verify is deprecated
const infoBody = await getInfoVersions(`${pkgName}`, registry);
expect(infoBody.name).toEqual(pkgName);
expect(infoBody.deprecated).toEqual(message);
}
);
test.each([['@verdaccio/deprecated-2']])('should un-deprecate a package %s', async (pkgName) => {
const message = 'some message';
const { tempFolder } = await prepareGenericEmptyProject(
pkgName,
'1.0.0',
registry.port,
registry.getToken(),
registry.getRegistryUrl()
);
await publish(tempFolder, pkgName, registry);
// deprecate one version
await deprecate(tempFolder, `${pkgName}@1.0.0`, registry, message);
// verify is deprecated
const infoBody = await getInfoVersions(`${pkgName}`, registry);
expect(infoBody.deprecated).toEqual(message);
// empty string is same as undeprecate
await deprecate(tempFolder, `${pkgName}@1.0.0`, registry, '');
const infoBody2 = await getInfoVersions(`${pkgName}`, registry);
expect(infoBody2.deprecated).toBeUndefined();
});
test.each([['@verdaccio/deprecated-3']])(
'should deprecate a multiple packages %s',
async (pkgName) => {
const message = 'some message';
const { tempFolder } = await prepareGenericEmptyProject(
pkgName,
'1.0.0',
registry.port,
registry.getToken(),
registry.getRegistryUrl()
);
// publish 1.0.0
await publish(tempFolder, pkgName, registry);
// publish 1.1.0
await bumbUp(tempFolder, registry);
await publish(tempFolder, pkgName, registry);
// publish 1.2.0
await bumbUp(tempFolder, registry);
await publish(tempFolder, pkgName, registry);
// publish 1.3.0
await bumbUp(tempFolder, registry);
await publish(tempFolder, pkgName, registry);
// // deprecate all version
await deprecate(tempFolder, pkgName, registry, message);
// verify is deprecated
for (let v of ['1.0.0', '1.1.0', '1.2.0', '1.3.0']) {
const infoResp = await getInfoVersions(`${pkgName}@${v}`, registry);
expect(infoResp.deprecated).toEqual(message);
}
// publish normal version
// publish 1.4.0
await bumbUp(tempFolder, registry);
await publish(tempFolder, pkgName, registry);
const infoResp = await getInfoVersions(`${pkgName}@1.4.0`, registry);
// must be not deprecated
expect(infoResp.deprecated).toBeUndefined();
}
);
afterAll(async () => {
registry.stop();
});
});

@ -1,6 +1,3 @@
const { defaults } = require('jest-config');
const config = require('../../../jest/config');
const config = require('../jest.config');
module.exports = Object.assign({}, config, {
moduleFileExtensions: [...defaults.moduleFileExtensions, 'ts'],
});
module.exports = { ...config };

@ -1,14 +1,3 @@
const { defaults } = require('jest-config');
const config = require('../../../jest/config');
const config = require('../jest.config');
module.exports = Object.assign({}, config, {
name: 'verdaccio-e2e-cli-jest',
// verbose: true,
// collectCoverage: false,
moduleFileExtensions: [...defaults.moduleFileExtensions, 'ts'],
// testEnvironment: './env_babel.js',
// globalSetup: './env_setup.js',
// globalTeardown: './env_teardown.js',
// testRegex: '(/test/e2e.*\\.spec)\\.ts',
testRegex: '(/test/*.*.spec)\\.ts',
});
module.exports = { ...config };

@ -23,9 +23,9 @@ describe('install a package', () => {
});
test('should run yarn 2 info json body', async () => {
const resp = await yarn(projectFolder, 'npm', 'info', 'verdaccio', '--json');
const resp = await yarn(projectFolder, 'npm', 'info', 'react', '--json');
const parsedBody = JSON.parse(resp.stdout as string);
expect(parsedBody.name).toEqual('verdaccio');
expect(parsedBody.name).toEqual('react');
expect(parsedBody.dependencies).toBeDefined();
});

@ -5,7 +5,7 @@ import { initialSetup, prepareYarnModernProject } from '@verdaccio/test-cli-comm
import { getYarnCommand, yarn } from './utils';
describe('install a packages', () => {
jest.setTimeout(10000);
jest.setTimeout(20000);
let registry;
let projectFolder;

@ -1,6 +1,3 @@
const { defaults } = require('jest-config');
const config = require('../../../jest/config');
const config = require('../jest.config');
module.exports = Object.assign({}, config, {
moduleFileExtensions: [...defaults.moduleFileExtensions, 'ts'],
});
module.exports = { ...config };

@ -24,9 +24,9 @@ describe('install a package', () => {
test('should run yarn 3 info json body', async () => {
await yarn(projectFolder, 'install');
const resp = await yarn(projectFolder, 'npm', 'info', 'verdaccio', '--json');
const resp = await yarn(projectFolder, 'npm', 'info', 'react', '--json');
const parsedBody = JSON.parse(resp.stdout as string);
expect(parsedBody.name).toEqual('verdaccio');
expect(parsedBody.name).toEqual('react');
expect(parsedBody.dependencies).toBeDefined();
});

@ -5,7 +5,7 @@ import { initialSetup, prepareYarnModernProject } from '@verdaccio/test-cli-comm
import { getYarnCommand, yarn } from './utils';
describe('install a packages', () => {
jest.setTimeout(10000);
jest.setTimeout(20000);
let registry;
let projectFolder;

@ -1,6 +1,3 @@
const { defaults } = require('jest-config');
const config = require('../../../jest/config');
const config = require('../jest.config');
module.exports = Object.assign({}, config, {
moduleFileExtensions: [...defaults.moduleFileExtensions, 'ts'],
});
module.exports = { ...config };

@ -23,9 +23,9 @@ describe('install a package', () => {
});
test('should run yarn 4 info json body', async () => {
const resp = await yarn(projectFolder, 'npm', 'info', 'verdaccio', '--json');
const resp = await yarn(projectFolder, 'npm', 'info', 'react', '--json');
const parsedBody = JSON.parse(resp.stdout as string);
expect(parsedBody.name).toEqual('verdaccio');
expect(parsedBody.name).toEqual('react');
expect(parsedBody.dependencies).toBeDefined();
});

@ -5,7 +5,7 @@ import { initialSetup, prepareYarnModernProject } from '@verdaccio/test-cli-comm
import { getYarnCommand, yarn } from './utils';
describe('install a packages', () => {
jest.setTimeout(10000);
jest.setTimeout(20000);
let registry;
let projectFolder;

@ -1,6 +1,3 @@
const { defaults } = require('jest-config');
const config = require('../../../jest/config');
const config = require('../jest.config');
module.exports = Object.assign({}, config, {
moduleFileExtensions: [...defaults.moduleFileExtensions, 'ts'],
});
module.exports = { ...config };

8
test/cli/jest.config.js Normal file

@ -0,0 +1,8 @@
const { defaults } = require('jest-config');
const config = require('../../jest/config');
module.exports = Object.assign({}, config, {
collectCoverage: false,
coverageReporters: ['text'],
moduleFileExtensions: [...defaults.moduleFileExtensions, 'ts'],
});