From f7faaa49181df3b98151e872913a03e4a1269296 Mon Sep 17 00:00:00 2001 From: jon4hz <me@jon4hz.io> Date: Mon, 27 Nov 2023 15:02:54 +0100 Subject: [PATCH] feat(datasource/galaxy-collection): support ansible automation hub (#25675) Co-authored-by: Rhys Arkins <rhys@arkins.net> Co-authored-by: Sebastian Poxhofer <secustor@users.noreply.github.com> Co-authored-by: HonkingGoose <34918129+HonkingGoose@users.noreply.github.com> --- .../__snapshots__/index.spec.ts.snap | 35 +++++++++++++- .../galaxy-collection/index.spec.ts | 46 ++++++++++++++++++- .../datasource/galaxy-collection/index.ts | 18 ++++++-- .../datasource/galaxy-collection/readme.md | 32 +++++++++++++ 4 files changed, 125 insertions(+), 6 deletions(-) create mode 100644 lib/modules/datasource/galaxy-collection/readme.md diff --git a/lib/modules/datasource/galaxy-collection/__snapshots__/index.spec.ts.snap b/lib/modules/datasource/galaxy-collection/__snapshots__/index.spec.ts.snap index 6510237324..9bbc296329 100644 --- a/lib/modules/datasource/galaxy-collection/__snapshots__/index.spec.ts.snap +++ b/lib/modules/datasource/galaxy-collection/__snapshots__/index.spec.ts.snap @@ -2,7 +2,40 @@ exports[`modules/datasource/galaxy-collection/index getReleases processes real data 1`] = ` { - "registryUrl": "https://galaxy.ansible.com", + "registryUrl": "https://galaxy.ansible.com/api", + "releases": [ + { + "dependencies": {}, + "downloadUrl": "https://galaxy.ansible.com/api/v3/plugin/ansible/content/published/collections/artifacts/community-kubernetes-0.11.1.tar.gz", + "isDeprecated": false, + "newDigest": "cd197084b32f8976394f269eb005bf475eff2122fddbb48380c76154ab4d4530", + "sourceUrl": "https://github.com/ansible-collections/community.kubernetes", + "version": "0.11.1", + }, + { + "dependencies": {}, + "downloadUrl": "https://galaxy.ansible.com/api/v3/plugin/ansible/content/published/collections/artifacts/community-kubernetes-1.2.0.tar.gz", + "isDeprecated": false, + "newDigest": "a53eaf6a51987d30cc48ebcd20f0102dae0f17a7a02071928381e5a62951a0ed", + "sourceUrl": "https://github.com/ansible-collections/community.kubernetes", + "version": "1.2.0", + }, + { + "dependencies": {}, + "downloadUrl": "https://galaxy.ansible.com/api/v3/plugin/ansible/content/published/collections/artifacts/community-kubernetes-1.2.1.tar.gz", + "isDeprecated": false, + "newDigest": "38e064bb32ee86781f0c6e56bd29fcfbaf48180f993e129185eb8420caabf223", + "sourceUrl": "https://github.com/ansible-collections/community.kubernetes", + "version": "1.2.1", + }, + ], + "sourceUrl": "https://github.com/ansible-collections/community.kubernetes", +} +`; + +exports[`modules/datasource/galaxy-collection/index getReleases processes real data with automation hub URL 1`] = ` +{ + "registryUrl": "https://my.automationhub.local/api/galaxy/content/published", "releases": [ { "dependencies": {}, diff --git a/lib/modules/datasource/galaxy-collection/index.spec.ts b/lib/modules/datasource/galaxy-collection/index.spec.ts index 12d93b0d41..e0a53bc256 100644 --- a/lib/modules/datasource/galaxy-collection/index.spec.ts +++ b/lib/modules/datasource/galaxy-collection/index.spec.ts @@ -18,9 +18,9 @@ const communityKubernetesDetails0111 = Fixtures.get( 'community_kubernetes_version_details_0.11.1.json', ); -const baseUrl = 'https://galaxy.ansible.com'; +const baseUrl = 'https://galaxy.ansible.com/api/'; const collectionAPIPath = - 'api/v3/plugin/ansible/content/published/collections/index'; + 'v3/plugin/ansible/content/published/collections/index'; const datasource = GalaxyCollectionDatasource.id; @@ -163,5 +163,47 @@ describe('modules/datasource/galaxy-collection/index', () => { expect(res).toBeDefined(); expect(res?.releases).toHaveLength(3); }); + + it('returns null but matches automation hub URL', async () => { + httpMock + .scope('https://my.automationhub.local/api/galaxy/content/community/') + .get(`/v3/plugin/ansible/content/community/collections/index/foo/bar/`) + .reply(500); + await expect( + getPkgReleases({ + datasource, + packageName: 'foo.bar', + registryUrls: [ + 'https://my.automationhub.local/api/galaxy/content/community/', + ], + }), + ).rejects.toThrow(EXTERNAL_HOST_ERROR); + }); + + it('processes real data with automation hub URL', async () => { + httpMock + .scope('https://my.automationhub.local/api/galaxy/content/published/') + .get(`/${collectionAPIPath}/community/kubernetes/`) + .reply(200, communityKubernetesBase) + .get(`/${collectionAPIPath}/community/kubernetes/versions/`) + .reply(200, communityKubernetesVersions) + .get(`/${collectionAPIPath}/community/kubernetes/versions/1.2.1/`) + .reply(200, communityKubernetesDetails121) + .get(`/${collectionAPIPath}/community/kubernetes/versions/1.2.0/`) + .reply(200, communityKubernetesDetails120) + .get(`/${collectionAPIPath}/community/kubernetes/versions/0.11.1/`) + .reply(200, communityKubernetesDetails0111); + const res = await getPkgReleases({ + datasource, + packageName: 'community.kubernetes', + registryUrls: [ + 'https://my.automationhub.local/api/galaxy/content/published/', + ], + }); + expect(res).toMatchSnapshot(); + expect(res).not.toBeNull(); + expect(res).toBeDefined(); + expect(res?.releases).toHaveLength(3); + }); }); }); diff --git a/lib/modules/datasource/galaxy-collection/index.ts b/lib/modules/datasource/galaxy-collection/index.ts index e6e8a63acf..3fd7e63ace 100644 --- a/lib/modules/datasource/galaxy-collection/index.ts +++ b/lib/modules/datasource/galaxy-collection/index.ts @@ -2,12 +2,17 @@ import is from '@sindresorhus/is'; import { logger } from '../../../logger'; import { cache } from '../../../util/cache/package/decorator'; import * as p from '../../../util/promises'; +import { regEx } from '../../../util/regex'; import { ensureTrailingSlash, joinUrlParts } from '../../../util/url'; import * as pep440Versioning from '../../versioning/pep440'; import { Datasource } from '../datasource'; import type { GetReleasesConfig, Release, ReleaseResult } from '../types'; import { GalaxyV3, GalaxyV3DetailedVersion, GalaxyV3Versions } from './schema'; +const repositoryRegex = regEx( + /^\S+\/api\/galaxy\/content\/(?<repository>[^/]+)/, +); + export class GalaxyCollectionDatasource extends Datasource { static readonly id = 'galaxy-collection'; @@ -15,9 +20,11 @@ export class GalaxyCollectionDatasource extends Datasource { super(GalaxyCollectionDatasource.id); } - override readonly customRegistrySupport = false; + override readonly customRegistrySupport = true; + + override readonly registryStrategy = 'hunt'; - override readonly defaultRegistryUrls = ['https://galaxy.ansible.com']; + override readonly defaultRegistryUrls = ['https://galaxy.ansible.com/api/']; override readonly defaultVersioning = pep440Versioning.id; @@ -31,10 +38,15 @@ export class GalaxyCollectionDatasource extends Datasource { }: GetReleasesConfig): Promise<ReleaseResult | null> { const [namespace, projectName] = packageName.split('.'); + const repository = + repositoryRegex.exec(registryUrl!)?.groups?.repository ?? 'published'; + const baseUrl = ensureTrailingSlash( joinUrlParts( registryUrl!, - 'api/v3/plugin/ansible/content/published/collections/index', + 'v3/plugin/ansible/content', + repository, + 'collections/index', namespace, projectName, ), diff --git a/lib/modules/datasource/galaxy-collection/readme.md b/lib/modules/datasource/galaxy-collection/readme.md new file mode 100644 index 0000000000..423a43fe7e --- /dev/null +++ b/lib/modules/datasource/galaxy-collection/readme.md @@ -0,0 +1,32 @@ +By default, the `galaxy-collection` datasource checks for dependencies on `https://galaxy.ansible.com`. +But you can override the default if you want. + +Set your own registries by: + +- setting a `source` in your `requirements.yaml` file, _or_ +- writing a `packageRule` to set a new `registryURLs` + +Then you can use Renovate with a private automation hub. + +```yaml title="Example config for requirements.yaml" +--- +collections: + - name: community.general + version: 3.0.0 + source: https://hub.mydomain.com/api/galaxy/content/community/ +``` + +```json title="Example config for renovate.json" +{ + "packageRules": [ + { + "matchDatasources": ["galaxy-collection"], + "registryUrls": [ + "https://hub.mydomain.com/api/galaxy/content/community/", + "https://hub.mydomain.com/api/galaxy/content/certified/", + "https://hub.mydomain.com/api/galaxy/content/myprivaterepo/" + ] + } + ] +} +``` -- GitLab