Skip to content

Commit c0ad57d

Browse files
Ensure language server refreshes modules on force refresh (#13278)
Closes #13254 ###### Microsoft Reviewers: [Open in CodeFlow](https://microsoft.github.io/open-pr/?codeflow=https://github.com/Azure/bicep/pull/13278)
1 parent 69631e3 commit c0ad57d

File tree

14 files changed

+182
-85
lines changed

14 files changed

+182
-85
lines changed

src/Bicep.Cli.IntegrationTests/PublishCommandTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -450,11 +450,11 @@ public async Task Publish_BicepModule_WithDescriptionAndDocUri_ShouldPlaceDescri
450450
var registryUri = new Uri($"https://{registryStr}");
451451
var repository = $"test/{moduleName}".ToLowerInvariant();
452452

453-
var (clientFactory, blobClients) = DataSetsExtensions.CreateMockRegistryClients((registryStr, repository));
453+
var (clientFactory, blobClients) = RegistryHelper.CreateMockRegistryClients((registryStr, repository));
454454

455455
var blobClient = blobClients[(registryUri, repository)];
456456

457-
await DataSetsExtensions.PublishModuleToRegistryAsync(clientFactory, "modulename", $"br:example.com/test/{moduleName}:v1", bicepModuleContents, publishSource: false, documentationUri);
457+
await RegistryHelper.PublishModuleToRegistry(clientFactory, "modulename", $"br:example.com/test/{moduleName}:v1", bicepModuleContents, publishSource: false, documentationUri);
458458

459459
var manifest = blobClient.Manifests.Single().Value.ToObjectFromJson<OciManifest>(new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
460460

src/Bicep.Cli.IntegrationTests/PublishProviderCommandTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public async Task Publish_provider_should_succeed()
3030
var repository = $"test/provider";
3131
var version = "0.0.1";
3232

33-
var (clientFactory, blobClientMocks) = DataSetsExtensions.CreateMockRegistryClients((registryStr, repository));
33+
var (clientFactory, blobClientMocks) = RegistryHelper.CreateMockRegistryClients((registryStr, repository));
3434
var mockBlobClient = blobClientMocks[(registryUri, repository)];
3535

3636
var indexPath = Path.Combine(outputDirectory, "index.json");

src/Bicep.Core.IntegrationTests/DynamicAzTypesTests.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ private async Task<ServiceBuilder> GetServices()
3333

3434
var services = new ServiceBuilder()
3535
.WithFeatureOverrides(new(ExtensibilityEnabled: true, DynamicTypeLoadingEnabled: true, CacheRootDirectory: cacheRoot))
36-
.WithContainerRegistryClientFactory(DataSetsExtensions.CreateOciClientForAzProvider());
36+
.WithContainerRegistryClientFactory(RegistryHelper.CreateOciClientForAzProvider());
3737

38-
await DataSetsExtensions.PublishAzProvider(services.Build(), indexJson);
38+
await RegistryHelper.PublishAzProvider(services.Build(), indexJson);
3939

4040
return services;
4141
}
@@ -125,12 +125,12 @@ public async Task Bicep_module_artifact_specified_in_provider_declaration_syntax
125125
{
126126
// ARRANGE
127127
var testArtifact = new ArtifactRegistryAddress(LanguageConstants.BicepPublicMcrRegistry, "bicep/providers/az", "0.2.661");
128-
var clientFactory = DataSetsExtensions.CreateMockRegistryClients((testArtifact.RegistryAddress, testArtifact.RepositoryPath)).factoryMock;
128+
var clientFactory = RegistryHelper.CreateMockRegistryClients((testArtifact.RegistryAddress, testArtifact.RepositoryPath)).factoryMock;
129129
var services = new ServiceBuilder()
130130
.WithFeatureOverrides(new(ExtensibilityEnabled: true, DynamicTypeLoadingEnabled: true))
131131
.WithContainerRegistryClientFactory(clientFactory);
132132

133-
await DataSetsExtensions.PublishModuleToRegistryAsync(
133+
await RegistryHelper.PublishModuleToRegistry(
134134
clientFactory,
135135
moduleName: "az",
136136
target: testArtifact.ToSpecificationString(':'),

src/Bicep.Core.IntegrationTests/ImportTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,11 @@ private async Task<ServiceBuilder> GetServices()
3535

3636
var services = new ServiceBuilder()
3737
.WithFeatureOverrides(new(ExtensibilityEnabled: true, DynamicTypeLoadingEnabled: true))
38-
.WithContainerRegistryClientFactory(DataSetsExtensions.CreateOciClientForAzProvider())
38+
.WithContainerRegistryClientFactory(RegistryHelper.CreateOciClientForAzProvider())
3939
.WithMockFileSystem(fileSystem)
4040
.WithAzResourceTypeLoader(azTypeLoaderLazy.Value);
4141

42-
await DataSetsExtensions.PublishAzProvider(services.Build(), "/types/index.json");
42+
await RegistryHelper.PublishAzProvider(services.Build(), "/types/index.json");
4343

4444
return services;
4545
}

src/Bicep.Core.IntegrationTests/RegistryProviderTests.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public class RegistryProviderTests : TestBase
1717
{
1818
private static ServiceBuilder GetServiceBuilder(IFileSystem fileSystem, string registryHost, string repositoryPath, bool extensibilityEnabledBool, bool providerRegistryBool)
1919
{
20-
var (clientFactory, _) = DataSetsExtensions.CreateMockRegistryClients((registryHost, repositoryPath));
20+
var clientFactory = RegistryHelper.CreateMockRegistryClient(registryHost, repositoryPath);
2121

2222
return new ServiceBuilder()
2323
.WithFeatureOverrides(new(ExtensibilityEnabled: extensibilityEnabledBool, ProviderRegistry: providerRegistryBool))
@@ -38,7 +38,7 @@ public async Task Providers_published_to_a_registry_can_be_compiled()
3838

3939
var services = GetServiceBuilder(fileSystem, registry, repository, true, true);
4040

41-
await DataSetsExtensions.PublishProviderToRegistryAsync(services.Build(), "/types/index.json", $"br:{registry}/{repository}:1.2.3");
41+
await RegistryHelper.PublishProviderToRegistryAsync(services.Build(), "/types/index.json", $"br:{registry}/{repository}:1.2.3");
4242

4343
var result = await CompilationHelper.RestoreAndCompile(services, """
4444
provider 'br:example.azurecr.io/test/provider/[email protected]'
@@ -69,7 +69,7 @@ public async Task Third_party_namespace_errors_with_configuration()
6969

7070
var services = GetServiceBuilder(fileSystem, registry, repository, true, true);
7171

72-
await DataSetsExtensions.PublishProviderToRegistryAsync(services.Build(), "/types/index.json", $"br:{registry}/{repository}:1.2.3");
72+
await RegistryHelper.PublishProviderToRegistryAsync(services.Build(), "/types/index.json", $"br:{registry}/{repository}:1.2.3");
7373

7474
var result = await CompilationHelper.RestoreAndCompile(services, """
7575
provider 'br:example.azurecr.io/test/provider/[email protected]' with {}
@@ -101,7 +101,7 @@ public async Task Third_party_imports_are_enabled_when_feature_is_enabled()
101101

102102
var services = GetServiceBuilder(fileSystem, registry, repository, true, true);
103103

104-
await DataSetsExtensions.PublishProviderToRegistryAsync(services.Build(), "/types/index.json", $"br:{registry}/{repository}:1.2.3");
104+
await RegistryHelper.PublishProviderToRegistryAsync(services.Build(), "/types/index.json", $"br:{registry}/{repository}:1.2.3");
105105

106106
var result = await CompilationHelper.RestoreAndCompile(services, @$"
107107
provider 'br:example.azurecr.io/test/provider/[email protected]'
@@ -147,7 +147,7 @@ public async Task Third_party_imports_are_disabled_unless_feature_is_enabled()
147147

148148
var services = GetServiceBuilder(fileSystem, registry, repository, false, false);
149149

150-
await DataSetsExtensions.PublishProviderToRegistryAsync(services.Build(), "/types/index.json", $"br:{registry}/{repository}:1.2.3");
150+
await RegistryHelper.PublishProviderToRegistryAsync(services.Build(), "/types/index.json", $"br:{registry}/{repository}:1.2.3");
151151

152152
var result = await CompilationHelper.RestoreAndCompile(services, @$"
153153
provider 'br:example.azurecr.io/test/provider/[email protected]'

src/Bicep.Core.IntegrationTests/TypeSystem/Providers/ResourceTypeProviderFactoryTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public async Task ProviderNameAndVersionAreUsedAsCacheKeys()
2929
var repositoryPath = $"test/provider";
3030
var repositoryNames = new[] { "foo", "bar" };
3131

32-
var (clientFactory, _) = DataSetsExtensions.CreateMockRegistryClients(repositoryNames.Select(name => (registry, $"{repositoryPath}/{name}")).ToArray());
32+
var (clientFactory, _) = RegistryHelper.CreateMockRegistryClients(repositoryNames.Select(name => (registry, $"{repositoryPath}/{name}")).ToArray());
3333

3434
var services = new ServiceBuilder()
3535
.WithFeatureOverrides(new(ExtensibilityEnabled: true, ProviderRegistry: true))
@@ -38,7 +38,7 @@ public async Task ProviderNameAndVersionAreUsedAsCacheKeys()
3838
foreach (var repoName in repositoryNames)
3939
{
4040
var indexJsonPath = Path.Combine(outputDirectory, "types", "index.json");
41-
await DataSetsExtensions.PublishProviderToRegistryAsync(services.Build(), indexJsonPath, $"br:{registry}/{repositoryPath}/{repoName}:1.2.3");
41+
await RegistryHelper.PublishProviderToRegistryAsync(services.Build(), indexJsonPath, $"br:{registry}/{repositoryPath}/{repoName}:1.2.3");
4242
}
4343

4444
var result = await CompilationHelper.RestoreAndCompile(

src/Bicep.Core.Samples/DataSetsExtensions.cs

Lines changed: 2 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -76,20 +76,7 @@ public static IContainerRegistryClientFactory CreateMockRegistryClients(Immutabl
7676
clients.Add((targetReference.Registry, targetReference.Repository));
7777
}
7878

79-
return CreateMockRegistryClients(clients.Concat(additionalClients).ToArray()).factoryMock;
80-
}
81-
82-
public static (IContainerRegistryClientFactory factoryMock, ImmutableDictionary<(Uri, string), MockRegistryBlobClient> blobClientMocks) CreateMockRegistryClients(params (string, string)[] clients)
83-
{
84-
var containerRegistryFactoryBuilder = new TestContainerRegistryClientFactoryBuilder();
85-
86-
foreach (var (registryHost, repository) in clients)
87-
{
88-
containerRegistryFactoryBuilder.RegisterMockRepositoryBlobClient(registryHost, repository);
89-
90-
}
91-
92-
return containerRegistryFactoryBuilder.Build();
79+
return RegistryHelper.CreateMockRegistryClients(clients.Concat(additionalClients).ToArray()).factoryMock;
9380
}
9481

9582
public static ITemplateSpecRepositoryFactory CreateEmptyTemplateSpecRepositoryFactory(bool enablePublishSource = false)
@@ -139,56 +126,10 @@ public static async Task PublishModulesToRegistryAsync(ImmutableDictionary<strin
139126
{
140127
foreach (var (moduleName, publishInfo) in registryModules)
141128
{
142-
await PublishModuleToRegistryAsync(clientFactory, moduleName, publishInfo.Metadata.Target, publishInfo.ModuleSource, publishSource, null);
143-
}
144-
}
145-
146-
public static async Task PublishModuleToRegistryAsync(IContainerRegistryClientFactory clientFactory, string moduleName, string target, string moduleSource, bool publishSource, string? documentationUri = null)
147-
{
148-
var featureProviderFactory = BicepTestConstants.CreateFeatureProviderFactory(new FeatureProviderOverrides(PublishSourceEnabled: publishSource));
149-
var dispatcher = ServiceBuilder.Create(s => s.WithDisabledAnalyzersConfiguration()
150-
.AddSingleton(clientFactory)
151-
.AddSingleton(BicepTestConstants.TemplateSpecRepositoryFactory)
152-
.AddSingleton(featureProviderFactory)
153-
).Construct<IModuleDispatcher>();
154-
155-
var targetReference = dispatcher.TryGetArtifactReference(ArtifactType.Module, target, RandomFileUri()).IsSuccess(out var @ref) ? @ref
156-
: throw new InvalidOperationException($"Module '{moduleName}' has an invalid target reference '{target}'. Specify a reference to an OCI artifact.");
157-
158-
var result = CompilationHelper.Compile(moduleSource);
159-
if (result.Template is null)
160-
{
161-
throw new InvalidOperationException($"Module {moduleName} failed to produce a template.");
129+
await RegistryHelper.PublishModuleToRegistry(clientFactory, moduleName, publishInfo.Metadata.Target, publishInfo.ModuleSource, publishSource, null);
162130
}
163-
164-
var features = featureProviderFactory.GetFeatureProvider(result.BicepFile.FileUri);
165-
BinaryData? sourcesStream = publishSource ? BinaryData.FromStream(SourceArchive.PackSourcesIntoStream(result.Compilation.SourceFileGrouping, features.CacheRootDirectory)) : null;
166-
await dispatcher.PublishModule(targetReference, BinaryData.FromString(result.Template.ToString()), sourcesStream, documentationUri);
167-
}
168-
169-
public static async Task PublishProviderToRegistryAsync(IDependencyHelper services, string pathToIndexJson, string target)
170-
{
171-
var dispatcher = services.Construct<IModuleDispatcher>();
172-
var fileSystem = services.Construct<IFileSystem>();
173-
174-
var targetReference = dispatcher.TryGetArtifactReference(ArtifactType.Provider, target, PathHelper.FilePathToFileUrl(pathToIndexJson)).IsSuccess(out var @ref) ? @ref
175-
: throw new InvalidOperationException($"Invalid target reference '{target}'. Specify a reference to an OCI artifact.");
176-
177-
var tgzStream = await TypesV1Archive.GenerateProviderTarStream(fileSystem, pathToIndexJson);
178-
179-
await dispatcher.PublishProvider(targetReference, tgzStream);
180131
}
181132

182133
private static Uri RandomFileUri() => PathHelper.FilePathToFileUrl(Path.GetTempFileName());
183-
184-
public static async Task PublishAzProvider(IDependencyHelper services, string pathToIndexJson)
185-
{
186-
var version = BicepTestConstants.BuiltinAzProviderVersion;
187-
var repository = "bicep/providers/az";
188-
await PublishProviderToRegistryAsync(services, pathToIndexJson, $"br:{LanguageConstants.BicepPublicMcrRegistry}/{repository}:{version}");
189-
}
190-
191-
public static IContainerRegistryClientFactory CreateOciClientForAzProvider()
192-
=> CreateMockRegistryClients((LanguageConstants.BicepPublicMcrRegistry, $"bicep/providers/az")).factoryMock;
193134
}
194135
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
using System.Collections.Immutable;
5+
using System.IO.Abstractions;
6+
using Bicep.Core.FileSystem;
7+
using Bicep.Core.Registry;
8+
using Bicep.Core.Registry.Providers;
9+
using Bicep.Core.SourceCode;
10+
using Bicep.Core.UnitTests.Features;
11+
using Bicep.Core.UnitTests.Registry;
12+
using Microsoft.Extensions.DependencyInjection;
13+
14+
namespace Bicep.Core.UnitTests.Utils;
15+
16+
public static class RegistryHelper
17+
{
18+
public static IContainerRegistryClientFactory CreateMockRegistryClient(string registry, string repository)
19+
{
20+
return new TestContainerRegistryClientFactoryBuilder()
21+
.RegisterMockRepositoryBlobClient(registry, repository)
22+
.Build().clientFactory;
23+
}
24+
25+
public static (IContainerRegistryClientFactory factoryMock, ImmutableDictionary<(Uri, string), MockRegistryBlobClient> blobClientMocks) CreateMockRegistryClients(params (string, string)[] clients)
26+
{
27+
var containerRegistryFactoryBuilder = new TestContainerRegistryClientFactoryBuilder();
28+
29+
foreach (var (registryHost, repository) in clients)
30+
{
31+
containerRegistryFactoryBuilder.RegisterMockRepositoryBlobClient(registryHost, repository);
32+
33+
}
34+
35+
return containerRegistryFactoryBuilder.Build();
36+
}
37+
38+
public static async Task PublishModuleToRegistry(IContainerRegistryClientFactory clientFactory, string moduleName, string target, string moduleSource, bool publishSource, string? documentationUri = null)
39+
{
40+
var featureProviderFactory = BicepTestConstants.CreateFeatureProviderFactory(new FeatureProviderOverrides(PublishSourceEnabled: publishSource));
41+
var dispatcher = ServiceBuilder.Create(s => s.WithDisabledAnalyzersConfiguration()
42+
.AddSingleton(clientFactory)
43+
.AddSingleton(BicepTestConstants.TemplateSpecRepositoryFactory)
44+
.AddSingleton(featureProviderFactory)
45+
).Construct<IModuleDispatcher>();
46+
47+
var targetReference = dispatcher.TryGetArtifactReference(ArtifactType.Module, target, RandomFileUri()).IsSuccess(out var @ref) ? @ref
48+
: throw new InvalidOperationException($"Module '{moduleName}' has an invalid target reference '{target}'. Specify a reference to an OCI artifact.");
49+
50+
var result = CompilationHelper.Compile(moduleSource);
51+
if (result.Template is null)
52+
{
53+
throw new InvalidOperationException($"Module {moduleName} failed to produce a template.");
54+
}
55+
56+
var features = featureProviderFactory.GetFeatureProvider(result.BicepFile.FileUri);
57+
BinaryData? sourcesStream = publishSource ? BinaryData.FromStream(SourceArchive.PackSourcesIntoStream(result.Compilation.SourceFileGrouping, features.CacheRootDirectory)) : null;
58+
await dispatcher.PublishModule(targetReference, BinaryData.FromString(result.Template.ToString()), sourcesStream, documentationUri);
59+
}
60+
61+
public static async Task PublishProviderToRegistryAsync(IDependencyHelper services, string pathToIndexJson, string target)
62+
{
63+
var dispatcher = services.Construct<IModuleDispatcher>();
64+
var fileSystem = services.Construct<IFileSystem>();
65+
66+
var targetReference = dispatcher.TryGetArtifactReference(ArtifactType.Provider, target, PathHelper.FilePathToFileUrl(pathToIndexJson)).IsSuccess(out var @ref) ? @ref
67+
: throw new InvalidOperationException($"Invalid target reference '{target}'. Specify a reference to an OCI artifact.");
68+
69+
var tgzStream = await TypesV1Archive.GenerateProviderTarStream(fileSystem, pathToIndexJson);
70+
71+
await dispatcher.PublishProvider(targetReference, tgzStream);
72+
}
73+
74+
private static Uri RandomFileUri() => PathHelper.FilePathToFileUrl(Path.GetTempFileName());
75+
76+
public static async Task PublishAzProvider(IDependencyHelper services, string pathToIndexJson)
77+
{
78+
var version = BicepTestConstants.BuiltinAzProviderVersion;
79+
var repository = "bicep/providers/az";
80+
await PublishProviderToRegistryAsync(services, pathToIndexJson, $"br:{LanguageConstants.BicepPublicMcrRegistry}/{repository}:{version}");
81+
}
82+
83+
public static IContainerRegistryClientFactory CreateOciClientForAzProvider()
84+
=> CreateMockRegistryClients((LanguageConstants.BicepPublicMcrRegistry, $"bicep/providers/az")).factoryMock;
85+
}

src/Bicep.Core.UnitTests/Utils/TestContainerRegistryClientFactoryBuilder.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@ public class TestContainerRegistryClientFactoryBuilder
1414
{
1515
private readonly ImmutableDictionary<(Uri registryUri, string repository), MockRegistryBlobClient>.Builder clientsBuilder = ImmutableDictionary.CreateBuilder<(Uri registryUri, string repository), MockRegistryBlobClient>();
1616

17-
public void RegisterMockRepositoryBlobClient(string registryHost, string repository)
17+
public TestContainerRegistryClientFactoryBuilder RegisterMockRepositoryBlobClient(string registryHost, string repository)
1818
{
1919
clientsBuilder.TryAdd((new Uri($"https://{registryHost}"), repository), new MockRegistryBlobClient());
20+
21+
return this;
2022
}
2123

2224
public void RegisterMockRepositoryBlobClient(string registryHost, string repository, MockRegistryBlobClient client)

src/Bicep.Core/Workspaces/SourceFileGrouping.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,13 @@ public SourceFileGrouping(IFileResolver fileResolver,
4242

4343
public ImmutableDictionary<ISourceFile, ImmutableHashSet<ISourceFile>> SourceFileParentLookup { get; }
4444

45-
public IEnumerable<ArtifactResolutionInfo> GetArtifactsToRestore()
45+
public IEnumerable<ArtifactResolutionInfo> GetArtifactsToRestore(bool force = false)
4646
{
4747
foreach (var (sourceFile, artifactResults) in FileUriResultByArtifactReference)
4848
{
4949
foreach (var (syntax, result) in artifactResults)
5050
{
51-
if (!result.IsSuccess(out _, out var failure) && failure.RequiresRestore)
51+
if (force || !result.IsSuccess(out _, out var failure) && failure.RequiresRestore)
5252
{
5353
yield return new(syntax, sourceFile);
5454
}

0 commit comments

Comments
 (0)