Skip to content

Commit fabe67e

Browse files
BFD-4847: Replace global node package installations with local package.json (#3254)
1 parent adae9a1 commit fabe67e

21 files changed

Lines changed: 1999 additions & 102 deletions

.github/workflows/build-release.yml

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -291,18 +291,6 @@ jobs:
291291
with:
292292
node-version: "22"
293293

294-
- name: Install Sushi
295-
run: |
296-
npm install -g fsh-sushi
297-
sushi build
298-
echo "Installed + run sushi"
299-
working-directory: apps/bfd-model-idr/sushi
300-
301-
- name: Install fhirpath
302-
run: |
303-
npm install fhirpath
304-
working-directory: apps/bfd-model-idr
305-
306294
- name: Install uv
307295
uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
308296
with:

.github/workflows/ci-pipeline-synthetic.yml

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,9 @@ jobs:
2929
with:
3030
java-version: "25"
3131
distribution: "corretto"
32-
- name: Install dependencies
33-
run: npm install -g fsh-sushi && npm install fhirpath
34-
working-directory: apps/bfd-model-idr
3532
- name: Sync UV in bfd-model-idr
3633
run: uv sync
3734
working-directory: apps/bfd-model-idr
38-
- name: Build sushi
39-
run: |
40-
cd ${{ github.workspace }}/apps/bfd-model-idr
41-
sushi build ./sushi
4235
- name: Generate v3 Data Dictionary
4336
run: uv run gen_dd.py
4437
working-directory: apps/bfd-model-idr

apps/bfd-model-idr/.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,5 @@ sushi/fsh-generated/*
2626
validator_cli.jar
2727
ReferenceTables/source-to-target-mappings
2828
data/*
29-
temp_packages/*
29+
temp_packages/*
30+
node_modules

apps/bfd-model-idr/README.md

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,6 @@ npm --version
2727
brew install npm
2828
```
2929

30-
```sh
31-
npm install -g fsh-sushi fhirpath
32-
```
3330

3431
### Install packages (via uv)
3532

@@ -51,7 +48,7 @@ uv sync
5148
To compile the .fsh files from this folder
5249

5350
```sh
54-
cd sushi && sushi build && cd ..
51+
npm run sushi-build
5552
```
5653

5754
This will generate the StructureDefinition and CodeSystem resources necessary for synthetic data generation. Running compile_resources.py is not necessary to generate synthetic data.

apps/bfd-model-idr/claims_generator.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@
3535
CLM_RLT_COND_SGNTR_MBR,
3636
CLM_VAL,
3737
CNTRCT_PBP_NUM,
38-
PRVDR_HSTRY,
3938
PRAUC,
39+
PRVDR_HSTRY,
4040
GeneratorUtil,
4141
RowAdapter,
4242
adapters_to_dicts,
@@ -788,7 +788,7 @@ def generate(
788788

789789
if sushi:
790790
print("Running sushi build")
791-
_, stderr = run_command(["sushi", "build"], cwd="./sushi")
791+
_, stderr = run_command("npm run sushi-build", cwd=".")
792792
if stderr:
793793
print("SUSHI errors:")
794794
print(stderr)
@@ -828,12 +828,12 @@ def generate(
828828

829829
other_util = OtherGeneratorUtil()
830830

831-
generated_provider_histories, generated_type_1_npis, generated_type_2_npis = other_util.gen_provider_history(amount=14, init_provider_historys=files[PRVDR_HSTRY])
832-
833-
out_tables[PRVDR_HSTRY].extend(
834-
generated_provider_histories
831+
generated_provider_histories, generated_type_1_npis, generated_type_2_npis = (
832+
other_util.gen_provider_history(amount=14, init_provider_historys=files[PRVDR_HSTRY])
835833
)
836834

835+
out_tables[PRVDR_HSTRY].extend(generated_provider_histories)
836+
837837
# This table is special in that its data is mostly static and read from a static file, so we
838838
# don't need to do anything fancy with it
839839
out_tables[CLM_ANSI_SGNTR] = other_util.gen_synthetic_clm_ansi_sgntr()
@@ -1051,7 +1051,7 @@ def generate(
10511051
else idx,
10521052
diagnoses=diagnoses,
10531053
init_clm_line=init_clm_line,
1054-
type_1_npis= generated_type_1_npis
1054+
type_1_npis=generated_type_1_npis,
10551055
)
10561056
adj_clms_tbls[CLM_LINE].append(clm_line)
10571057

apps/bfd-model-idr/compile_resources.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22
import json
33
import subprocess
44
import sys
5-
import requests
65
from pathlib import Path
76

8-
MATCHBOX_SERVER = "http://localhost:8080/matchboxv3"
7+
import requests
8+
9+
MATCHBOX_SERVER = "http://localhost:18080/matchboxv3"
910

1011

1112
def run_command(cmd, cwd=None):
@@ -39,6 +40,7 @@ def get_referenced_maps(compiled_map_path):
3940
print("Error reading map:", e)
4041
return set()
4142

43+
4244
def get_sushi_resources():
4345
try:
4446
sushi_dir = Path(__file__).parent.absolute() / "sushi" / "fsh-generated" / "resources"
@@ -50,6 +52,7 @@ def get_sushi_resources():
5052
print(f"Error getting SUSHI resources: {e}")
5153
return ""
5254

55+
5356
# populate matchbox's tx library
5457
def upload_resources(resource_dir, server_url):
5558
print("Uploading resources to matchbox")
@@ -196,9 +199,10 @@ def main():
196199
script_dir = Path(__file__).parent.absolute()
197200

198201
# Generate Structure Definitions + CodeSystems
199-
if(args.sushi):
202+
if args.sushi:
200203
print("Running sushi build")
201-
stdout, stderr = run_command("sushi build", cwd=script_dir / "sushi")
204+
run_command("npm install", cwd=script_dir)
205+
stdout, stderr = run_command("npm run sushi-build", cwd=script_dir)
202206
print("SUSHI output:")
203207
print(stdout)
204208
if stderr:
@@ -234,14 +238,14 @@ def main():
234238
referenced_maps = get_referenced_maps(compiled_map_path)
235239
map_imports = " ".join([f"-ig {map_file}" for map_file in referenced_maps])
236240

237-
#Augment source file if needed. Currently just for providers.
241+
# Augment source file if needed. Currently just for providers.
238242
(input_file,) = {args.input}
239-
if 'EOB' in input_file:
243+
if "EOB" in input_file:
240244
print("Augmenting input file")
241245
profile_flag = f" {args.profileType}" if args.profileType else ""
242246
augmentation_cmd = f"python augment_sample_resources.py {args.input}{profile_flag}"
243247
stdout, stderr = run_command(augmentation_cmd, cwd=script_dir)
244-
input_file = 'out/temporary-sample.json'
248+
input_file = "out/temporary-sample.json"
245249

246250
print("Executing Transform")
247251
execute_cmd = f"java -jar validator_cli.jar {input_file} -output {args.output} -transform \

apps/bfd-model-idr/docker-compose.yml

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,30 @@ services:
44
container_name: matchbox
55
restart: on-failure
66
ports:
7-
- "8080:8080"
7+
- "18080:8080"
88
depends_on:
99
- matchbox-db
10-
entrypoint: ["java", "-Xms1G", "-Xmx4G", "-XX:+UseG1GC", "-XX:+UseCompressedOops", "-Xss512k", "-Dfhir.settings.path=/config/fhir-settings.json", "-Dspring.config.additional-location=optional:file:/config/application.yaml", "-jar", "/matchbox.jar"]
10+
entrypoint:
11+
[
12+
"java",
13+
"-Xms1G",
14+
"-Xmx4G",
15+
"-XX:+UseG1GC",
16+
"-XX:+UseCompressedOops",
17+
"-Xss512k",
18+
"-Dfhir.settings.path=/config/fhir-settings.json",
19+
"-Dspring.config.additional-location=optional:file:/config/application.yaml",
20+
"-jar",
21+
"/matchbox.jar",
22+
]
1123
healthcheck:
12-
test: ["CMD", "curl", "-f", "http://localhost:8080/matchboxv3/actuator/health"]
24+
test:
25+
[
26+
"CMD",
27+
"curl",
28+
"-f",
29+
"http://localhost:8080/matchboxv3/actuator/health",
30+
]
1331
interval: 5s
1432
timeout: 5s
1533
retries: 30
@@ -34,8 +52,8 @@ services:
3452
ports:
3553
- "15432:5432"
3654
environment:
37-
POSTGRES_DB: 'matchbox'
38-
POSTGRES_USER: 'matchbox'
39-
POSTGRES_PASSWORD: 'matchbox'
55+
POSTGRES_DB: "matchbox"
56+
POSTGRES_USER: "matchbox"
57+
POSTGRES_PASSWORD: "matchbox"
4058
volumes:
4159
- ./data:/var/lib/postgresql/data

apps/bfd-model-idr/gen_dd.py

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,21 @@
4949
dd_df = []
5050
structure_def_names_descriptions = {}
5151

52+
53+
def run_subprocess(args: list[str]) -> subprocess.CompletedProcess[bytes]:
54+
return subprocess.run(
55+
args,
56+
cwd=Path().parent,
57+
check=True,
58+
stdout=subprocess.PIPE,
59+
)
60+
61+
62+
if not Path("./sushi/fsh-generated/resources").exists():
63+
print("Generating sushi files")
64+
run_subprocess(["npm", "install"])
65+
run_subprocess(["npm", "run", "sushi-build"])
66+
5267
for resource_type in sample_sources_by_profile:
5368
with Path(sample_sources_by_profile[resource_type]).open() as file:
5469
sample_resources_by_profile[resource_type] = json.load(file)
@@ -84,10 +99,13 @@
8499
"Pharmacy",
85100
"PriorAuth",
86101
]
102+
103+
87104
for walk_info in os.walk(dd_support_folder):
88105
files = list(filter(lambda file: ".yaml" in file, walk_info[2]))
89106
for file_name in files:
90107
with Path(str(dd_support_folder) + "/" + str(file_name)).open() as file:
108+
print("Generating", file_name)
91109
data = yaml.safe_load(file)
92110
current_resource_type = file_name[0 : len(file_name) - 5]
93111
for entry in data:
@@ -110,16 +128,13 @@
110128
entry["FHIR Resource"] = "AuditEvent"
111129

112130
# This opportunistically populates examples based upon the samples created from executing FML
113-
result = subprocess.run(
131+
result = run_subprocess(
114132
[
115133
"node",
116134
"eval_fhirpath.js",
117135
json.dumps(sample_resources_by_profile[entry["appliesTo"][0]]),
118136
entry["fhirPath"],
119-
],
120-
cwd=os.path.dirname(__file__),
121-
check=True,
122-
stdout=subprocess.PIPE,
137+
]
123138
)
124139
entry["example"] = json.loads(result.stdout)
125140
if "iif" in entry["fhirPath"] or "union" in entry["fhirPath"]:
@@ -134,20 +149,20 @@
134149

135150
# Populate the element names + missing descriptions
136151
if entry["inputPath"] in structure_def_names_descriptions:
137-
entry["Field Name"] = structure_def_names_descriptions[
138-
entry["inputPath"]
139-
]["name"]
152+
entry["Field Name"] = structure_def_names_descriptions[entry["inputPath"]][
153+
"name"
154+
]
140155
if "definition" in structure_def_names_descriptions[entry["inputPath"]]:
141156
entry["Description"] = structure_def_names_descriptions[
142157
entry["inputPath"]
143-
]["definition"]
144-
#nameOverride and definitionOverride only exist when a field is derived IN fml.
158+
]["definition"]
159+
# nameOverride and definitionOverride only exist when a field is derived IN fml.
145160
if "nameOverride" in entry:
146161
entry["Field Name"] = entry["nameOverride"]
147162
entry["Description"] = entry["definitionOverride"]
148163
elif "Description" not in entry or not entry["Description"]:
149164
raise ValueError(
150-
f"Entry {entry.get("inputPath", 'Unknown')} has no definition. "
165+
f"Entry {entry.get('inputPath', 'Unknown')} has no definition. "
151166
)
152167
entry.pop("inputPath")
153168
dd_df.append(entry)
@@ -156,8 +171,7 @@
156171

157172

158173
def replace_str(input_str):
159-
# Yes, the below is intentional.
160-
if input_str == input_str and len(str(input_str)) > 0:
174+
if isinstance(input_str, str) and len(str(input_str)) > 0:
161175
return "https://bluebutton.cms.gov/fhir/CodeSystem/" + str(input_str).replace("_", "-")
162176
return ""
163177

0 commit comments

Comments
 (0)