Skip to content

Commit

Permalink
feat/24458-bun-init
Browse files Browse the repository at this point in the history
  • Loading branch information
rarkins committed Sep 17, 2023
1 parent a71371e commit f7cf554
Show file tree
Hide file tree
Showing 9 changed files with 212 additions and 2 deletions.
2 changes: 2 additions & 0 deletions lib/modules/manager/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import * as bazelisk from './bazelisk';
import * as bicep from './bicep';
import * as bitbucketPipelines from './bitbucket-pipelines';
import * as buildkite from './buildkite';
import * as bun from './bun';
import * as bundler from './bundler';
import * as cake from './cake';
import * as cargo from './cargo';
Expand Down Expand Up @@ -101,6 +102,7 @@ api.set('bazelisk', bazelisk);
api.set('bicep', bicep);
api.set('bitbucket-pipelines', bitbucketPipelines);
api.set('buildkite', buildkite);
api.set('bun', bun);
api.set('bundler', bundler);
api.set('cake', cake);
api.set('cargo', cargo);
Expand Down
84 changes: 84 additions & 0 deletions lib/modules/manager/bun/artifacts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import is from '@sindresorhus/is';
import { TEMPORARY_ERROR } from '../../../constants/error-messages';
import { logger } from '../../../logger';
import { exec } from '../../../util/exec';
import type { ExecOptions } from '../../../util/exec/types';
import {
deleteLocalFile,
readLocalFile,
writeLocalFile,
} from '../../../util/fs';
import type { UpdateArtifact, UpdateArtifactsResult } from '../types';

export async function updateArtifacts(
updateArtifact: UpdateArtifact
): Promise<UpdateArtifactsResult[] | null> {
const { packageFileName, updatedDeps, newPackageFileContent, config } =
updateArtifact;
logger.debug({ updateArtifact }, `bun.updateArtifacts(${packageFileName})`);
const isLockFileMaintenance = config.updateType === 'lockFileMaintenance';

if (is.emptyArray(updatedDeps) && !isLockFileMaintenance) {
logger.debug('No updated bun deps - returning null');
return null;
}

const lockFileName = config.lockFiles?.[0];

if (!lockFileName) {
logger.debug(`No ${lockFileName} found`);
return null;
}

const oldLockFileContent = await readLocalFile(lockFileName, 'utf8');
if (!oldLockFileContent) {
logger.debug(`No ${lockFileName} found`);
return null;
}

try {
await writeLocalFile(packageFileName, newPackageFileContent);
if (config.isLockFileMaintenance) {
await deleteLocalFile(lockFileName);
}

const execOptions: ExecOptions = {
cwdFile: packageFileName,
docker: {},
toolConstraints: [
{
toolName: 'bun',
},
],
};

await exec('bun install', execOptions);
const newLockFileContent = await readLocalFile(lockFileName, 'utf8');
if (oldLockFileContent === newLockFileContent) {
return null;
}
return [
{
file: {
type: 'addition',
path: lockFileName,
contents: newLockFileContent,
},
},
];
} catch (err) {
// istanbul ignore if
if (err.message === TEMPORARY_ERROR) {
throw err;
}
logger.warn({ lockfile: lockFileName, err }, `Failed to update lock file`);
return [
{
artifactError: {
lockFile: lockFileName,
stderr: err.message,
},
},
];
}
}
57 changes: 57 additions & 0 deletions lib/modules/manager/bun/extract/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { logger } from '../../../../logger';
import { getSiblingFileName, readLocalFile } from '../../../../util/fs';

import { extractPackageJson } from '../../npm/extract/common/package-file';
import type { NpmPackage } from '../../npm/extract/types';
import type { NpmManagerData } from '../../npm/types';
import type { ExtractConfig, PackageFile } from '../../types';

function safeParseJson(json: string): any {
try {
return JSON.parse(json);
} catch (err) {
logger.debug({ err }, 'Error parsing JSON');
return null;
}
}

function matchesName(fileName: string, name: string): boolean {
return fileName === name || fileName.endsWith(`/${name}`);
}

export async function extractAllPackageFiles(
config: ExtractConfig,
matchedFiles: string[]
): Promise<PackageFile[]> {
const packageFiles: PackageFile<NpmManagerData>[] = [];
for (const matchedFile of matchedFiles) {
if (!matchesName(matchedFile, 'bun.lockb')) {
logger.warn({ matchedFile }, 'Invalid bun lockfile match');
continue;
}
const packageFile = getSiblingFileName(matchedFile, 'package.json');
const packageFileContent = await readLocalFile(packageFile, 'utf8');
if (!packageFileContent) {
logger.debug({ packageFileName: packageFile }, 'No package.json found');
continue;
}
const packageJson: NpmPackage = safeParseJson(packageFileContent);
if (!packageJson) {
logger.debug({ packageFileName: packageFile }, 'Invalid package.json');
continue;
}

const extracted = extractPackageJson(packageJson, packageFile);
if (!extracted) {
logger.debug({ packageFileName: packageFile }, 'No dependencies found');
continue;
}
packageFiles.push({
...extracted,
packageFile,
lockFiles: [matchedFile],
});
}

return packageFiles;
}
Empty file.
30 changes: 30 additions & 0 deletions lib/modules/manager/bun/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import type { Category } from '../../../constants';
import { GithubTagsDatasource } from '../../datasource/github-tags';
import { NpmDatasource } from '../../datasource/npm';
import * as npmVersioning from '../../versioning/npm';

