github.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. package porter_app
  2. import (
  3. "context"
  4. "net/http"
  5. "strconv"
  6. "strings"
  7. "github.com/bradleyfalzon/ghinstallation/v2"
  8. "github.com/google/go-github/v39/github"
  9. "github.com/porter-dev/porter/internal/repository"
  10. "github.com/porter-dev/porter/internal/telemetry"
  11. )
  12. type SetRepoWebhookInput struct {
  13. PorterAppName string
  14. ClusterID uint
  15. GithubAppSecret []byte
  16. GithubAppID string
  17. GithubWebhookSecret string
  18. WebhookURL string
  19. PorterAppRepository repository.PorterAppRepository
  20. }
  21. func SetRepoWebhook(ctx context.Context, inp SetRepoWebhookInput) error {
  22. ctx, span := telemetry.NewSpan(ctx, "porter-app-set-repo-webhook")
  23. defer span.End()
  24. if inp.PorterAppName == "" {
  25. return telemetry.Error(ctx, span, nil, "porter app name is empty")
  26. }
  27. if inp.ClusterID == 0 {
  28. return telemetry.Error(ctx, span, nil, "cluster id is empty")
  29. }
  30. if inp.GithubAppSecret == nil {
  31. return telemetry.Error(ctx, span, nil, "github app secret is nil")
  32. }
  33. if inp.GithubAppID == "" {
  34. return telemetry.Error(ctx, span, nil, "github app id is empty")
  35. }
  36. if inp.GithubWebhookSecret == "" {
  37. return telemetry.Error(ctx, span, nil, "github webhook secret is empty")
  38. }
  39. if inp.PorterAppRepository == nil {
  40. return telemetry.Error(ctx, span, nil, "porter app repository is nil")
  41. }
  42. porterApp, err := inp.PorterAppRepository.ReadPorterAppByName(inp.ClusterID, inp.PorterAppName)
  43. if err != nil {
  44. return telemetry.Error(ctx, span, err, "could not read porter app by name")
  45. }
  46. if porterApp.ID == 0 {
  47. return telemetry.Error(ctx, span, nil, "porter app not found")
  48. }
  49. if porterApp.GitRepoID == 0 {
  50. return telemetry.Error(ctx, span, nil, "porter app git repo id is empty")
  51. }
  52. githubClient, err := getGithubClientByRepoID(ctx, porterApp.GitRepoID, inp.GithubAppSecret, inp.GithubAppID)
  53. if err != nil {
  54. return telemetry.Error(ctx, span, err, "error creating github client")
  55. }
  56. repoDetails := strings.Split(porterApp.RepoName, "/")
  57. if len(repoDetails) != 2 {
  58. return telemetry.Error(ctx, span, nil, "repo name is not in the format <org>/<repo>")
  59. }
  60. if _, _, err := githubClient.Repositories.Get(ctx, repoDetails[0], repoDetails[1]); err != nil {
  61. return telemetry.Error(ctx, span, err, "error getting github repo")
  62. }
  63. hook := &github.Hook{
  64. Config: map[string]interface{}{
  65. "url": inp.WebhookURL,
  66. "content_type": "json",
  67. "secret": inp.GithubWebhookSecret,
  68. },
  69. Events: []string{"pull_request", "push"},
  70. Active: github.Bool(true),
  71. }
  72. if porterApp.GithubWebhookID != 0 {
  73. _, _, err := githubClient.Repositories.EditHook(
  74. context.Background(), repoDetails[0], repoDetails[1], porterApp.GithubWebhookID, hook,
  75. )
  76. if err != nil {
  77. return telemetry.Error(ctx, span, err, "could not edit hook")
  78. }
  79. return nil
  80. }
  81. hook, _, err = githubClient.Repositories.CreateHook(
  82. context.Background(), repoDetails[0], repoDetails[1], hook,
  83. )
  84. if err != nil {
  85. return telemetry.Error(ctx, span, err, "could not create hook")
  86. }
  87. porterApp.GithubWebhookID = hook.GetID()
  88. _, err = inp.PorterAppRepository.UpdatePorterApp(porterApp)
  89. if err != nil {
  90. return telemetry.Error(ctx, span, err, "could not update porter app")
  91. }
  92. return nil
  93. }
  94. func getGithubClientByRepoID(ctx context.Context, repoID uint, githubAppSecret []byte, githubAppID string) (*github.Client, error) {
  95. ctx, span := telemetry.NewSpan(ctx, "get-github-client-by-repo-id")
  96. defer span.End()
  97. if githubAppSecret == nil {
  98. return nil, telemetry.Error(ctx, span, nil, "github app secret is nil")
  99. }
  100. if githubAppID == "" {
  101. return nil, telemetry.Error(ctx, span, nil, "github app id is empty")
  102. }
  103. appID, err := strconv.Atoi(githubAppID)
  104. if err != nil {
  105. return nil, telemetry.Error(ctx, span, err, "could not convert github app id to int")
  106. }
  107. itr, err := ghinstallation.New(
  108. http.DefaultTransport,
  109. int64(appID),
  110. int64(repoID),
  111. githubAppSecret,
  112. )
  113. if err != nil {
  114. return nil, telemetry.Error(ctx, span, err, "could not create github app client")
  115. }
  116. return github.NewClient(&http.Client{Transport: itr}), nil
  117. }