Skip to content

Commit 9fe6aac

Browse files
authored
Merge pull request #984 from FirelyTeam/feature/972/973-add-cql-packager-support-for-config-profiles
Feature/972/973 add cql packager support for config profiles
2 parents 6f053e7 + 902e8ea commit 9fe6aac

File tree

108 files changed

+105800
-109
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

108 files changed

+105800
-109
lines changed

Cql-Sdk-All.sln

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CqlSdkExamples", "Examples\
144144
EndProject
145145
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CqlSdkExamplesPreview", "Examples\CqlSdkExamplesPreview\CqlSdkExamplesPreview.csproj", "{A1234567-89AB-CDEF-1234-567890ABCDEF}"
146146
EndProject
147+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Measures.ecqm-content-cms-2025", "Demo\Measures.ecqm-content-cms-2025\Measures.ecqm-content-cms-2025.csproj", "{4125CA3B-A8E7-23C9-4E7B-DAA8D5226E9E}"
148+
EndProject
149+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Measures.ecqm-content-qicore-2025", "Demo\Measures.ecqm-content-qicore-2025\Measures.ecqm-content-qicore-2025.csproj", "{32AF150E-FA7A-DACF-B262-49754A42D628}"
150+
EndProject
147151
Global
148152
GlobalSection(SolutionConfigurationPlatforms) = preSolution
149153
Debug|Any CPU = Debug|Any CPU
@@ -270,6 +274,14 @@ Global
270274
{A1234567-89AB-CDEF-1234-567890ABCDEF}.Debug|Any CPU.Build.0 = Debug|Any CPU
271275
{A1234567-89AB-CDEF-1234-567890ABCDEF}.Release|Any CPU.ActiveCfg = Release|Any CPU
272276
{A1234567-89AB-CDEF-1234-567890ABCDEF}.Release|Any CPU.Build.0 = Release|Any CPU
277+
{4125CA3B-A8E7-23C9-4E7B-DAA8D5226E9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
278+
{4125CA3B-A8E7-23C9-4E7B-DAA8D5226E9E}.Debug|Any CPU.Build.0 = Debug|Any CPU
279+
{4125CA3B-A8E7-23C9-4E7B-DAA8D5226E9E}.Release|Any CPU.ActiveCfg = Release|Any CPU
280+
{4125CA3B-A8E7-23C9-4E7B-DAA8D5226E9E}.Release|Any CPU.Build.0 = Release|Any CPU
281+
{32AF150E-FA7A-DACF-B262-49754A42D628}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
282+
{32AF150E-FA7A-DACF-B262-49754A42D628}.Debug|Any CPU.Build.0 = Debug|Any CPU
283+
{32AF150E-FA7A-DACF-B262-49754A42D628}.Release|Any CPU.ActiveCfg = Release|Any CPU
284+
{32AF150E-FA7A-DACF-B262-49754A42D628}.Release|Any CPU.Build.0 = Release|Any CPU
273285
EndGlobalSection
274286
GlobalSection(SolutionProperties) = preSolution
275287
HideSolutionNode = FALSE
@@ -316,6 +328,8 @@ Global
316328
{BAEF695A-5581-B3EE-B352-CBF447240E55} = {1AF2E4B2-99C5-4678-B926-D224CC83A8F7}
317329
{93532653-75AF-025F-00F7-1B34C75DF1C1} = {14ED22C5-F918-42DB-A301-04B3AED51EBC}
318330
{A1234567-89AB-CDEF-1234-567890ABCDEF} = {14ED22C5-F918-42DB-A301-04B3AED51EBC}
331+
{4125CA3B-A8E7-23C9-4E7B-DAA8D5226E9E} = {85401759-2C64-414D-9882-4DB1EA41C2ED}
332+
{32AF150E-FA7A-DACF-B262-49754A42D628} = {85401759-2C64-414D-9882-4DB1EA41C2ED}
319333
EndGlobalSection
320334
GlobalSection(ExtensibilityGlobals) = postSolution
321335
SolutionGuid = {366252DE-C2FB-4EAC-96EE-22210BD43DE2}

Cql-Sdk-Demos-Examples.slnf

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,10 @@
2222
"Demo\\CLI\\CLI.csproj",
2323
"Demo\\Cql\\Cql.csproj",
2424
"Demo\\Measures.Authoring\\Measures.Authoring.csproj",
25-
"Demo\\Measures.ecqm-content-qicore-2024\\Measures.ecqm-content-qicore-2024.csproj",
2625
"Demo\\Measures.Demo\\Measures.Demo.csproj",
26+
"Demo\\Measures.ecqm-content-cms-2025\\Measures.ecqm-content-cms-2025.csproj",
27+
"Demo\\Measures.ecqm-content-qicore-2024\\Measures.ecqm-content-qicore-2024.csproj",
28+
"Demo\\Measures.ecqm-content-qicore-2025\\Measures.ecqm-content-qicore-2025.csproj",
2729
"Demo\\Test.Measures.Demo\\Test.Measures.Demo.csproj",
2830
"Examples\\CqlSdkExamplesPreview\\CqlSdkExamplesPreview.csproj",
2931
"Examples\\CqlSdkExamples\\CqlSdkExamples.csproj"

Cql/PackagerCLI/Commands.CqlToFhir/CqlToFhirProgram.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using Hl7.Cql.CodeGeneration.NET.Toolkit.Extensions;
1111
using Hl7.Cql.CqlToElm.Toolkit;
1212
using Hl7.Cql.CqlToElm.Toolkit.Extensions;
13+
using Hl7.Cql.Packager.Commands.Global;
1314
using Hl7.Cql.Packager.Commands.Logging;
1415
using Hl7.Cql.Packager.Options;
1516
using Hl7.Cql.Packaging.Toolkit;
@@ -32,10 +33,12 @@ public class CqlToFhirProgram
3233
public static int CommandHandler(
3334
IConsole console,
3435
LoggingCommand loggingCommand,
36+
GlobalCommand globalCommand,
3537
CqlToFhirCommand cqlToFhirCommand) =>
3638
RunProgram<CqlToFhirProgram>(
3739
console,
3840
loggingCommand,
41+
globalCommand,
3942
cqlToFhirCommand.GetConfigMapping,
4043
(_, services) =>
4144
services.AddAndBindOptions<CqlToFhirOptions>());

Cql/PackagerCLI/Commands.ElmToFhir/ElmToFhirProgram.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using Hl7.Cql.CodeGeneration.NET.Toolkit.Extensions;
1111
using Hl7.Cql.CqlToElm.Toolkit;
1212
using Hl7.Cql.CqlToElm.Toolkit.Extensions;
13+
using Hl7.Cql.Packager.Commands.Global;
1314
using Hl7.Cql.Packager.Commands.Logging;
1415
using Hl7.Cql.Packager.Options;
1516
using Hl7.Cql.Packaging.Toolkit;
@@ -152,10 +153,12 @@ public int Run()
152153
internal static int CommandHandler(
153154
IConsole console,
154155
LoggingCommand loggingCommand,
156+
GlobalCommand globalCommand,
155157
ElmToFhirCommand elmToFhirCommand) =>
156158
RunProgram<ElmToFhirProgram>(
157159
console,
158160
loggingCommand,
161+
globalCommand,
159162
elmToFhirCommand.GetConfigMapping,
160163
(_, services) =>
161164
services.AddAndBindOptions<ElmToFhirOptions>());
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
* Copyright(c) 2025, Firely, NCQA and contributors
3+
* See the file CONTRIBUTORS for details.
4+
*
5+
* This file is licensed under the BSD 3-Clause license
6+
* available at https://raw.githubusercontent.com/FirelyTeam/firely-cql-sdk/main/LICENSE
7+
*/
8+
9+
namespace Hl7.Cql.Packager.Commands.Global;
10+
11+
[UsedImplicitly]
12+
public sealed record GlobalCommand(string? Profile)
13+
{
14+
public static readonly Option[] Options =
15+
[
16+
Option<string?>(
17+
"--profile",
18+
"""
19+
The name of the profile to use from the configuration file. e.g. {App}.{Profile}.appsettings.json.
20+
This can be used to load different profiles, for example a name of a library set.
21+
"""
22+
)
23+
];
24+
25+
public string Profile { get; init; } = CalcProfile(Profile);
26+
27+
private static string CalcProfile(string? profile) =>
28+
profile
29+
?? Environment.GetEnvironmentVariable($"{PackagerCliServiceCollectionExtensions.EnvironmentVariablePrefix}_PROFILE")
30+
?? "";
31+
}

Cql/PackagerCLI/DependencyInjection/PackagerCliServiceCollectionExtensions.cs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
* available at https://raw.githubusercontent.com/FirelyTeam/firely-cql-sdk/main/LICENSE
77
*/
88

9+
using System.Collections;
910
using Hl7.Cql.Packager;
1011
using Hl7.Cql.Packager.Commands.Logging;
1112
using Hl7.Cql.Packager.Options;
@@ -17,6 +18,8 @@ namespace Microsoft.Extensions.DependencyInjection;
1718

1819
internal static class PackagerCliServiceCollectionExtensions
1920
{
21+
public const string? EnvironmentVariablePrefix = "CQLPACKAGE";
22+
2023
public static IServiceCollection AddPackagerCliOptions(
2124
this IServiceCollection services) =>
2225
services.AddAndBindOptions<CqlOptions>()
@@ -26,6 +29,7 @@ public static IServiceCollection AddPackagerCliOptions(
2629

2730
public static IConfigurationBuilder AddPackagerCliAppSettings(
2831
this IConfigurationBuilder config,
32+
string profile,
2933
Func<IEnumerable<(object? value, string[] sectionPath)>>? additionalConfiguration = null)
3034
{
3135
var buildConfiguration = typeof(Program).Assembly.GetCustomAttribute<AssemblyConfigurationAttribute>()?.Configuration?.ToLowerInvariant();
@@ -36,15 +40,24 @@ public static IConfigurationBuilder AddPackagerCliAppSettings(
3640
var asmDirName = asmFileInfo.DirectoryName!;
3741
var asmFileNameNoExt = asmFileInfo.Name[..^4]; // Trim ".dll"
3842

39-
config.AddEnvironmentVariables("CQLPACKAGE");
43+
config.AddEnvironmentVariables(EnvironmentVariablePrefix);
4044

4145
IEnumerable<string> files =
4246
[
4347
Path.Combine(asmDirName, $"{asmFileNameNoExt}.appsettings.json"),
4448
Path.Combine(curDirName, $"{asmFileNameNoExt}.appsettings.json"),
4549
Path.Combine(asmDirName, $"{asmFileNameNoExt}.appsettings.{buildConfiguration}.json"),
46-
Path.Combine(curDirName, $"{asmFileNameNoExt}.appsettings.{buildConfiguration}.json")
50+
Path.Combine(curDirName, $"{asmFileNameNoExt}.appsettings.{buildConfiguration}.json"),
4751
];
52+
53+
if (profile.Trim() is { Length: > 0 } p)
54+
{
55+
files = files.Concat(
56+
[
57+
Path.Combine(asmDirName, $"{asmFileNameNoExt}.{p}.appsettings.json"),
58+
Path.Combine(curDirName, $"{asmFileNameNoExt}.{p}.appsettings.json")
59+
]);
60+
}
4861
files = files.Distinct();
4962
foreach (var file in files)
5063
config.AddJsonFile(file, optional: true, reloadOnChange: false);
@@ -54,7 +67,7 @@ public static IConfigurationBuilder AddPackagerCliAppSettings(
5467
?.Invoke()
5568
.Where(ad => ad.value is not null)
5669
.Select(KeyValuePair!)
57-
.ToArray() is { } additionalData)
70+
.ToArray() is { Length: >= 0 } additionalData)
5871
config.Sources.Add(new MemoryConfigurationSource { InitialData = additionalData });
5972

6073
return config;

Cql/PackagerCLI/GlobalMethods.cs

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
* available at https://raw.githubusercontent.com/FirelyTeam/firely-cql-sdk/main/LICENSE
77
*/
88

9+
using Hl7.Cql.Packager.Commands.Global;
910
using Hl7.Cql.Packager.Commands.Logging;
1011
using Hl7.Cql.Packager.Options;
1112

@@ -17,36 +18,39 @@ internal static class GlobalMethods
1718

1819
private static IHostBuilder CreateHostBuilder(
1920
IConsole console,
21+
string profile,
2022
Func<IEnumerable<(object? value, string[] sectionPath)>>? additionalConfiguration = null) =>
2123
Host.CreateDefaultBuilder()
22-
.ConfigureAppConfiguration(
23-
(context, config) =>
24-
config.AddPackagerCliAppSettings(additionalConfiguration))
25-
.ConfigureLogging(
26-
(context, logging) =>
27-
logging.AddPackagerCLiLogging(context.Configuration))
28-
.ConfigureServices(
29-
(context, services) =>
30-
services
31-
.AddPackagerCliOptions()
32-
.AddSingleton<OptionsConsoleDumper>()
33-
.AddSingleton<PdbOptionsValidator>()
34-
.AddSingleton(console))
24+
.ConfigureAppConfiguration((context, config) => config.AddPackagerCliAppSettings(profile, additionalConfiguration))
25+
.ConfigureLogging((context, logging) => logging.AddPackagerCLiLogging(context.Configuration))
26+
.ConfigureServices((context, services) =>
27+
services
28+
.AddPackagerCliOptions()
29+
.AddSingleton<OptionsConsoleDumper>()
30+
.AddSingleton<PdbOptionsValidator>()
31+
.AddSingleton(console))
3532
.UseConsoleLifetime();
3633

3734
internal static int RunProgram<TProgram>(
3835
IConsole console,
3936
LoggingCommand loggingCommand,
37+
GlobalCommand globalCommand,
4038
Func<IEnumerable<(object? value, string[] sectionPath)>>? additionalConfiguration = null,
4139
Action<HostBuilderContext, IServiceCollection>? configureAdditionalServices = null)
4240
where TProgram : class, IProgram =>
43-
CreateHostBuilder(console, () =>
44-
{
45-
var loggingConfig = loggingCommand.GetConfigMapping();
46-
if (additionalConfiguration?.Invoke() is {} additionalConfig)
47-
loggingConfig = loggingConfig.Concat(additionalConfig);
48-
return loggingConfig;
49-
})
50-
.ConfigureServices(configureAdditionalServices ?? delegate { })
51-
.RunProgram<TProgram>();
41+
CreateHostBuilder(
42+
console,
43+
globalCommand.Profile,
44+
() =>
45+
{
46+
IEnumerable<(object? value, string[] sectionPath)> config = [];
47+
config = config.Concat(loggingCommand.GetConfigMapping());
48+
49+
if (additionalConfiguration?.Invoke() is { } additionalConfig)
50+
config = config.Concat(additionalConfig);
51+
52+
return config;
53+
})
54+
.ConfigureServices(configureAdditionalServices ?? delegate { })
55+
.RunProgram<TProgram>();
5256
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"Elm": {
3+
"SkipFiles": [
4+
]
5+
}
6+
}

Cql/PackagerCLI/Hl7.Cql.Packager.appsettings.json

Lines changed: 2 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -23,40 +23,8 @@
2323
"JsonPretty": false, // --json-pretty
2424
"DebugSymbolsFormat": "None", // --debug-symbols : "None", "PortablePdb", "Embedded"
2525
"SkipFiles": [
26-
27-
// These contain a union between incompatible tuples,
28-
// see https://chat.fhir.org/#narrow/stream/179220-cql/topic/Union.20of.20tuples.20with.20convertible.20types
29-
"AntithromboticTherapyByEndofHospitalDay2FHIR.json",
30-
"CMS72FHIRSTKAntithromboticDay2.json",
31-
32-
"IntensiveCareUnitVenousThromboembolismProphylaxisFHIR.json",
33-
"CMS190VTEProphylaxisICUFHIR.json",
34-
35-
36-
"VenousThromboembolismProphylaxisFHIR.json",
37-
"CMS108VTEProphylaxisFHIR.json",
38-
"CMS108FHIRVTEProphylaxis.json",
39-
40-
// These uses choice types, move into a property on such a choice, and then calls an
41-
// overloaded function, so we cannot find out which overload to call.
42-
// A solution is to either a) Introduce choice types in our system instead of object,
43-
// b) introduce runtime resolution, based on the runtime types of the arguments when one of
44-
// the arguments is a choice (=object).
45-
"InitiationandEngagementofSubstanceUseDisorderTreatmentFHIR.json",
46-
"CMS506FHIRSafeUseofOpioids.json",
47-
48-
"PCSBMIScreenAndFollowUpFHIR.json",
49-
"CMS69FHIRPCSBMIScreenAndFollowUp",
50-
51-
// Tuple element value does not have a resultTypeSpecifier
52-
"CADBetaBlockerTherapyPriorMIorLVSDFHIR.json",
53-
54-
"PCSDepressionScreenAndFollowUpFHIR.json",
55-
"CMS2FHIRPCSDepressionScreenAndFollowUp.json",
56-
57-
// Multiple sort fields not supported yet
58-
"HospitalHarmAcuteKidneyInjuryFHIR.json",
59-
"CMS832HHAKIFHIR.json"
26+
// JSON Files that are skipped during the packaging process.
27+
// See the specific profile appsettings e.g. Hl7.Cql.Packager.appsettings.CMSMeasures.json
6028
]
6129
},
6230
"Packaging": {
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"Elm": {
3+
"SkipFiles": [
4+
// Tuple element value does not have a resultTypeSpecifier
5+
"CMS2FHIRPCSDepressionScreenAndFollowUp.json",
6+
7+
// Exception: cannot convert from 'Hl7.Fhir.Model.Id' to 'Hl7.Fhir.Model.Code<Hl7.Fhir.Model.Account.AccountStatus>'
8+
"NHSNHelpers.json",
9+
10+
// Exception: Cannot convert System.Collections.Generic.List`1[Hl7.Fhir.Model.ResourceReference] to Hl7.Fhir.Model.ResourceReference.
11+
"NHSNGlycemicControlHypoglycemiaInitialPopulation.json"
12+
]
13+
}
14+
}

0 commit comments

Comments
 (0)