Bladeren bron

Add orchestration_id to git user-agent when ACTIONS_ORCHESTRATION_ID is set (#2355)

* Initial plan

* Add orchestration ID support to git user-agent

Co-authored-by: TingluoHuang <1750815+TingluoHuang@users.noreply.github.com>

* Apply suggestion from @Copilot

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Improve tests to verify user-agent content and handle empty sanitized IDs

Co-authored-by: TingluoHuang <1750815+TingluoHuang@users.noreply.github.com>

* Simplify orchestration ID validation to accept any non-empty sanitized value

Co-authored-by: TingluoHuang <1750815+TingluoHuang@users.noreply.github.com>

* Remove test for orchestration ID with only invalid characters

Co-authored-by: TingluoHuang <1750815+TingluoHuang@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: TingluoHuang <1750815+TingluoHuang@users.noreply.github.com>
Co-authored-by: Tingluo Huang <tingluohuang@github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copilot 5 maanden geleden
bovenliggende
commit
064fe7f331
3 gewijzigde bestanden met toevoegingen van 141 en 2 verwijderingen
  1. 117 0
      __test__/git-command-manager.test.ts
  2. 11 1
      dist/index.js
  3. 13 1
      src/git-command-manager.ts

+ 117 - 0
__test__/git-command-manager.test.ts

@@ -376,3 +376,120 @@ describe('Test fetchDepth and fetchTags options', () => {
     )
   })
 })
+
+describe('git user-agent with orchestration ID', () => {
+  beforeEach(async () => {
+    jest.spyOn(fshelper, 'fileExistsSync').mockImplementation(jest.fn())
+    jest.spyOn(fshelper, 'directoryExistsSync').mockImplementation(jest.fn())
+  })
+
+  afterEach(() => {
+    jest.restoreAllMocks()
+    // Clean up environment variable to prevent test pollution
+    delete process.env['ACTIONS_ORCHESTRATION_ID']
+  })
+
+  it('should include orchestration ID in user-agent when ACTIONS_ORCHESTRATION_ID is set', async () => {
+    const orchId = 'test-orch-id-12345'
+    process.env['ACTIONS_ORCHESTRATION_ID'] = orchId
+
+    let capturedEnv: any = null
+    mockExec.mockImplementation((path, args, options) => {
+      if (args.includes('version')) {
+        options.listeners.stdout(Buffer.from('2.18'))
+      }
+      // Capture env on any command
+      capturedEnv = options.env
+      return 0
+    })
+    jest.spyOn(exec, 'exec').mockImplementation(mockExec)
+
+    const workingDirectory = 'test'
+    const lfs = false
+    const doSparseCheckout = false
+    git = await commandManager.createCommandManager(
+      workingDirectory,
+      lfs,
+      doSparseCheckout
+    )
+
+    // Call a git command to trigger env capture after user-agent is set
+    await git.init()
+
+    // Verify the user agent includes the orchestration ID
+    expect(git).toBeDefined()
+    expect(capturedEnv).toBeDefined()
+    expect(capturedEnv['GIT_HTTP_USER_AGENT']).toBe(
+      `git/2.18 (github-actions-checkout) actions_orchestration_id/${orchId}`
+    )
+  })
+
+  it('should sanitize invalid characters in orchestration ID', async () => {
+    const orchId = 'test (with) special/chars'
+    process.env['ACTIONS_ORCHESTRATION_ID'] = orchId
+
+    let capturedEnv: any = null
+    mockExec.mockImplementation((path, args, options) => {
+      if (args.includes('version')) {
+        options.listeners.stdout(Buffer.from('2.18'))
+      }
+      // Capture env on any command
+      capturedEnv = options.env
+      return 0
+    })
+    jest.spyOn(exec, 'exec').mockImplementation(mockExec)
+
+    const workingDirectory = 'test'
+    const lfs = false
+    const doSparseCheckout = false
+    git = await commandManager.createCommandManager(
+      workingDirectory,
+      lfs,
+      doSparseCheckout
+    )
+
+    // Call a git command to trigger env capture after user-agent is set
+    await git.init()
+
+    // Verify the user agent has sanitized orchestration ID (spaces, parentheses, slash replaced)
+    expect(git).toBeDefined()
+    expect(capturedEnv).toBeDefined()
+    expect(capturedEnv['GIT_HTTP_USER_AGENT']).toBe(
+      'git/2.18 (github-actions-checkout) actions_orchestration_id/test__with__special_chars'
+    )
+  })
+
+  it('should not modify user-agent when ACTIONS_ORCHESTRATION_ID is not set', async () => {
+    delete process.env['ACTIONS_ORCHESTRATION_ID']
+
+    let capturedEnv: any = null
+    mockExec.mockImplementation((path, args, options) => {
+      if (args.includes('version')) {
+        options.listeners.stdout(Buffer.from('2.18'))
+      }
+      // Capture env on any command
+      capturedEnv = options.env
+      return 0
+    })
+    jest.spyOn(exec, 'exec').mockImplementation(mockExec)
+
+    const workingDirectory = 'test'
+    const lfs = false
+    const doSparseCheckout = false
+    git = await commandManager.createCommandManager(
+      workingDirectory,
+      lfs,
+      doSparseCheckout
+    )
+
+    // Call a git command to trigger env capture after user-agent is set
+    await git.init()
+
+    // Verify the user agent does NOT contain orchestration ID
+    expect(git).toBeDefined()
+    expect(capturedEnv).toBeDefined()
+    expect(capturedEnv['GIT_HTTP_USER_AGENT']).toBe(
+      'git/2.18 (github-actions-checkout)'
+    )
+  })
+})

