Repository: FHIR/sushi (ts)

Issue:
Warn when ig.ini does not point to the IG that SUSHI generated
It's usually a mistake when the ig.ini does not point to the IG resource that SUSHI generated; otherwise, why have SUSHI generate the IG resource at all?  So... have SUSHI generate a warning in this case.  Of course, if `FSHOnly` is true, then it's not necessary to check (since SUSHI is not expected to create an IG resource).

Pull request description:
Warn when ig.ini does not point to SUSHI-generated IG JSON
Fixes #1173.

The SUSHI-generated ImplementationGuide resource is intended to be used as input to the IG Publisher. If the `ig.ini` file points to a _different_ resource, log a hard-to-miss warning -- because this is almost always a mistake.

To test, run this branch against a valid example IG. There should be no warnings. Then change the `ig.ini` file so the `ig` points to a different location and run this branch again. Now you should see a warning. Finally, change the `sushi-config.yaml` to contain `FSHOnly: true` and run this branch once more. Now there should no longer be a warning.

Patch:
diff --git a/.tool-versions b/.tool-versions
new file mode 100644
index 0000000..961648f
--- /dev/null
+++ b/.tool-versions
@@ -0,0 +1,1 @@
+nodejs 12.22.12
diff --git a/src/ig/IGExporter.ts b/src/ig/IGExporter.ts
index 452a7ee..038e619 100644
--- a/src/ig/IGExporter.ts
+++ b/src/ig/IGExporter.ts
@@ -2,7 +2,7 @@ import path from 'path';
 import ini from 'ini';
 import sanitize from 'sanitize-filename';
 import { EOL } from 'os';
