Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions .azure-pipelines/generation-pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,6 @@ resources:
type: github
endpoint: microsoftgraph (22)
name: microsoftgraph/microsoft-graph-docs
- repository: Agents-M365Copilot
type: github
endpoint: microsoftkiota
name: microsoft/Agents-M365Copilot
- repository: 1ESPipelineTemplates
type: git
name: 1ESPipelineTemplates/1ESPipelineTemplates
Expand Down Expand Up @@ -190,7 +186,6 @@ extends:
- repository: msgraph-beta-sdk-python
- repository: msgraph-metadata
- repository: microsoft-graph-docs
- repository: Agents-M365Copilot
- repository: 1ESPipelineTemplates
pool:
name: Azure-Pipelines-1ESPT-ExDShared
Expand Down Expand Up @@ -963,6 +958,7 @@ extends:
targetClassName: "BaseAgentsM365CopilotServiceClient"
targetNamespace: "Microsoft.Agents.M365Copilot"
commitMessagePrefix: "feat(generation): update request builders and models for dotnet v1"
useGitHubAppAuth: true
customArguments: "-i '**/copilot/**'" # include only copilot paths
cleanMetadataFolder: $(cleanOpenAPIFolderV1)
pathExclusionArguments: ''
Expand Down Expand Up @@ -1009,6 +1005,7 @@ extends:
targetClassName: "BaseAgentsM365CopilotBetaServiceClient"
targetNamespace: "Microsoft.Agents.M365Copilot.Beta"
commitMessagePrefix: "feat(generation): update request builders and models for dotnet beta"
useGitHubAppAuth: true
customArguments: "-i '**/copilot/**'" # include only copilot paths
cleanMetadataFolder: $(cleanOpenAPIFolderBeta)
pathExclusionArguments: ''
Expand Down Expand Up @@ -1057,6 +1054,7 @@ extends:
customArguments: "-i '**/copilot/**'" # include only copilot paths
cleanMetadataFolder: $(cleanOpenAPIFolderV1)
commitMessagePrefix: "feat(generation): update request builders and models for python v1"
useGitHubAppAuth: true
pathExclusionArguments: ''
languageSpecificSteps:
- template: /.azure-pipelines/generation-templates/python.yml@self
Expand Down Expand Up @@ -1103,6 +1101,7 @@ extends:
customArguments: "-i '**/copilot/**'" # include only copilot paths
cleanMetadataFolder: $(cleanOpenAPIFolderBeta)
commitMessagePrefix: "feat(generation): update request builders and models for python beta"
useGitHubAppAuth: true
pathExclusionArguments: ''
languageSpecificSteps:
- template: /.azure-pipelines/generation-templates/python.yml@self
Expand Down Expand Up @@ -1145,6 +1144,7 @@ extends:
baseBranchName: 'main'
branchName: 'ccs-typescript/$(v1Branch)'
commitMessagePrefix: "feat(generation): update request builders and models for typescript v1"
useGitHubAppAuth: true
targetClassName: "BaseAgentsM365CopilotServiceClient"
targetNamespace: "github.com/microsoft/Agents-M365Copilot/typescript/"
customArguments: "-i '**/copilot/**'"
Expand Down Expand Up @@ -1191,6 +1191,7 @@ extends:
baseBranchName: 'main'
branchName: 'ccs-typescript/$(betaBranch)'
commitMessagePrefix: "feat(generation): update request builders and models for typescript beta"
useGitHubAppAuth: true
targetClassName: "BaseAgentsM365CopilotBetaServiceClient"
targetNamespace: "github.com/microsoft/Agents-M365Copilot/typescript/"
customArguments: "-i '**/copilot/**'"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,25 @@ parameters:
type: string
default: "-e '/copilot' -e '/copilot/**'"

# When true, the target repository is read anonymously (public repo) and the generated
# files are pushed using a GitHub App installation token instead of a PAT-backed service
# connection. PR creation is App-based regardless. Defaults to false to preserve the
# existing service connection based behaviour for the microsoftgraph SDK repos.
- name: useGitHubAppAuth
type: boolean
default: false

steps:
- template: /.azure-pipelines/generation-templates/set-up-for-generation-kiota.yml@self
parameters:
cleanMetadataFolder: ${{ parameters.cleanMetadataFolder }}

- checkout: ${{ parameters.repoName }}
displayName: 'checkout ${{ parameters.repoName }}'
fetchDepth: 1
persistCredentials: true
# Default path: check out the target repo via its service connection.
${{ if eq(parameters.useGitHubAppAuth, false) }}:
- checkout: ${{ parameters.repoName }}
displayName: 'checkout ${{ parameters.repoName }}'
fetchDepth: 1
persistCredentials: true

# need this for the shared scripts (maybe we should move them to msgraph-metadata)
# no need for recursive, just scripts from the main repo
Expand All @@ -73,6 +83,16 @@ steps:
fetchDepth: 1
persistCredentials: true

