renovate/lib/modules/manager/terraform/lockfile/index.spec.ts

1241 lines
33 KiB
TypeScript

import { codeBlock } from 'common-tags';
import { mockDeep } from 'jest-mock-extended';
import { join } from 'upath';
import { fs, mocked } from '../../../../../test/util';
import { GlobalConfig } from '../../../../config/global';
import { getPkgReleases } from '../../../datasource';
import type { UpdateArtifactsConfig } from '../../types';
import { updateArtifacts } from '../index';
import { TerraformProviderHash } from './hash';
import { getNewConstraint } from './index';
// auto-mock fs
jest.mock('../../../../util/fs');
jest.mock('./hash');
jest.mock('../../../datasource', () => mockDeep());
const config = {
constraints: {},
};
const adminConfig = {
// `join` fixes Windows CI
localDir: join('/tmp/github/some/repo'),
cacheDir: join('/tmp/renovate/cache'),
containerbaseDir: join('/tmp/renovate/cache/containerbase'),
};
const mockHash = mocked(TerraformProviderHash).createHashes;
const mockGetPkgReleases = getPkgReleases as jest.MockedFunction<
typeof getPkgReleases
>;
describe('modules/manager/terraform/lockfile/index', () => {
beforeEach(() => {
GlobalConfig.set(adminConfig);
});
it('returns null if no .terraform.lock.hcl found', async () => {
expect(
await updateArtifacts({
packageFileName: 'main.tf',
updatedDeps: [{ depName: 'aws' }],
newPackageFileContent: '',
config,
}),
).toBeNull();
});
it('returns null if .terraform.lock.hcl is empty', async () => {
fs.readLocalFile.mockResolvedValueOnce('');
fs.findLocalSiblingOrParent.mockResolvedValueOnce('.terraform.lock.hcl');
expect(
await updateArtifacts({
packageFileName: 'main.tf',
updatedDeps: [{ depName: 'aws' }],
newPackageFileContent: '',
config,
}),
).toBeNull();
});
it('returns null if .terraform.lock.hcl is invalid', async () => {
fs.readLocalFile.mockResolvedValueOnce('empty');
fs.findLocalSiblingOrParent.mockResolvedValueOnce('.terraform.lock.hcl');
expect(
await updateArtifacts({
packageFileName: 'main.tf',
updatedDeps: [{ depName: 'aws' }],
newPackageFileContent: '',
config,
}),
).toBeNull();
});
it('update single dependency with exact constraint and depType provider', async () => {
fs.readLocalFile.mockResolvedValueOnce(codeBlock`
provider "registry.opentofu.org/hashicorp/aws" {
version = "3.0.0"
constraints = "3.0.0"
hashes = [
"aaa",
"bbb",
"ccc",
]
}
`);
fs.findLocalSiblingOrParent.mockResolvedValueOnce('.terraform.lock.hcl');
mockHash.mockResolvedValueOnce([
'h1:lDsKRxDRXPEzA4AxkK4t+lJd3IQIP2UoaplJGjQSp2s=',
'h1:6zB2hX7YIOW26OrKsLJn0uLMnjqbPNxcz9RhlWEuuSY=',
]);
const result = await updateArtifacts({
packageFileName: 'main.tf',
updatedDeps: [
{
depName: 'hashicorp/aws',
packageName: 'hashicorp/aws',
depType: 'provider',
newVersion: '3.36.0',
newValue: '3.36.0',
},
],
newPackageFileContent: '',
config,
});
expect(result).toEqual([
{
file: {
contents: codeBlock`
provider "registry.opentofu.org/hashicorp/aws" {
version = "3.36.0"
constraints = "3.36.0"
hashes = [
"h1:lDsKRxDRXPEzA4AxkK4t+lJd3IQIP2UoaplJGjQSp2s=",
"h1:6zB2hX7YIOW26OrKsLJn0uLMnjqbPNxcz9RhlWEuuSY=",
]
}
`,
path: '.terraform.lock.hcl',
type: 'addition',
},
},
]);
expect(mockHash.mock.calls).toEqual([
['https://registry.opentofu.org', 'hashicorp/aws', '3.36.0'],
]);
});
it('update single dependency with exact constraint and and depType required_provider', async () => {
fs.readLocalFile.mockResolvedValueOnce(codeBlock`
provider "registry.terraform.io/hashicorp/aws" {
version = "3.0.0"
constraints = "3.0.0"
hashes = [
"aaa",
"bbb",
"ccc",
]
}
`);
fs.findLocalSiblingOrParent.mockResolvedValueOnce('.terraform.lock.hcl');
mockHash.mockResolvedValueOnce([
'h1:lDsKRxDRXPEzA4AxkK4t+lJd3IQIP2UoaplJGjQSp2s=',
'h1:6zB2hX7YIOW26OrKsLJn0uLMnjqbPNxcz9RhlWEuuSY=',
]);
const result = await updateArtifacts({
packageFileName: 'main.tf',
updatedDeps: [
{
depName: 'hashicorp/aws',
packageName: 'hashicorp/aws',
depType: 'required_provider',
newVersion: '3.36.0',
newValue: '3.36.0',
},
],
newPackageFileContent: '',
config,
});
expect(result).toEqual([
{
file: {
contents: codeBlock`
provider "registry.terraform.io/hashicorp/aws" {
version = "3.36.0"
constraints = "3.36.0"
hashes = [
"h1:lDsKRxDRXPEzA4AxkK4t+lJd3IQIP2UoaplJGjQSp2s=",
"h1:6zB2hX7YIOW26OrKsLJn0uLMnjqbPNxcz9RhlWEuuSY=",
]
}
`,
path: '.terraform.lock.hcl',
type: 'addition',
},
},
]);
expect(mockHash.mock.calls).toEqual([
['https://registry.terraform.io', 'hashicorp/aws', '3.36.0'],
]);
});
it('does not update dependency with exact constraint during lockfile update', async () => {
fs.readLocalFile.mockResolvedValueOnce(codeBlock`
provider "registry.terraform.io/hashicorp/aws" {
version = "3.0.0"
constraints = "3.0.0"
hashes = [
"aaa",
"bbb",
"ccc",
]
}
`);
fs.findLocalSiblingOrParent.mockResolvedValueOnce('.terraform.lock.hcl');
mockHash.mockResolvedValueOnce([
'h1:lDsKRxDRXPEzA4AxkK4t+lJd3IQIP2UoaplJGjQSp2s=',
'h1:6zB2hX7YIOW26OrKsLJn0uLMnjqbPNxcz9RhlWEuuSY=',
]);
const result = await updateArtifacts({
packageFileName: 'main.tf',
updatedDeps: [
{
depName: 'hashicorp/aws',
packageName: 'hashicorp/aws',
depType: 'required_provider',
currentVersion: '3.0.0',
currentValue: '3.0.0',
newVersion: '3.36.0',
newValue: '3.36.0',
isLockfileUpdate: true,
},
],
newPackageFileContent: '',
config,
});
expect(result).toBeNull();
});
it('does not update dependency with exact constraint within multiple during lockfile update', async () => {
fs.readLocalFile.mockResolvedValueOnce(codeBlock`
provider "registry.terraform.io/hashicorp/aws" {
version = "3.0.0"
constraints = "~> 3.0, 3.0.0"
hashes = [
"aaa",
"bbb",
"ccc",
]
}
`);
fs.findLocalSiblingOrParent.mockResolvedValueOnce('.terraform.lock.hcl');
mockHash.mockResolvedValueOnce([
'h1:lDsKRxDRXPEzA4AxkK4t+lJd3IQIP2UoaplJGjQSp2s=',
'h1:6zB2hX7YIOW26OrKsLJn0uLMnjqbPNxcz9RhlWEuuSY=',
]);
const result = await updateArtifacts({
packageFileName: 'main.tf',
updatedDeps: [
{
depName: 'hashicorp/aws',
packageName: 'hashicorp/aws',
depType: 'required_provider',
currentVersion: '3.0.0',
currentValue: '3.0.0',
newVersion: '3.36.0',
newValue: '3.36.0',
isLockfileUpdate: true,
},
],
newPackageFileContent: '',
config,
});
expect(result).toBeNull();
});
it('do not update dependency with depType module', async () => {
const result = await updateArtifacts({
packageFileName: 'main.tf',
updatedDeps: [
{
depName: 'terraform-aws-modules/vpc/aws',
packageName: 'terraform-aws-modules/vpc/aws',
depType: 'module',
newVersion: '3.36.0',
newValue: '3.36.0',
},
],
newPackageFileContent: '',
config,
});
expect(result).toBeNull();
});
it('update single dependency with range constraint and minor update from private registry', async () => {
fs.readLocalFile.mockResolvedValueOnce(codeBlock`
provider "registry.terraform.io/hashicorp/azurerm" {
version = "2.50.0"
constraints = "~> 2.50"
hashes = [
"a",
"b",
"c",
]
}
`);
fs.findLocalSiblingOrParent.mockResolvedValueOnce('.terraform.lock.hcl');
mockHash.mockResolvedValueOnce([
'h1:lDsKRxDRXPEzA4AxkK4t+lJd3IQIP2UoaplJGjQSp2s=',
'h1:6zB2hX7YIOW26OrKsLJn0uLMnjqbPNxcz9RhlWEuuSY=',
]);
const result = await updateArtifacts({
packageFileName: 'main.tf',
updatedDeps: [
{
depName: 'azurerm',
depType: 'provider',
packageName: 'azurerm',
registryUrls: ['https://registry.example.com'],
newVersion: '2.56.0',
newValue: '~> 2.50',
},
],
newPackageFileContent: '',
config,
});
expect(result).toEqual([
{
file: {
contents: codeBlock`
provider "registry.terraform.io/hashicorp/azurerm" {
version = "2.56.0"
constraints = "~> 2.50"
hashes = [
"h1:lDsKRxDRXPEzA4AxkK4t+lJd3IQIP2UoaplJGjQSp2s=",
"h1:6zB2hX7YIOW26OrKsLJn0uLMnjqbPNxcz9RhlWEuuSY=",
]
}
`,
path: '.terraform.lock.hcl',
type: 'addition',
},
},
]);
expect(mockHash.mock.calls).toEqual([
['https://registry.example.com', 'hashicorp/azurerm', '2.56.0'],
]);
});
it('update single dependency with range constraint and major update', async () => {
fs.readLocalFile.mockResolvedValueOnce(codeBlock`
provider "registry.terraform.io/hashicorp/random" {
version = "2.2.1"
constraints = "~> 2.2"
hashes = [
"a",
"b",
"c",
]
}
`);
fs.findLocalSiblingOrParent.mockResolvedValueOnce('.terraform.lock.hcl');
mockHash.mockResolvedValueOnce([
'h1:lDsKRxDRXPEzA4AxkK4t+lJd3IQIP2UoaplJGjQSp2s=',
'h1:6zB2hX7YIOW26OrKsLJn0uLMnjqbPNxcz9RhlWEuuSY=',
]);
const result = await updateArtifacts({
packageFileName: 'main.tf',
updatedDeps: [
{
depName: 'random',
packageName: 'hashicorp/random',
depType: 'provider',
newVersion: '3.1.0',
newValue: '~> 3.0',
},
],
newPackageFileContent: '',
config,
});
expect(result).toEqual([
{
file: {
contents: codeBlock`
provider "registry.terraform.io/hashicorp/random" {
version = "3.1.0"
constraints = "~> 3.0"
hashes = [
"h1:lDsKRxDRXPEzA4AxkK4t+lJd3IQIP2UoaplJGjQSp2s=",
"h1:6zB2hX7YIOW26OrKsLJn0uLMnjqbPNxcz9RhlWEuuSY=",
]
}
`,
path: '.terraform.lock.hcl',
type: 'addition',
},
},
]);
expect(mockHash.mock.calls).toEqual([
['https://registry.terraform.io', 'hashicorp/random', '3.1.0'],
]);
});
it('update single dependency in subfolder', async () => {
fs.readLocalFile.mockResolvedValueOnce(codeBlock`
provider "registry.terraform.io/hashicorp/random" {
version = "2.2.1"
constraints = "~> 2.2"
hashes = [
"a",
"b",
"c",
]
}
`);
fs.findLocalSiblingOrParent.mockResolvedValueOnce(
'test/.terraform.lock.hcl',
);
mockHash.mockResolvedValueOnce([
'h1:lDsKRxDRXPEzA4AxkK4t+lJd3IQIP2UoaplJGjQSp2s=',
'h1:6zB2hX7YIOW26OrKsLJn0uLMnjqbPNxcz9RhlWEuuSY=',
]);
const result = await updateArtifacts({
packageFileName: 'test/main.tf',
updatedDeps: [
{
depName: 'random',
packageName: 'hashicorp/random',
depType: 'provider',
newVersion: '3.1.0',
newValue: '~> 3.0',
},
],
newPackageFileContent: '',
config,
});
expect(result).toEqual([
{
file: {
contents: codeBlock`
provider "registry.terraform.io/hashicorp/random" {
version = "3.1.0"
constraints = "~> 3.0"
hashes = [
"h1:lDsKRxDRXPEzA4AxkK4t+lJd3IQIP2UoaplJGjQSp2s=",
"h1:6zB2hX7YIOW26OrKsLJn0uLMnjqbPNxcz9RhlWEuuSY=",
]
}
`,
path: 'test/.terraform.lock.hcl',
type: 'addition',
},
},
]);
expect(mockHash.mock.calls).toEqual([
['https://registry.terraform.io', 'hashicorp/random', '3.1.0'],
]);
});
it('update multiple dependencies which are not ordered', async () => {
fs.readLocalFile.mockResolvedValue(codeBlock`
provider "registry.terraform.io/hashicorp/aws" {
version = "3.0.0"
constraints = "~> 3.0"
hashes = [
"a",
"b",
]
}
provider "registry.terraform.io/hashicorp/azurerm" {
version = "2.56.0"
constraints = "~> 2.50"
hashes = [
"c",
"d",
]
}
provider "registry.terraform.io/hashicorp/random" {
version = "3.1.0"
constraints = "~> 3.0"
hashes = [
"e",
"f",
]
}
provider "registry.terraform.io/telmate/proxmox" {
version = "2.7.0"
constraints = "~> 2.7.0"
hashes = [
"g",
"h",
]
}
`);
fs.findLocalSiblingOrParent.mockResolvedValueOnce(
'test/.terraform.lock.hcl',
);
mockHash.mockResolvedValue([
'h1:lDsKRxDRXPEzA4AxkK4t+lJd3IQIP2UoaplJGjQSp2s=',
'h1:6zB2hX7YIOW26OrKsLJn0uLMnjqbPNxcz9RhlWEuuSY=',
]);
const result = await updateArtifacts({
packageFileName: 'test/main.tf',
updatedDeps: [
{
depName: 'aws',
packageName: 'hashicorp/aws',
depType: 'provider',
newVersion: '3.1.0',
newValue: '~> 3.0',
},
{
depName: 'random',
packageName: 'hashicorp/random',
depType: 'provider',
newVersion: '3.1.0',
newValue: '~> 3.0',
},
{
depName: 'azurerm',
packageName: 'hashicorp/azurerm',
depType: 'provider',
newVersion: '2.56.0',
newValue: '~> 2.50',
},
{
depName: 'proxmox',
packageName: 'Telmate/proxmox',
depType: 'provider',
newVersion: '2.7.0',
newValue: '~> 2.7.0',
},
],
newPackageFileContent: '',
config,
});
expect(result).toEqual([
{
file: {
contents: codeBlock`
provider "registry.terraform.io/hashicorp/aws" {
version = "3.1.0"
constraints = "~> 3.0"
hashes = [
"h1:lDsKRxDRXPEzA4AxkK4t+lJd3IQIP2UoaplJGjQSp2s=",
"h1:6zB2hX7YIOW26OrKsLJn0uLMnjqbPNxcz9RhlWEuuSY=",
]
}
provider "registry.terraform.io/hashicorp/azurerm" {
version = "2.56.0"
constraints = "~> 2.50"
hashes = [
"h1:lDsKRxDRXPEzA4AxkK4t+lJd3IQIP2UoaplJGjQSp2s=",
"h1:6zB2hX7YIOW26OrKsLJn0uLMnjqbPNxcz9RhlWEuuSY=",
]
}
provider "registry.terraform.io/hashicorp/random" {
version = "3.1.0"
constraints = "~> 3.0"
hashes = [
"h1:lDsKRxDRXPEzA4AxkK4t+lJd3IQIP2UoaplJGjQSp2s=",
"h1:6zB2hX7YIOW26OrKsLJn0uLMnjqbPNxcz9RhlWEuuSY=",
]
}
provider "registry.terraform.io/telmate/proxmox" {
version = "2.7.0"
constraints = "~> 2.7.0"
hashes = [
"h1:lDsKRxDRXPEzA4AxkK4t+lJd3IQIP2UoaplJGjQSp2s=",
"h1:6zB2hX7YIOW26OrKsLJn0uLMnjqbPNxcz9RhlWEuuSY=",
]
}
`,
path: 'test/.terraform.lock.hcl',
type: 'addition',
},
},
]);
expect(mockHash.mock.calls).toEqual([
['https://registry.terraform.io', 'hashicorp/aws', '3.1.0'],
['https://registry.terraform.io', 'hashicorp/random', '3.1.0'],
['https://registry.terraform.io', 'hashicorp/azurerm', '2.56.0'],
['https://registry.terraform.io', 'telmate/proxmox', '2.7.0'],
]);
});
it('do full lock file maintenance', async () => {
fs.readLocalFile.mockResolvedValueOnce(codeBlock`
provider "registry.terraform.io/hashicorp/aws" {
version = "3.0.0"
constraints = "3.0.0"
hashes = [
"foo",
]
}
provider "registry.terraform.io/hashicorp/azurerm" {
version = "2.50.0"
constraints = "~> 2.50"
hashes = [
"bar",
]
}
provider "registry.terraform.io/hashicorp/random" {
version = "2.2.1"
constraints = "~> 2.2"
hashes = [
"baz",
]
}
`);
fs.findLocalSiblingOrParent.mockResolvedValueOnce('.terraform.lock.hcl');
mockGetPkgReleases
.mockResolvedValueOnce({
// aws
releases: [
{ version: '2.30.0' },
{ version: '3.0.0' },
{ version: '3.36.0' },
],
})
.mockResolvedValueOnce({
// azurerm
releases: [
{ version: '2.50.0' },
{ version: '2.55.0' },
{ version: '2.56.0' },
],
})
.mockResolvedValueOnce({
// random
releases: [
{ version: '2.2.1' },
{ version: '2.2.2' },
{ version: '3.0.0' },
],
});
mockHash.mockResolvedValue([
'h1:lDsKRxDRXPEzA4AxkK4t+lJd3IQIP2UoaplJGjQSp2s=',
'h1:6zB2hX7YIOW26OrKsLJn0uLMnjqbPNxcz9RhlWEuuSY=',
]);
const localConfig: UpdateArtifactsConfig = {
updateType: 'lockFileMaintenance',
...config,
};
const result = await updateArtifacts({
packageFileName: '',
updatedDeps: [],
newPackageFileContent: '',
config: localConfig,
});
expect(result).toEqual([
{
file: {
contents: codeBlock`
provider "registry.terraform.io/hashicorp/aws" {
version = "3.0.0"
constraints = "3.0.0"
hashes = [
"foo",
]
}
provider "registry.terraform.io/hashicorp/azurerm" {
version = "2.56.0"
constraints = "~> 2.50"
hashes = [
"h1:lDsKRxDRXPEzA4AxkK4t+lJd3IQIP2UoaplJGjQSp2s=",
"h1:6zB2hX7YIOW26OrKsLJn0uLMnjqbPNxcz9RhlWEuuSY=",
]
}
provider "registry.terraform.io/hashicorp/random" {
version = "2.2.2"
constraints = "~> 2.2"
hashes = [
"h1:lDsKRxDRXPEzA4AxkK4t+lJd3IQIP2UoaplJGjQSp2s=",
"h1:6zB2hX7YIOW26OrKsLJn0uLMnjqbPNxcz9RhlWEuuSY=",
]
}
`,
path: '.terraform.lock.hcl',
type: 'addition',
},
},
]);
expect(mockHash.mock.calls).toEqual([
['https://registry.terraform.io', 'hashicorp/azurerm', '2.56.0'],
['https://registry.terraform.io', 'hashicorp/random', '2.2.2'],
]);
});
it('do full lock file maintenance with lockfile in subfolder', async () => {
fs.readLocalFile.mockResolvedValueOnce(codeBlock`
provider "registry.terraform.io/hashicorp/aws" {
version = "3.0.0"
constraints = "3.0.0"
hashes = [
"foo",
]
}
provider "registry.terraform.io/hashicorp/azurerm" {
version = "2.50.0"
constraints = "~> 2.50"
hashes = [
"bar",
]
}
provider "registry.terraform.io/hashicorp/random" {
version = "2.2.1"
constraints = "~> 2.2"
hashes = [
"baz",
]
}
`);
fs.findLocalSiblingOrParent.mockResolvedValueOnce(
'subfolder/.terraform.lock.hcl',
);
mockGetPkgReleases
.mockResolvedValueOnce({
// aws
releases: [
{ version: '2.30.0' },
{ version: '3.0.0' },
{ version: '3.36.0' },
],
})
.mockResolvedValueOnce({
// azurerm
releases: [
{ version: '2.50.0' },
{ version: '2.55.0' },
{ version: '2.56.0' },
],
})
.mockResolvedValueOnce(
// random
null,
);
mockHash.mockResolvedValue([
'h1:lDsKRxDRXPEzA4AxkK4t+lJd3IQIP2UoaplJGjQSp2s=',
'h1:6zB2hX7YIOW26OrKsLJn0uLMnjqbPNxcz9RhlWEuuSY=',
]);
const localConfig: UpdateArtifactsConfig = {
updateType: 'lockFileMaintenance',
...config,
};
const result = await updateArtifacts({
packageFileName: '',
updatedDeps: [],
newPackageFileContent: '',
config: localConfig,
});
expect(result).toEqual([
{
file: {
contents: codeBlock`
provider "registry.terraform.io/hashicorp/aws" {
version = "3.0.0"
constraints = "3.0.0"
hashes = [
"foo",
]
}
provider "registry.terraform.io/hashicorp/azurerm" {
version = "2.56.0"
constraints = "~> 2.50"
hashes = [
"h1:lDsKRxDRXPEzA4AxkK4t+lJd3IQIP2UoaplJGjQSp2s=",
"h1:6zB2hX7YIOW26OrKsLJn0uLMnjqbPNxcz9RhlWEuuSY=",
]
}
provider "registry.terraform.io/hashicorp/random" {
version = "2.2.1"
constraints = "~> 2.2"
hashes = [
"baz",
]
}
`,
path: 'subfolder/.terraform.lock.hcl',
type: 'addition',
},
},
]);
expect(mockHash.mock.calls).toMatchInlineSnapshot(
[['https://registry.terraform.io', 'hashicorp/azurerm', '2.56.0']],
`
[
[
"https://registry.terraform.io",
"hashicorp/azurerm",
"2.56.0",
],
]
`,
);
});
it('do full lock file maintenance without necessary changes', async () => {
fs.readLocalFile.mockResolvedValueOnce(codeBlock`
provider "registry.terraform.io/hashicorp/aws" {
version = "3.0.0"
constraints = "3.0.0"
hashes = [
"foo",
]
}
provider "registry.terraform.io/hashicorp/azurerm" {
version = "2.50.0"
constraints = "~> 2.50"
hashes = [
"bar",
]
}
provider "registry.terraform.io/hashicorp/random" {
version = "2.2.1"
constraints = "~> 2.2"
hashes = [
"baz",
]
}
`);
mockGetPkgReleases
.mockResolvedValueOnce({
// aws
releases: [{ version: '2.30.0' }, { version: '3.0.0' }],
})
.mockResolvedValueOnce({
// azurerm
releases: [{ version: '2.50.0' }],
})
.mockResolvedValueOnce({
// random
releases: [{ version: '2.2.1' }],
});
mockHash.mockResolvedValue([
'h1:lDsKRxDRXPEzA4AxkK4t+lJd3IQIP2UoaplJGjQSp2s=',
'h1:6zB2hX7YIOW26OrKsLJn0uLMnjqbPNxcz9RhlWEuuSY=',
]);
const localConfig: UpdateArtifactsConfig = {
updateType: 'lockFileMaintenance',
...config,
};
const result = await updateArtifacts({
packageFileName: '',
updatedDeps: [],
newPackageFileContent: '',
config: localConfig,
});
expect(result).toBeNull();
expect(mockHash.mock.calls).toBeEmptyArray();
});
it('return null if hashing fails', async () => {
fs.readLocalFile.mockResolvedValueOnce(codeBlock`
provider "registry.terraform.io/hashicorp/aws" {
version = "3.0.0"
constraints = "3.0.0"
hashes = [
"foo",
]
}
provider "registry.terraform.io/hashicorp/azurerm" {
version = "2.50.0"
constraints = "~> 2.50"
hashes = [
"bar",
]
}
provider "registry.terraform.io/hashicorp/random" {
version = "2.2.1"
constraints = "~> 2.2"
hashes = [
"baz",
]
}
`);
fs.findLocalSiblingOrParent.mockResolvedValueOnce('.terraform.lock.hcl');
mockGetPkgReleases
.mockResolvedValueOnce({
// aws
releases: [
{ version: '2.30.0' },
{ version: '3.0.0' },
{ version: '3.36.0' },
],
})
.mockResolvedValueOnce({
// azurerm
releases: [
{ version: '2.50.0' },
{ version: '2.55.0' },
{ version: '2.56.0' },
],
})
.mockResolvedValueOnce({
// random
releases: [
{ version: '2.2.1' },
{ version: '2.2.2' },
{ version: '3.0.0' },
],
});
mockHash.mockResolvedValue(null);
const localConfig: UpdateArtifactsConfig = {
updateType: 'lockFileMaintenance',
...config,
};
const result = await updateArtifacts({
packageFileName: '',
updatedDeps: [],
newPackageFileContent: '',
config: localConfig,
});
expect(result).toBeNull();
expect(mockHash.mock.calls).toMatchInlineSnapshot(
[
['https://registry.terraform.io', 'hashicorp/azurerm', '2.56.0'],
['https://registry.terraform.io', 'hashicorp/random', '2.2.2'],
],
`
[
[
"https://registry.terraform.io",
"hashicorp/azurerm",
"2.56.0",
],
[
"https://registry.terraform.io",
"hashicorp/random",
"2.2.2",
],
]
`,
);
});
it('return null if experimental flag is not set', async () => {
const localConfig: UpdateArtifactsConfig = {
updateType: 'lockFileMaintenance',
...config,
};
const result = await updateArtifacts({
packageFileName: '',
updatedDeps: [],
newPackageFileContent: '',
config: localConfig,
});
expect(result).toBeNull();
});
it('preserves constraints when current value and new value are same', async () => {
fs.readLocalFile.mockResolvedValueOnce(codeBlock`
provider "registry.terraform.io/hashicorp/aws" {
version = "3.0.0"
constraints = "~> 3.0.0"
hashes = [
"aaa",
"bbb",
"ccc",
]
}
`);
fs.findLocalSiblingOrParent.mockResolvedValueOnce('.terraform.lock.hcl');
mockHash.mockResolvedValueOnce([
'h1:lDsKRxDRXPEzA4AxkK4t+lJd3IQIP2UoaplJGjQSp2s=',
'h1:6zB2hX7YIOW26OrKsLJn0uLMnjqbPNxcz9RhlWEuuSY=',
]);
const result = await updateArtifacts({
packageFileName: 'main.tf',
updatedDeps: [
{
depName: 'aws',
depType: 'provider',
packageName: 'hashicorp/aws',
registryUrls: ['https://registry.example.com'],
newVersion: '3.36.1',
currentValue: '~> 3.36',
newValue: '~> 3.36',
},
],
newPackageFileContent: '',
config,
});
expect(result).toEqual([
{
file: {
contents: codeBlock`
provider "registry.terraform.io/hashicorp/aws" {
version = "3.36.1"
constraints = "~> 3.0.0"
hashes = [
"h1:lDsKRxDRXPEzA4AxkK4t+lJd3IQIP2UoaplJGjQSp2s=",
"h1:6zB2hX7YIOW26OrKsLJn0uLMnjqbPNxcz9RhlWEuuSY=",
]
}
`,
path: '.terraform.lock.hcl',
type: 'addition',
},
},
]);
expect(mockHash.mock.calls).toEqual([
['https://registry.example.com', 'hashicorp/aws', '3.36.1'],
]);
});
it('replaces current value to new version within a constraint', async () => {
fs.readLocalFile.mockResolvedValueOnce(codeBlock`
provider "registry.terraform.io/hashicorp/aws" {
version = "3.0.0"
constraints = "~> 3.0.0"
hashes = [
"aaa",
"bbb",
"ccc",
]
}
`);
fs.findLocalSiblingOrParent.mockResolvedValueOnce('.terraform.lock.hcl');
mockHash.mockResolvedValueOnce([
'h1:lDsKRxDRXPEzA4AxkK4t+lJd3IQIP2UoaplJGjQSp2s=',
'h1:6zB2hX7YIOW26OrKsLJn0uLMnjqbPNxcz9RhlWEuuSY=',
]);
const result = await updateArtifacts({
packageFileName: 'main.tf',
updatedDeps: [
{
depName: 'aws',
depType: 'provider',
packageName: 'hashicorp/aws',
registryUrls: ['https://registry.example.com'],
newVersion: '3.37.0',
currentValue: '~> 3.0.0',
newValue: '~> 3.37.0',
},
],
newPackageFileContent: '',
config,
});
expect(result).toEqual([
{
file: {
contents: codeBlock`
provider "registry.terraform.io/hashicorp/aws" {
version = "3.37.0"
constraints = "~> 3.37.0"
hashes = [
"h1:lDsKRxDRXPEzA4AxkK4t+lJd3IQIP2UoaplJGjQSp2s=",
"h1:6zB2hX7YIOW26OrKsLJn0uLMnjqbPNxcz9RhlWEuuSY=",
]
}
`,
path: '.terraform.lock.hcl',
type: 'addition',
},
},
]);
expect(mockHash.mock.calls).toEqual([
['https://registry.example.com', 'hashicorp/aws', '3.37.0'],
]);
});
it('replaces current version to new version within a constraint', async () => {
fs.readLocalFile.mockResolvedValueOnce(codeBlock`
provider "registry.terraform.io/hashicorp/aws" {
version = "3.0.0"
constraints = "~> 3.0.0"
hashes = [
"aaa",
"bbb",
"ccc",
]
}
`);
fs.findLocalSiblingOrParent.mockResolvedValueOnce('.terraform.lock.hcl');
mockHash.mockResolvedValueOnce([
'h1:lDsKRxDRXPEzA4AxkK4t+lJd3IQIP2UoaplJGjQSp2s=',
'h1:6zB2hX7YIOW26OrKsLJn0uLMnjqbPNxcz9RhlWEuuSY=',
]);
const result = await updateArtifacts({
packageFileName: 'main.tf',
updatedDeps: [
{
depName: 'aws',
depType: 'provider',
packageName: 'hashicorp/aws',
registryUrls: ['https://registry.example.com'],
newVersion: '3.37.0',
currentVersion: '3.0.0',
},
],
newPackageFileContent: '',
config,
});
expect(result).toEqual([
{
file: {
contents: codeBlock`
provider "registry.terraform.io/hashicorp/aws" {
version = "3.37.0"
constraints = "~> 3.37.0"
hashes = [
"h1:lDsKRxDRXPEzA4AxkK4t+lJd3IQIP2UoaplJGjQSp2s=",
"h1:6zB2hX7YIOW26OrKsLJn0uLMnjqbPNxcz9RhlWEuuSY=",
]
}
`,
path: '.terraform.lock.hcl',
type: 'addition',
},
},
]);
expect(mockHash.mock.calls).toEqual([
['https://registry.example.com', 'hashicorp/aws', '3.37.0'],
]);
});
describe('getNewConstraint', () => {
it('correctly calculate new constraint on pinning', () => {
expect(
getNewConstraint(
{
currentValue: '>= 4.3',
newValue: '5.26.0',
newVersion: '5.26.0',
},
'>= 4.3.0',
),
).toBe('5.26.0');
});
it('update constraint with multiple elements', () => {
expect(
getNewConstraint(
{
currentValue: '2.41.0',
newValue: '2.46.0',
newVersion: '2.46.0',
},
'>= 2.36.0, 2.41.0',
),
).toBe('>= 2.36.0, 2.46.0');
});
it('update constraint when current version is matched multiple times', () => {
expect(
getNewConstraint(
{
currentValue: '2.41.0',
newValue: '2.46.0',
newVersion: '2.46.0',
},
'>= 2.41.0, 2.41.0',
),
).toBe('>= 2.41.0, 2.46.0');
});
it('update constraint when current version is in a complicated constraint', () => {
expect(
getNewConstraint(
{
currentValue: '<= 2.41.0',
newValue: '<= 2.46.0',
newVersion: '2.46.0',
},
'>= 2.41.0, <= 2.41.0, >= 2.0.0',
),
).toBe('>= 2.41.0, <= 2.46.0, >= 2.0.0');
});
it('create constraint with full version', () => {
expect(
getNewConstraint(
{
currentValue: '>= 4.0, <4.12',
newValue: '< 4.21',
newVersion: '4.20.0',
},
'>= 4.0.0, < 4.12.0',
),
).toBe('< 4.21.0');
});
});
});