diff --git a/lib/workers/repository/update/pr/changelog/github.spec.ts b/lib/workers/repository/update/pr/changelog/github.spec.ts
index 6ec4b8ac548c7bc378aec96ce5eb4f655c875798..7d1e4c746c72e1a858ca1e17f214408cd925f030 100644
--- a/lib/workers/repository/update/pr/changelog/github.spec.ts
+++ b/lib/workers/repository/update/pr/changelog/github.spec.ts
@@ -1,6 +1,9 @@
 import * as httpMock from '../../../../../../test/http-mock';
+import { partial } from '../../../../../../test/util';
 import { GlobalConfig } from '../../../../../config/global';
 import * as semverVersioning from '../../../../../modules/versioning/semver';
+import * as githubGraphql from '../../../../../util/github/graphql';
+import type { GithubTagItem } from '../../../../../util/github/graphql/types';
 import * as hostRules from '../../../../../util/host-rules';
 import type { BranchUpgradeConfig } from '../../../../types';
 import { getChangeLogJSON } from '.';
@@ -356,15 +359,15 @@ describe('workers/repository/update/pr/changelog/github', () => {
     });
 
     it('works with same version releases but different prefix', async () => {
-      httpMock
-        .scope('https://api.github.com/')
-        .get('/repos/chalk/chalk/tags?per_page=100')
-        .reply(200, [
-          { name: 'v1.0.1' },
-          { name: '1.0.1' },
-          { name: 'correctPrefix/target@1.0.1' },
-          { name: 'wrongPrefix/target-1.0.1' },
-        ]);
+      const githubTagsMock = jest.spyOn(githubGraphql, 'queryTags');
+      githubTagsMock.mockResolvedValue(
+        partial<GithubTagItem>([
+          { version: 'v1.0.1' },
+          { version: '1.0.1' },
+          { version: 'correctPrefix/target@1.0.1' },
+          { version: 'wrongPrefix/target-1.0.1' },
+        ])
+      );
 
       const upgradeData: BranchUpgradeConfig = {
         manager: 'some-manager',
diff --git a/lib/workers/repository/update/pr/changelog/github/index.ts b/lib/workers/repository/update/pr/changelog/github/index.ts
index 05697a617a85b0bde45ec942955f075efa12e0e6..c989b2fa0b988f14699e3a560905b7306f14ab5c 100644
--- a/lib/workers/repository/update/pr/changelog/github/index.ts
+++ b/lib/workers/repository/update/pr/changelog/github/index.ts
@@ -5,13 +5,13 @@ import type {
   GithubGitTree,
   GithubGitTreeNode,
 } from '../../../../../../types/platform/github';
-import type {
-  GithubRestRelease,
-  GithubRestTag,
-} from '../../../../../../util/github/types';
+import {
+  queryReleases,
+  queryTags,
+} from '../../../../../../util/github/graphql';
 import { GithubHttp } from '../../../../../../util/http/github';
 import { fromBase64 } from '../../../../../../util/string';
-import { ensureTrailingSlash } from '../../../../../../util/url';
+import { ensureTrailingSlash, joinUrlParts } from '../../../../../../util/url';
 import type {
   ChangeLogFile,
   ChangeLogNotes,
@@ -28,18 +28,20 @@ export async function getTags(
 ): Promise<string[]> {
   logger.trace('github.getTags()');
   try {
-    const url = `${endpoint}repos/${repository}/tags?per_page=100`;
-    const res = await http.getJson<GithubRestTag[]>(url, {
-      paginate: true,
-    });
-    const tags = res.body;
+    const tags = await queryTags(
+      {
+        registryUrl: endpoint,
+        packageName: repository,
+      },
+      http
+    );
 
     // istanbul ignore if
     if (!tags.length) {
       logger.debug(`No Github tags found for repository:${repository}`);
     }
 
-    return tags.map((tag) => tag.name).filter(Boolean);
+    return tags.map(({ version }) => version);
   } catch (err) {
     logger.debug(
       { sourceRepo: repository, err },
@@ -114,23 +116,34 @@ export async function getReleaseNotesMd(
 
 export async function getReleaseList(
   project: ChangeLogProject,
-  release: ChangeLogRelease
+  _release: ChangeLogRelease
 ): Promise<ChangeLogNotes[]> {
   logger.trace('github.getReleaseList()');
-  // TODO #7154
-  const apiBaseUrl = project.apiBaseUrl!;
+  const apiBaseUrl = project.apiBaseUrl!; // TODO #7154
   const repository = project.repository;
-  const url = `${ensureTrailingSlash(apiBaseUrl)}repos/${repository}/releases`;
-  const res = await http.getJson<GithubRestRelease[]>(`${url}?per_page=100`, {
-    paginate: true,
-  });
+  const notesSourceUrl = joinUrlParts(
+    apiBaseUrl,
+    'repos',
+    repository,
+    'releases'
+  );
+  const releases = await queryReleases(
+    {
+      registryUrl: apiBaseUrl,
+      packageName: repository,
+    },
+    http
+  );
 
-  return res.body.map((release) => ({
-    url: release.html_url,
-    notesSourceUrl: url,
-    id: release.id,
-    tag: release.tag_name,
-    name: release.name,
-    body: release.body,
-  }));
+  const result = releases.map(
+    ({ url, id, version: tag, name, description: body }) => ({
+      url,
+      notesSourceUrl,
+      id,
+      tag,
+      name,
+      body,
+    })
+  );
+  return result;
 }
diff --git a/lib/workers/repository/update/pr/changelog/index.spec.ts b/lib/workers/repository/update/pr/changelog/index.spec.ts
index 34ceaa05ddbce65384052ba04e3700d9e65dbe0a..c3a3439f4cc773934f57f34201bdf0876643fa16 100644
--- a/lib/workers/repository/update/pr/changelog/index.spec.ts
+++ b/lib/workers/repository/update/pr/changelog/index.spec.ts
@@ -2,6 +2,7 @@ import * as httpMock from '../../../../../../test/http-mock';
 import { partial } from '../../../../../../test/util';
 import { GlobalConfig } from '../../../../../config/global';
 import * as semverVersioning from '../../../../../modules/versioning/semver';
+import * as githubGraphql from '../../../../../util/github/graphql';
 import * as hostRules from '../../../../../util/host-rules';
 import type { BranchConfig } from '../../../../types';
 import { getChangeLogJSON } from '.';
@@ -10,6 +11,9 @@ jest.mock('../../../../../modules/datasource/npm');
 
 const githubApiHost = 'https://api.github.com';
 
+const githubTagsMock = jest.spyOn(githubGraphql, 'queryTags');
+const githubReleasesMock = jest.spyOn(githubGraphql, 'queryReleases');
+
 const upgrade: BranchConfig = partial<BranchConfig>({
   endpoint: 'https://api.github.com/',
   depName: 'renovate',
@@ -81,15 +85,12 @@ describe('workers/repository/update/pr/changelog/index', () => {
     });
 
     it('works without Github', async () => {
+      githubTagsMock.mockRejectedValueOnce(new Error('Unknown'));
+      githubReleasesMock.mockRejectedValueOnce(new Error('Unknown'));
       httpMock
         .scope(githubApiHost)
         .get('/repos/chalk/chalk')
         .times(4)
-        .reply(500)
-        .get('/repos/chalk/chalk/tags?per_page=100')
-        .reply(500)
-        .get('/repos/chalk/chalk/releases?per_page=100')
-        .times(4)
         .reply(500);
       expect(
         await getChangeLogJSON({
@@ -116,20 +117,16 @@ describe('workers/repository/update/pr/changelog/index', () => {
     });
 
     it('uses GitHub tags', async () => {
-      httpMock
-        .scope(githubApiHost)
-        .get('/repos/chalk/chalk/tags?per_page=100')
-        .reply(200, [
-          { name: '0.9.0' },
-          { name: '1.0.0' },
-          { name: '1.4.0' },
-          { name: 'v2.3.0' },
-          { name: '2.2.2' },
-          { name: 'v2.4.2' },
-        ])
-        .persist()
-        .get(/.*/)
-        .reply(200, []);
+      httpMock.scope(githubApiHost).get(/.*/).reply(200, []).persist();
+      githubTagsMock.mockResolvedValue([
+        { version: '0.9.0' },
+        { version: '1.0.0' },
+        { version: '1.4.0' },
+        { version: 'v2.3.0' },
+        { version: '2.2.2' },
+        { version: 'v2.4.2' },
+      ] as never);
+      githubReleasesMock.mockResolvedValue([]);
       expect(
         await getChangeLogJSON({
           ...upgrade,
@@ -155,6 +152,10 @@ describe('workers/repository/update/pr/changelog/index', () => {
     });
 
     it('filters unnecessary warns', async () => {
+      githubTagsMock.mockRejectedValueOnce(new Error('Unknown Github Repo'));
+      githubReleasesMock.mockRejectedValueOnce(
+        new Error('Unknown Github Repo')
+      );
       httpMock.scope(githubApiHost).get(/.*/).reply(200, []).persist();
       const res = await getChangeLogJSON({
         ...upgrade,
@@ -181,6 +182,8 @@ describe('workers/repository/update/pr/changelog/index', () => {
     });
 
     it('supports node engines', async () => {
+      githubTagsMock.mockRejectedValueOnce([]);
+      githubReleasesMock.mockRejectedValueOnce([]);
       expect(
         await getChangeLogJSON({
           ...upgrade,
@@ -255,6 +258,8 @@ describe('workers/repository/update/pr/changelog/index', () => {
     });
 
     it('supports github enterprise and github.com changelog', async () => {
+      githubTagsMock.mockRejectedValueOnce([]);
+      githubReleasesMock.mockRejectedValueOnce([]);
       httpMock.scope(githubApiHost).persist().get(/.*/).reply(200, []);
       hostRules.add({
         hostType: 'github',
@@ -287,6 +292,8 @@ describe('workers/repository/update/pr/changelog/index', () => {
     });
 
     it('supports github enterprise and github enterprise changelog', async () => {
+      githubTagsMock.mockRejectedValueOnce([]);
+      githubReleasesMock.mockRejectedValueOnce([]);
       httpMock
         .scope('https://github-enterprise.example.com')
         .persist()
@@ -325,6 +332,8 @@ describe('workers/repository/update/pr/changelog/index', () => {
     });
 
     it('supports github.com and github enterprise changelog', async () => {
+      githubTagsMock.mockRejectedValueOnce([]);
+      githubReleasesMock.mockRejectedValueOnce([]);
       httpMock
         .scope('https://github-enterprise.example.com')
         .persist()
diff --git a/lib/workers/repository/update/pr/changelog/release-notes.spec.ts b/lib/workers/repository/update/pr/changelog/release-notes.spec.ts
index e4066da18aa5074f116f6538197064874b56a027..c44ff547ecc0da46766a17cbf94825dd6c35db9d 100644
--- a/lib/workers/repository/update/pr/changelog/release-notes.spec.ts
+++ b/lib/workers/repository/update/pr/changelog/release-notes.spec.ts
@@ -3,6 +3,7 @@ import { Fixtures } from '../../../../../../test/fixtures';
 import * as httpMock from '../../../../../../test/http-mock';
 import { mocked } from '../../../../../../test/util';
 import { clone } from '../../../../../util/clone';
+import * as githubGraphql from '../../../../../util/github/graphql';
 import * as _hostRules from '../../../../../util/host-rules';
 import { toBase64 } from '../../../../../util/string';
 import type { BranchUpgradeConfig } from '../../../../types';
@@ -58,6 +59,8 @@ const gitlabProject = {
 } as ChangeLogProject;
 
 describe('workers/repository/update/pr/changelog/release-notes', () => {
+  const githubReleasesMock = jest.spyOn(githubGraphql, 'queryReleases');
+
   beforeEach(() => {
     hostRules.find.mockReturnValue({});
     hostRules.hosts.mockReturnValue([]);
@@ -178,17 +181,25 @@ describe('workers/repository/update/pr/changelog/release-notes', () => {
     });
 
     it('should return release list for github repo', async () => {
-      httpMock
-        .scope('https://api.github.com/')
-        .get('/repos/some/yet-other-repository/releases?per_page=100')
-        .reply(200, [
-          { tag_name: `v1.0.0` },
-          {
-            tag_name: `v1.0.1`,
-            body: 'some body #123, [#124](https://github.com/some/yet-other-repository/issues/124)',
-          },
-        ]);
-
+      githubReleasesMock.mockResolvedValueOnce([
+        {
+          version: `v1.0.0`,
+          releaseTimestamp: '2020-01-01',
+          id: 1,
+          url: 'https://example.com',
+          name: 'some/dep',
+          description: 'some body',
+        },
+        {
+          version: `v1.0.1`,
+          releaseTimestamp: '2020-01-01',
+          id: 1,
+          url: 'https://example.com',
+          name: 'some/dep',
+          description:
+            'some body #123, [#124](https://github.com/some/yet-other-repository/issues/124)',
+        },
+      ]);
       const res = await getReleaseList(
         {
           ...githubProject,
@@ -289,10 +300,24 @@ describe('workers/repository/update/pr/changelog/release-notes', () => {
 
   describe('getReleaseNotes()', () => {
     it('should return null for release notes without body and name', async () => {
-      httpMock
-        .scope('https://api.github.com/')
-        .get('/repos/some/repository/releases?per_page=100')
-        .reply(200, [{ tag_name: 'v1.0.0' }, { tag_name: 'v1.0.1' }]);
+      githubReleasesMock.mockResolvedValueOnce([
+        {
+          version: '1.0.0',
+          releaseTimestamp: '2020-01-01',
+          id: 1,
+          url: 'https://github.com/some/other-repository/releases/1.0.0',
+          name: '',
+          description: '',
+        },
+        {
+          version: '1.0.1',
+          releaseTimestamp: '2020-01-01',
+          id: 2,
+          url: 'https://github.com/some/other-repository/releases/1.0.1',
+          name: '',
+          description: '',
+        },
+      ]);
       const res = await getReleaseNotes(
         {
           ...githubProject,
@@ -309,17 +334,25 @@ describe('workers/repository/update/pr/changelog/release-notes', () => {
     });
 
     it('gets release notes with body ""', async () => {
-      const prefix = '';
-      httpMock
-        .scope('https://api.github.com/')
-        .get('/repos/some/other-repository/releases?per_page=100')
-        .reply(200, [
-          { tag_name: `${prefix}1.0.0` },
-          {
-            tag_name: `${prefix}1.0.1`,
-            body: 'some body #123, [#124](https://github.com/some/yet-other-repository/issues/124)',
-          },
-        ]);
+      githubReleasesMock.mockResolvedValueOnce([
+        {
+          version: '1.0.0',
+          releaseTimestamp: '2020-01-01',
+          id: 1,
+          url: 'https://github.com/some/other-repository/releases/1.0.0',
+          name: 'some/dep',
+          description: 'some body',
+        },
+        {
+          version: '1.0.1',
+          releaseTimestamp: '2020-01-01',
+          id: 2,
+          url: 'https://github.com/some/other-repository/releases/1.0.1',
+          name: 'some/dep',
+          description:
+            'some body #123, [#124](https://github.com/some/yet-other-repository/issues/124)',
+        },
+      ]);
       const res = await getReleaseNotes(
         {
           ...githubProject,
@@ -334,8 +367,8 @@ describe('workers/repository/update/pr/changelog/release-notes', () => {
       );
       expect(res).toEqual({
         body: 'some body [#123](https://github.com/some/other-repository/issues/123), [#124](https://github.com/some/yet-other-repository/issues/124)\n',
-        id: undefined,
-        name: undefined,
+        id: 2,
+        name: 'some/dep',
         notesSourceUrl:
           'https://api.github.com/repos/some/other-repository/releases',
         tag: '1.0.1',
@@ -344,18 +377,24 @@ describe('workers/repository/update/pr/changelog/release-notes', () => {
     });
 
     it('gets release notes with name ""', async () => {
-      const prefix = '';
-      httpMock
-        .scope('https://api.github.com/')
-        .get('/repos/some/other-repository/releases?per_page=100')
-        .reply(200, [
-          { tag_name: `${prefix}1.0.0` },
-          {
-            tag_name: `${prefix}1.0.1`,
-            name: 'some release name',
-            body: undefined,
-          },
-        ]);
+      githubReleasesMock.mockResolvedValueOnce([
+        {
+          version: '1.0.0',
+          releaseTimestamp: '2020-01-01',
+          id: 1,
+          url: 'https://github.com/some/other-repository/releases/1.0.0',
+          name: 'some/dep',
+          description: '',
+        },
+        {
+          version: '1.0.1',
+          releaseTimestamp: '2020-01-01',
+          id: 2,
+          url: 'https://github.com/some/other-repository/releases/1.0.1',
+          name: 'some release name',
+          description: '',
+        },
+      ]);
       const res = await getReleaseNotes(
         {
           ...githubProject,
@@ -370,7 +409,7 @@ describe('workers/repository/update/pr/changelog/release-notes', () => {
       );
       expect(res).toEqual({
         body: '',
-        id: undefined,
+        id: 2,
         name: 'some release name',
         notesSourceUrl:
           'https://api.github.com/repos/some/other-repository/releases',
@@ -380,18 +419,24 @@ describe('workers/repository/update/pr/changelog/release-notes', () => {
     });
 
     it('filters release note name when same as version', async () => {
-      const prefix = '';
-      httpMock
-        .scope('https://api.github.com/')
-        .get('/repos/some/other-repository/releases?per_page=100')
-        .reply(200, [
-          { tag_name: `${prefix}1.0.0`, name: 'Release v1.0.0' },
-          {
-            tag_name: `${prefix}1.0.1`,
-            name: '1.0.1',
-            body: 'some body',
-          },
-        ]);
+      githubReleasesMock.mockResolvedValueOnce([
+        {
+          version: '1.0.0',
+          releaseTimestamp: '2020-01-01',
+          id: 1,
+          url: 'https://github.com/some/other-repository/releases/1.0.0',
+          name: 'Release v1.0.0',
+          description: 'some body',
+        },
+        {
+          version: '1.0.1',
+          releaseTimestamp: '2020-01-01',
+          id: 2,
+          url: 'https://github.com/some/other-repository/releases/1.0.1',
+          name: '1.0.1',
+          description: 'some body',
+        },
+      ]);
       const res = await getReleaseNotes(
         {
           ...githubProject,
@@ -406,7 +451,7 @@ describe('workers/repository/update/pr/changelog/release-notes', () => {
       );
       expect(res).toEqual({
         body: 'some body\n',
-        id: undefined,
+        id: 2,
         name: undefined,
         notesSourceUrl:
           'https://api.github.com/repos/some/other-repository/releases',
@@ -416,18 +461,24 @@ describe('workers/repository/update/pr/changelog/release-notes', () => {
     });
 
     it('strips release note with version prefixed name', async () => {
-      const prefix = '';
-      httpMock
-        .scope('https://api.github.com/')
-        .get('/repos/some/other-repository/releases?per_page=100')
-        .reply(200, [
-          { tag_name: `${prefix}1.0.0` },
-          {
-            tag_name: `${prefix}1.0.1`,
-            name: 'v1.0.1 some release',
-            body: 'some body',
-          },
-        ]);
+      githubReleasesMock.mockResolvedValueOnce([
+        {
+          version: '1.0.0',
+          releaseTimestamp: '2020-01-01',
+          id: 1,
+          url: 'https://github.com/some/other-repository/releases/1.0.1',
+          name: 'some/dep',
+          description: 'some body',
+        },
+        {
+          version: '1.0.1',
+          releaseTimestamp: '2020-01-01',
+          id: 2,
+          url: 'https://github.com/some/other-repository/releases/1.0.1',
+          name: 'v1.0.1 some release',
+          description: 'some body',
+        },
+      ]);
       const res = await getReleaseNotes(
         {
           ...githubProject,
@@ -442,7 +493,7 @@ describe('workers/repository/update/pr/changelog/release-notes', () => {
       );
       expect(res).toEqual({
         body: 'some body\n',
-        id: undefined,
+        id: 2,
         name: 'some release',
         notesSourceUrl:
           'https://api.github.com/repos/some/other-repository/releases',
@@ -452,17 +503,24 @@ describe('workers/repository/update/pr/changelog/release-notes', () => {
     });
 
     it('release notes without body and name that matches version tag returns null', async () => {
-      const prefix = '';
-      httpMock
-        .scope('https://api.github.com/')
-        .get('/repos/some/other-repository/releases?per_page=100')
-        .reply(200, [
-          { tag_name: `${prefix}1.0.0` },
-          {
-            tag_name: `${prefix}1.0.1`,
-            name: '1.0.1',
-          },
-        ]);
+      githubReleasesMock.mockResolvedValueOnce([
+        {
+          version: '1.0.0',
+          releaseTimestamp: '2020-01-01',
+          id: 1,
+          url: 'correct/url/tag.com',
+          name: 'some/dep',
+          description: '',
+        },
+        {
+          version: '1.0.1',
+          releaseTimestamp: '2020-01-01',
+          id: 2,
+          url: 'correct/url/tag.com',
+          name: '1.0.1',
+          description: '',
+        },
+      ]);
       const res = await getReleaseNotes(
         {
           ...githubProject,
@@ -479,17 +537,25 @@ describe('workers/repository/update/pr/changelog/release-notes', () => {
     });
 
     it('gets release notes with body "v"', async () => {
-      const prefix = 'v';
-      httpMock
-        .scope('https://api.github.com/')
-        .get('/repos/some/other-repository/releases?per_page=100')
-        .reply(200, [
-          { tag_name: `${prefix}1.0.0` },
-          {
-            tag_name: `${prefix}1.0.1`,
-            body: 'some body #123, [#124](https://github.com/some/yet-other-repository/issues/124)',
-          },
-        ]);
+      githubReleasesMock.mockResolvedValueOnce([
+        {
+          version: 'v1.0.0',
+          releaseTimestamp: '2020-01-01',
+          id: 1,
+          url: 'https://github.com/some/other-repository/releases/v1.0.0',
+          name: 'some/dep',
+          description: 'some body',
+        },
+        {
+          version: 'v1.0.1',
+          releaseTimestamp: '2020-01-01',
+          id: 2,
+          url: 'https://github.com/some/other-repository/releases/v1.0.1',
+          name: 'some/dep',
+          description:
+            'some body #123, [#124](https://github.com/some/yet-other-repository/issues/124)',
+        },
+      ]);
       const res = await getReleaseNotes(
         {
           ...githubProject,
@@ -504,8 +570,8 @@ describe('workers/repository/update/pr/changelog/release-notes', () => {
       );
       expect(res).toEqual({
         body: 'some body [#123](https://github.com/some/other-repository/issues/123), [#124](https://github.com/some/yet-other-repository/issues/124)\n',
-        id: undefined,
-        name: undefined,
+        id: 2,
+        name: 'some/dep',
         notesSourceUrl:
           'https://api.github.com/repos/some/other-repository/releases',
         tag: 'v1.0.1',
@@ -514,17 +580,25 @@ describe('workers/repository/update/pr/changelog/release-notes', () => {
     });
 
     it('gets release notes with body "other-"', async () => {
-      const prefix = 'other-';
-      httpMock
-        .scope('https://api.github.com/')
-        .get('/repos/some/other-repository/releases?per_page=100')
-        .reply(200, [
-          { tag_name: `${prefix}1.0.0` },
-          {
-            tag_name: `${prefix}1.0.1`,
-            body: 'some body #123, [#124](https://github.com/some/yet-other-repository/issues/124)',
-          },
-        ]);
+      githubReleasesMock.mockResolvedValueOnce([
+        {
+          version: 'other-1.0.0',
+          releaseTimestamp: '2020-01-01',
+          id: 1,
+          url: 'https://github.com/some/other-repository/releases/other-1.0.0',
+          name: 'some/dep',
+          description: 'some body',
+        },
+        {
+          version: 'other-1.0.1',
+          releaseTimestamp: '2020-01-01',
+          id: 2,
+          url: 'https://github.com/some/other-repository/releases/other-1.0.1',
+          name: 'some/dep',
+          description:
+            'some body #123, [#124](https://github.com/some/yet-other-repository/issues/124)',
+        },
+      ]);
 
       const res = await getReleaseNotes(
         {
@@ -540,8 +614,8 @@ describe('workers/repository/update/pr/changelog/release-notes', () => {
       );
       expect(res).toEqual({
         body: 'some body [#123](https://github.com/some/other-repository/issues/123), [#124](https://github.com/some/yet-other-repository/issues/124)\n',
-        id: undefined,
-        name: undefined,
+        id: 2,
+        name: 'some/dep',
         notesSourceUrl:
           'https://api.github.com/repos/some/other-repository/releases',
         tag: 'other-1.0.1',
@@ -550,17 +624,25 @@ describe('workers/repository/update/pr/changelog/release-notes', () => {
     });
 
     it('gets release notes with body "other_v"', async () => {
-      const prefix = 'other_v';
-      httpMock
-        .scope('https://api.github.com/')
-        .get('/repos/some/other-repository/releases?per_page=100')
-        .reply(200, [
-          { tag_name: `${prefix}1.0.0` },
-          {
-            tag_name: `${prefix}1.0.1`,
-            body: 'some body #123, [#124](https://github.com/some/yet-other-repository/issues/124)',
-          },
-        ]);
+      githubReleasesMock.mockResolvedValueOnce([
+        {
+          version: 'other_v1.0.0',
+          releaseTimestamp: '2020-01-01',
+          id: 1,
+          url: 'https://github.com/some/other-repository/releases/other_v1.0.0',
+          name: 'some/dep',
+          description: 'some body',
+        },
+        {
+          version: 'other_v1.0.1',
+          releaseTimestamp: '2020-01-01',
+          id: 2,
+          url: 'https://github.com/some/other-repository/releases/other_v1.0.1',
+          name: 'some/dep',
+          description:
+            'some body #123, [#124](https://github.com/some/yet-other-repository/issues/124)',
+        },
+      ]);
 
       const res = await getReleaseNotes(
         {
@@ -576,8 +658,8 @@ describe('workers/repository/update/pr/changelog/release-notes', () => {
       );
       expect(res).toEqual({
         body: 'some body [#123](https://github.com/some/other-repository/issues/123), [#124](https://github.com/some/yet-other-repository/issues/124)\n',
-        id: undefined,
-        name: undefined,
+        id: 2,
+        name: 'some/dep',
         notesSourceUrl:
           'https://api.github.com/repos/some/other-repository/releases',
         tag: 'other_v1.0.1',
@@ -586,17 +668,25 @@ describe('workers/repository/update/pr/changelog/release-notes', () => {
     });
 
     it('gets release notes with body "other@"', async () => {
-      const prefix = 'other@';
-      httpMock
-        .scope('https://api.github.com/')
-        .get('/repos/some/other-repository/releases?per_page=100')
-        .reply(200, [
-          { tag_name: `${prefix}1.0.0` },
-          {
-            tag_name: `${prefix}1.0.1`,
-            body: 'some body #123, [#124](https://github.com/some/yet-other-repository/issues/124)',
-          },
-        ]);
+      githubReleasesMock.mockResolvedValueOnce([
+        {
+          version: 'other@1.0.0',
+          id: 1,
+          releaseTimestamp: '2020-01-01',
+          url: 'https://github.com/some/other-repository/releases/other@1.0.0',
+          name: 'some/dep',
+          description: 'some body',
+        } as never,
+        {
+          version: 'other@1.0.1',
+          description:
+            'some body #123, [#124](https://github.com/some/yet-other-repository/issues/124)',
+          id: 2,
+          releaseTimestamp: '2020-01-01',
+          url: 'https://github.com/some/other-repository/releases/other@1.0.1',
+          name: 'some/dep',
+        },
+      ]);
       const res = await getReleaseNotes(
         {
           ...githubProject,
@@ -611,8 +701,8 @@ describe('workers/repository/update/pr/changelog/release-notes', () => {
       );
       expect(res).toEqual({
         body: 'some body [#123](https://github.com/some/other-repository/issues/123), [#124](https://github.com/some/yet-other-repository/issues/124)\n',
-        id: undefined,
-        name: undefined,
+        id: 2,
+        name: 'some/dep',
         notesSourceUrl:
           'https://api.github.com/repos/some/other-repository/releases',
         tag: 'other@1.0.1',
@@ -750,20 +840,32 @@ describe('workers/repository/update/pr/changelog/release-notes', () => {
 
     it('handles same version but different repo releases', async () => {
       const depName = 'correctTagPrefix/exampleDep';
-      httpMock
-        .scope('https://api.github.com/')
-        .get('/repos/some/other-repository/releases?per_page=100')
-        .reply(200, [
-          {
-            tag_name: `${depName}@1.0.0`,
-            html_url: 'correct/url/tag.com',
-            body: 'some body',
-          },
-          { tag_name: `someOtherRelease1/exampleDep_1.0.0` },
-          {
-            tag_name: `someOtherRelease2/exampleDep-1.0.0`,
-          },
-        ]);
+      githubReleasesMock.mockResolvedValueOnce([
+        {
+          id: 1,
+          version: `${depName}@1.0.0`,
+          releaseTimestamp: '2020-01-01',
+          url: 'correct/url/tag.com',
+          name: 'some/dep',
+          description: 'some body',
+        },
+        {
+          id: 2,
+          version: `someOtherRelease1/exampleDep_1.0.0`,
+          releaseTimestamp: '2020-01-01',
+          url: 'correct/url/tag.com',
+          name: 'some/dep',
+          description: 'some body',
+        },
+        {
+          id: 3,
+          version: `someOtherRelease2/exampleDep-1.0.0`,
+          releaseTimestamp: '2020-01-01',
+          url: 'correct/url/tag.com',
+          name: 'some/dep',
+          description: 'some body',
+        },
+      ]);
       const res = await getReleaseNotes(
         {
           ...githubProject,
@@ -780,24 +882,24 @@ describe('workers/repository/update/pr/changelog/release-notes', () => {
         url: 'correct/url/tag.com',
         notesSourceUrl:
           'https://api.github.com/repos/some/other-repository/releases',
-        id: undefined,
+        id: 1,
         tag: 'correctTagPrefix/exampleDep@1.0.0',
-        name: undefined,
+        name: 'some/dep',
         body: 'some body\n',
       });
     });
 
     it('fallback to extractVersion', async () => {
-      httpMock
-        .scope('https://api.github.com/')
-        .get('/repos/some/other-repository/releases?per_page=100')
-        .reply(200, [
-          {
-            tag_name: `app-1.0.0`,
-            html_url: 'correct/url/tag.com',
-            body: 'some body',
-          },
-        ]);
+      githubReleasesMock.mockResolvedValueOnce([
+        {
+          id: 123,
+          version: `app-1.0.0`,
+          releaseTimestamp: '2020-01-01',
+          url: 'correct/url/tag.com',
+          description: 'some body',
+          name: 'some/dep',
+        },
+      ]);
       const res = await getReleaseNotes(
         {
           ...githubProject,
@@ -814,9 +916,9 @@ describe('workers/repository/update/pr/changelog/release-notes', () => {
         url: 'correct/url/tag.com',
         notesSourceUrl:
           'https://api.github.com/repos/some/other-repository/releases',
-        id: undefined,
+        id: 123,
         tag: 'app-1.0.0',
-        name: undefined,
+        name: 'some/dep',
         body: 'some body\n',
       });
     });
diff --git a/lib/workers/repository/update/pr/changelog/release-notes.ts b/lib/workers/repository/update/pr/changelog/release-notes.ts
index 1162de48d499a12fa74a87e802e0f78040ac760f..514a46623b1437f3294ddb26000b05cd71c12b95 100644
--- a/lib/workers/repository/update/pr/changelog/release-notes.ts
+++ b/lib/workers/repository/update/pr/changelog/release-notes.ts
@@ -6,6 +6,7 @@ import MarkdownIt from 'markdown-it';
 import { logger } from '../../../../../logger';
 import * as memCache from '../../../../../util/cache/memory';
 import * as packageCache from '../../../../../util/cache/package';
+import { detectPlatform } from '../../../../../util/common';
 import { linkify } from '../../../../../util/markdown';
 import { newlineRegex, regEx } from '../../../../../util/regex';
 import type { BranchUpgradeConfig } from '../../../../types';
@@ -178,14 +179,13 @@ async function releaseNotesResult(
   }
   const { baseUrl, repository } = project;
   const releaseNotes: ChangeLogNotes = releaseMatch;
-  if (releaseMatch.url && !baseUrl.includes('gitlab')) {
-    // there is a ready link
-    releaseNotes.url = releaseMatch.url;
+  if (detectPlatform(baseUrl) === 'gitlab') {
+    releaseNotes.url = `${baseUrl}${repository}/tags/${releaseMatch.tag!}`;
   } else {
-    // TODO: types (#7154)
-    releaseNotes.url = baseUrl.includes('gitlab')
-      ? `${baseUrl}${repository}/tags/${releaseMatch.tag!}`
-      : `${baseUrl}${repository}/releases/${releaseMatch.tag!}`;
+    releaseNotes.url = releaseMatch.url
+      ? releaseMatch.url
+      : /* istanbul ignore next */
+        `${baseUrl}${repository}/releases/${releaseMatch.tag!}`;
   }
   // set body for release notes
   releaseNotes.body = massageBody(releaseNotes.body, baseUrl);