Skip to content

Commit

Permalink
feat(managers/git-submodules): support updating git-tag versions
Browse files Browse the repository at this point in the history
  • Loading branch information
Shegox committed Jul 9, 2024
1 parent 2695ca9 commit 34ca381
Show file tree
Hide file tree
Showing 8 changed files with 160 additions and 8 deletions.
12 changes: 12 additions & 0 deletions lib/modules/manager/git-submodules/__fixtures__/.gitmodules.8
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[submodule "renovate1"]
path = deps/renovate1
url = https://github.com/renovatebot/renovate.git
branch = v0.0.1
[submodule "renovate2"]
path = deps/renovate2
url = https://github.com/renovatebot/renovate.git
branch = 0.0.1
[submodule "renovate3"]
path = deps/renovate3
url = https://github.com/renovatebot/renovate.git
branch = not-a-semver
44 changes: 40 additions & 4 deletions lib/modules/manager/git-submodules/artifact.spec.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import { fs } from '../../../../test/util';
import { updateArtifacts } from '.';

jest.mock('../../../util/fs');

describe('modules/manager/git-submodules/artifact', () => {
describe('updateArtifacts()', () => {
it('returns empty content', () => {
it('returns empty content', async () => {
expect(
updateArtifacts({
await updateArtifacts({
packageFileName: '',
updatedDeps: [{ depName: '' }],
newPackageFileContent: '',
Expand All @@ -13,9 +16,9 @@ describe('modules/manager/git-submodules/artifact', () => {
).toMatchObject([{ file: { type: 'addition', path: '', contents: '' } }]);
});

it('returns two modules', () => {
it('returns two modules', async () => {
expect(
updateArtifacts({
await updateArtifacts({
packageFileName: '',
updatedDeps: [{ depName: 'renovate' }, { depName: 'renovate-pro' }],
newPackageFileContent: '',
Expand All @@ -26,5 +29,38 @@ describe('modules/manager/git-submodules/artifact', () => {
{ file: { type: 'addition', path: 'renovate-pro', contents: '' } },
]);
});

it('returns updated .gitmodules with new value as branch value', async () => {
const updatedGitModules = `[submodule "renovate"]
path = deps/renovate
url = https://github.com/renovatebot/renovate.git
branch = v0.0.2`;
fs.readLocalFile.mockResolvedValueOnce(updatedGitModules);
expect(
await updateArtifacts({
packageFileName: '',
updatedDeps: [
{
depName: 'renovate',
currentValue: 'v0.0.1',
newValue: 'v0.0.2',
packageFile: '.gitmodules',
},
],
newPackageFileContent: '',
config: {},
}),
).toMatchObject([
{ file: { type: 'addition', path: 'renovate', contents: '' } },
{
file: {
type: 'addition',
path: '.gitmodules',
contents: updatedGitModules,
},
},
]);
expect(fs.readLocalFile).toHaveBeenCalledWith('.gitmodules');
});
});
});
18 changes: 14 additions & 4 deletions lib/modules/manager/git-submodules/artifacts.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
import { logger } from '../../../logger';
import { readLocalFile } from '../../../util/fs';
import type { UpdateArtifact, UpdateArtifactsResult } from '../types';

export default function updateArtifacts({
export default async function updateArtifacts({
updatedDeps,
}: UpdateArtifact): UpdateArtifactsResult[] | null {
}: UpdateArtifact): Promise<UpdateArtifactsResult[] | null> {
const res: UpdateArtifactsResult[] = [];
updatedDeps.forEach((dep) => {
for (const dep of updatedDeps) {
// TODO: types (#22198)
logger.info(`Updating submodule ${dep.depName}`);
res.push({
file: { type: 'addition', path: dep.depName!, contents: '' },
});
});
if (dep.newValue && dep.currentValue !== dep.newValue) {
res.push({
file: {
type: 'addition',
path: dep.packageFile!,
contents: await readLocalFile(dep.packageFile!),
},
});
}
}
return res;
}
30 changes: 30 additions & 0 deletions lib/modules/manager/git-submodules/extract.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ describe('modules/manager/git-submodules/extract', () => {
it('default to master if no branch can be detected', async () => {
const res = await extractPackageFile('', '.gitmodules.2', {});
expect(res?.deps).toHaveLength(1);
expect(res?.deps[0].versioning).toBeUndefined();
expect(res?.deps[0].currentValue).toBe('master');
});

Expand Down Expand Up @@ -336,5 +337,34 @@ describe('modules/manager/git-submodules/extract', () => {
],
});
});

it('given semver version is extracted from branch and versioning is set to semver-coerced', async () => {
const res = await extractPackageFile('', '.gitmodules.8', {});
expect(res).toEqual({
datasource: 'git-refs',
deps: [
{
currentDigest: '4b825dc642cb6eb9a060e54bf8d69288fbee4904',
currentValue: 'v0.0.1',
depName: 'deps/renovate1',
packageName: 'https://github.com/renovatebot/renovate.git',
versioning: 'semver-coerced',
},
{
currentDigest: '4b825dc642cb6eb9a060e54bf8d69288fbee4904',
currentValue: '0.0.1',
depName: 'deps/renovate2',
packageName: 'https://github.com/renovatebot/renovate.git',
versioning: 'semver-coerced',
},
{
currentDigest: '4b825dc642cb6eb9a060e54bf8d69288fbee4904',
currentValue: 'not-a-semver',
packageName: 'https://github.com/renovatebot/renovate.git',
depName: 'deps/renovate3',
},
],
});
});
});
});
4 changes: 4 additions & 0 deletions lib/modules/manager/git-submodules/extract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { simpleGitConfig } from '../../../util/git/config';
import { getHttpUrl } from '../../../util/git/url';
import { regEx } from '../../../util/regex';
import { GitRefsDatasource } from '../../datasource/git-refs';
import * as semVerCoercedVersioning from '../../versioning/semver-coerced';
import type { ExtractConfig, PackageFileContent } from '../types';
import type { GitModule } from './types';

Expand Down Expand Up @@ -138,6 +139,9 @@ export default async function extractPackageFile(
packageName: httpSubModuleUrl,
currentValue,
currentDigest,
...(semVerCoercedVersioning.api.isVersion(currentValue)
? { versioning: semVerCoercedVersioning.id }
: {}),
});
} catch (err) /* istanbul ignore next */ {
logger.warn(
Expand Down
13 changes: 13 additions & 0 deletions lib/modules/manager/git-submodules/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,19 @@ You can customize the per-submodule checks of the git-submodules manager like th
}
```

### Updating to tag values

If you want to update your git submodules to a specific tag, you can set the current tag as `branch` in the `.gitmodules`-files and Renovate will update this version to the latest git tag.

```ini
[submodule "renovate"]
path = deps/renovate
url = https://github.com/renovatebot/renovate.git
branch = v0.0.1
```

Notice: Using this will break the native git submodule update experience using `git submodule update --remote` with an error like `fatal: Unable to find refs/remotes ... revision in submodule path ...`.

### Private Modules Authentication

Before running the `git` commands to update the submodules, Renovate exports `git` [`insteadOf`](https://git-scm.com/docs/git-config#Documentation/git-config.txt-urlltbasegtinsteadOf) directives in environment variables.
Expand Down
39 changes: 39 additions & 0 deletions lib/modules/manager/git-submodules/update.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,45 @@ describe('modules/manager/git-submodules/update', () => {
});
});

it('update gitmodule branch value if value changed', async () => {
gitMock.submoduleUpdate.mockResolvedValue('');
gitMock.checkout.mockResolvedValue('');
upgrade = {
depName: 'renovate',
currentValue: 'v0.0.1',
newValue: 'v0.0.2',
packageFile: '.gitmodules',
};
const update = await updateDependency({
fileContent: '',
upgrade,
});
expect(update).toBe('');
expect(gitMock.subModule).toHaveBeenCalledWith([
'set-branch',
'--branch',
'v0.0.2',
'renovate',
]);
});

it('do not update gitmodule branch value if value not changed', async () => {
gitMock.submoduleUpdate.mockResolvedValue('');
gitMock.checkout.mockResolvedValue('');
upgrade = {
depName: 'renovate',
currentValue: 'main',
newValue: 'main',
packageFile: '.gitmodules',
};
const update = await updateDependency({
fileContent: '',
upgrade,
});
expect(update).toBe('');
expect(gitMock.subModule).toHaveBeenCalledTimes(0);
});

it('returns content on update and uses git environment variables for git-tags/git-refs', async () => {
gitMock.submoduleUpdate.mockResolvedValue('');
gitMock.checkout.mockResolvedValue('');
Expand Down
8 changes: 8 additions & 0 deletions lib/modules/manager/git-submodules/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ export default async function updateDependency({
try {
await git.submoduleUpdate(['--init', upgrade.depName!]);
await submoduleGit.checkout([upgrade.newDigest!]);
if (upgrade.newValue && upgrade.currentValue !== upgrade.newValue) {
await git.subModule([
'set-branch',
'--branch',
upgrade.newValue,
upgrade.depName!,
]);
}
return fileContent;
} catch (err) {
logger.debug({ err }, 'submodule checkout error');
Expand Down

0 comments on commit 34ca381

Please sign in to comment.