Skip to content

Azure DevOps #18038

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open

Azure DevOps #18038

wants to merge 6 commits into from

Conversation

michelle0927
Copy link
Collaborator

@michelle0927 michelle0927 commented Aug 13, 2025

Resolves #17986

Summary by CodeRabbit

  • New Features
    • Added dual-token authentication support (OAuth and Personal Access Token) and made account listing use OAuth.
  • Improvements
    • Better validation and clearer error messaging when a Personal Access Token is required but missing.
  • Chores
    • Bumped component package version to 0.1.0 and updated platform dependency to a newer major release.
    • Incremented source module version.
  • Refactor
    • Minor formatting and internal call structure cleanup with no behavioral changes.

Copy link

vercel bot commented Aug 13, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

3 Skipped Deployments
Project Deployment Preview Comments Updated (UTC)
docs-v2 Ignored Ignored Aug 19, 2025 3:38pm
pipedream-docs Ignored Ignored Aug 19, 2025 3:38pm
pipedream-docs-redirect-do-not-edit Ignored Ignored Aug 19, 2025 3:38pm

Copy link
Contributor

coderabbitai bot commented Aug 13, 2025

Walkthrough

Introduces dual-token authorization in the Azure DevOps app: requests can use OAuth or a Personal Access Token (PAT). Adds _personalAccessToken(), changes _headers(useOAuth) and _makeRequest(args) to accept useOAuth, and updates listAccounts to request OAuth. Bumps package version and dependency; minor source formatting change.

Changes

Cohort / File(s) Summary
Auth token selection & request flow
components/azure_devops/azure_devops.app.mjs
Added _personalAccessToken(); changed _headers()_headers(useOAuth) to select token via useOAuth ? _oauthAccessToken() : _personalAccessToken() and throw ConfigurationError if PAT missing; _makeRequest(args = {}) now destructures useOAuth and forwards it; listAccounts calls _makeRequest({ useOAuth: true }).
Package metadata
components/azure_devops/package.json
Bumped version 0.0.4 → 0.1.0; updated dependencies["@pipedream/platform"] ^1.2.1 → ^3.1.0.
Source minor update
components/azure_devops/sources/new-event/new-event.mjs
Bumped exported version 0.0.2 → 0.0.3; reformatted createSubscription call (no semantic change).

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant Client as Pipedream Component
  participant App as AzureDevOpsApp
  participant Req as _makeRequest({ useOAuth })
  participant H as _headers(useOAuth)
  participant ADO as Azure DevOps API

  User->>Client: Trigger action
  Client->>App: call API method(args)
  App->>Req: _makeRequest({ useOAuth })
  Req->>H: _headers(useOAuth)
  alt useOAuth = true
    H->>App: _oauthAccessToken()
  else useOAuth = false
    H->>App: _personalAccessToken()
  end
  H-->>Req: Authorization header
  Req->>ADO: HTTP request with header
  ADO-->>Req: Response
  Req-->>App: Data
  App-->>Client: Result
Loading
sequenceDiagram
  autonumber
  participant App as AzureDevOpsApp
  participant Req as _makeRequest({ useOAuth:true })
  participant H as _headers(true)
  participant OAuth as _oauthAccessToken()
  participant ADO as Azure DevOps Accounts API

  App->>Req: listAccounts({ useOAuth:true })
  Req->>H: build headers (useOAuth:true)
  H->>OAuth: fetch OAuth access token
  OAuth-->>H: token
  H-->>Req: Authorization: Bearer <token>
  Req->>ADO: GET /accounts
  ADO-->>Req: Accounts list
  Req-->>App: Data
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Assessment against linked issues

