diff --git a/apps.go b/apps.go index 0287a4f..017cd15 100644 --- a/apps.go +++ b/apps.go @@ -2,42 +2,95 @@ package github import ( "errors" + "fmt" + "net/http" + "net/url" + "strings" + "github.com/bradleyfalzon/ghinstallation/v2" "github.com/go-git/go-git/v5" + "github.com/google/go-github/v54/github" ) // GitHubApp is a struct to interact with GitHub App's API type GitHubApp struct { - Config *GitHubAppConfig - Auth Auth - gitRepo *git.Repository - worktree *git.Worktree + Config *GitHubAppConfig + Auth Auth + gitClient *git.Repository + githubClient *github.Client + worktree *git.Worktree } // Configuration for the GitHub App interaction type GitHubAppConfig struct { + repoName string RepoURL string - ApplicationID string - InstallationID string + ApplicationID int64 + InstallationID int64 LocalPath string - PrivateKey []byte + PrivateKey string } var githubAPIURL string = "https://api.github.com" +// extractRepoName extracts the repository name from the URL +func extractRepoName(gitURL string) (string, error) { + parsedURL, err := url.Parse(gitURL) + if err != nil { + return "", err + } + + // Splitting the path based on slashes + parts := strings.Split(parsedURL.Path, "/") + + // Ensure at least one segment exists + if len(parts) == 0 { + return "", fmt.Errorf("could not extract repository name") + } + + // The last part of the URL is typically 'repo.git', so we need to further process it to extract 'repo' + repoName := parts[len(parts)-1] + + // Removing .git extension if present + if strings.HasSuffix(repoName, ".git") { + repoName = repoName[:len(repoName)-len(".git")] + } + + return repoName, nil +} + // Creates a new GitHubApp struct configured by GitHubAppConfig func NewGitHubApp(cfg *GitHubAppConfig) (*GitHubApp, error) { - if cfg.ApplicationID == "" && cfg.InstallationID == "" { + // check if application ID and installation ID are defined + if cfg.ApplicationID == 0 && cfg.InstallationID == 0 { return nil, errors.New("provide App ID and Installation ID") } + // set localPath if not passed if cfg.LocalPath == "" { cfg.LocalPath = "./" } + + // get new key for github + itr, err := ghinstallation.NewKeyFromFile(http.DefaultTransport, cfg.ApplicationID, cfg.InstallationID, cfg.PrivateKey) + if err != nil { + return nil, err + } + + repoName, err := extractRepoName(cfg.RepoURL) + if err != nil { + return nil, err + } + // set repoName + cfg.repoName = repoName + + // initialise a new GitHubApp ghApp := &GitHubApp{ - Config: cfg, + Config: cfg, + githubClient: github.NewClient(&http.Client{Transport: itr}), } - err := ghApp.authenticate() + // authenticate + err = ghApp.authenticate() if err != nil { return nil, err } diff --git a/apps_test.go b/apps_test.go index abf259f..ba9681a 100644 --- a/apps_test.go +++ b/apps_test.go @@ -32,7 +32,7 @@ Uqt+kzgPAoGBAOeI2EoJSOtpHlJgXT5v8qvqCFdu/oiiS/i9d25CkL0AIlT0YJZu VAeKVKieSln/vQZfuklfdcmREwcn7LiMmU7KeLm5ehsfUAtjT/9c4KOj6+/unrQZ NAYPACY/P+sO1+RN3UkezoYdbgnperNKSMreQtrxL/0wkDaKdmUWm0ty -----END RSA PRIVATE KEY----- -`) + `) func TestNewGitHubApp(t *testing.T) { @@ -45,7 +45,7 @@ func TestNewGitHubApp(t *testing.T) { // Test Case 2: Missing Application ID cfg = &GitHubAppConfig{ - InstallationID: "123", + InstallationID: 123, } _, err = NewGitHubApp(cfg) if err == nil { @@ -54,7 +54,7 @@ func TestNewGitHubApp(t *testing.T) { // Test Case 3: Missing Installation ID cfg = &GitHubAppConfig{ - ApplicationID: "298674", + ApplicationID: 298674, } _, err = NewGitHubApp(cfg) if err == nil { @@ -63,8 +63,8 @@ func TestNewGitHubApp(t *testing.T) { // Test Case 4: Missing Private Key cfg = &GitHubAppConfig{ - ApplicationID: "298674", - InstallationID: "123", + ApplicationID: 298674, + InstallationID: 123, } _, err = NewGitHubApp(cfg) if err == nil { diff --git a/auth.go b/auth.go index 42c1ad2..fa5cde3 100644 --- a/auth.go +++ b/auth.go @@ -4,8 +4,9 @@ import ( "encoding/json" "errors" "fmt" - "io/ioutil" + "io" "net/http" + "os" "time" "github.com/golang-jwt/jwt" @@ -25,8 +26,14 @@ func (ghApp *GitHubApp) buildJWTToken() error { claims["exp"] = time.Now().Add(10 * time.Minute).Unix() claims["iss"] = ghApp.Config.ApplicationID + // Read file + keyData, err := os.ReadFile(ghApp.Config.PrivateKey) + if err != nil { + return err + } + // Parse RSA private key - key, err := jwt.ParseRSAPrivateKeyFromPEM(ghApp.Config.PrivateKey) + key, err := jwt.ParseRSAPrivateKeyFromPEM(keyData) if err != nil { return err } @@ -49,7 +56,7 @@ type TokenResponse struct { // Gets the access token to authenticate with github func (ghApp *GitHubApp) GetAccessToken() (string, error) { // Parse url - url := fmt.Sprintf("%s/app/installations/%s/access_tokens", githubAPIURL, ghApp.Config.InstallationID) + url := fmt.Sprintf("%s/app/installations/%d/access_tokens", githubAPIURL, ghApp.Config.InstallationID) // Create the request to github's api req, _ := http.NewRequest("POST", url, nil) @@ -68,7 +75,7 @@ func (ghApp *GitHubApp) GetAccessToken() (string, error) { } // Read the the response from the server - body, err := ioutil.ReadAll(resp.Body) + body, err := io.ReadAll(resp.Body) if err != nil { return "", err } diff --git a/auth_test.go b/auth_test.go index 4f166e8..f59a97a 100644 --- a/auth_test.go +++ b/auth_test.go @@ -1,14 +1,19 @@ package github import ( + "os" "testing" ) func TestBuildJWTToken(t *testing.T) { + // Create temp key file + tmpKeyFile := "/tmp/key.pem" + os.WriteFile(tmpKeyFile, testPrivateKey, 0644) + // Test Case 1: Invalid private key cfg := &GitHubAppConfig{ - ApplicationID: "123", - PrivateKey: []byte("invalid"), + ApplicationID: 123, + PrivateKey: "invalid", } ghApp := &GitHubApp{ Config: cfg, @@ -20,8 +25,8 @@ func TestBuildJWTToken(t *testing.T) { // Test Case 2: Valid private key cfg = &GitHubAppConfig{ - ApplicationID: "298674", - PrivateKey: testPrivateKey, + ApplicationID: 298674, + PrivateKey: tmpKeyFile, } ghApp = &GitHubApp{ Config: cfg, @@ -33,4 +38,7 @@ func TestBuildJWTToken(t *testing.T) { if ghApp.Auth.JWTToken == "" { t.Errorf("Empty JWT token") } + + // Cleanup + os.Remove(tmpKeyFile) } diff --git a/cmd/main.go b/cmd/main.go index a9352d0..0c18ce2 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -1,36 +1,36 @@ package main import ( - "bufio" "flag" "fmt" "os" - "strings" + "strconv" "github.com/kununu/go-github" ) var ( - appId string - instId string + appId int64 + instId int64 key string ) func init() { - flag.StringVar(&appId, "a", "", "App ID to use for authentication") flag.StringVar(&key, "k", "", "Path to key file for authentication") - flag.StringVar(&instId, "i", "", "Installation ID that identifies the APP installation ID on GitHub") + flag.Int64Var(&appId, "a", 0, "App ID to use for authentication") + flag.Int64Var(&instId, "i", 0, "Installation ID that identifies the APP installation ID on GitHub") flag.Parse() } func main() { - keyBytes := []byte{} // Get the values from the environment variables if they are set with parameters - if appId == "" { - appId = os.Getenv("GITHUB_APP_ID") + if appId == 0 { + appIdInt, _ := strconv.ParseInt(os.Getenv("GITHUB_APP_ID"), 10, 64) + appId = appIdInt } - if instId == "" { - instId = os.Getenv("GITHUB_INST_ID") + if instId == 0 { + instIdInt, _ := strconv.ParseInt(os.Getenv("GITHUB_INST_ID"), 10, 64) + instId = instIdInt } if key == "" { key = os.Getenv("GITHUB_KEY_PATH") @@ -45,46 +45,23 @@ func main() { fmt.Printf("you need to pass the private key either with `-k` parameter or by setting GITHUB_KEY_PATH or even passing through STDIN\n") os.Exit(1) } - var lines []string - reader := bufio.NewReader(os.Stdin) - for { - // read line from stdin using newline as separator - line, _ := reader.ReadString('\n') - // if line is empty, break the loop - if len(strings.TrimSpace(line)) == 0 { - break - } - //append the line to a slice - lines = append(lines, line) - keyBytes = append(keyBytes, []byte(line)...) - } key = "stdin" } } // Verify if the necessary information is set - if appId == "" || instId == "" { + if appId == 0 || instId == 0 { fmt.Println("You need to define the App ID and the path to the key file") fmt.Println("by passing the values the -a, -i and -k options or") fmt.Println("by setting GITHUB_APP_ID, GITHUB_INST_ID and GITHUB_KEY_PATH environment variables.") - os.Exit(0) - } - - // Read the key from the file - if key != "stdin" { - var err error - keyBytes, err = os.ReadFile(key) - if err != nil { - fmt.Println("error reading the key file") - os.Exit(1) - } + os.Exit(1) } // Create a new GitHubApp ghApp, err := github.NewGitHubApp(&github.GitHubAppConfig{ ApplicationID: appId, InstallationID: instId, - PrivateKey: keyBytes, + PrivateKey: key, }) if err != nil { fmt.Println(err.Error()) diff --git a/git.go b/git.go index bdd3c17..0a2ac07 100644 --- a/git.go +++ b/git.go @@ -1,11 +1,15 @@ package github import ( + "context" + "fmt" "time" "github.com/go-git/go-git/v5" + "github.com/go-git/go-git/v5/plumbing" "github.com/go-git/go-git/v5/plumbing/object" "github.com/go-git/go-git/v5/plumbing/transport/http" + "github.com/google/go-github/v54/github" ) // User information @@ -14,10 +18,16 @@ type UserInfo struct { Email string } +// PullRequest information +type PullRequest struct { + SourceBranch string + TargetBranch string +} + // Clones the repository func (ghApp *GitHubApp) Clone() error { var err error - ghApp.gitRepo, err = git.PlainClone(ghApp.Config.LocalPath, false, &git.CloneOptions{ + ghApp.gitClient, err = git.PlainClone(ghApp.Config.LocalPath, false, &git.CloneOptions{ URL: ghApp.Config.RepoURL, Auth: &http.BasicAuth{ Username: "github", @@ -27,7 +37,7 @@ func (ghApp *GitHubApp) Clone() error { if err != nil { return err } - ghApp.worktree, err = ghApp.gitRepo.Worktree() + ghApp.worktree, err = ghApp.gitClient.Worktree() if err != nil { return err } @@ -41,12 +51,13 @@ func (ghApp *GitHubApp) HasChanges() bool { if err != nil { return false } - return status.IsClean() + return !status.IsClean() } // Adds files to the repository -func (ghApp *GitHubApp) Add(path string) { - ghApp.worktree.Add(path) +func (ghApp *GitHubApp) Add(path string) error { + _, err := ghApp.worktree.Add(path) + return err } // Commits the changes @@ -66,7 +77,7 @@ func (ghApp *GitHubApp) Commit(msg string, user UserInfo) error { // Pushes the changes func (ghApp *GitHubApp) Push() error { - err := ghApp.gitRepo.Push(&git.PushOptions{ + err := ghApp.gitClient.Push(&git.PushOptions{ RemoteName: "origin", Auth: &http.BasicAuth{ Username: "github", @@ -79,3 +90,33 @@ func (ghApp *GitHubApp) Push() error { return nil } + +// Create a new branch +func (ghApp *GitHubApp) NewBranch(name string, checkout bool) error { + + return ghApp.worktree.Checkout(&git.CheckoutOptions{ + Branch: plumbing.ReferenceName(fmt.Sprintf("refs/heads/%s", name)), + Create: checkout, + }) + +} + +// Create new pull request +func (ghApp *GitHubApp) NewPullRequest(source string, target string, title string, body string) error { + // Create PR + newPR := &github.NewPullRequest{ + Title: github.String(title), + Head: github.String(source), // source branch + Base: github.String(target), // target branch + Body: github.String(body), + MaintainerCanModify: github.Bool(true), + } + ctx := context.Background() + + _, _, err := ghApp.githubClient.PullRequests.Create(ctx, "kununu", ghApp.Config.repoName, newPR) + if err != nil { + return err + } + + return nil +} diff --git a/go.mod b/go.mod index 1423f88..76ba80a 100644 --- a/go.mod +++ b/go.mod @@ -1,20 +1,26 @@ module github.com/kununu/go-github -go 1.20 +go 1.21 require ( + github.com/bradleyfalzon/ghinstallation/v2 v2.6.0 github.com/go-git/go-git/v5 v5.6.1 github.com/golang-jwt/jwt v3.2.2+incompatible + github.com/google/go-github/v54 v54.0.0 ) require ( github.com/Microsoft/go-winio v0.5.2 // indirect - github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 // indirect + github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95 // indirect github.com/acomagu/bufpipe v1.0.4 // indirect - github.com/cloudflare/circl v1.1.0 // indirect + github.com/cloudflare/circl v1.3.3 // indirect github.com/emirpasic/gods v1.18.1 // indirect github.com/go-git/gcfg v1.5.0 // indirect github.com/go-git/go-billy/v5 v5.4.1 // indirect + github.com/golang-jwt/jwt/v4 v4.5.0 // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/google/go-github/v53 v53.2.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect github.com/imdario/mergo v0.3.13 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect @@ -22,8 +28,11 @@ require ( github.com/sergi/go-diff v1.1.0 // indirect github.com/skeema/knownhosts v1.1.0 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect - golang.org/x/crypto v0.6.0 // indirect - golang.org/x/net v0.7.0 // indirect - golang.org/x/sys v0.5.0 // indirect + golang.org/x/crypto v0.12.0 // indirect + golang.org/x/net v0.14.0 // indirect + golang.org/x/oauth2 v0.11.0 // indirect + golang.org/x/sys v0.11.0 // indirect + google.golang.org/appengine v1.6.7 // indirect + google.golang.org/protobuf v1.31.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect ) diff --git a/go.sum b/go.sum index 3181ae6..2269b63 100644 --- a/go.sum +++ b/go.sum @@ -1,16 +1,22 @@ +cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA= github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= -github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 h1:wPbRQzjjwFc0ih8puEVAOFGELsn1zoIIYdxvML7mDxA= github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8/go.mod h1:I0gYDMZ6Z5GRU7l58bNFSkPTFN6Yl12dsUlAZ8xy98g= +github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95 h1:KLq8BE0KwCL+mmXnjLWEAOYO+2l2AE4YMmqG1ZpZHBs= +github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ= github.com/acomagu/bufpipe v1.0.4/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/bradleyfalzon/ghinstallation/v2 v2.6.0 h1:IRY7Xy588KylkoycsUhFpW7cdGpy5Y5BPsz4IfuJtGk= +github.com/bradleyfalzon/ghinstallation/v2 v2.6.0/go.mod h1:oQ3etOwN3TRH4EwgW5/7MxSVMGlMlzG/O8TU7eYdoSk= github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= -github.com/cloudflare/circl v1.1.0 h1:bZgT/A+cikZnKIwn7xL2OBj012Bmvho/o6RpRvv3GKY= +github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I= +github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs= +github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -30,8 +36,24 @@ github.com/go-git/go-git/v5 v5.6.1 h1:q4ZRqQl4pR/ZJHc1L5CFjGA1a10u76aV1iC+nh+bHs github.com/go-git/go-git/v5 v5.6.1/go.mod h1:mvyoL6Unz0PiTQrGQfSfiLFhBH1c1e84ylC2MDs4ee8= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= +github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-github/v53 v53.2.0 h1:wvz3FyF53v4BK+AsnvCmeNhf8AkTaeh2SoYu/XUvTtI= +github.com/google/go-github/v53 v53.2.0/go.mod h1:XhFRObz+m/l+UCm9b7KSIC3lT3NWSXGt7mOsAWEloao= +github.com/google/go-github/v54 v54.0.0 h1:OZdXwow4EAD5jEo5qg+dGFH2DpkyZvVsAehjvJuUL/c= +github.com/google/go-github/v54 v54.0.0/go.mod h1:Sw1LXWHhXRZtzJ9LI5fyJg9wbQzYvFhW8W5P2yaAQ7s= +github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= @@ -76,21 +98,34 @@ golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0 golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= -golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= +golang.org/x/oauth2 v0.11.0 h1:vPL4xzxBM4niKCW6g9whtaWVXTJf1U5e4aZxxFx/gbU= +golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -106,27 +141,48 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0= +golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=