mirror of
https://github.com/renovatebot/renovate.git
synced 2026-10-25 15:01:49 +00:00
0ff55d2d34
* feat: add XcodeGen manager for Swift package dependencies in project.yml files * chore(xcodegen): inline project.yml fixture * fix(xcodegen): use semver instead of swift versioning * fix(xcodegen): use glob syntax for manager file pattern * tests(xcodegen): expect logger is called on invalid packages * tests(xcodegen): better assert extracted package contents * chore(xcodegen): simplify regex usage * chore(xcodegen): log projects without dependencies * chore(xcodegen): simplify dependency resolving and remove regular expressions in favor of the `detectPlatform` helper function * chore(xcodegen): use `coerceString` on package versions to simplify testing and improve coverage * chore(xcodegen): address PR review comments. --------- Co-authored-by: Michael Kriese <michael.kriese@visualon.de>
470 lines
12 KiB
TypeScript
470 lines
12 KiB
TypeScript
import { codeBlock } from 'common-tags';
|
|
import { logger } from '~test/util.ts';
|
|
import { extractPackageFile } from './index.ts';
|
|
|
|
describe('modules/manager/xcodegen/extract', () => {
|
|
describe('extractPackageFile()', () => {
|
|
it('returns null for empty content', () => {
|
|
expect(extractPackageFile('', 'project.yml')).toBeNull();
|
|
});
|
|
|
|
it('returns null for invalid YAML', () => {
|
|
expect(extractPackageFile('nothing here: [', 'project.yml')).toBeNull();
|
|
expect(logger.logger.debug).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
packageFile: 'project.yml',
|
|
err: expect.any(Error),
|
|
}),
|
|
'Parsing XcodeGen project YAML failed',
|
|
);
|
|
});
|
|
|
|
it('returns null for YAML without packages', () => {
|
|
const content = codeBlock`
|
|
name: MyProject
|
|
targets:
|
|
App:
|
|
type: application
|
|
`;
|
|
expect(extractPackageFile(content, 'project.yml')).toBeNull();
|
|
expect(logger.logger.trace).toHaveBeenCalledWith(
|
|
expect.objectContaining({ packageFile: 'project.yml' }),
|
|
'XcodeGen project file has no packages',
|
|
);
|
|
});
|
|
|
|
it('returns null for empty packages', () => {
|
|
const content = codeBlock`
|
|
name: MyProject
|
|
packages: {}
|
|
`;
|
|
expect(extractPackageFile(content, 'project.yml')).toBeNull();
|
|
});
|
|
|
|
it('extracts packages from a realistic project.yml', () => {
|
|
const content = codeBlock`
|
|
name: MyProject
|
|
packages:
|
|
Yams:
|
|
url: https://github.com/jpsim/Yams
|
|
from: 2.0.0
|
|
RxClient:
|
|
path: ../RxClient
|
|
`;
|
|
expect(extractPackageFile(content, 'project.yml')).toEqual({
|
|
deps: [
|
|
{
|
|
depName: 'Yams',
|
|
packageName: 'jpsim/Yams',
|
|
datasource: 'github-tags',
|
|
currentValue: '2.0.0',
|
|
depType: 'from',
|
|
},
|
|
{
|
|
depName: 'RxClient',
|
|
skipReason: 'path-dependency',
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
it('extracts remote package with url and from', () => {
|
|
const content = codeBlock`
|
|
packages:
|
|
Yams:
|
|
url: https://github.com/jpsim/Yams
|
|
from: 2.0.0
|
|
`;
|
|
const result = extractPackageFile(content, 'project.yml');
|
|
expect(result).toEqual({
|
|
deps: [
|
|
{
|
|
depName: 'Yams',
|
|
packageName: 'jpsim/Yams',
|
|
datasource: 'github-tags',
|
|
currentValue: '2.0.0',
|
|
depType: 'from',
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
it('extracts remote package with github shorthand', () => {
|
|
const content = codeBlock`
|
|
packages:
|
|
Ink:
|
|
github: JohnSundell/Ink
|
|
from: 0.5.0
|
|
`;
|
|
const result = extractPackageFile(content, 'project.yml');
|
|
expect(result).toEqual({
|
|
deps: [
|
|
{
|
|
depName: 'Ink',
|
|
packageName: 'JohnSundell/Ink',
|
|
datasource: 'github-tags',
|
|
currentValue: '0.5.0',
|
|
depType: 'from',
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
it('extracts remote package with majorVersion', () => {
|
|
const content = codeBlock`
|
|
packages:
|
|
Alamofire:
|
|
url: https://github.com/Alamofire/Alamofire
|
|
majorVersion: 5.0.0
|
|
`;
|
|
const result = extractPackageFile(content, 'project.yml');
|
|
expect(result).toEqual({
|
|
deps: [
|
|
{
|
|
depName: 'Alamofire',
|
|
packageName: 'Alamofire/Alamofire',
|
|
datasource: 'github-tags',
|
|
currentValue: '5.0.0',
|
|
depType: 'majorVersion',
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
it('extracts remote package with minorVersion', () => {
|
|
const content = codeBlock`
|
|
packages:
|
|
SnapKit:
|
|
url: https://github.com/SnapKit/SnapKit
|
|
minorVersion: 5.6.0
|
|
`;
|
|
const result = extractPackageFile(content, 'project.yml');
|
|
expect(result).toEqual({
|
|
deps: [
|
|
{
|
|
depName: 'SnapKit',
|
|
packageName: 'SnapKit/SnapKit',
|
|
datasource: 'github-tags',
|
|
currentValue: '5.6.0',
|
|
depType: 'minorVersion',
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
it('extracts remote package with exactVersion', () => {
|
|
const content = codeBlock`
|
|
packages:
|
|
SwiftLint:
|
|
url: https://github.com/realm/SwiftLint
|
|
exactVersion: 0.50.3
|
|
`;
|
|
const result = extractPackageFile(content, 'project.yml');
|
|
expect(result).toEqual({
|
|
deps: [
|
|
{
|
|
depName: 'SwiftLint',
|
|
packageName: 'realm/SwiftLint',
|
|
datasource: 'github-tags',
|
|
currentValue: '0.50.3',
|
|
depType: 'exactVersion',
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
it('extracts remote package with version', () => {
|
|
const content = codeBlock`
|
|
packages:
|
|
Moya:
|
|
url: https://github.com/Moya/Moya
|
|
version: 15.0.0
|
|
`;
|
|
const result = extractPackageFile(content, 'project.yml');
|
|
expect(result).toEqual({
|
|
deps: [
|
|
{
|
|
depName: 'Moya',
|
|
packageName: 'Moya/Moya',
|
|
datasource: 'github-tags',
|
|
currentValue: '15.0.0',
|
|
depType: 'version',
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
it('skips local packages with path', () => {
|
|
const content = codeBlock`
|
|
packages:
|
|
RxClient:
|
|
path: ../RxClient
|
|
`;
|
|
const result = extractPackageFile(content, 'project.yml');
|
|
expect(result).toEqual({
|
|
deps: [
|
|
{
|
|
depName: 'RxClient',
|
|
skipReason: 'path-dependency',
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
it('skips packages with branch reference', () => {
|
|
const content = codeBlock`
|
|
packages:
|
|
SwiftPM:
|
|
url: https://github.com/apple/swift-package-manager
|
|
branch: swift-5.0-branch
|
|
`;
|
|
const result = extractPackageFile(content, 'project.yml');
|
|
expect(result).toEqual({
|
|
deps: [
|
|
{
|
|
depName: 'SwiftPM',
|
|
skipReason: 'unversioned-reference',
|
|
currentValue: 'swift-5.0-branch',
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
it('skips packages with revision reference', () => {
|
|
const content = codeBlock`
|
|
packages:
|
|
SomePkg:
|
|
url: https://github.com/example/some-pkg
|
|
revision: abc123
|
|
`;
|
|
const result = extractPackageFile(content, 'project.yml');
|
|
expect(result).toEqual({
|
|
deps: [
|
|
{
|
|
depName: 'SomePkg',
|
|
skipReason: 'unversioned-reference',
|
|
currentValue: 'abc123',
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
it('skips packages with minVersion/maxVersion range', () => {
|
|
const content = codeBlock`
|
|
packages:
|
|
SomePkg:
|
|
url: https://github.com/example/some-pkg
|
|
minVersion: 1.0.0
|
|
maxVersion: 2.0.0
|
|
`;
|
|
const result = extractPackageFile(content, 'project.yml');
|
|
expect(result).toEqual({
|
|
deps: [
|
|
{
|
|
depName: 'SomePkg',
|
|
skipReason: 'unsupported-version',
|
|
currentValue: '1.0.0 - 2.0.0',
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
it('uses gitlab-tags datasource for GitLab URLs', () => {
|
|
const content = codeBlock`
|
|
packages:
|
|
GitLabPkg:
|
|
url: https://gitlab.com/some-group/some-project
|
|
from: 1.0.0
|
|
`;
|
|
const result = extractPackageFile(content, 'project.yml');
|
|
expect(result).toEqual({
|
|
deps: [
|
|
{
|
|
depName: 'GitLabPkg',
|
|
packageName: 'some-group/some-project',
|
|
datasource: 'gitlab-tags',
|
|
currentValue: '1.0.0',
|
|
depType: 'from',
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
it('uses github-tags datasource with registryUrls for self-hosted GHES', () => {
|
|
const content = codeBlock`
|
|
packages:
|
|
Yams:
|
|
url: https://github.example.com/jpsim/Yams
|
|
from: 2.0.0
|
|
`;
|
|
expect(extractPackageFile(content, 'project.yml')).toEqual({
|
|
deps: [
|
|
{
|
|
depName: 'Yams',
|
|
packageName: 'jpsim/Yams',
|
|
datasource: 'github-tags',
|
|
registryUrls: ['https://github.example.com'],
|
|
currentValue: '2.0.0',
|
|
depType: 'from',
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
it('uses gitlab-tags datasource with registryUrls for self-hosted GitLab', () => {
|
|
const content = codeBlock`
|
|
packages:
|
|
GitLabPkg:
|
|
url: https://gitlab.example.com/some-group/some-project
|
|
from: 1.0.0
|
|
`;
|
|
expect(extractPackageFile(content, 'project.yml')).toEqual({
|
|
deps: [
|
|
{
|
|
depName: 'GitLabPkg',
|
|
packageName: 'some-group/some-project',
|
|
datasource: 'gitlab-tags',
|
|
registryUrls: ['https://gitlab.example.com'],
|
|
currentValue: '1.0.0',
|
|
depType: 'from',
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
it('uses git-tags datasource for non-GitHub/GitLab URLs', () => {
|
|
const content = codeBlock`
|
|
packages:
|
|
GenericPkg:
|
|
url: https://example.com/some/repo.git
|
|
from: 3.0.0
|
|
`;
|
|
const result = extractPackageFile(content, 'project.yml');
|
|
expect(result).toEqual({
|
|
deps: [
|
|
{
|
|
depName: 'GenericPkg',
|
|
packageName: 'https://example.com/some/repo.git',
|
|
datasource: 'git-tags',
|
|
currentValue: '3.0.0',
|
|
depType: 'from',
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
it('skips packages without url or github', () => {
|
|
const content = codeBlock`
|
|
packages:
|
|
BadPkg:
|
|
from: 1.0.0
|
|
`;
|
|
const result = extractPackageFile(content, 'project.yml');
|
|
expect(result).toEqual({
|
|
deps: [
|
|
{
|
|
depName: 'BadPkg',
|
|
skipReason: 'invalid-url',
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
it('skips packages without version specifier', () => {
|
|
const content = codeBlock`
|
|
packages:
|
|
NoPkg:
|
|
url: https://github.com/example/no-version
|
|
`;
|
|
const result = extractPackageFile(content, 'project.yml');
|
|
expect(result).toEqual({
|
|
deps: [
|
|
{
|
|
depName: 'NoPkg',
|
|
skipReason: 'unspecified-version',
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
it('extracts multiple packages correctly', () => {
|
|
const content = codeBlock`
|
|
packages:
|
|
Yams:
|
|
url: https://github.com/jpsim/Yams
|
|
from: 2.0.0
|
|
Ink:
|
|
github: JohnSundell/Ink
|
|
from: 0.5.0
|
|
RxClient:
|
|
path: ../RxClient
|
|
`;
|
|
const result = extractPackageFile(content, 'project.yml');
|
|
expect(result).toEqual({
|
|
deps: [
|
|
{
|
|
depName: 'Yams',
|
|
packageName: 'jpsim/Yams',
|
|
datasource: 'github-tags',
|
|
currentValue: '2.0.0',
|
|
depType: 'from',
|
|
},
|
|
{
|
|
depName: 'Ink',
|
|
packageName: 'JohnSundell/Ink',
|
|
datasource: 'github-tags',
|
|
currentValue: '0.5.0',
|
|
depType: 'from',
|
|
},
|
|
{
|
|
depName: 'RxClient',
|
|
skipReason: 'path-dependency',
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
it('handles github URL with .git suffix', () => {
|
|
const content = codeBlock`
|
|
packages:
|
|
Yams:
|
|
url: https://github.com/jpsim/Yams.git
|
|
from: 2.0.0
|
|
`;
|
|
const result = extractPackageFile(content, 'project.yml');
|
|
expect(result).toEqual({
|
|
deps: [
|
|
{
|
|
depName: 'Yams',
|
|
packageName: 'jpsim/Yams',
|
|
datasource: 'github-tags',
|
|
currentValue: '2.0.0',
|
|
depType: 'from',
|
|
},
|
|
],
|
|
});
|
|
});
|
|
|
|
it('handles numeric version values from YAML parsing', () => {
|
|
const content = codeBlock`
|
|
packages:
|
|
SomePkg:
|
|
url: https://github.com/example/some-pkg
|
|
from: 5
|
|
`;
|
|
const result = extractPackageFile(content, 'project.yml');
|
|
expect(result).toEqual({
|
|
deps: [
|
|
{
|
|
depName: 'SomePkg',
|
|
packageName: 'example/some-pkg',
|
|
datasource: 'github-tags',
|
|
currentValue: '5',
|
|
depType: 'from',
|
|
},
|
|
],
|
|
});
|
|
});
|
|
});
|
|
});
|