Repository: FHIR/sushi (ts)

Issue:
SUSHI fails to load current version of IGs that use "main" branch
If a SUSHI project specifies a dependency with version `current`, and that dependency uses `main` as its default branch in GitHub, SUSHI will fail to load it and log an error like this:
> Failed to load ihe.iti.basicaudit#current: Request failed with status code 404

This is because SUSHI is looking for the `package.tgz` in the root location on the build server (e.g., https://build.fhir.org/ig/IHE/ITI.BasicAudit/package.tgz).  This works when the default branch is `master`, but not when it is `main`.  When it is `main`, the package only exists in the branch-specific location (e.g., http://build.fhir.org/ig/IHE/ITI.BasicAudit/branches/main/package.tgz).

SUSHI should be updated to always look in the branch-specific location.  This should be safe, because:
* Both `master` and `main` are available at their respective branch-specific locations
* SUSHI was recently updated to filter out all non-`master`/non-`main` branches

Pull request:
Always use branch-specific location for current packages
Instead of looking for current packages in the IG's root folder on the build server, look in the branch-specific folder. This is necessary to support IGs that use the main branch, since they don't get copied to the root folder.

To reproduce, create a simple SUSHI project with the following dependency:
```yaml
dependencies:
  ihe.iti.basicaudit: current
```

Using the release version of SUSHI (or master), SUSHI will fail to download the current version and will report a 404 error.  Using this PR branch, SUSHI will succeed.

Fixes #1075

Patch:
diff --git a/src/fhirdefs/load.ts b/src/fhirdefs/load.ts
index 28e7201..5f98cd2 100644
--- a/src/fhirdefs/load.ts
+++ b/src/fhirdefs/load.ts
@@ -77,8 +77,8 @@ export async function loadDependency(
       })[0];
     }
     if (newestPackage?.repo) {
-      const [org, repo] = newestPackage.repo.split('/');
-      const igUrl = `${baseUrl}/${org}/${repo}`;
+      const packagePath = newestPackage.repo.slice(0, -8); // remove "/qa.json" from end
+      const igUrl = `${baseUrl}/${packagePath}`;
       // get the package.manifest.json for the newest version of the package on build.fhir.org
       const manifest = await axiosGet(`${igUrl}/package.manifest.json`);
       let cachedPackageJSON;


Test patch:
diff --git a/test/fhirdefs/load.test.ts b/test/fhirdefs/load.test.ts
index 98ab681..d62726c 100644
--- a/test/fhirdefs/load.test.ts
+++ b/test/fhirdefs/load.test.ts
@@ -174,7 +174,7 @@ describe('#loadDependency()', () => {
           ]
         };
       } else if (
-        uri === 'https://build.fhir.org/ig/HL7/US-Core-R4/package.manifest.json' ||
+        uri === 'https://build.fhir.org/ig/HL7/US-Core-R4/branches/main/package.manifest.json' ||
         (uri.startsWith('https://build.fhir.org/ig/sushi/sushi-test') && uri.endsWith('json'))
       ) {
         return {
@@ -184,8 +184,8 @@ describe('#loadDependency()', () => {
         };
       } else if (
         uri === 'https://packages.fhir.org/sushi-test/0.2.0' ||
-        uri === 'https://build.fhir.org/ig/sushi/sushi-test-old/package.tgz' ||
-        uri === 'https://build.fhir.org/ig/HL7/US-Core-R4/package.tgz' ||
+        uri === 'https://build.fhir.org/ig/sushi/sushi-test-old/branches/master/package.tgz' ||
+        uri === 'https://build.fhir.org/ig/HL7/US-Core-R4/branches/main/package.tgz' ||
         uri === 'https://build.fhir.org/hl7.fhir.r5.core.tgz' ||
         uri === 'https://packages2.fhir.org/packages/hl7.fhir.r4b.core/4.1.0' ||
         uri === 'https://packages.fhir.org/hl7.fhir.r4b.core/4.3.0' ||
@@ -337,7 +337,7 @@ describe('#loadDependency()', () => {
     );
     expect(axiosSpy.mock.calls).toEqual([
       ['https://build.fhir.org/ig/qas.json'],
-      ['https://build.fhir.org/ig/sushi/sushi-test/package.manifest.json']
+      ['https://build.fhir.org/ig/sushi/sushi-test/branches/master/package.manifest.json']
     ]);
   });
 
@@ -346,7 +346,7 @@ describe('#loadDependency()', () => {
       'The package hl7.fhir.us.core.r4#current could not be loaded locally or from the FHIR package registry'
     ); // the package is never actually added to the cache, since tar is mocked
     expectDownloadSequence(
-      'https://build.fhir.org/ig/HL7/US-Core-R4/package.tgz',
+      'https://build.fhir.org/ig/HL7/US-Core-R4/branches/main/package.tgz',
       path.join('foo', 'hl7.fhir.us.core.r4#current'),
       true
     );
@@ -357,7 +357,7 @@ describe('#loadDependency()', () => {
       loadDependency('sushi-test-old', 'current', defs, cachePath)
     ).resolves.toBeTruthy(); // Since tar is mocked, the actual cache is not updated
     expectDownloadSequence(
-      'https://build.fhir.org/ig/sushi/sushi-test-old/package.tgz',
+      'https://build.fhir.org/ig/sushi/sushi-test-old/branches/master/package.tgz',
       path.join(cachePath, 'sushi-test-old#current'),
       true
     );
@@ -369,7 +369,7 @@ describe('#loadDependency()', () => {
       'The package sushi-no-main#current is not available on https://build.fhir.org/ig/qas.json, so no current version can be loaded'
     );
     expectDownloadSequence(
-      'https://build.fhir.org/ig/sushi/sushi-no-main/package.tgz',
+      'https://build.fhir.org/ig/sushi/sushi-no-main/branches/master/package.tgz',
       null,
       true,
       false
@@ -394,7 +394,7 @@ describe('#loadDependency()', () => {
       loadDependency('sushi-test-no-download', 'current', defs, cachePath)
     ).resolves.toEqual(expectedDefs);
     expectDownloadSequence(
-      'https://build.fhir.org/ig/sushi/sushi-test-no-download/package.tgz',
+      'https://build.fhir.org/ig/sushi/sushi-test-no-download/branches/master/package.tgz',
       null,
       true
     );
@@ -423,7 +423,7 @@ describe('#loadDependency()', () => {
         )
     ).toBeTruthy();
     expectDownloadSequence(
-      'https://build.fhir.org/ig/sushi/sushi-test-old/package.tgz',
+      'https://build.fhir.org/ig/sushi/sushi-test-old/branches/master/package.tgz',
       path.join(cachePath, 'sushi-test-old#current'),
       true
     );