export { updateArtifacts } from './artifacts';
export { extractAllPackageFiles } from './extract';
export { getRangeStrategy, updateDependency } from '../npm';

export const supercedesManagers = ['npm'];
export const supportsLockFileMaintenance = true;

export const defaultConfig = {
fileMatch: ['(^|/)bun\\.lockb$'],
versioning: npmVersioning.id,
digest: {
prBodyDefinitions: {
Change:
'{{#if displayFrom}}`{{{displayFrom}}}` -> {{else}}{{#if currentValue}}`{{{currentValue}}}` -> {{/if}}{{/if}}{{#if displayTo}}`{{{displayTo}}}`{{else}}`{{{newValue}}}`{{/if}}',
},
},
prBodyDefinitions: {
Change:
"[{{#if displayFrom}}`{{{displayFrom}}}` -> {{else}}{{#if currentValue}}`{{{currentValue}}}` -> {{/if}}{{/if}}{{#if displayTo}}`{{{displayTo}}}`{{else}}`{{{newValue}}}`{{/if}}]({{#if depName}}https://renovatebot.com/diffs/npm/{{replace '/' '%2f' depName}}/{{{currentVersion}}}/{{{newVersion}}}{{/if}})",
},
};

export const categories: Category[] = ['js'];

export const supportedDatasources = [GithubTagsDatasource.id, NpmDatasource.id];
5 changes: 5 additions & 0 deletions lib/modules/manager/bun/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Used for updating bun projects.
Bun is a tool for JavaScript projects and therefore an alternative to managers like npm, pnpm and Yarn.

If a `package.json` is found to be part of `bun` manager results then the same file will be excluded from the `npm` manager results so that it's not duplicated.
This means that supporting a `bun.lockb` file in addition to other JS lock files is not supported - Bun will take priority.
3 changes: 2 additions & 1 deletion lib/modules/manager/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export interface UpdateArtifactsConfig {
newVersion?: string;
newMajor?: number;
registryAliases?: Record<string, string>;
lockFiles?: string[];
}

export interface RangeConfig<T = Record<string, any>> extends ManagerData<T> {
Expand Down Expand Up @@ -226,7 +227,7 @@ export interface ManagerApi extends ModuleApi {

categories?: Category[];
supportsLockFileMaintenance?: boolean;

supercedesManagers?: string[];
supportedDatasources: string[];

bumpPackageVersion?(
Expand Down
6 changes: 6 additions & 0 deletions lib/util/exec/containerbase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ import { id as semverCoercedVersioningId } from '../../modules/versioning/semver
import type { Opt, ToolConfig, ToolConstraint } from './types';

const allToolConfig: Record<string, ToolConfig> = {
bun: {
datasource: 'github-releases',
packageName: 'oven-sh/bun',
extractVersion: '^bun-v(?<version>.*)$',
versioning: npmVersioningId,
},
bundler: {
datasource: 'rubygems',
packageName: 'bundler',
Expand Down
27 changes: 26 additions & 1 deletion lib/workers/repository/extract/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import is from '@sindresorhus/is';
import { getManagerConfig, mergeChildConfig } from '../../../config';
import type { ManagerConfig, RenovateConfig } from '../../../config/types';
import { logger } from '../../../logger';
import { allManagersList, hashMap } from '../../../modules/manager';
import { allManagersList, get, hashMap } from '../../../modules/manager';
import { isCustomManager } from '../../../modules/manager/custom';
import { scm } from '../../../modules/platform/scm';
import type { ExtractResult, WorkerExtractConfig } from '../../types';
Expand Down Expand Up @@ -66,6 +66,31 @@ export async function extractAllDependencies(
return { manager: managerConfig.manager, packageFiles };
})
);
for (const { manager, packageFiles } of extractResults) {
if (!packageFiles) {
continue;
}
const supercedesManagers = get(manager, 'supercedesManagers');
if (is.nonEmptyArray(supercedesManagers)) {
const supercedingPackageFileNames = packageFiles.map(
(packageFile) => packageFile.packageFile
);
for (const supercededManager of supercedesManagers) {
const supercededManagerResults = extractResults.find(
(result) => result.manager === supercededManager
);
if (supercededManagerResults?.packageFiles) {
supercededManagerResults.packageFiles =
supercededManagerResults.packageFiles.filter(({ packageFile }) => {
!supercedingPackageFileNames.includes(packageFile);
});
if (!supercededManagerResults.packageFiles.length) {
supercededManagerResults.packageFiles = null;
}
}
}
}
}
logger.debug(
{ managers: extractDurations },
'manager extract durations (ms)'
Expand Down

0 comments on commit f7cf554

Please sign in to comment.