From 224d5e771701d111785bb892d8824275c6fe18e0 Mon Sep 17 00:00:00 2001
From: Gabriel-Ladzaretti
 <97394622+Gabriel-Ladzaretti@users.noreply.github.com>
Date: Mon, 16 May 2022 13:20:31 +0300
Subject: [PATCH] feat(core/dashboard): include list of detected package files
 (#15418)

---
 .../master-issue_with_2_PR_closed_ignored.txt |   5 +
 .../master-issue_with_2_PR_edited.txt         |   5 +
 .../master-issue_with_3_PR_in_approval.txt    |   5 +
 .../master-issue_with_3_PR_in_progress.txt    |   5 +
 .../__fixtures__/master-issue_with_8_PR.txt   |   5 +
 .../__fixtures__/package-files.json           | 275 +++++++++++++++++
 .../dependency-dashboard.spec.ts.snap         | 278 ++++++++++++++++++
 .../repository/dependency-dashboard.spec.ts   | 115 +++++++-
 .../repository/dependency-dashboard.ts        |   3 +
 lib/workers/repository/finalise/index.ts      |   2 +
 lib/workers/repository/package-files.ts       |  66 +++++
 lib/workers/repository/process/fetch.ts       |   2 +
 12 files changed, 758 insertions(+), 8 deletions(-)
 create mode 100644 lib/workers/repository/__fixtures__/package-files.json
 create mode 100644 lib/workers/repository/package-files.ts

diff --git a/lib/workers/repository/__fixtures__/master-issue_with_2_PR_closed_ignored.txt b/lib/workers/repository/__fixtures__/master-issue_with_2_PR_closed_ignored.txt
index fae1e9ad07..fcf12bce59 100644
--- a/lib/workers/repository/__fixtures__/master-issue_with_2_PR_closed_ignored.txt
+++ b/lib/workers/repository/__fixtures__/master-issue_with_2_PR_closed_ignored.txt
@@ -7,3 +7,8 @@ These are blocked by an existing closed PR and will not be recreated unless you
  - [ ] <!-- recreate-branch=branchName1 -->pr1
  - [ ] <!-- recreate-branch=branchName2 -->pr2 (`dep2`, `dep3`)
 
+## Detected dependencies
+
+None detected
+
+
diff --git a/lib/workers/repository/__fixtures__/master-issue_with_2_PR_edited.txt b/lib/workers/repository/__fixtures__/master-issue_with_2_PR_edited.txt
index 793b2717ad..c1dd60e3ff 100644
--- a/lib/workers/repository/__fixtures__/master-issue_with_2_PR_edited.txt
+++ b/lib/workers/repository/__fixtures__/master-issue_with_2_PR_edited.txt
@@ -7,3 +7,8 @@ These updates have been manually edited so Renovate will no longer make changes.
  - [ ] <!-- rebase-branch=branchName1 -->[pr1](../pull/1)
  - [ ] <!-- rebase-branch=branchName2 -->[pr2](../pull/2) (`dep2`, `dep3`)
 
+## Detected dependencies
+
+None detected
+
+
diff --git a/lib/workers/repository/__fixtures__/master-issue_with_3_PR_in_approval.txt b/lib/workers/repository/__fixtures__/master-issue_with_3_PR_in_approval.txt
index 10a26e9b56..3c6275a9c6 100644
--- a/lib/workers/repository/__fixtures__/master-issue_with_3_PR_in_approval.txt
+++ b/lib/workers/repository/__fixtures__/master-issue_with_3_PR_in_approval.txt
@@ -14,3 +14,8 @@ These updates await pending status checks. To force their creation now, click th
 
  - [ ] <!-- approvePr-branch=branchName4 -->pr4
 
+## Detected dependencies
+
+None detected
+
+
diff --git a/lib/workers/repository/__fixtures__/master-issue_with_3_PR_in_progress.txt b/lib/workers/repository/__fixtures__/master-issue_with_3_PR_in_progress.txt
index cb6da6175d..e403823a1e 100644
--- a/lib/workers/repository/__fixtures__/master-issue_with_3_PR_in_progress.txt
+++ b/lib/workers/repository/__fixtures__/master-issue_with_3_PR_in_progress.txt
@@ -9,3 +9,8 @@ These updates have all been created already. Click a checkbox below to force a r
  - [ ] <!-- rebase-branch=branchName3 -->[pr3](../pull/3)
  - [ ] <!-- rebase-all-open-prs -->**Click on this checkbox to rebase all open PRs at once**
 
+## Detected dependencies
+
+None detected
+
+
diff --git a/lib/workers/repository/__fixtures__/master-issue_with_8_PR.txt b/lib/workers/repository/__fixtures__/master-issue_with_8_PR.txt
index b8803a5575..c34516c0d3 100644
--- a/lib/workers/repository/__fixtures__/master-issue_with_8_PR.txt
+++ b/lib/workers/repository/__fixtures__/master-issue_with_8_PR.txt
@@ -34,3 +34,8 @@ These updates await pending status checks before automerging. Click on a checkbo
 
  - [ ] <!-- approvePr-branch=branchName9 -->pr9
 
+## Detected dependencies
+
+None detected
+
+
diff --git a/lib/workers/repository/__fixtures__/package-files.json b/lib/workers/repository/__fixtures__/package-files.json
new file mode 100644
index 0000000000..ae932d13fc
--- /dev/null
+++ b/lib/workers/repository/__fixtures__/package-files.json
@@ -0,0 +1,275 @@
+{
+  "dockerfile": [
+    {
+      "packageFile": "Dockerfile",
+      "deps": [
+        {
+          "depName": "ubuntu",
+          "currentValue": "20.04",
+          "replaceString": "ubuntu:20.04",
+          "autoReplaceStringTemplate": "{{depName}}{{#if newValue}}:{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}",
+          "datasource": "docker",
+          "versioning": "ubuntu",
+          "depType": "final",
+          "depIndex": 0,
+          "updates": [
+            {
+              "bucket": "major",
+              "newVersion": "jammy",
+              "newValue": "22.04",
+              "newMajor": 22,
+              "newMinor": 4,
+              "updateType": "major",
+              "branchName": "renovate/ubuntu-22.x"
+            }
+          ],
+          "warnings": [],
+          "currentVersion": "20.04",
+          "isSingleVersion": true,
+          "fixedVersion": "20.04"
+        }
+      ]
+    }
+  ],
+  "npm": [
+    {
+      "packageFile": "package.json",
+      "deps": [
+        {
+          "depType": "dependencies",
+          "depName": "cookie-parser",
+          "currentValue": "^1.4.5",
+          "datasource": "npm",
+          "prettyDepType": "dependency",
+          "depIndex": 0,
+          "updates": [],
+          "warnings": [],
+          "versioning": "npm",
+          "sourceUrl": "https://github.com/expressjs/cookie-parser",
+          "currentVersion": "1.4.6"
+        },
+        {
+          "depType": "dependencies",
+          "depName": "express",
+          "currentValue": "~4.17.1",
+          "datasource": "npm",
+          "prettyDepType": "dependency",
+          "depIndex": 1,
+          "updates": [
+            {
+              "bucket": "non-major",
+              "newVersion": "4.18.1",
+              "newValue": "~4.18.0",
+              "releaseTimestamp": "2022-04-29T19:33:40.441Z",
+              "newMajor": 4,
+              "newMinor": 18,
+              "updateType": "minor",
+              "isRange": true,
+              "branchName": "renovate/express-4.x"
+            }
+          ],
+          "warnings": [],
+          "versioning": "npm",
+          "sourceUrl": "https://github.com/expressjs/express",
+          "homepage": "http://expressjs.com/",
+          "currentVersion": "4.17.3",
+          "isSingleVersion": false
+        },
+        {
+          "depType": "dependencies",
+          "depName": "express-handlebars",
+          "currentValue": ">=5.3.4",
+          "datasource": "npm",
+          "prettyDepType": "dependency",
+          "depIndex": 2,
+          "updates": [],
+          "warnings": [],
+          "versioning": "npm",
+          "sourceUrl": "https://github.com/express-handlebars/express-handlebars",
+          "currentVersion": "6.0.5"
+        },
+        {
+          "depType": "dependencies",
+          "depName": "geoip-lite",
+          "currentValue": "1.4.*",
+          "datasource": "npm",
+          "prettyDepType": "dependency",
+          "depIndex": 3,
+          "updates": [],
+          "warnings": [],
+          "versioning": "npm",
+          "sourceUrl": "https://github.com/geoip-lite/node-geoip",
+          "currentVersion": "1.4.5"
+        },
+        {
+          "depType": "dependencies",
+          "depName": "nodemailer",
+          "currentValue": "6.7.0",
+          "datasource": "npm",
+          "prettyDepType": "dependency",
+          "depIndex": 4,
+          "updates": [
+            {
+              "bucket": "non-major",
+              "newVersion": "6.7.4",
+              "newValue": "6.7.4",
+              "releaseTimestamp": "2022-04-28T21:51:54.336Z",
+              "newMajor": 6,
+              "newMinor": 7,
+              "updateType": "patch",
+              "branchName": "renovate/nodemailer-6.x"
+            }
+          ],
+          "warnings": [],
+          "versioning": "npm",
+          "sourceUrl": "https://github.com/nodemailer/nodemailer",
+          "homepage": "https://nodemailer.com/",
+          "currentVersion": "6.7.0",
+          "isSingleVersion": true,
+          "fixedVersion": "6.7.0"
+        },
+        {
+          "depType": "dependencies",
+          "depName": "redis",
+          "currentValue": "3.1.2-3.4.0",
+          "datasource": "npm",
+          "prettyDepType": "dependency",
+          "depIndex": 5,
+          "updates": [
+            {
+              "bucket": "rollback",
+              "newMajor": 3,
+              "newValue": "3.1.1",
+              "newVersion": "3.1.1",
+              "updateType": "rollback",
+              "branchName": "renovate/redis-rollback"
+            },
+            {
+              "bucket": "non-major",
+              "newVersion": "3.1.2",
+              "newValue": "3.1.2",
+              "releaseTimestamp": "2021-04-20T22:26:05.946Z",
+              "newMajor": 3,
+              "newMinor": 1,
+              "updateType": "patch",
+              "branchName": "renovate/redis-3.x"
+            },
+            {
+              "bucket": "major",
+              "newVersion": "4.1.0",
+              "newValue": "4.1.0",
+              "releaseTimestamp": "2022-05-02T16:04:07.111Z",
+              "newMajor": 4,
+              "newMinor": 1,
+              "updateType": "major",
+              "branchName": "renovate/redis-4.x"
+            }
+          ],
+          "warnings": [],
+          "versioning": "npm",
+          "sourceUrl": "https://github.com/redis/node-redis",
+          "currentVersion": "3.1.2-3.4.0",
+          "isSingleVersion": true,
+          "fixedVersion": "3.1.2-3.4.0"
+        },
+        {
+          "depType": "devDependencies",
+          "depName": "dotenv",
+          "currentValue": "10.0.0",
+          "datasource": "npm",
+          "prettyDepType": "devDependency",
+          "depIndex": 6,
+          "updates": [
+            {
+              "bucket": "major",
+              "newVersion": "16.0.0",
+              "newValue": "16.0.0",
+              "releaseTimestamp": "2022-02-02T21:26:07.108Z",
+              "newMajor": 16,
+              "newMinor": 0,
+              "updateType": "major",
+              "branchName": "renovate/dotenv-16.x"
+            }
+          ],
+          "warnings": [],
+          "versioning": "npm",
+          "sourceUrl": "https://github.com/motdotla/dotenv",
+          "currentVersion": "10.0.0",
+          "isSingleVersion": true,
+          "fixedVersion": "10.0.0"
+        },
+        {
+          "depType": "devDependencies",
+          "depName": "nodemon",
+          "currentValue": "2.0.14",
+          "datasource": "npm",
+          "prettyDepType": "devDependency",
+          "depIndex": 7,
+          "updates": [
+            {
+              "bucket": "non-major",
+              "newVersion": "2.0.16",
+              "newValue": "2.0.16",
+              "releaseTimestamp": "2022-04-29T10:09:23.199Z",
+              "newMajor": 2,
+              "newMinor": 0,
+              "updateType": "patch",
+              "branchName": "renovate/nodemon-2.x"
+            }
+          ],
+          "warnings": [],
+          "versioning": "npm",
+          "sourceUrl": "https://github.com/remy/nodemon",
+          "homepage": "https://nodemon.io",
+          "currentVersion": "2.0.14",
+          "isSingleVersion": true,
+          "fixedVersion": "2.0.14"
+        }
+      ],
+      "packageJsonType": "app",
+      "managerData": {
+        "yarnZeroInstall": false
+      },
+      "skipInstalls": true,
+      "constraints": {}
+    }
+  ],
+  "poetry": [
+    {
+      "packageFile": "pyproject.toml",
+      "deps": [
+        {
+          "depName": "six",
+          "depType": "dependencies",
+          "currentValue": "<=1.3.0",
+          "managerData": {
+            "nestedVersion": false
+          },
+          "datasource": "pypi",
+          "versioning": "pep440",
+          "depIndex": 0,
+          "updates": [
+            {
+              "bucket": "non-major",
+              "newVersion": "1.16.0",
+              "newValue": "<=1.16.0",
+              "releaseTimestamp": "2021-05-05T14:18:17.000Z",
+              "newMajor": 1,
+              "newMinor": 16,
+              "updateType": "minor",
+              "isRange": true,
+              "branchName": "renovate/six-1.x"
+            }
+          ],
+          "warnings": [],
+          "sourceUrl": "https://github.com/benjaminp/six",
+          "currentVersion": "1.3.0",
+          "isSingleVersion": false
+        }
+      ],
+      "constraints": {
+        "python": "^3.10"
+      }
+    }
+  ]
+}
diff --git a/lib/workers/repository/__snapshots__/dependency-dashboard.spec.ts.snap b/lib/workers/repository/__snapshots__/dependency-dashboard.spec.ts.snap
index 94ce71462f..cfd52ab4d7 100644
--- a/lib/workers/repository/__snapshots__/dependency-dashboard.spec.ts.snap
+++ b/lib/workers/repository/__snapshots__/dependency-dashboard.spec.ts.snap
@@ -1,5 +1,263 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
+exports[`workers/repository/dependency-dashboard ensureDependencyDashboard() checks detected dependencies section multi base branch repo add detected dependencies to the Dependency Dashboard body 1`] = `
+"This issue provides visibility into Renovate updates and their statuses. [Learn more](https://docs.renovatebot.com/key-concepts/dashboard/)
+
+This repository currently has no open or pending branches.
+
+## Detected dependencies
+
+<details><summary>Branch main
+</summary>
+
+
+<ul><details><summary>dockerfile</summary>
+
+<ul><details><summary>Dockerfile</summary>
+
+ - \`ubuntu 20.04\`
+
+</details></ul>
+</details></ul>
+<ul><details><summary>npm</summary>
+
+<ul><details><summary>package.json</summary>
+
+ - \`cookie-parser ^1.4.5\`
+ - \`express ~4.17.1\`
+ - \`express-handlebars >=5.3.4\`
+ - \`geoip-lite 1.4.*\`
+ - \`nodemailer 6.7.0\`
+ - \`redis 3.1.2-3.4.0\`
+ - \`dotenv 10.0.0\`
+ - \`nodemon 2.0.14\`
+
+</details></ul>
+</details></ul>
+<ul><details><summary>poetry</summary>
+
+<ul><details><summary>pyproject.toml</summary>
+
+ - \`six <=1.3.0\`
+
+</details></ul>
+</details></ul>
+</details>
+
+<details><summary>Branch dev
+</summary>
+
+
+<ul><details><summary>dockerfile</summary>
+
+<ul><details><summary>Dockerfile</summary>
+
+ - \`ubuntu 20.04\`
+
+</details></ul>
+</details></ul>
+<ul><details><summary>npm</summary>
+
+<ul><details><summary>package.json</summary>
+
+ - \`cookie-parser ^1.4.5\`
+ - \`express ~4.17.1\`
+ - \`express-handlebars >=5.3.4\`
+ - \`geoip-lite 1.4.*\`
+ - \`nodemailer 6.7.0\`
+ - \`redis 3.1.2-3.4.0\`
+ - \`dotenv 10.0.0\`
+ - \`nodemon 2.0.14\`
+
+</details></ul>
+</details></ul>
+<ul><details><summary>poetry</summary>
+
+<ul><details><summary>pyproject.toml</summary>
+
+ - \`six <=1.3.0\`
+
+</details></ul>
+</details></ul>
+</details>
+
+"
+`;
+
+exports[`workers/repository/dependency-dashboard ensureDependencyDashboard() checks detected dependencies section multi base branch repo show default message in issues body when packageFiles is empty 1`] = `
+"This issue provides visibility into Renovate updates and their statuses. [Learn more](https://docs.renovatebot.com/key-concepts/dashboard/)
+
+This repository currently has no open or pending branches.
+
+## Detected dependencies
+
+<details><summary>Branch main
+</summary>
+
+None detected
+
+
+</details>
+
+<details><summary>Branch dev
+</summary>
+
+
+<ul><details><summary>dockerfile</summary>
+
+<ul><details><summary>Dockerfile</summary>
+
+ - \`ubuntu 20.04\`
+
+</details></ul>
+</details></ul>
+<ul><details><summary>npm</summary>
+
+<ul><details><summary>package.json</summary>
+
+ - \`cookie-parser ^1.4.5\`
+ - \`express ~4.17.1\`
+ - \`express-handlebars >=5.3.4\`
+ - \`geoip-lite 1.4.*\`
+ - \`nodemailer 6.7.0\`
+ - \`redis 3.1.2-3.4.0\`
+ - \`dotenv 10.0.0\`
+ - \`nodemon 2.0.14\`
+
+</details></ul>
+</details></ul>
+<ul><details><summary>poetry</summary>
+
+<ul><details><summary>pyproject.toml</summary>
+
+ - \`six <=1.3.0\`
+
+</details></ul>
+</details></ul>
+</details>
+
+"
+`;
+
+exports[`workers/repository/dependency-dashboard ensureDependencyDashboard() checks detected dependencies section multi base branch repo show default message in issues body when when packageFiles is null 1`] = `
+"This issue provides visibility into Renovate updates and their statuses. [Learn more](https://docs.renovatebot.com/key-concepts/dashboard/)
+
+This repository currently has no open or pending branches.
+
+## Detected dependencies
+
+<details><summary>Branch main
+</summary>
+
+None detected
+
+
+</details>
+
+<details><summary>Branch dev
+</summary>
+
+
+<ul><details><summary>dockerfile</summary>
+
+<ul><details><summary>Dockerfile</summary>
+
+ - \`ubuntu 20.04\`
+
+</details></ul>
+</details></ul>
+<ul><details><summary>npm</summary>
+
+<ul><details><summary>package.json</summary>
+
+ - \`cookie-parser ^1.4.5\`
+ - \`express ~4.17.1\`
+ - \`express-handlebars >=5.3.4\`
+ - \`geoip-lite 1.4.*\`
+ - \`nodemailer 6.7.0\`
+ - \`redis 3.1.2-3.4.0\`
+ - \`dotenv 10.0.0\`
+ - \`nodemon 2.0.14\`
+
+</details></ul>
+</details></ul>
+<ul><details><summary>poetry</summary>
+
+<ul><details><summary>pyproject.toml</summary>
+
+ - \`six <=1.3.0\`
+
+</details></ul>
+</details></ul>
+</details>
+
+"
+`;
+
+exports[`workers/repository/dependency-dashboard ensureDependencyDashboard() checks detected dependencies section single base branch repo add detected dependencies to the Dependency Dashboard body 1`] = `
+"This issue provides visibility into Renovate updates and their statuses. [Learn more](https://docs.renovatebot.com/key-concepts/dashboard/)
+
+This repository currently has no open or pending branches.
+
+## Detected dependencies
+
+<details><summary>dockerfile</summary>
+
+<ul><details><summary>Dockerfile</summary>
+
+ - \`ubuntu 20.04\`
+
+</details></ul>
+</details><details><summary>npm</summary>
+
+<ul><details><summary>package.json</summary>
+
+ - \`cookie-parser ^1.4.5\`
+ - \`express ~4.17.1\`
+ - \`express-handlebars >=5.3.4\`
+ - \`geoip-lite 1.4.*\`
+ - \`nodemailer 6.7.0\`
+ - \`redis 3.1.2-3.4.0\`
+ - \`dotenv 10.0.0\`
+ - \`nodemon 2.0.14\`
+
+</details></ul>
+</details><details><summary>poetry</summary>
+
+<ul><details><summary>pyproject.toml</summary>
+
+ - \`six <=1.3.0\`
+
+</details></ul>
+</details>"
+`;
+
+exports[`workers/repository/dependency-dashboard ensureDependencyDashboard() checks detected dependencies section single base branch repo show default message in issues body when packageFiles is empty 1`] = `
+"This issue provides visibility into Renovate updates and their statuses. [Learn more](https://docs.renovatebot.com/key-concepts/dashboard/)
+
+This repository currently has no open or pending branches.
+
+## Detected dependencies
+
+None detected
+
+
+"
+`;
+
+exports[`workers/repository/dependency-dashboard ensureDependencyDashboard() checks detected dependencies section single base branch repo show default message in issues body when when packageFiles is null 1`] = `
+"This issue provides visibility into Renovate updates and their statuses. [Learn more](https://docs.renovatebot.com/key-concepts/dashboard/)
+
+This repository currently has no open or pending branches.
+
+## Detected dependencies
+
+None detected
+
+
+"
+`;
+
 exports[`workers/repository/dependency-dashboard ensureDependencyDashboard() contains logged problems 1`] = `
 "This issue provides visibility into Renovate updates and their statuses. [Learn more](https://docs.renovatebot.com/key-concepts/dashboard/)
 
@@ -19,6 +277,11 @@ These updates await pending status checks. To force their creation now, click th
 
  - [ ] <!-- approvePr-branch=branchName1 -->pr1
 
+## Detected dependencies
+
+None detected
+
+
 "
 `;
 
@@ -27,6 +290,11 @@ exports[`workers/repository/dependency-dashboard ensureDependencyDashboard() ope
 
 This repository currently has no open or pending branches.
 
+## Detected dependencies
+
+None detected
+
+
 ---
 And this is a footer
 "
@@ -37,6 +305,11 @@ exports[`workers/repository/dependency-dashboard ensureDependencyDashboard() ope
 
 This repository currently has no open or pending branches.
 
+## Detected dependencies
+
+None detected
+
+
 ---
 And this is a footer for repository:test
 "
@@ -58,5 +331,10 @@ These updates are awaiting their schedule. Click on a checkbox to get an update
 
  - [x] <!-- unschedule-branch=branchName3 -->pr3
 
+## Detected dependencies
+
+None detected
+
+
 "
 `;
diff --git a/lib/workers/repository/dependency-dashboard.spec.ts b/lib/workers/repository/dependency-dashboard.spec.ts
index 56338e0279..2781334215 100644
--- a/lib/workers/repository/dependency-dashboard.spec.ts
+++ b/lib/workers/repository/dependency-dashboard.spec.ts
@@ -1,9 +1,9 @@
 import { ERROR, WARN } from 'bunyan';
 import { mock } from 'jest-mock-extended';
+import { Fixtures } from '../../../test/fixtures';
 import {
   RenovateConfig,
   getConfig,
-  loadFixture,
   logger,
   platform,
 } from '../../../test/util';
@@ -12,6 +12,7 @@ import { PlatformId } from '../../constants';
 import type { Platform } from '../../modules/platform';
 import { BranchConfig, BranchResult, BranchUpgradeConfig } from '../types';
 import * as dependencyDashboard from './dependency-dashboard';
+import { PackageFiles } from './package-files';
 
 type PrUpgrade = BranchUpgradeConfig;
 
@@ -27,7 +28,6 @@ beforeEach(() => {
 
 async function dryRun(
   branches: BranchConfig[],
-
   platform: jest.Mocked<Platform>,
   ensureIssueClosingCalls = 0,
   ensureIssueCalls = 0
@@ -50,7 +50,7 @@ describe('workers/repository/dependency-dashboard', () => {
         title: '',
         number: 1,
         body:
-          loadFixture('master-issue_with_8_PR.txt').replace('- [ ]', '- [x]') +
+          Fixtures.get('master-issue_with_8_PR.txt').replace('- [ ]', '- [x]') +
           '\n\n - [x] <!-- rebase-all-open-prs -->',
       });
       await dependencyDashboard.readDashboardBody(conf);
@@ -68,6 +68,7 @@ describe('workers/repository/dependency-dashboard', () => {
 
   describe('ensureDependencyDashboard()', () => {
     beforeEach(() => {
+      PackageFiles.add('main', null);
       GlobalConfig.reset();
     });
 
@@ -266,7 +267,7 @@ describe('workers/repository/dependency-dashboard', () => {
         config.dependencyDashboardTitle
       );
       expect(platform.ensureIssue.mock.calls[0][0].body).toBe(
-        loadFixture('master-issue_with_8_PR.txt')
+        Fixtures.get('master-issue_with_8_PR.txt')
       );
 
       // same with dry run
@@ -303,7 +304,7 @@ describe('workers/repository/dependency-dashboard', () => {
         config.dependencyDashboardTitle
       );
       expect(platform.ensureIssue.mock.calls[0][0].body).toBe(
-        loadFixture('master-issue_with_2_PR_edited.txt')
+        Fixtures.get('master-issue_with_2_PR_edited.txt')
       );
 
       // same with dry run
@@ -348,7 +349,7 @@ describe('workers/repository/dependency-dashboard', () => {
         config.dependencyDashboardTitle
       );
       expect(platform.ensureIssue.mock.calls[0][0].body).toBe(
-        loadFixture('master-issue_with_3_PR_in_progress.txt')
+        Fixtures.get('master-issue_with_3_PR_in_progress.txt')
       );
 
       // same with dry run
@@ -383,7 +384,7 @@ describe('workers/repository/dependency-dashboard', () => {
         config.dependencyDashboardTitle
       );
       expect(platform.ensureIssue.mock.calls[0][0].body).toBe(
-        loadFixture('master-issue_with_2_PR_closed_ignored.txt')
+        Fixtures.get('master-issue_with_2_PR_closed_ignored.txt')
       );
 
       // same with dry run
@@ -433,7 +434,7 @@ describe('workers/repository/dependency-dashboard', () => {
         config.dependencyDashboardTitle
       );
       expect(platform.ensureIssue.mock.calls[0][0].body).toBe(
-        loadFixture('master-issue_with_3_PR_in_approval.txt')
+        Fixtures.get('master-issue_with_3_PR_in_approval.txt')
       );
 
       // same with dry run
@@ -554,5 +555,103 @@ describe('workers/repository/dependency-dashboard', () => {
       // same with dry run
       await dryRun(branches, platform);
     });
+
+    describe('checks detected dependencies section', () => {
+      const packageFiles = Fixtures.getJson('./package-files.json');
+      let config: RenovateConfig;
+
+      beforeAll(() => {
+        GlobalConfig.reset();
+        config = getConfig();
+        config.dependencyDashboard = true;
+      });
+
+      describe('single base branch repo', () => {
+        beforeEach(() => {
+          PackageFiles.add('main', packageFiles);
+        });
+
+        afterEach(() => {
+          PackageFiles.clear();
+        });
+
+        it('add detected dependencies to the Dependency Dashboard body', async () => {
+          const branches: BranchConfig[] = [];
+          await dependencyDashboard.ensureDependencyDashboard(config, branches);
+          expect(platform.ensureIssue).toHaveBeenCalledTimes(1);
+          expect(platform.ensureIssue.mock.calls[0][0].body).toMatchSnapshot();
+
+          // same with dry run
+          await dryRun(branches, platform);
+        });
+
+        it('show default message in issues body when packageFiles is empty', async () => {
+          const branches: BranchConfig[] = [];
+          PackageFiles.clear();
+          PackageFiles.add('main', {});
+          await dependencyDashboard.ensureDependencyDashboard(config, branches);
+          expect(platform.ensureIssue).toHaveBeenCalledTimes(1);
+          expect(platform.ensureIssue.mock.calls[0][0].body).toMatchSnapshot();
+
+          // same with dry run
+          await dryRun(branches, platform);
+        });
+
+        it('show default message in issues body when when packageFiles is null', async () => {
+          const branches: BranchConfig[] = [];
+          PackageFiles.clear();
+          PackageFiles.add('main', null);
+          await dependencyDashboard.ensureDependencyDashboard(config, branches);
+          expect(platform.ensureIssue).toHaveBeenCalledTimes(1);
+          expect(platform.ensureIssue.mock.calls[0][0].body).toMatchSnapshot();
+
+          // same with dry run
+          await dryRun(branches, platform);
+        });
+      });
+
+      describe('multi base branch repo', () => {
+        beforeEach(() => {
+          PackageFiles.add('main', packageFiles);
+          PackageFiles.add('dev', packageFiles);
+        });
+
+        afterEach(() => {
+          PackageFiles.clear();
+        });
+
+        it('add detected dependencies to the Dependency Dashboard body', async () => {
+          const branches: BranchConfig[] = [];
+          await dependencyDashboard.ensureDependencyDashboard(config, branches);
+          expect(platform.ensureIssue).toHaveBeenCalledTimes(1);
+          expect(platform.ensureIssue.mock.calls[0][0].body).toMatchSnapshot();
+
+          // same with dry run
+          await dryRun(branches, platform);
+        });
+
+        it('show default message in issues body when packageFiles is empty', async () => {
+          const branches: BranchConfig[] = [];
+          PackageFiles.add('main', {});
+          await dependencyDashboard.ensureDependencyDashboard(config, branches);
+          expect(platform.ensureIssue).toHaveBeenCalledTimes(1);
+          expect(platform.ensureIssue.mock.calls[0][0].body).toMatchSnapshot();
+
+          // same with dry run
+          await dryRun(branches, platform);
+        });
+
+        it('show default message in issues body when when packageFiles is null', async () => {
+          const branches: BranchConfig[] = [];
+          PackageFiles.add('main', null);
+          await dependencyDashboard.ensureDependencyDashboard(config, branches);
+          expect(platform.ensureIssue).toHaveBeenCalledTimes(1);
+          expect(platform.ensureIssue.mock.calls[0][0].body).toMatchSnapshot();
+
+          // same with dry run
+          await dryRun(branches, platform);
+        });
+      });
+    });
   });
 });
diff --git a/lib/workers/repository/dependency-dashboard.ts b/lib/workers/repository/dependency-dashboard.ts
index b158de8771..634b91eb98 100644
--- a/lib/workers/repository/dependency-dashboard.ts
+++ b/lib/workers/repository/dependency-dashboard.ts
@@ -7,6 +7,7 @@ import { platform } from '../../modules/platform';
 import { regEx } from '../../util/regex';
 import * as template from '../../util/template';
 import { BranchConfig, BranchResult } from '../types';
+import { PackageFiles } from './package-files';
 
 interface DependencyDashboard {
   dependencyDashboardChecks: Record<string, string>;
@@ -316,6 +317,8 @@ export async function ensureDependencyDashboard(
       'This repository currently has no open or pending branches.\n\n';
   }
 
+  issueBody += PackageFiles.getDashboardMarkdown(config);
+
   if (config.dependencyDashboardFooter?.length) {
     issueBody +=
       '---\n' +
diff --git a/lib/workers/repository/finalise/index.ts b/lib/workers/repository/finalise/index.ts
index 419a3a5cda..1f239204c1 100644
--- a/lib/workers/repository/finalise/index.ts
+++ b/lib/workers/repository/finalise/index.ts
@@ -3,6 +3,7 @@ import { logger } from '../../../logger';
 import { platform } from '../../../modules/platform';
 import * as repositoryCache from '../../../util/cache/repository';
 import { clearRenovateRefs } from '../../../util/git';
+import { PackageFiles } from '../package-files';
 import { pruneStaleBranches } from './prune';
 import { runRenovateRepoStats } from './repository-statistics';
 
@@ -17,6 +18,7 @@ export async function finaliseRepo(
     `Action Required: Fix Renovate Configuration`
   );
   await clearRenovateRefs();
+  PackageFiles.clear();
   const prList = await platform.getPrList();
   if (
     prList?.some(
diff --git a/lib/workers/repository/package-files.ts b/lib/workers/repository/package-files.ts
new file mode 100644
index 0000000000..e16abdbcc4
--- /dev/null
+++ b/lib/workers/repository/package-files.ts
@@ -0,0 +1,66 @@
+import type { RenovateConfig } from '../../config/types';
+import { logger } from '../../logger';
+import type { PackageFile } from '../../modules/manager/types';
+
+export class PackageFiles {
+  private static data = new Map<string, Record<string, PackageFile[]> | null>();
+
+  public static add(
+    baseBranch: string,
+    packageFiles: Record<string, PackageFile[]> | null
+  ): void {
+    logger.debug(
+      { baseBranch },
+      `PackageFiles.add() - Package file saved for branch`
+    );
+    this.data.set(baseBranch, packageFiles);
+  }
+
+  public static clear(): void {
+    logger.debug(
+      { baseBranches: [...this.data.keys()] },
+      'PackageFiles.clear() - Package files deleted'
+    );
+    this.data.clear();
+  }
+
+  public static getDashboardMarkdown(config: RenovateConfig): string {
+    const title = `## Detected dependencies\n\n`;
+    const none = 'None detected\n\n';
+    const pad = this.data.size > 1; // padding condition for a multi base branch repo
+    let deps = '';
+
+    for (const [branch, packageFiles] of this.data) {
+      deps += pad ? `<details><summary>Branch ${branch}\n</summary>\n\n` : '';
+      if (packageFiles === null) {
+        deps += none;
+        deps += pad ? '\n</details>\n\n' : '\n';
+        continue;
+      }
+
+      const managers = Object.keys(packageFiles);
+      if (managers.length === 0) {
+        deps += none;
+        deps += pad ? '\n</details>\n\n' : '\n';
+        continue;
+      }
+
+      for (const manager of managers) {
+        deps += `${
+          pad ? '\n<ul>' : ''
+        }<details><summary>${manager}</summary>\n\n`;
+        for (const packageFile of packageFiles[manager]) {
+          deps += `<ul><details><summary>${packageFile.packageFile}</summary>\n\n`;
+          for (const dep of packageFile.deps) {
+            deps += ` - \`${dep.depName} ${dep.currentValue}\`\n`;
+          }
+          deps += '\n</details></ul>';
+        }
+        deps += `\n</details>${pad ? '</ul>' : ''}`;
+      }
+      deps += pad ? '\n</details>\n\n' : '';
+    }
+
+    return title + deps;
+  }
+}
diff --git a/lib/workers/repository/process/fetch.ts b/lib/workers/repository/process/fetch.ts
index f3368f7237..4b6324a4d9 100644
--- a/lib/workers/repository/process/fetch.ts
+++ b/lib/workers/repository/process/fetch.ts
@@ -10,6 +10,7 @@ import type {
 } from '../../../modules/manager/types';
 import { clone } from '../../../util/clone';
 import { applyPackageRules } from '../../../util/package-rules';
+import { PackageFiles } from '../package-files';
 import { lookupUpdates } from './lookup';
 import type { LookupUpdateConfig } from './lookup/types';
 
@@ -100,6 +101,7 @@ export async function fetchUpdates(
     fetchManagerUpdates(config, packageFiles, manager)
   );
   await Promise.all(allManagerJobs);
+  PackageFiles.add(config.baseBranch, { ...packageFiles });
   logger.debug(
     { baseBranch: config.baseBranch },
     'Package releases lookups complete'
-- 
GitLab