-import { sortBy, words, pad, padEnd, repeat, cloneDeep } from 'lodash';
+import { sortBy, words, pad, padEnd, repeat, cloneDeep, escapeRegExp } from 'lodash';
 import { titleCase } from 'title-case';
 import {
   ensureDirSync,
@@ -1275,8 +1275,8 @@ export class IGExporter {
     }
     const filePathString = path.join(path.basename(this.inputPath), 'ig.ini');
     if (inputIni.IG) {
+      const igValue = `fsh-generated/resources/ImplementationGuide-${this.config.id}.json`;
       if (inputIni.IG.ig == null) {
-        const igValue = `fsh-generated/resources/ImplementationGuide-${this.config.id}.json`;
         inputIni.IG.ig = igValue;
         logger.error(
           'The ig.ini file must have an "ig" property pointing to the IG file. Please add the following line ' +
@@ -1286,6 +1286,21 @@ export class IGExporter {
             file: inputIniPath
           }
         );
+      } else if (
+        !new RegExp(
+          `(.*[/\\\\])?fsh-generated[/\\\\]resources[/\\\\]ImplementationGuide-${escapeRegExp(
+            this.config.id
+          )}\.json$`
+        ).test(inputIni.IG.ig)
+      ) {
+        logger.warn(
+          '\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! IMPORTANT !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n' +
+            'Your ig.ini file does NOT point to the Implementation Guide resource that SUSHI generates. As a\n' +
+            'result, the IG Publisher will IGNORE the SUSHI-generated ImplementationGuide resource. To fix this,\n' +
+            'please do one of the following:\n' +
+            `- Update your ig.ini file with \'ig = ${igValue}\' (recommended), or\n` +
+            "- Update your sushi-config.yaml file with 'FSHOnly: true' to tell SUSHI NOT to generate the IG resource\n\n"
+        );
       }
       if (inputIni.IG.template == null) {
         const templateValue = 'fhir.base.template';


Test patch:
diff --git a/test/ig/IGExporter.ig-ini.test.ts b/test/ig/IGExporter.ig-ini.test.ts
index 715c2b1..fc0663e 100644
--- a/test/ig/IGExporter.ig-ini.test.ts
+++ b/test/ig/IGExporter.ig-ini.test.ts
@@ -90,6 +90,42 @@ describe('IGExporter', () => {
       expect(loggerSpy.getAllMessages()).toHaveLength(0);
     });
 
+    it('should log a warning when ig property in ig.ini does not point to SUSHI IG JSON', () => {
+      const pkg = new Package(minimalConfig);
+      const igDataPath = path.resolve(__dirname, 'fixtures', 'ig-ini-with-non-generated-ig');
+      const exporter = new IGExporter(pkg, null, igDataPath);
+      exporter.checkIgIni();
+      const igIniPath = path.join(tempOut, 'ig.ini');
+      expect(fs.existsSync(igIniPath)).toBeFalsy();
+      expect(loggerSpy.getAllMessages()).toHaveLength(1);
+      expect(loggerSpy.getLastMessage('warn')).toMatch(
+        'Your ig.ini file does NOT point to the Implementation Guide resource that SUSHI generates.'
+      );
+      expect(loggerSpy.getLastMessage('warn')).toMatch(
+        /'ig = fsh-generated\/resources\/ImplementationGuide-fhir\.us\.minimal\.json'/
+      );
+    });
+
+    it('should not log a warning when ig property in ig.ini is full path to SUSHI IG JSON', () => {
+      const pkg = new Package(minimalConfig);
+      const igDataPath = path.resolve(__dirname, 'fixtures', 'ig-ini-with-full-ig-path');
+      const exporter = new IGExporter(pkg, null, igDataPath);
+      exporter.checkIgIni();
+      const igIniPath = path.join(tempOut, 'ig.ini');
+      expect(fs.existsSync(igIniPath)).toBeFalsy();
+      expect(loggerSpy.getAllMessages()).toHaveLength(0);
+    });
+
+    it('should not log a warning when ig property in ig.ini is full windows path to SUSHI IG JSON', () => {
+      const pkg = new Package(minimalConfig);
+      const igDataPath = path.resolve(__dirname, 'fixtures', 'ig-ini-with-full-win-ig-path');
+      const exporter = new IGExporter(pkg, null, igDataPath);
+      exporter.checkIgIni();
+      const igIniPath = path.join(tempOut, 'ig.ini');
+      expect(fs.existsSync(igIniPath)).toBeFalsy();
+      expect(loggerSpy.getAllMessages()).toHaveLength(0);
+    });
+
     it('should log an error when missing required properties and not copy provided ig.ini when template is not defined', () => {
       const pkg = new Package(minimalConfig);
       const igDataPath = path.resolve(__dirname, 'fixtures', 'ig-ini-missing-properties');
diff --git a/test/ig/fixtures/customized-ig-with-local-template/ig.ini b/test/ig/fixtures/customized-ig-with-local-template/ig.ini
index ee642fe..b1f5a1e 100644
--- a/test/ig/fixtures/customized-ig-with-local-template/ig.ini
+++ b/test/ig/fixtures/customized-ig-with-local-template/ig.ini
@@ -1,3 +1,3 @@
 [IG]
-ig = input/ImplementationGuide-sushi-test.json
+ig = fsh-generated/resources/ImplementationGuide-fhir.us.minimal.json
 template = #local-template
diff --git a/test/ig/fixtures/customized-ig/ig.ini b/test/ig/fixtures/customized-ig/ig.ini
index f434b0c..0698757 100644
--- a/test/ig/fixtures/customized-ig/ig.ini
+++ b/test/ig/fixtures/customized-ig/ig.ini
@@ -1,3 +1,3 @@
 [IG]
-ig = input/ImplementationGuide-sushi-test.json
+ig = fsh-generated/resources/ImplementationGuide-fhir.us.minimal.json
 template = hl7.fhir.template#0.1.0
diff --git a/test/ig/fixtures/ig-ini-with-deprecated-properties/ig.ini b/test/ig/fixtures/ig-ini-with-deprecated-properties/ig.ini
index f522266..ab541ca 100644
--- a/test/ig/fixtures/ig-ini-with-deprecated-properties/ig.ini
+++ b/test/ig/fixtures/ig-ini-with-deprecated-properties/ig.ini
@@ -1,5 +1,5 @@
 [IG]
-ig = input/ImplementationGuide-sushi-test.json
+ig = fsh-generated/resources/ImplementationGuide-fhir.us.minimal.json
 template = hl7.fhir.template#0.1.0
 usage-stats-opt-out = true
 copyrightyear = 2018+
diff --git a/test/ig/fixtures/ig-ini-with-full-ig-path/ig.ini b/test/ig/fixtures/ig-ini-with-full-ig-path/ig.ini
new file mode 100644
index 0000000..d4884fa
--- /dev/null
+++ b/test/ig/fixtures/ig-ini-with-full-ig-path/ig.ini
@@ -0,0 +1,3 @@
+[IG]
+ig = /Users/bob/my-ig/fsh-generated/resources/ImplementationGuide-fhir.us.minimal.json
+template = hl7.fhir.template#0.1.0
diff --git a/test/ig/fixtures/ig-ini-with-full-win-ig-path/ig.ini b/test/ig/fixtures/ig-ini-with-full-win-ig-path/ig.ini
new file mode 100644
index 0000000..ef501e3
--- /dev/null
+++ b/test/ig/fixtures/ig-ini-with-full-win-ig-path/ig.ini
@@ -0,0 +1,3 @@
+[IG]
+ig = C:\Users\bob\Documents\my-ig\fsh-generated\resources\ImplementationGuide-fhir.us.minimal.json
+template = hl7.fhir.template#0.1.0
diff --git a/test/ig/fixtures/ig-ini-with-non-generated-ig/ig.ini b/test/ig/fixtures/ig-ini-with-non-generated-ig/ig.ini
new file mode 100644
index 0000000..a3a28df
--- /dev/null
+++ b/test/ig/fixtures/ig-ini-with-non-generated-ig/ig.ini
@@ -0,0 +1,3 @@
+[IG]
+ig = input/ImplementationGuide-fhir.us.minimal.json
+template = hl7.fhir.template#0.1.0