Repository: backstage/backstage
Pull request #29985: Legacy Azure URL support ADO
Author: login: fcamgz
Labels: name: area:catalog
description: Related to the Catalog Project Area
Created: 2025-05-16T14:27:16Z | Merged: 2025-05-20T08:20:01Z

## Hey, I just made a Pull Request!

Include hostname endsWith visualstudio.com to enable code search for legacy Azure Url. #29938


#### :heavy_check_mark: Checklist

<!--- Please include the following in your Pull Request when applicable: -->

- [x] A changeset describing the change and affected packages. ([more info](https://github.com/backstage/backstage/blob/master/CONTRIBUTING.md#creating-changesets))
- [ ] Added or updated documentation
- [x] Tests for new functionality and regression tests for bug fixes
- [ ] Screenshots attached (for UI changes)
- [x] All your commits have a `Signed-off-by` line in the message. ([more info](https://github.com/backstage/backstage/blob/master/CONTRIBUTING.md#developer-certificate-of-origin))


Diff:
diff --git a/.changeset/wise-teeth-study.md b/.changeset/wise-teeth-study.md
new file mode 100644
index 00000000000000..0695f983359568
--- /dev/null
+++ b/.changeset/wise-teeth-study.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-catalog-backend-module-azure': patch
+---
+
+visualstudio.com domains are now supported along with dev.azure.com
diff --git a/plugins/catalog-backend-module-azure/src/lib/azure.test.ts b/plugins/catalog-backend-module-azure/src/lib/azure.test.ts
index 4839b625d20618..f033a85113e671 100644
--- a/plugins/catalog-backend-module-azure/src/lib/azure.test.ts
+++ b/plugins/catalog-backend-module-azure/src/lib/azure.test.ts
@@ -392,4 +392,97 @@ describe('azure', () => {
       ),
     ).resolves.toHaveLength(totalCount);
   });
+
+  it('can search using visualstudio.com domain', async () => {
+    const response: CodeSearchResponse = {
+      count: 1,
+      results: [
+        {
+          fileName: 'catalog-info.yaml',
+          path: '/catalog-info.yaml',
+          repository: {
+            name: 'backstage',
+          },
+          project: {
+            name: '*',
+          },
+        },
+      ],
+    };
+
+    server.use(
+      rest.post(
+        `https://almsearch.dev.azure.com/shopify/_apis/search/codesearchresults`,
+        (req, res, ctx) => {
+          expect(req.headers.get('Authorization')).toBe('Basic OkFCQw==');
+          expect(req.body).toEqual({
+            searchText: 'path:/catalog-info.yaml repo:* proj:engineering',
+            $orderBy: [
+              {
+                field: 'path',
+                sortOrder: 'ASC',
+              },
+            ],
+            $skip: 0,
+            $top: 1000,
+          });
+          return res(ctx.json(response));
+        },
+      ),
+    );
+
+    const { credentialsProvider, azureConfig } = createFixture(
+      'backstage.visualstudio.com',
+      'ABC',
+    );
+
+    await expect(
+      codeSearch(
+        credentialsProvider,
+        azureConfig,
+        'shopify',
+        'engineering',
+        '',
+        '/catalog-info.yaml',
+        '',
+      ),
+    ).resolves.toEqual(response.results);
+  });
+
+  it('identifies both dev.azure.com and visualstudio.com domains as cloud', async () => {
+    const domains = [
+      { host: 'dev.azure.com', expectedCloud: true },
+      { host: 'example.visualstudio.com', expectedCloud: true },
+      { host: 'on-premise.company.com', expectedCloud: false },
+    ];
+
+    for (const { host, expectedCloud } of domains) {
+      const mockResponse = { count: 0, results: [] };
+
+      const expectedBaseUrl = expectedCloud
+        ? 'https://almsearch.dev.azure.com'
+        : `https://${host}`;
+
+      server.use(
+        rest.post(
+          `${expectedBaseUrl}/test-org/_apis/search/codesearchresults`,
+          (_req, res, ctx) => {
+            return res(ctx.json(mockResponse));
+          },
+        ),
+      );
+
+      const { credentialsProvider, azureConfig } = createFixture(host, 'TOKEN');
+
+      await codeSearch(
+        credentialsProvider,
+        azureConfig,
+        'test-org',
+        'test-project',
+        '',
+        '/test-path',
+        '',
+      );
+    }
+  });
 });
diff --git a/plugins/catalog-backend-module-azure/src/lib/azure.ts b/plugins/catalog-backend-module-azure/src/lib/azure.ts
index 0b0d89c15bdbcf..7e9bf203eabac4 100644
--- a/plugins/catalog-backend-module-azure/src/lib/azure.ts
+++ b/plugins/catalog-backend-module-azure/src/lib/azure.ts
@@ -46,7 +46,18 @@ interface CodeSearchRequest {
   };
 }
 
-const isCloud = (host: string) => host === 'dev.azure.com';
+const isCloud = (host: string) => {
+  if (host === 'dev.azure.com') {
+    return true;
+  }
+
+  if (host.endsWith('.visualstudio.com')) {
+    return true;
+  }
+
+  return false;
+};
+
 const PAGE_SIZE = 1000;
 
 // codeSearch returns all files that matches the given search path.