Objective Addressed Explanation
Fix “Bad option response for prop type eventType” in Azure DevOps app (#17986) The change ensures OAuth usage for account listing and adds PAT support, but does not explicitly modify eventType options fetching or its request path; impact on the reported error is unclear.

Assessment against linked issues: Out-of-scope changes

Code Change Explanation
Dependency upgrade to @pipedream/platform ^3.1.0 (components/azure_devops/package.json) Dependency bump not referenced in issue objectives; unrelated to eventType options behavior.
Package version bump 0.0.4 → 0.1.0 (components/azure_devops/package.json) Release/version change not required by the bug report and doesn't address eventType option handling.

I twitch my whiskers at headers true,
Two tokens, one path — which will you choose?
I bound through lists with OAuth light,
PAT waits patient in the moonlight.
A hop, a bump—new versions delight. 🐇✨

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch issue-17986

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@michelle0927
Copy link
Collaborator Author

@vunguyenhung
I think the problem may be that Microsoft has deprecated Oauth authentication for DevOps (https://learn.microsoft.com/en-us/azure/devops/integrate/get-started/authentication/oauth?view=azure-devops#azure-devops-oauth-deprecated).

The docs here (https://learn.microsoft.com/en-us/rest/api/azure/devops/hooks/publishers/list-event-types?view=azure-devops-rest-5.0&tabs=HTTP) say to use a "personal access token".

I tested and created this PR which is a work in progress, but shows that using a personal access token does work to get event types, create webhooks, and delete webhooks. Strangely, the endpoint to get organizations still seems to need the oauth_access_token.

The first link I pasted above recommends migrating to Microsoft Entra ID OAuth. I think we should either do that or add a personal_access_token field to the $auth for Azure Devops.

@vunguyenhung
Copy link
Collaborator

Hi @michelle0927, thank you for your information.

Here's the next steps:

  1. I've created a new ticket here to add the new app for Azure DevOps using Microsoft Entra ID OAuth: [APP] Azure DevOps (Microsoft Entra ID OAuth) #18106
  2. I've added the personal access token prop to the app (named personal_access_token), you can use this property in your action code
image 3. In the future, we can shift the Azure DevOps app to use Personal Access Token only, so that user will have 2 options for authentication

@michelle0927 michelle0927 marked this pull request as ready for review August 19, 2025 15:22
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (4)
components/azure_devops/azure_devops.app.mjs (4)

31-37: Use Bearer for OAuth and Basic for PAT (align with Azure DevOps auth model)

Azure DevOps REST APIs expect:

  • OAuth: Authorization: Bearer <access_token>
  • PAT: Authorization: Basic base64(:) (username can be empty)

Currently both paths use Basic. Recommend switching to Bearer for OAuth and using the empty-username pattern for PAT. Also add explicit checks to fail fast with helpful errors when tokens are missing.

Apply:

-    _headers(useOAuth) {
-      const basicAuth = Buffer.from(`${this._oauthUid()}:${useOAuth
-        ? this._oauthAccessToken()
-        : this._personalAccessToken()}`).toString("base64");
-      return {
-        Authorization: `Basic ${basicAuth}`,
-      };
-    },
+    _headers(useOAuth) {
+      if (useOAuth) {
+        const token = this._oauthAccessToken();
+        if (!token) {
+          throw new Error("Azure DevOps OAuth access token is missing. Please reconnect your Azure DevOps account.");
+        }
+        return { Authorization: `Bearer ${token}` };
+      }
+      const pat = this._personalAccessToken();
+      if (!pat) {
+        throw new Error("Azure DevOps Personal Access Token is required for this operation. Add it to your Azure DevOps connection.");
+      }
+      // Basic auth with PAT: username can be blank
+      const basicAuth = Buffer.from(`:${pat}`).toString("base64");
+      return { Authorization: `Basic ${basicAuth}` };
+    },

Optionally, confirm listAccounts still succeeds with Bearer headers against vssps.


53-59: Prevent accidental header override; merge user headers with auth header

Spreading otherArgs after headers allows a caller to unintentionally drop Authorization. Merge instead and still allow explicit override.

-      const config = {
-        url: url || `${this._baseUrl()}${path}`,
-        headers: this._headers(useOAuth),
-        ...otherArgs,
-      };
+      const {
+        headers: userHeaders,
+        ...restArgs
+      } = otherArgs;
+      const config = {
+        url: url || `${this._baseUrl()}${path}`,
+        headers: {
+          ...this._headers(useOAuth),
+          ...(userHeaders || {}),
+        },
+        ...restArgs,
+      };

69-72: Validate OAuth presence for listAccounts and provide actionable error

If users haven’t connected OAuth (but added only a PAT), this will fail in a non-obvious way. Add a guard with a clear message.

-      const { value } = await this._makeRequest({
+      if (!this._oauthUid() || !this._oauthAccessToken()) {
+        throw new Error("Listing organizations requires OAuth. Connect Azure DevOps via Microsoft Entra ID OAuth in the app settings.");
+      }
+      const { value } = await this._makeRequest({
         url: `https://app.vssps.visualstudio.com/_apis/accounts?memberId=${this._oauthUid()}`,
         useOAuth: true,
         ...args,
       });

Follow-up: Consider documenting which operations require PAT vs OAuth in the app description to reduce support pings.


45-47: Expose PAT accessor is fine; ensure friendly failure at call sites

Getter looks good. The more important part is surfacing a clear error if PAT is missing when required (addressed in the _headers() suggestion). No change needed here if you adopt that guard.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 041fec0 and a21b351.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (3)
  • components/azure_devops/azure_devops.app.mjs (3 hunks)
  • components/azure_devops/package.json (2 hunks)
  • components/azure_devops/sources/new-event/new-event.mjs (2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2024-12-12T19:23:09.039Z
Learnt from: jcortes
PR: PipedreamHQ/pipedream#14935
File: components/sailpoint/package.json:15-18
Timestamp: 2024-12-12T19:23:09.039Z
Learning: When developing Pipedream components, do not add built-in Node.js modules like `fs` to `package.json` dependencies, as they are native modules provided by the Node.js runtime.

Applied to files:

  • components/azure_devops/package.json
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Verify TypeScript components
  • GitHub Check: Publish TypeScript components
  • GitHub Check: pnpm publish
  • GitHub Check: Lint Code Base
🔇 Additional comments (4)
components/azure_devops/package.json (2)

3-3: Version bump aligns with auth behavior change

Minor bump to 0.1.0 makes sense given the auth semantics change (PAT support + flagged OAuth usage). No issues.


16-16: Verify major upgrade of @pipedream/platform

You’ve bumped components/azure_devops/package.json from ^1.2.1 to ^3.1.0—a major release with potential breaking changes. Please confirm:

  • All imports of @pipedream/platform still resolve correctly.
  • Direct calls to axios (via the platform or standalone) behave as expected.
  • Any use of platform helpers ($http, $step, $steps, etc.) hasn’t been deprecated or changed.
  • Your existing tests and any manual smoke tests around HTTP or step executions pass under v3.x.
components/azure_devops/sources/new-event/new-event.mjs (2)

5-5: Version bump acknowledged

Source version bump to 0.0.3 is appropriate; no functional deltas here.


43-48: No behavioral change; formatting is fine

Multi-line invocation reads cleaner and doesn’t alter behavior. Assuming createSubscription uses PAT by default (per app changes), this should resolve the “event type” options issue end-to-end.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
components/azure_devops/azure_devops.app.mjs (1)

23-26: Bug: Mismatched prop name breaks event type options (organization vs organizationName)

The eventType options function expects { organization }, but the prop is defined as organizationName. This passes undefined to listEventTypes and can produce the “Bad option response for prop type eventType”.

-      async options({ organization }) {
-        const types = await this.listEventTypes(organization);
+      async options({ organizationName }) {
+        const types = await this.listEventTypes(organizationName);
         return types?.map((type) => type.id);
       },
🧹 Nitpick comments (1)
components/azure_devops/azure_devops.app.mjs (1)

89-94: Nit: Extra space after return

Minor style nit to remove the double-space.

-      return  this._makeRequest({
+      return this._makeRequest({
         method: "POST",
         path: `/${organization}/_apis/hooks/subscriptions`,
         ...args,
       });
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between a21b351 and 6df65bf.

📒 Files selected for processing (1)
  • components/azure_devops/azure_devops.app.mjs (4 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Lint Code Base
  • GitHub Check: Verify TypeScript components
  • GitHub Check: Publish TypeScript components
🔇 Additional comments (3)
components/azure_devops/azure_devops.app.mjs (3)

1-3: LGTM: Importing ConfigurationError is appropriate here

Good call importing ConfigurationError alongside axios for clear, actionable config errors.


51-53: LGTM: Accessor for PAT

Simple, clear method to access the PAT from $auth.


59-66: LGTM: Plumbs useOAuth through _makeRequest

Passing the useOAuth flag into _headers centralizes auth behavior per endpoint neatly.

Copy link
Collaborator

@jcortes jcortes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @michelle0927 lgtm! Ready for QA!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Azure DevOps
3 participants