diff --git a/lib/modules/manager/composer/__fixtures__/composer6.json b/lib/modules/manager/composer/__fixtures__/composer6.json new file mode 100644 index 0000000000000000000000000000000000000000..d0376da5da6a9a0fd96a1b52f15591274f6c0734 --- /dev/null +++ b/lib/modules/manager/composer/__fixtures__/composer6.json @@ -0,0 +1,31 @@ +{ + "name": "acme/git-sources", + "description": "Fetch Packages via bitbucket-tags", + "repositories": [ + { + "name": "awesome/bitbucket-repo1", + "type": "vcs", + "url": "https://bitbucket.org/awesome/bitbucket-repo1.git" + }, + { + "name": "awesome/bitbucket-repo2", + "type": "vcs", + "url": "git@bitbucket.org/awesome/bitbucket-repo2.git" + }, + { + "name": "awesome/bitbucket-repo3", + "type": "vcs", + "url": "git@bitbucket.org/awesome/bitbucket-repo3" + } + ], + "require": { + "awesome/bitbucket-repo1": "dev-trunk", + "awesome/bitbucket-repo2": "dev-trunk", + "awesome/bitbucket-repo3": "dev-trunk" + }, + "autoload": { + "psr-0": { + "Acme": "src/" + } + } +} diff --git a/lib/modules/manager/composer/extract.spec.ts b/lib/modules/manager/composer/extract.spec.ts index bb32a14e4d77664be485dca0049fe6734f1293da..9cccbb73dea575f4c5c9d48564e1fbadb78b2936 100644 --- a/lib/modules/manager/composer/extract.spec.ts +++ b/lib/modules/manager/composer/extract.spec.ts @@ -10,6 +10,7 @@ const requirements2 = Fixtures.get('composer2.json'); const requirements3 = Fixtures.get('composer3.json'); const requirements4 = Fixtures.get('composer4.json'); const requirements5 = Fixtures.get('composer5.json'); +const requirements6 = Fixtures.get('composer6.json'); const requirements5Lock = Fixtures.get('composer5.lock'); describe('modules/manager/composer/extract', () => { @@ -215,6 +216,35 @@ describe('modules/manager/composer/extract', () => { }); }); + it('extracts bitbucket repositories and registryUrls', async () => { + const res = await extractPackageFile(requirements6, packageFile); + expect(res).toEqual({ + deps: [ + { + currentValue: 'dev-trunk', + datasource: 'bitbucket-tags', + depName: 'awesome/bitbucket-repo1', + depType: 'require', + packageName: 'awesome/bitbucket-repo1', + }, + { + currentValue: 'dev-trunk', + datasource: 'bitbucket-tags', + depName: 'awesome/bitbucket-repo2', + depType: 'require', + packageName: 'awesome/bitbucket-repo2', + }, + { + currentValue: 'dev-trunk', + datasource: 'bitbucket-tags', + depName: 'awesome/bitbucket-repo3', + depType: 'require', + packageName: 'awesome/bitbucket-repo3', + }, + ], + }); + }); + it('extracts object repositories and registryUrls with lock file', async () => { fs.readLocalFile.mockResolvedValue(requirements5Lock); const res = await extractPackageFile(requirements5, packageFile); diff --git a/lib/modules/manager/composer/index.ts b/lib/modules/manager/composer/index.ts index 9561047cc2ee778a50ac6a71ce12f76154f4c3cb..2402f2f201c1c66dcd1e39eaa7a00999ed3120d5 100644 --- a/lib/modules/manager/composer/index.ts +++ b/lib/modules/manager/composer/index.ts @@ -1,4 +1,5 @@ import type { Category } from '../../../constants'; +import { BitbucketTagsDatasource } from '../../datasource/bitbucket-tags'; import { GitTagsDatasource } from '../../datasource/git-tags'; import { PackagistDatasource } from '../../datasource/packagist'; import { updateArtifacts } from './artifacts'; @@ -24,6 +25,7 @@ export const defaultConfig = { export const categories: Category[] = ['php']; export const supportedDatasources = [ + BitbucketTagsDatasource.id, GitTagsDatasource.id, PackagistDatasource.id, ]; diff --git a/lib/modules/manager/composer/schema.ts b/lib/modules/manager/composer/schema.ts index 6dbcfbec67568ee692c6ebf01516effd4464dfa7..e8e12e3f9c7e7c3331b06242eafe4ebdcdf0dbba 100644 --- a/lib/modules/manager/composer/schema.ts +++ b/lib/modules/manager/composer/schema.ts @@ -3,6 +3,7 @@ import { logger } from '../../../logger'; import { readLocalFile } from '../../../util/fs'; import { regEx } from '../../../util/regex'; import { Json, LooseArray, LooseRecord } from '../../../util/schema-utils'; +import { BitbucketTagsDatasource } from '../../datasource/bitbucket-tags'; import { GitTagsDatasource } from '../../datasource/git-tags'; import { GithubTagsDatasource } from '../../datasource/github-tags'; import { PackagistDatasource } from '../../datasource/packagist'; @@ -60,6 +61,10 @@ export type NamedRepo = z.infer<typeof NamedRepo>; const DisablePackagist = z.object({ type: z.literal('disable-packagist') }); export type DisablePackagist = z.infer<typeof DisablePackagist>; +const bitbucketUrlRegex = regEx( + /^(?:https:\/\/|git@)bitbucket\.org[/:](?<packageName>[^/]+\/[^/]+?)(?:\.git)?$/ +); + export const ReposRecord = LooseRecord(z.union([Repo, z.literal(false)]), { onError: ({ error: err }) => { logger.debug({ err }, 'Composer: error parsing repositories object'); @@ -304,6 +309,17 @@ export const ComposerExtract = z const gitRepo = gitRepos[depName]; if (gitRepo) { + const bitbucketMatchGroups = bitbucketUrlRegex.exec( + gitRepo.url + )?.groups; + + if (bitbucketMatchGroups) { + dep.datasource = BitbucketTagsDatasource.id; + dep.packageName = bitbucketMatchGroups.packageName; + deps.push(dep); + continue; + } + dep.datasource = GitTagsDatasource.id; dep.packageName = gitRepo.url; deps.push(dep);