Skip to content

Commit

Permalink
more app support
Browse files Browse the repository at this point in the history
  • Loading branch information
gdams committed Feb 18, 2025
1 parent 471a258 commit 5ea1a9f
Show file tree
Hide file tree
Showing 9 changed files with 198 additions and 102 deletions.
19 changes: 16 additions & 3 deletions cmd/releasego/create-release-day-issue.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ var releaseIssueLabels = []string{"Area-Release"}
func handleCreateReleaseDayIssue(p subcmd.ParseFunc) error {
repo := githubutil.BindRepoFlag()
pat := githubutil.BindPATFlag()
ghAppId := githubutil.BindAPPIDFlag()
ghAppInstallation := githubutil.BindAppInstallationFlag()
ghAppPrivateKey := githubutil.BindAppPrivateKeyFlag()
releasesFlag := flag.String(
"releases", "",
"[Required] The release numbers to track releasing during this day, separated by ','.")
Expand Down Expand Up @@ -75,9 +78,19 @@ func handleCreateReleaseDayIssue(p subcmd.ParseFunc) error {
}

ctx := context.Background()
client, err := githubutil.NewClient(ctx, *pat)
if err != nil {
return err

var client *github.Client

if *ghAppId != 0 {
client, err = githubutil.NewInstallationClient(ctx, *ghAppId, *ghAppInstallation, *ghAppPrivateKey)
if err != nil {
return err
}
} else {
client, err = githubutil.NewClient(ctx, *pat)
if err != nil {
return err
}
}

log.Printf("Creating comment on %v/%v with title %#q and content:\n%v\n", owner, name, title, desc)
Expand Down
18 changes: 15 additions & 3 deletions cmd/releasego/get-merged-pr-commit.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ alert a dev that the process is not proceeding smoothly.
func handleGetMergedPRCommit(p subcmd.ParseFunc) error {
repo := githubutil.BindRepoFlag()
pat := githubutil.BindPATFlag()
ghAppId := githubutil.BindAPPIDFlag()
ghAppInstallation := githubutil.BindAppInstallationFlag()
ghAppPrivateKey := githubutil.BindAppPrivateKeyFlag()
prNumber := flag.Int("pr", 0, "[Required] The PR number to check.")
pollDelaySeconds := flag.Int("poll-delay", 5, "Number of seconds to wait between each poll attempt.")
setVariable := flag.String("set-azdo-variable", "", "An AzDO variable name to set.")
Expand All @@ -52,9 +55,18 @@ func handleGetMergedPRCommit(p subcmd.ParseFunc) error {
pollDelay := time.Duration(*pollDelaySeconds) * time.Second

ctx := context.Background()
client, err := githubutil.NewClient(ctx, *pat)
if err != nil {
return err
var client *github.Client

if *ghAppId != 0 {
client, err = githubutil.NewInstallationClient(ctx, *ghAppId, *ghAppInstallation, *ghAppPrivateKey)
if err != nil {
return err
}
} else {
client, err = githubutil.NewClient(ctx, *pat)
if err != nil {
return err
}
}

var commit string
Expand Down
18 changes: 15 additions & 3 deletions cmd/releasego/repo-release.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ func handleRepoRelease(p subcmd.ParseFunc) error {
tag := tagFlag()
repo := githubutil.BindRepoFlag()
pat := githubutil.BindPATFlag()
ghAppId := githubutil.BindAPPIDFlag()
ghAppInstallation := githubutil.BindAppInstallationFlag()
ghAppPrivateKey := githubutil.BindAppPrivateKeyFlag()
buildAssetJSON := flag.String("build-asset-json", "", "[Required] The build asset JSON file to release.")
buildDir := flag.String("build-dir", "", "[Required] The directory containing build artifacts to attach.")

Expand Down Expand Up @@ -70,9 +73,18 @@ func handleRepoRelease(p subcmd.ParseFunc) error {
}

ctx := context.Background()
client, err := githubutil.NewClient(ctx, *pat)
if err != nil {
return err
var client *github.Client

if *ghAppId != 0 {
client, err = githubutil.NewInstallationClient(ctx, *ghAppId, *ghAppInstallation, *ghAppPrivateKey)
if err != nil {
return err
}
} else {
client, err = githubutil.NewClient(ctx, *pat)
if err != nil {
return err
}
}

log.Printf("Creating draft release %v...\n", *tag)
Expand Down
18 changes: 15 additions & 3 deletions cmd/releasego/tag.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ func handleTag(p subcmd.ParseFunc) error {
tag := tagFlag()
repo := githubutil.BindRepoFlag()
pat := githubutil.BindPATFlag()
ghAppId := githubutil.BindAPPIDFlag()
ghAppInstallation := githubutil.BindAppInstallationFlag()
ghAppPrivateKey := githubutil.BindAppPrivateKeyFlag()
commit := flag.String("commit", "", "The commit hash to tag.")

if err := p(); err != nil {
Expand All @@ -49,9 +52,18 @@ func handleTag(p subcmd.ParseFunc) error {
}

ctx := context.Background()
client, err := githubutil.NewClient(ctx, *pat)
if err != nil {
return err
var client *github.Client

if *ghAppId != 0 {
client, err = githubutil.NewInstallationClient(ctx, *ghAppId, *ghAppInstallation, *ghAppPrivateKey)
if err != nil {
return err
}
} else {
client, err = githubutil.NewClient(ctx, *pat)
if err != nil {
return err
}
}

ref := "refs/tags/" + *tag
Expand Down
9 changes: 0 additions & 9 deletions eng/pipelines/jobs/releasego.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,15 +71,6 @@ jobs:
buildStatus: InProgress
start: true

- script: releasego check-limits -pat '$(GitHubPAT)'
displayName: Check GitHub rate limit

- ${{ each step in parameters.steps }}:
- ${{ step }}

- script: releasego check-limits -pat '$(GitHubPAT)'
displayName: Check GitHub rate limit

- ${{ if ne(parameters.retryInstructionsFlags, '') }}:
- script: |
releasego add-retry-instructions ${{ parameters.retryInstructionsFlags }}
Expand Down
4 changes: 3 additions & 1 deletion eng/pipelines/release-go-start-pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,9 @@ extends:
-notify '${{ parameters.notify }}' \
-releases '${{ join(',', parameters.releaseVersions) }}' \
-repo '$(TargetGitHubRepo)' \
-pat '$(GitHubPAT)' \
-github-app-id $(BotAccount-bot-for-go-app-id) `
-github-app-installation $(BotAccount-bot-for-go-installation) `
-github-app-private-key $(BotAccount-bot-for-go-private-key) `
-set-azdo-variable-name GO_RELEASE_DAY_ISSUE_NUMBER
displayName: Create release day tracking issue
Expand Down
27 changes: 19 additions & 8 deletions eng/pipelines/steps/release-build-steps.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@ steps:
-commit '$(upstreamReleasedCommit)' \
-version '${{ parameters.releaseVersion }}' \
-git-auth pat \
-github-user '$(GitHubUser)' \
-github-pat '$(GitHubPAT)' \
-github-app-id $(BotAccount-bot-for-go-app-id) `
-github-app-installation $(BotAccount-bot-for-go-installation) `
-github-app-private-key $(BotAccount-bot-for-go-private-key) `
-github-pat-reviewer '$(GitHubPATReviewer)' \
-azdo-dnceng-pat '$(AzDODncengPAT)' \
-create-branches \
Expand All @@ -43,7 +44,9 @@ steps:
releasego get-merged-pr-commit \
-repo '$(TargetGitHubRepo)' \
-pr '$(poll1MicrosoftGoPRNumber)' \
-pat '$(GitHubPAT)' \
-github-app-id $(BotAccount-bot-for-go-app-id) `
-github-app-installation $(BotAccount-bot-for-go-installation) `
-github-app-private-key $(BotAccount-bot-for-go-private-key) `
-set-azdo-variable poll2MicrosoftGoCommitHash
displayName: ⌚ Get sync PR merged commit hash
timeoutInMinutes: 90
Expand Down Expand Up @@ -200,7 +203,9 @@ steps:
-tag 'v$(buildAssetVersion)' \
-commit '$(BuildInfoSourceVersion)' \
-repo '$(TargetGitHubRepo)' \
-pat '$(GitHubPAT)'
-github-app-id $(BotAccount-bot-for-go-app-id) `
-github-app-installation $(BotAccount-bot-for-go-installation) `
-github-app-private-key $(BotAccount-bot-for-go-private-key) `
displayName: 🎓 Create GitHub tag
- ${{ if eq(parameters.runGitHubRelease, true) }}:
Expand All @@ -210,7 +215,9 @@ steps:
-repo '$(TargetGitHubRepo)' \
-build-asset-json '$(buildAssetJsonFile)' \
-build-dir '$(artifactsDir)' \
-pat '$(GitHubPAT)'
-github-app-id $(BotAccount-bot-for-go-app-id) `
-github-app-installation $(BotAccount-bot-for-go-installation) `
-github-app-private-key $(BotAccount-bot-for-go-private-key) `
displayName: 🎓 Create GitHub release
- ${{ if eq(parameters.runAkaMSUpdate, true) }}:
Expand Down Expand Up @@ -253,8 +260,10 @@ steps:
sudo apt update && sudo apt install -y jq
go run ./cmd/dockerupdatepr \
-origin 'https://_:$(GitHubPAT)@github.com/$(TargetGoImagesGitHubRepo)' \
-github-pat '$(GitHubPAT)' \
-origin 'https://github.com/$(TargetGoImagesGitHubRepo)' \
-github-app-id $(BotAccount-bot-for-go-app-id) `
-github-app-installation $(BotAccount-bot-for-go-installation) `
-github-app-private-key $(BotAccount-bot-for-go-private-key) `
-github-pat-reviewer '$(GitHubPATReviewer)' \
-build-asset-json '$(buildAssetJsonFile)' \
-manual-branch '$(TargetGoImagesBranch)' \
Expand All @@ -269,7 +278,9 @@ steps:
releasego get-merged-pr-commit \
-repo '$(TargetGoImagesGitHubRepo)' \
-pr '$(poll4MicrosoftGoImagesPRNumber)' \
-pat '$(GitHubPAT)'
-github-app-id $(BotAccount-bot-for-go-app-id) `
-github-app-installation $(BotAccount-bot-for-go-installation) `
-github-app-private-key $(BotAccount-bot-for-go-private-key) `
displayName: ⌚ Wait for go-images update PR merge
timeoutInMinutes: 120
# Skip this task if the PR number isn't set. This might intentionally happen if we have to
Expand Down
75 changes: 3 additions & 72 deletions gitcmd/gitcmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,6 @@
package gitcmd

import (
"crypto/x509"
"encoding/base64"
"encoding/json"
"encoding/pem"
"fmt"
"log"
"net/http"
Expand All @@ -19,15 +15,14 @@ import (
"strings"
"time"

"github.com/golang-jwt/jwt/v5"
"github.com/microsoft/go-infra/executil"
"github.com/microsoft/go-infra/githubutil"
"github.com/microsoft/go-infra/stringutil"
)

const (
githubPrefix = "https://github.com/"
azdoDncengPrefix = "https://[email protected]/"
githubAPI = "https://api.github.com"
)

// URLAuther manipulates a Git repository URL (GitHub, AzDO, ...) such that Git commands taking a
Expand Down Expand Up @@ -106,83 +101,19 @@ func (a GitHubAppAuther) InsertHTTPAuth(req *http.Request) {

func (a GitHubAppAuther) getInstallationToken() (string, error) {
// Generate a JWT using the private key
jwt, err := generateJWT(a.AppID, a.PrivateKey)
jwt, err := githubutil.GenerateJWT(a.AppID, a.PrivateKey)
if err != nil {
return "", err
}

// Exchange JWT for an installation token
token, err := fetchInstallationToken(jwt, a.InstallationID)
token, err := githubutil.FetchInstallationToken(jwt, a.InstallationID)
if err != nil {
return "", err
}
return token, nil
}

// generateJWT creates a JWT for the GitHub App.
func generateJWT(appID int64, privateKey string) (string, error) {
privkey, err := base64.StdEncoding.DecodeString(privateKey)
if err != nil {
return "", fmt.Errorf("failed to decode private key: %v", err)
}
block, _ := pem.Decode(privkey)
if block == nil {
return "", fmt.Errorf("failed to decode private key")
}

key, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return "", fmt.Errorf("failed to parse RSA private key: %v", err)
}

now := time.Now().Unix()
claims := jwt.MapClaims{
"iat": now, // Issued at time
"exp": now + 600, // Expiration time (10 min)
"iss": appID, // GitHub App ID
}

token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
signedToken, err := token.SignedString(key)
if err != nil {
return "", fmt.Errorf("failed to sign JWT: %v", err)
}
return signedToken, nil
}

// fetchInstallationToken exchanges a JWT for an installation access token.
func fetchInstallationToken(jwt string, installationID int64) (string, error) {
url := fmt.Sprintf("%s/app/installations/%d/access_tokens", githubAPI, installationID)

req, err := http.NewRequest("POST", url, nil)
if err != nil {
return "", err
}
req.Header.Set("Authorization", "Bearer "+jwt)
req.Header.Set("Accept", "application/vnd.github+json")

client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusCreated {
return "", fmt.Errorf("failed to get installation token, status: %d", resp.StatusCode)
}

var result struct {
Token string `json:"token"`
}
err = json.NewDecoder(resp.Body).Decode(&result)
if err != nil {
return "", err
}

return result.Token, nil
}

// AzDOPATAuther adds a PAT into the https-style Azure DevOps repository URL.
type AzDOPATAuther struct {
PAT string
Expand Down
Loading

0 comments on commit 5ea1a9f

Please sign in to comment.