# App-auth path: the target repo is public, so clone it anonymously (no PAT). The push
# remote is switched to a GitHub App token in a later step before the push happens.
${{ if eq(parameters.useGitHubAppAuth, true) }}:
- pwsh: |
$repoDir = "$(Build.SourcesDirectory)/${{ parameters.repoName }}"
if (Test-Path $repoDir) { Remove-Item $repoDir -Recurse -Force }
git clone --depth 1 "https://github.com/${{ parameters.orgName }}/${{ parameters.repoName }}.git" "$repoDir"
if ($LASTEXITCODE -ne 0) { throw "Failed to clone ${{ parameters.orgName }}/${{ parameters.repoName }}" }
displayName: 'Clone ${{ parameters.repoName }} (anonymous, public repo)'

- pwsh: '$(scriptsDirectory)/checkout-custom-base-branch.ps1'
displayName: 'Checking out custom base branch ${{ parameters.baseBranchName }}'
env:
Expand Down Expand Up @@ -103,6 +123,25 @@ steps:

- ${{ parameters.languageSpecificSteps }}

# App-auth path: fetch the App secrets and switch the push remote to the App token
# BEFORE pushing.
${{ if eq(parameters.useGitHubAppAuth, true) }}:
- task: AzureKeyVault@2
displayName: "Azure Key Vault: Get Secrets"
inputs:
azureSubscription: "Federated AKV Managed Identity Connection"
KeyVaultName: akv-prod-eastus
SecretsFilter: "microsoft-graph-devx-bot-appid,microsoft-graph-devx-bot-privatekey"

- pwsh: '$(scriptsDirectory)/set-app-token-push-url.ps1'
displayName: 'Git: use GitHub App token for push'
env:
GhAppId: $(microsoft-graph-devx-bot-appid)
GhAppKey: $(microsoft-graph-devx-bot-privatekey)
RepoName: '${{ parameters.orgName }}/${{ parameters.repoName }}'
ScriptsDirectory: $(scriptsDirectory)
workingDirectory: ${{ parameters.repoName }}

- pwsh: '$(scriptsDirectory)/git-push-files.ps1'
displayName: 'Git: push generated files'
env:
Expand All @@ -112,12 +151,15 @@ steps:
CommitMessagePrefix: ${{ parameters.commitMessagePrefix }}
workingDirectory: ${{ parameters.repoName }}

- task: AzureKeyVault@2
displayName: "Azure Key Vault: Get Secrets"
inputs:
azureSubscription: "Federated AKV Managed Identity Connection"
KeyVaultName: akv-prod-eastus
SecretsFilter: "microsoft-graph-devx-bot-appid,microsoft-graph-devx-bot-privatekey"
# Default path: secrets are fetched after the push, just before PR creation. On the
# App-auth path the secrets were already fetched above and persist for the PR step.
${{ if eq(parameters.useGitHubAppAuth, false) }}:
- task: AzureKeyVault@2
displayName: "Azure Key Vault: Get Secrets"
inputs:
azureSubscription: "Federated AKV Managed Identity Connection"
KeyVaultName: akv-prod-eastus
SecretsFilter: "microsoft-graph-devx-bot-appid,microsoft-graph-devx-bot-privatekey"

- pwsh: '$(scriptsDirectory)/create-pull-request.ps1'
displayName: 'Create Pull Request for the generated build for ${{ parameters.repoName }}'
Expand Down
40 changes: 40 additions & 0 deletions scripts/set-app-token-push-url.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.

# Configure the 'origin' push URL of an already-cloned repository to authenticate with a
# GitHub App installation token instead of a PAT. The fetch URL is left untouched so reads
# stay anonymous for public repositories.
#
# Required environment variables:
# GhAppId - GitHub App client ID (from AKV)
# GhAppKey - GitHub App private key (from AKV)
# RepoName - Target repo in "owner/repo" format (e.g. "microsoft/Agents-M365Copilot")
# ScriptsDirectory - Path to the scripts folder containing Generate-Github-Token.ps1
# Runs from the repository working directory (the cloned repo).

[CmdletBinding()]
param ()

$ErrorActionPreference = "Stop"

if ([string]::IsNullOrWhiteSpace($env:GhAppId)) { throw "GhAppId is required" }
if ([string]::IsNullOrWhiteSpace($env:GhAppKey)) { throw "GhAppKey is required" }
if ([string]::IsNullOrWhiteSpace($env:RepoName)) { throw "RepoName is required" }
if ([string]::IsNullOrWhiteSpace($env:ScriptsDirectory)){ throw "ScriptsDirectory is required" }

# The installed application is required to have contents:write on the target repository.
$tokenGenerationScript = Join-Path $env:ScriptsDirectory "Generate-Github-Token.ps1"
$token = & $tokenGenerationScript -AppClientId $env:GhAppId -AppPrivateKeyContents $env:GhAppKey -Repository $env:RepoName
if ([string]::IsNullOrWhiteSpace($token)) {
throw "Failed to generate GitHub App installation token (empty result)"
}

# Mask the token so it is never surfaced in pipeline logs.
Write-Host "##vso[task.setsecret]$token"

# Set the push URL only; leave the (anonymous) fetch URL alone.
$pushUrl = "https://x-access-token:$token@github.com/$($env:RepoName).git"
git remote set-url --push origin $pushUrl
if ($LASTEXITCODE -ne 0) { throw "Failed to set push URL for origin" }

Write-Host "Configured origin push URL to use the GitHub App installation token." -ForegroundColor Green
Loading