Skip to content

Commit

Permalink
feat(registries): allowed-hosts are updated for lockfile lint with li…
Browse files Browse the repository at this point in the history
…fting registries
  • Loading branch information
travi committed Sep 22, 2024
1 parent 8887993 commit 40cfa76
Show file tree
Hide file tree
Showing 7 changed files with 146 additions and 19 deletions.
4 changes: 2 additions & 2 deletions src/lockfile-lint/allowed-hosts-builder.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export default function ({packageManager, registries}) {
export default function ({packageManager, registries = {}}) {
return [
...(!registries || (registries && !registries.registry)) ? [packageManager] : [],
...!registries.registry ? [packageManager] : [],
...Object.values(Object.fromEntries(Object.entries(registries).filter(([scope]) => 'publish' !== scope)))
];
}
4 changes: 4 additions & 0 deletions src/lockfile-lint/allowed-hosts-builder.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ describe('allowed-hosts builder', () => {
expect(buildAllowedHostsList({packageManager, registries: {}})).toEqual([packageManager]);
});

it('should list the package-manager in the allowed list, even when no registries are provided', () => {
expect(buildAllowedHostsList({packageManager, registries: undefined})).toEqual([packageManager]);
});

it('should allow additional registries when provided', () => {
const registries = any.simpleObject();

Expand Down
33 changes: 30 additions & 3 deletions src/registries/lifter.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,43 @@
import {
scaffold as scaffoldLockfileLint,
test as lockfileLintIsAlreadyConfigured,
read as readLockfileLintConfig,
write as writeLockfileLintConfig
} from '../lockfile-lint/index.js';
import {read as readNpmConfig, write as writeNpmConfig} from '../npm-config/index.js';
import buildRegistriesConfig from './npm-config/list-builder.js';
import buildAllowedHostsList from '../lockfile-lint/allowed-hosts-builder.js';

export default async function ({projectRoot, configs}) {
const registries = buildRegistriesConfig(configs.registries);
async function updateRegistriesInNpmConfig(registries, projectRoot) {
const registriesForNpmConfig = buildRegistriesConfig(registries);

await writeNpmConfig({
projectRoot,
config: {
...(await readNpmConfig({projectRoot})),
...registries
...registriesForNpmConfig
}
});
}

async function updateRegistriesInLockfileLintConfig(projectRoot, packageManager, registries) {
await writeLockfileLintConfig({
projectRoot,
config: {
...await readLockfileLintConfig(),
'allowed-hosts': buildAllowedHostsList({packageManager, registries})
}
});
}

export default async function ({projectRoot, packageManager, configs: {registries}}) {
await updateRegistriesInNpmConfig(registries, projectRoot);

if (!(await lockfileLintIsAlreadyConfigured({projectRoot}))) {
return scaffoldLockfileLint({projectRoot, packageManager, registries});
}

await updateRegistriesInLockfileLintConfig(projectRoot, packageManager, registries);

return {};
}
50 changes: 42 additions & 8 deletions src/registries/lifter.test.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,63 @@
import any from '@travi/any';
import {describe, expect, it, vi} from 'vitest';
import {beforeEach, describe, expect, it, vi} from 'vitest';
import {when} from 'jest-when';

import buildAllowedHostsList from '../lockfile-lint/allowed-hosts-builder.js';
import {
scaffold as scaffoldLockfileLint,
test as lockfileLintIsAlreadyConfigured,
read as readLockfileLintConfig,
write as writeLockfileLintConfig
} from '../lockfile-lint/index.js';
import {read as readNpmConfig, write as writeNpmConfig} from '../npm-config/index.js';
import buildRegistriesConfig from './npm-config/list-builder.js';
import liftRegistries from './lifter.js';

vi.mock('../lockfile-lint/allowed-hosts-builder.js');
vi.mock('../lockfile-lint/index.js');
vi.mock('../registries/npm-config/list-builder.js');
vi.mock('../npm-config/index.js');

describe('registries lifter', () => {
it('should define the registries in the npmrc and lockfile-lint configs', async () => {
const projectRoot = any.string();
const registries = any.simpleObject();
const configs = {...any.simpleObject(), registries};
const processedRegistryDetails = any.simpleObject();
const existingNpmConfig = any.simpleObject();
const projectRoot = any.string();
const packageManager = any.word();
const registries = any.simpleObject();
const configs = {...any.simpleObject(), registries};
const processedRegistryDetails = any.simpleObject();
const existingNpmConfig = any.simpleObject();

beforeEach(() => {
when(readNpmConfig).calledWith({projectRoot}).mockResolvedValue(existingNpmConfig);
when(buildRegistriesConfig).calledWith(registries).mockReturnValue(processedRegistryDetails);
});

it('should define the registries in the npmrc and lockfile-lint configs', async () => {
const existingLockfileLintConfig = any.simpleObject();
const allowedHosts = any.listOf(any.url);
when(lockfileLintIsAlreadyConfigured).calledWith({projectRoot}).mockResolvedValue(true);
readLockfileLintConfig.mockResolvedValue(existingLockfileLintConfig);
when(buildAllowedHostsList).calledWith({packageManager, registries}).mockReturnValue(allowedHosts);

expect(await liftRegistries({projectRoot, configs})).toEqual({});
expect(await liftRegistries({projectRoot, packageManager, configs})).toEqual({});

expect(writeNpmConfig).toHaveBeenCalledWith({
projectRoot,
config: {...existingNpmConfig, ...processedRegistryDetails}
});
expect(writeLockfileLintConfig).toHaveBeenCalledWith({
projectRoot,
config: {...existingLockfileLintConfig, 'allowed-hosts': allowedHosts}
});
});

it('should scaffold lockfile-lint if not already present', async () => {
const lockfileLintResults = any.simpleObject();
when(lockfileLintIsAlreadyConfigured).calledWith({projectRoot}).mockResolvedValue(false);
when(scaffoldLockfileLint)
.calledWith({projectRoot, packageManager, registries})
.mockResolvedValue(lockfileLintResults);

expect(await liftRegistries({projectRoot, packageManager, configs}))
.toEqual(lockfileLintResults);
});
});
12 changes: 11 additions & 1 deletion test/integration/features/lift/registries.feature
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,37 @@ Feature: Lift Registries
Scenario: npmrc exists, no registry defined, no registries provided
Given the npmrc does not define registry
And an "npm" lockfile exists
And lockfile-lint is configured
And husky v5 is installed
When the scaffolder results are processed
Then registry is defined as the official registry
And the lockfile-lint config allows the "npm" registry

Scenario: npmrc exists, no registry defined, custom registry provided
Given the npmrc does not define registry
And an "npm" lockfile exists
And husky v5 is installed
And lockfile-lint is configured
And an override is defined for the official registry
When the scaffolder results are processed
Then registry is defined as an alternate registry
And the lockfile-lint config allows the custom registry

Scenario: npmrc exists, no registry defined, custom scoped registry provided
Given the npmrc does not define registry
And an "npm" lockfile exists
And lockfile-lint is configured
And husky v5 is installed
And registries are defined for scopes
When the scaffolder results are processed
Then registry is defined as the official registry
And the lockfile-lint config allows the "npm" registry
And the lockfile-lint config allows the scoped registries

Scenario: no npmrc exists
Scenario: no npmrc or lockfile-lint config exists
Given an "npm" lockfile exists
And lockfile-lint is not configured
And husky v5 is installed
When the scaffolder results are processed
Then registry is defined as the official registry
And the lockfile-lint config allows the "npm" registry
3 changes: 3 additions & 0 deletions test/integration/features/lift/scripts.feature
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Feature: Scripts
Given no additional scripts are included in the results
And an "npm" lockfile exists
And husky is not installed
And lockfile-lint is configured
When the scaffolder results are processed
Then the existing scripts still exist
And no extra scripts were added
Expand All @@ -12,6 +13,7 @@ Feature: Scripts
Given additional scripts are included in the results
And an "npm" lockfile exists
And husky is not installed
And lockfile-lint is configured
When the scaffolder results are processed
Then the existing scripts still exist
And the additional scripts exist
Expand All @@ -20,6 +22,7 @@ Feature: Scripts
Given additional scripts that duplicate existing scripts are included in the results
And an "npm" lockfile exists
And husky is not installed
And lockfile-lint is configured
When the scaffolder results are processed
Then the additional scripts exist

Expand Down
59 changes: 54 additions & 5 deletions test/integration/features/step_definitions/registries-steps.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import {promises as fs} from 'fs';
import {parse} from 'ini';
import {fileTypes} from '@form8ion/core';
import {write} from '@form8ion/config-file';

import {Given, Then} from '@cucumber/cucumber';
import any from '@travi/any';
import {assert} from 'chai';

import {read as readNpmConfig} from '../../../../src/npm-config/index.js';

Given('registries are defined for scopes', async function () {
this.registries = any.objectWithKeys(any.listOf(any.word), {factory: any.url});
});
Expand All @@ -20,12 +24,27 @@ Given('the npmrc does not define registry', async function () {
await fs.writeFile(`${this.projectRoot}/.npmrc`, '');
});

Given('lockfile-lint is configured', async function () {
await write({
name: 'lockfile-lint',
format: fileTypes.JSON,
path: this.projectRoot,
config: {
...any.simpleObject(),
'allowed-hosts': any.listOf(any.url)
}
});
});

Given('lockfile-lint is not configured', async function () {
return undefined;
});

Then('the registry configuration is defined', async function () {
const [npmConfigIni, lockfileLintJson] = await Promise.all([
fs.readFile(`${this.projectRoot}/.npmrc`, 'utf-8'),
const [npmConfig, lockfileLintJson] = await Promise.all([
readNpmConfig({projectRoot: this.projectRoot}),
fs.readFile(`${this.projectRoot}/.lockfile-lintrc.json`, 'utf-8')
]);
const npmConfig = parse(npmConfigIni);
const lockfileLintConfig = JSON.parse(lockfileLintJson);

Object.entries(this.registries).forEach(([scope, url]) => {
Expand All @@ -51,7 +70,37 @@ Then('the publish registry is defined', async function () {
});

Then('registry is defined as the official registry', async function () {
const npmConfig = parse(await fs.readFile(`${this.projectRoot}/.npmrc`, 'utf-8'));
const npmConfig = await readNpmConfig({projectRoot: this.projectRoot});

assert.equal(npmConfig.registry, 'https://registry.npmjs.org');
});

Then('registry is defined as an alternate registry', async function () {
const npmConfig = await readNpmConfig({projectRoot: this.projectRoot});

assert.equal(npmConfig.registry, this.registries.registry);
});

Then('the lockfile-lint config allows the {string} registry', async function (packageManager) {
const {
'allowed-hosts': allowedHosts
} = JSON.parse(await fs.readFile(`${this.projectRoot}/.lockfile-lintrc.json`, 'utf-8'));

assert.include(allowedHosts, packageManager);
});

Then('the lockfile-lint config allows the custom registry', async function () {
const {
'allowed-hosts': allowedHosts
} = JSON.parse(await fs.readFile(`${this.projectRoot}/.lockfile-lintrc.json`, 'utf-8'));

assert.include(allowedHosts, this.registries.registry);
});

Then('the lockfile-lint config allows the scoped registries', async function () {
const {
'allowed-hosts': allowedHosts
} = JSON.parse(await fs.readFile(`${this.projectRoot}/.lockfile-lintrc.json`, 'utf-8'));

Object.values(this.registries).forEach(registry => assert.include(allowedHosts, registry));
});

0 comments on commit 40cfa76

Please sign in to comment.