+ 11 - 1
dist/index.js

@@ -1206,7 +1206,17 @@ class GitCommandManager {
                 }
             }
             // Set the user agent
-            const gitHttpUserAgent = `git/${this.gitVersion} (github-actions-checkout)`;
+            let gitHttpUserAgent = `git/${this.gitVersion} (github-actions-checkout)`;
+            // Append orchestration ID if set
+            const orchId = process.env['ACTIONS_ORCHESTRATION_ID'];
+            if (orchId) {
+                // Sanitize the orchestration ID to ensure it contains only valid characters
+                // Valid characters: 0-9, a-z, _, -, .
+                const sanitizedId = orchId.replace(/[^a-z0-9_.-]/gi, '_');
+                if (sanitizedId) {
+                    gitHttpUserAgent = `${gitHttpUserAgent} actions_orchestration_id/${sanitizedId}`;
+                }
+            }
             core.debug(`Set git useragent to: ${gitHttpUserAgent}`);
             this.gitEnv['GIT_HTTP_USER_AGENT'] = gitHttpUserAgent;
         });

+ 13 - 1
src/git-command-manager.ts

@@ -730,7 +730,19 @@ class GitCommandManager {
       }
     }
     // Set the user agent
-    const gitHttpUserAgent = `git/${this.gitVersion} (github-actions-checkout)`
+    let gitHttpUserAgent = `git/${this.gitVersion} (github-actions-checkout)`
+
+    // Append orchestration ID if set
+    const orchId = process.env['ACTIONS_ORCHESTRATION_ID']
+    if (orchId) {
+      // Sanitize the orchestration ID to ensure it contains only valid characters
+      // Valid characters: 0-9, a-z, _, -, .
+      const sanitizedId = orchId.replace(/[^a-z0-9_.-]/gi, '_')
+      if (sanitizedId) {
+        gitHttpUserAgent = `${gitHttpUserAgent} actions_orchestration_id/${sanitizedId}`
+      }
+    }
+
     core.debug(`Set git useragent to: ${gitHttpUserAgent}`)
     this.gitEnv['GIT_HTTP_USER_AGENT'] = gitHttpUserAgent
   }