Reviews:
user: login: github-advanced-security[bot]
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T14:32:49Z
user: login: awanlin
body: Thanks for your contribution @fcamgz, left a few small comments.

I'm not sure this will fix all the issues noted in #29938, this would address the entity provider aspect but not the issue when running a template. I would need more details to suggest a fix for that as the stack trace in the error isn't pointing me in a direction to suggest.
state: CHANGES_REQUESTED
author_association: COLLABORATOR
submitted_at: 2025-05-16T18:38:05Z
user: login: freben
body: Let's go! The comments seem to have been addressed.
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-20T08:19:52Z

Review comments:
diff_hunk: @@ -46,7 +46,8 @@
   };
 }
 
-const isCloud = (host: string) => host === 'dev.azure.com';
+const isCloud = (host: string) =>
+  host === 'dev.azure.com' || host.endsWith('visualstudio.com');
path: plugins/catalog-backend-module-azure/src/lib/azure.ts
user: login: github-advanced-security[bot]
body: ## Incomplete URL substring sanitization

'[visualstudio.com](1)' may be preceded by an arbitrary host name.

[Show more details](https://github.com/backstage/backstage/security/code-scanning/1061)
created_at: 2025-05-16T14:32:49Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,20 @@
+---
+'@backstage/plugin-catalog-backend-module-azure': minor
path: .changeset/wise-teeth-study.md
user: login: awanlin
body: ```suggestion
'@backstage/plugin-catalog-backend-module-azure': patch
```

As the existing functionality still work this can be set as just a `patch`
created_at: 2025-05-16T18:06:19Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,20 @@
+---
+'@backstage/plugin-catalog-backend-module-azure': minor
+---
+
+isCloud function now also checks if hostname is visualstudio.com or endswith visualstudio.com along with dev.azure.com
+git s
+```diff
+- const isCloud = (host: string) => host === 'dev.azure.com';
++ const isCloud = (host: string) => {
++   if (host === 'dev.azure.com') {
++     return true;
++   }
+
++   if (host === 'visualstudio.com' || host.endsWith('.visualstudio.com')) {
++     return true;
++   }
+
++   return false;
++ };
+```
path: .changeset/wise-teeth-study.md
user: login: awanlin
body: Please remove this, we can always see the diff here in the commit history. 👍 
created_at: 2025-05-16T18:08:33Z
author_association: COLLABORATOR
diff_hunk: @@ -46,7 +46,18 @@ interface CodeSearchRequest {
   };
 }
 
-const isCloud = (host: string) => host === 'dev.azure.com';
+const isCloud = (host: string) => {
+  if (host === 'dev.azure.com') {
+    return true;
+  }
+
+  if (host === 'visualstudio.com' || host.endsWith('.visualstudio.com')) {
path: plugins/catalog-backend-module-azure/src/lib/azure.ts
user: login: awanlin
body: Would this `host === 'visualstudio.com'` ever be `true`? My understanding it's always `{org}.visualstudio.com`. If that's right we should remove the first part of this check.
created_at: 2025-05-16T18:16:32Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,20 @@
+---
+'@backstage/plugin-catalog-backend-module-azure': minor
+---
+
+The `isCloud` function now also checks if hostname is visualstudio.com or ends with .visualstudio.com along with dev.azure.com
path: .changeset/wise-teeth-study.md
user: login: awanlin
body: ```suggestion
```suggestion
visualstudio.com domains are now supported  along with dev.azure.com
```

The changeset will get rolled up in the the changelog, we generally like to keep them short and to the point. 👍 
```
created_at: 2025-05-16T18:36:24Z
author_association: COLLABORATOR

PR comments:
user: login: backstage-goalie[bot]
created_at: 2025-05-16T14:27:53Z
body: ## Changed Packages

| Package Name | Package Path | Changeset Bump | Current Version |
|:-------------|:-------------|:--------------:|:----------------|
| @backstage/plugin-catalog-backend-module-azure | plugins/catalog-backend-module-azure | **patch** | `v0.3.5-next.3` |


<!-- changeset-feedback -->
author_association: CONTRIBUTOR
user: login: awanlin
created_at: 2025-05-16T17:07:32Z
body: HI @fcamgz, I'll give this a closer look in a few hours but for next time it would be really helpful to keep the checklist in place in the description as it helps both you and I make sure things are in a good state. Like the initially missing changeset and the still missing signed DCO. 👍 
author_association: COLLABORATOR
user: login: backstage-goalie[bot]
created_at: 2025-05-16T17:12:28Z
body: 
Thanks for the contribution!
All commits need to be DCO signed before they are reviewed. Please refer to the the [DCO section in CONTRIBUTING.md](https://github.com/backstage/backstage/blob/master/CONTRIBUTING.md#developer-certificate-of-origin) or the [DCO](https://github.com/backstage/backstage/runs/42375884889) status for more info.
<!-- dco -->
author_association: CONTRIBUTOR
user: login: fcamgz
created_at: 2025-05-16T18:37:47Z
body: Thanks for the heads up @awanlin! Apologies for the missing information, I will make sure to add/update them correctly next time upon creating a PR
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-05-20T08:20:38Z
body: Thank you for contributing to Backstage! The changes in this pull request will be part of the `1.39.0` release, scheduled for Tue, 20 May 2025.
author_association: CONTRIBUTOR