Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(dashboard): show deprecated dependency warnings #29694

Merged
merged 11 commits into from
Jun 17, 2024
13 changes: 13 additions & 0 deletions docs/usage/key-concepts/dashboard.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,19 @@ To disable the Dependency Dashboard, add the preset `:disableDependencyDashboard

This section explains some common use cases where having the Dependency Dashboard can help.

### Warnings for deprecated dependencies

If deprecated packages are found - or any packages have community-sourced replacement PRs available - then Renovate will add a prominent warning about these packages near the top of the Dependency Dashboard.
rarkins marked this conversation as resolved.
Show resolved Hide resolved
Here is an example of how this can look:

> [!WARNING]
rarkins marked this conversation as resolved.
Show resolved Hide resolved
> The following dependencies are deprecated:

| Datasource | Name | Replacement? |
| ---------- | ------------------- | --------------------------------------------------------------------------------- |
| npm | `airbnb-prop-types` | ![Available](https://img.shields.io/badge/available-green?style=flat-square) |
rarkins marked this conversation as resolved.
Show resolved Hide resolved
| npm | `left-pad` | ![Unavailable](https://img.shields.io/badge/unavailable-orange?style=flat-square) |
rarkins marked this conversation as resolved.
Show resolved Hide resolved
rarkins marked this conversation as resolved.
Show resolved Hide resolved

### Visibility into rejected/deferred updates

Renovate's Dependency Dashboard shows an overview of all updates that are still "to do".
Expand Down
32 changes: 32 additions & 0 deletions lib/workers/repository/dependency-dashboard.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
GitHubMaxPrBodyLen,
massageMarkdown,
} from '../../modules/platform/github';
import { clone } from '../../util/clone';
import { regEx } from '../../util/regex';
import type { BranchConfig, BranchUpgradeConfig } from '../types';
import * as dependencyDashboard from './dependency-dashboard';
Expand Down Expand Up @@ -981,6 +982,37 @@ None detected
// same with dry run
await dryRun(branches, platform, 0, 1);
});

it('shows deprecations', async () => {
const branches: BranchConfig[] = [];
const packageFilesWithDeprecations = clone(packageFiles);
packageFilesWithDeprecations.npm[0].deps[0].deprecationMessage =
'some deprecation message';
packageFilesWithDeprecations.npm[0].deps[2].updates.push({
updateType: 'replacement',
newName: 'prop-types-tools',
newValue: '2.17.0',
branchName: 'renovate/airbnb-prop-types-replacement',
});
PackageFiles.add('main', packageFilesWithDeprecations);
await dependencyDashboard.ensureDependencyDashboard(
config,
branches,
packageFilesWithDeprecations,
);
expect(platform.ensureIssue).toHaveBeenCalledTimes(1);
expect(platform.ensureIssue.mock.calls[0][0].body).toInclude(
'The following dependencies are deprecated',
);
expect(platform.ensureIssue.mock.calls[0][0].body).toInclude(
'| npm | `cookie-parser` | ![Unavailable]',
);
expect(platform.ensureIssue.mock.calls[0][0].body).toInclude(
'npm | `express-handlebars` | ![Available]',
);
// same with dry run
await dryRun(branches, platform, 0, 1);
});
});

describe('multi base branch repo', () => {
Expand Down
42 changes: 41 additions & 1 deletion lib/workers/repository/dependency-dashboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,8 +224,29 @@ export async function ensureDependencyDashboard(
return;
}
logger.debug('Ensuring Dependency Dashboard');

// Check packageFiles for any deprecations
let hasDeprecations = false;
const deprecatedPackages: Record<string, Record<string, boolean>> = {};
logger.debug({ packageFiles }, 'Checking packageFiles for deprecations');
rarkins marked this conversation as resolved.
Show resolved Hide resolved
for (const [manager, fileNames] of Object.entries(packageFiles)) {
for (const fileName of fileNames) {
for (const dep of fileName.deps) {
const name = dep.packageName ?? dep.depName;
const hasReplacement = !!dep.updates?.find(
(updates) => updates.updateType === 'replacement',
);
if (name && (dep.deprecationMessage ?? hasReplacement)) {
hasDeprecations = true;
deprecatedPackages[manager] ??= {};
deprecatedPackages[manager][name] ??= hasReplacement;
}
}
}
}
rarkins marked this conversation as resolved.
Show resolved Hide resolved

const hasBranches = is.nonEmptyArray(branches);
if (config.dependencyDashboardAutoclose && !hasBranches) {
if (config.dependencyDashboardAutoclose && !hasBranches && !hasDeprecations) {
if (GlobalConfig.get('dryRun')) {
logger.info(
{ title: config.dependencyDashboardTitle },
Expand All @@ -245,6 +266,25 @@ export async function ensureDependencyDashboard(

issueBody = appendRepoProblems(config, issueBody);

if (hasDeprecations) {
issueBody += '> ⚠ **Warning**\n> \n';
issueBody += 'The following dependencies are deprecated:\n\n';
rarkins marked this conversation as resolved.
Show resolved Hide resolved
issueBody += '| Datasource | Name | Replacement? |\n';
rarkins marked this conversation as resolved.
Show resolved Hide resolved
issueBody += '|------------|------|--------------|\n';
for (const manager of Object.keys(deprecatedPackages).sort()) {
const deps = deprecatedPackages[manager];
for (const depName of Object.keys(deps).sort()) {
const hasReplacement = deps[depName];
issueBody += `| ${manager} | \`${depName}\` | ${
hasReplacement
? '![Available](https://img.shields.io/badge/available-green?style=flat-square)'
: '![Unavailable](https://img.shields.io/badge/unavailable-orange?style=flat-square)'
viceice marked this conversation as resolved.
Show resolved Hide resolved
} |\n`;
}
}
issueBody += '\n';
}

const pendingApprovals = branches.filter(
(branch) => branch.result === 'needs-approval',
);
Expand Down