Skip to content

Commit

Permalink
feat: support resolutions
Browse files Browse the repository at this point in the history
  • Loading branch information
iowillhoit committed Jul 28, 2022
1 parent d30032c commit f6902d8
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 26 deletions.
10 changes: 8 additions & 2 deletions src/commands/cli/latestrc/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { ensureString } from '@salesforce/ts-types';
import { Env } from '@salesforce/kit';
import { Octokit } from '@octokit/core';
import { bold } from 'chalk';
import { Messages } from '@salesforce/core';
import { Messages, SfdxError } from '@salesforce/core';
import { SinglePackageRepo } from '../../../repository';

Messages.importMessagesDirectory(__dirname);
Expand Down Expand Up @@ -82,7 +82,13 @@ export default class build extends SfdxCommand {

if (only) {
this.ux.log(`bumping the following dependencies only: ${only.join(', ')}`);
repo.package.bumpDependencyVersions(only);
const bumped = repo.package.bumpDependencyVersions(only);

if (!bumped.length) {
throw new SfdxError(
'No version changes made. Confirm you are passing the correct dependency and version to --only.'
);
}
} else {
// bump resolution deps
if (this.flags.resolutions) {
Expand Down
52 changes: 32 additions & 20 deletions src/package.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,9 +180,8 @@ export class Package extends AsyncOptionalCreatable {

// Lookup dependency info by package name or npm alias
// Examples: @salesforce/plugin-info or @sf/info
public getDependencyInfo(name: string): DependencyInfo {
const { dependencies } = this.packageJson;

// Pass in the dependencies you want to search through (dependencies, devDependencies, resolutions, etc)
public getDependencyInfo(name: string, dependencies: Record<string, string>): DependencyInfo {
for (const [key, value] of Object.entries(dependencies)) {
if (key === name) {
if (value.startsWith('npm:')) {
Expand Down Expand Up @@ -217,28 +216,41 @@ export class Package extends AsyncOptionalCreatable {
cli.error(`${name} was not found in the dependencies section of the package.json`);
}

public bumpDependencyVersions(dependencies: string[]): DependencyInfo[] {
return dependencies.map((dep) => {
// regex for npm package with optional namespace and version
// https://regex101.com/r/HmIu3N/1
const npmPackageRegex = /^((?:@[^/]+\/)?[^@/]+)(?:@([^@/]+))?$/;
const [, name, version] = npmPackageRegex.exec(dep);
public bumpDependencyVersions(targetDependencies: string[]): DependencyInfo[] {
return targetDependencies
.map((dep) => {
// regex for npm package with optional namespace and version
// https://regex101.com/r/HmIu3N/1
const npmPackageRegex = /^((?:@[^/]+\/)?[^@/]+)(?:@([^@/]+))?$/;
const [, name, version] = npmPackageRegex.exec(dep);

// find dependency in package.json (could be an npm alias)
const depInfo = this.getDependencyInfo(name);
// We will look for packages in dependencies and resolutions
const { dependencies, resolutions } = this.packageJson;

// If a version is not provided, we'll look up the "latest" version
depInfo.finalVersion = version ?? this.getDistTags(depInfo.packageName).latest;
// find dependency in package.json (could be an npm alias)
const depInfo = this.getDependencyInfo(name, { ...dependencies, ...resolutions });

// override final version if npm alias is used
if (depInfo.alias) {
depInfo.finalVersion = `npm:${depInfo.packageName}@${depInfo.finalVersion}`;
}
// if a version is not provided, we'll look up the "latest" version
depInfo.finalVersion = version ?? this.getDistTags(depInfo.packageName).latest;

this.packageJson.dependencies[depInfo.dependencyName] = depInfo.finalVersion;
// return if version did not change
if (depInfo.currentVersion === depInfo.finalVersion) return;

return depInfo;
});
// override final version if npm alias is used
if (depInfo.alias) {
depInfo.finalVersion = `npm:${depInfo.packageName}@${depInfo.finalVersion}`;
}

// update dependency (or resolution) in package.json
if (dependencies[depInfo.dependencyName]) {
this.packageJson.dependencies[depInfo.dependencyName] = depInfo.finalVersion;
} else {
this.packageJson.resolutions[depInfo.dependencyName] = depInfo.finalVersion;
}

return depInfo;
})
.filter(Boolean); // remove falsy values, in this case the `undefined` if version did not change
}

public getNextRCVersion(tag: string, isPatch = false): string {
Expand Down
28 changes: 24 additions & 4 deletions test/package.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,8 @@ describe('Package', () => {

it('should find dependency using an npm alias', async () => {
const pkg = await Package.create();
const dependency = pkg.getDependencyInfo('@sf/info');
const deps = pkg.packageJson.dependencies;
const dependency = pkg.getDependencyInfo('@sf/info', deps);

expect(dependency).to.deep.equal({
dependencyName: '@sf/info',
Expand All @@ -179,7 +180,8 @@ describe('Package', () => {

it('should find an npm alias with a package name', async () => {
const pkg = await Package.create();
const dependency = pkg.getDependencyInfo('@salesforce/plugin-info');
const deps = pkg.packageJson.dependencies;
const dependency = pkg.getDependencyInfo('@salesforce/plugin-info', deps);

expect(dependency).to.deep.equal({
dependencyName: '@sf/info',
Expand All @@ -191,7 +193,8 @@ describe('Package', () => {

it('should find a dependency using a package name', async () => {
const pkg = await Package.create();
const dependency = pkg.getDependencyInfo('@salesforce/plugin-config');
const deps = pkg.packageJson.dependencies;
const dependency = pkg.getDependencyInfo('@salesforce/plugin-config', deps);

expect(dependency).to.deep.equal({
dependencyName: '@salesforce/plugin-config',
Expand All @@ -213,6 +216,9 @@ describe('Package', () => {
'@salesforce/plugin-config': '1.2.3',
'left-pad': '1.1.1',
},
resolutions: {
'@salesforce/source-deploy-retrieve': '1.0.0',
},
})
);
stubMethod($$.SANDBOX, Package.prototype, 'getDistTags').returns({
Expand Down Expand Up @@ -272,12 +278,26 @@ describe('Package', () => {
]);
});

it('should update package.json', async () => {
it('should return an empty array if all versions are already up to date', async () => {
const pkg = await Package.create();
const results = pkg.bumpDependencyVersions(['@sf/info@2.0.1', '@salesforce/plugin-config@1.2.3']);

expect(results).to.deep.equal([]);
});

it('should update dependencies in package.json', async () => {
const pkg = await Package.create();
pkg.bumpDependencyVersions(['@sf/info@2.2.2', '@salesforce/plugin-config@3.3.3']);

expect(pkg.packageJson.dependencies['@sf/info']).to.equal('npm:@salesforce/plugin-info@2.2.2');
expect(pkg.packageJson.dependencies['@salesforce/plugin-config']).to.equal('3.3.3');
});

it('should update resolutions in package.json', async () => {
const pkg = await Package.create();
pkg.bumpDependencyVersions(['@salesforce/source-deploy-retrieve@1.0.1']);

expect(pkg.packageJson.resolutions['@salesforce/source-deploy-retrieve']).to.equal('1.0.1');
});
});
});

0 comments on commit f6902d8

Please sign in to comment.