Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(gomod): Support go work vendor #29216

Merged
merged 11 commits into from
Jun 11, 2024
117 changes: 116 additions & 1 deletion lib/modules/manager/gomod/artifacts.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { codeBlock } from 'common-tags';
import { mockDeep } from 'jest-mock-extended';
import { join } from 'upath';
import { envMock, mockExecAll } from '../../../../test/exec-util';
import {
envMock,
mockExecAll,
mockExecSequence,
} from '../../../../test/exec-util';
import { env, fs, git, mocked, partial } from '../../../../test/util';
import { GlobalConfig } from '../../../config/global';
import type { RepoGlobalConfig } from '../../../config/types';
Expand Down Expand Up @@ -252,6 +256,10 @@ describe('modules/manager/gomod/artifacts', () => {
]);

expect(execSnapshots).toMatchObject([
{
cmd: 'go env GOWORK',
options: { cwd: '/tmp/github/some/repo' },
},
{
cmd: 'go get -d -t ./...',
options: { cwd: '/tmp/github/some/repo' },
Expand All @@ -268,6 +276,113 @@ describe('modules/manager/gomod/artifacts', () => {
cmd: 'go mod tidy',
options: { cwd: '/tmp/github/some/repo' },
},
]);
});

it('supports vendor directory update with go.work', async () => {
const foo = join('vendor/github.com/foo/foo/go.mod');
const bar = join('vendor/github.com/bar/bar/go.mod');
const baz = join('vendor/github.com/baz/baz/go.mod');

fs.readLocalFile.mockResolvedValueOnce('Current go.sum');
fs.readLocalFile.mockResolvedValueOnce('modules.txt content'); // vendor modules filename
fs.readLocalFile.mockResolvedValueOnce('Current go.work'); // go.work
const execSnapshots = mockExecSequence([
// Set the output returned by go env GOWORK
{ stdout: '/tmp/github/some/repo/go.work', stderr: '' },
// Remaining output does not matter
{ stdout: '', stderr: '' },
{ stdout: '', stderr: '' },
{ stdout: '', stderr: '' },
{ stdout: '', stderr: '' },
{ stdout: '', stderr: '' },
]);
git.getRepoStatus.mockResolvedValueOnce(
partial<StatusResult>({
modified: ['go.sum', 'go.work.sum', foo],
not_added: [bar],
deleted: [baz],
}),
);
fs.readLocalFile.mockResolvedValueOnce('New go.sum');
fs.readLocalFile.mockResolvedValueOnce('New go.work.sum');
fs.readLocalFile.mockResolvedValueOnce('Foo go.sum');
fs.readLocalFile.mockResolvedValueOnce('Bar go.sum');
fs.readLocalFile.mockResolvedValueOnce('New go.mod');
const res = await gomod.updateArtifacts({
packageFileName: 'go.mod',
updatedDeps: [],
newPackageFileContent: gomod1,
config: {
...config,
postUpdateOptions: ['gomodTidy'],
},
});
expect(res).toEqual([
{
file: {
contents: 'New go.sum',
path: 'go.sum',
type: 'addition',
},
},
{
file: {
contents: 'New go.work.sum',
path: 'go.work.sum',
type: 'addition',
},
},
{
file: {
contents: 'Foo go.sum',
path: 'vendor/github.com/foo/foo/go.mod',
type: 'addition',
},
},
{
file: {
contents: 'Bar go.sum',
path: 'vendor/github.com/bar/bar/go.mod',
type: 'addition',
},
},
{
file: {
path: 'vendor/github.com/baz/baz/go.mod',
type: 'deletion',
},
},
{
file: {
contents: 'New go.mod',
path: 'go.mod',
type: 'addition',
},
},
]);

expect(execSnapshots).toMatchObject([
{
cmd: 'go env GOWORK',
options: { cwd: '/tmp/github/some/repo' },
},
{
cmd: 'go get -d -t ./...',
options: { cwd: '/tmp/github/some/repo' },
},
{
cmd: 'go mod tidy',
options: { cwd: '/tmp/github/some/repo' },
},
{
cmd: 'go work vendor',
options: { cwd: '/tmp/github/some/repo' },
},
{
cmd: 'go work sync',
options: { cwd: '/tmp/github/some/repo' },
},
{
cmd: 'go mod tidy',
options: { cwd: '/tmp/github/some/repo' },
Expand Down
46 changes: 38 additions & 8 deletions lib/modules/manager/gomod/artifacts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,9 @@ export async function updateArtifacts({
return null;
}

const vendorDir = upath.join(upath.dirname(goModFileName), 'vendor/');
const goModDir = upath.dirname(goModFileName);

const vendorDir = upath.join(goModDir, 'vendor/');
const vendorModulesFileName = upath.join(vendorDir, 'modules.txt');
const useVendor = (await readLocalFile(vendorModulesFileName)) !== null;

Expand Down Expand Up @@ -281,13 +283,29 @@ export async function updateArtifacts({
execCommands.push(`${cmd} ${args}`);
}

const goWorkSumFileName = upath.join(goModDir, 'go.work.sum');
if (useVendor) {
args = 'mod vendor';
logger.debug('go mod tidy command included');
execCommands.push(`${cmd} ${args}`);
if (isGoModTidyRequired) {
args = 'mod tidy' + tidyOpts;
chancez marked this conversation as resolved.
Show resolved Hide resolved
logger.debug('go mod tidy command included');
// If go env GOWORK returns a non-empty path, check that it exists and if
chancez marked this conversation as resolved.
Show resolved Hide resolved
// it does, then use go workspace vendoring.
const goWorkEnv = await exec(`${cmd} env GOWORK`, execOptions);
const goWorkFile = goWorkEnv?.stdout?.trim() || '';
chancez marked this conversation as resolved.
Show resolved Hide resolved
const useGoWork =
goWorkFile.length && (await readLocalFile(goWorkFile)) !== null;
if (!useGoWork) {
logger.debug('No go.work found');
}

if (useGoWork) {
args = 'work vendor';
logger.debug('using go work vendor');
rarkins marked this conversation as resolved.
Show resolved Hide resolved
execCommands.push(`${cmd} ${args}`);

args = 'work sync';
logger.debug('using go work sync');
execCommands.push(`${cmd} ${args}`);
} else {
args = 'mod vendor';
logger.debug('using go mod vendor');
execCommands.push(`${cmd} ${args}`);
}
}
Expand All @@ -304,7 +322,8 @@ export async function updateArtifacts({
const status = await getRepoStatus();
if (
!status.modified.includes(sumFileName) &&
!status.modified.includes(goModFileName)
!status.modified.includes(goModFileName) &&
!status.modified.includes(goWorkSumFileName)
) {
return null;
}
Expand All @@ -321,6 +340,17 @@ export async function updateArtifacts({
});
}

if (status.modified.includes(goWorkSumFileName)) {
logger.debug('Returning updated go.work.sum');
res.push({
file: {
type: 'addition',
path: goWorkSumFileName,
contents: await readLocalFile(goWorkSumFileName),
},
});
}

// Include all the .go file import changes
if (isImportPathUpdateRequired) {
logger.debug('Returning updated go source files for import path changes');
Expand Down