|
|
@@ -1,9 +1,16 @@
|
|
|
package stacks
|
|
|
|
|
|
import (
|
|
|
+ "context"
|
|
|
"errors"
|
|
|
+ "fmt"
|
|
|
"net/http"
|
|
|
+ "reflect"
|
|
|
+ "strconv"
|
|
|
|
|
|
+ "github.com/bradleyfalzon/ghinstallation/v2"
|
|
|
+ "github.com/google/go-github/v41/github"
|
|
|
+ "github.com/google/uuid"
|
|
|
"github.com/gorilla/schema"
|
|
|
"github.com/porter-dev/porter/api/server/handlers"
|
|
|
"github.com/porter-dev/porter/api/server/shared"
|
|
|
@@ -13,6 +20,7 @@ import (
|
|
|
"github.com/porter-dev/porter/api/types"
|
|
|
"github.com/porter-dev/porter/internal/models"
|
|
|
"github.com/porter-dev/porter/internal/repository/gorm/helpers"
|
|
|
+ "github.com/porter-dev/porter/internal/telemetry"
|
|
|
"gorm.io/gorm"
|
|
|
)
|
|
|
|
|
|
@@ -53,7 +61,7 @@ func (p *PorterAppEventListHandler) ServeHTTP(w http.ResponseWriter, r *http.Req
|
|
|
return
|
|
|
}
|
|
|
|
|
|
- porterApps, paginatedResult, err := p.Repo().PorterAppEvent().ListEventsByPorterAppID(app.ID, helpers.WithPageSize(20), helpers.WithPage(int(pr.Page)))
|
|
|
+ porterAppEvents, paginatedResult, err := p.Repo().PorterAppEvent().ListEventsByPorterAppID(ctx, app.ID, helpers.WithPageSize(20), helpers.WithPage(int(pr.Page)))
|
|
|
if err != nil {
|
|
|
if !errors.Is(err, gorm.ErrRecordNotFound) {
|
|
|
p.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(reqErr, http.StatusBadRequest))
|
|
|
@@ -61,6 +69,17 @@ func (p *PorterAppEventListHandler) ServeHTTP(w http.ResponseWriter, r *http.Req
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ for idx, appEvent := range porterAppEvents {
|
|
|
+ if appEvent.Status == "PROGRESSING" {
|
|
|
+ pae, err := p.updateExistingAppEvent(ctx, *cluster, stackName, appEvent.ID)
|
|
|
+ if err != nil {
|
|
|
+ p.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(reqErr, http.StatusBadRequest))
|
|
|
+ return
|
|
|
+ }
|
|
|
+ porterAppEvents[idx] = &pae
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
res := struct {
|
|
|
Events []types.PorterAppEvent `json:"events"`
|
|
|
types.PaginationResponse
|
|
|
@@ -69,7 +88,7 @@ func (p *PorterAppEventListHandler) ServeHTTP(w http.ResponseWriter, r *http.Req
|
|
|
}
|
|
|
res.Events = make([]types.PorterAppEvent, 0)
|
|
|
|
|
|
- for _, porterApp := range porterApps {
|
|
|
+ for _, porterApp := range porterAppEvents {
|
|
|
if porterApp == nil {
|
|
|
continue
|
|
|
}
|
|
|
@@ -78,3 +97,111 @@ func (p *PorterAppEventListHandler) ServeHTTP(w http.ResponseWriter, r *http.Req
|
|
|
}
|
|
|
p.WriteResult(w, r, res)
|
|
|
}
|
|
|
+
|
|
|
+func (p *PorterAppEventListHandler) updateExistingAppEvent(ctx context.Context, cluster models.Cluster, stackName string, id uuid.UUID) (models.PorterAppEvent, error) {
|
|
|
+ ctx, span := telemetry.NewSpan(ctx, "update-porter-app-event")
|
|
|
+ defer span.End()
|
|
|
+
|
|
|
+ event, err := p.Repo().PorterAppEvent().ReadEvent(ctx, id)
|
|
|
+ if err != nil {
|
|
|
+ return models.PorterAppEvent{}, telemetry.Error(ctx, span, nil, "error retrieving porter app by name for cluster")
|
|
|
+ }
|
|
|
+
|
|
|
+ telemetry.WithAttributes(span,
|
|
|
+ telemetry.AttributeKV{Key: "porter-app-id", Value: event.PorterAppID},
|
|
|
+ telemetry.AttributeKV{Key: "porter-app-event-id", Value: event.ID.String()},
|
|
|
+ telemetry.AttributeKV{Key: "porter-app-event-status", Value: event.Status},
|
|
|
+ telemetry.AttributeKV{Key: "cluster-id", Value: int(cluster.ID)},
|
|
|
+ telemetry.AttributeKV{Key: "project-id", Value: int(cluster.ProjectID)},
|
|
|
+ )
|
|
|
+
|
|
|
+ repoOrg, ok := event.Metadata["org"].(string)
|
|
|
+ if !ok {
|
|
|
+ return models.PorterAppEvent{}, telemetry.Error(ctx, span, nil, "error retrieving repo org from metadata")
|
|
|
+ }
|
|
|
+
|
|
|
+ repoName, ok := event.Metadata["repo"].(string)
|
|
|
+ if !ok {
|
|
|
+ return models.PorterAppEvent{}, telemetry.Error(ctx, span, nil, "error retrieving repo name from metadata")
|
|
|
+ }
|
|
|
+
|
|
|
+ actionRunIDIface, ok := event.Metadata["action_run_id"]
|
|
|
+ if !ok {
|
|
|
+ return models.PorterAppEvent{}, telemetry.Error(ctx, span, nil, "error retrieving action run id from metadata")
|
|
|
+ }
|
|
|
+ actionRunID, ok := actionRunIDIface.(float64)
|
|
|
+ if !ok {
|
|
|
+ telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "action-run-id-type", Value: reflect.TypeOf(actionRunIDIface).String()})
|
|
|
+ return models.PorterAppEvent{}, telemetry.Error(ctx, span, nil, "error converting action run id to int")
|
|
|
+ }
|
|
|
+
|
|
|
+ accountIDIface, ok := event.Metadata["github_account_id"]
|
|
|
+ if !ok {
|
|
|
+ return models.PorterAppEvent{}, telemetry.Error(ctx, span, nil, "error retrieving github account id from metadata")
|
|
|
+ }
|
|
|
+ githubAccountID, ok := accountIDIface.(float64)
|
|
|
+ if !ok {
|
|
|
+ telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "github-account-id-type", Value: reflect.TypeOf(accountIDIface).String()})
|
|
|
+ return models.PorterAppEvent{}, telemetry.Error(ctx, span, nil, "error converting github account id to int")
|
|
|
+ }
|
|
|
+
|
|
|
+ // read the environment to get the environment id
|
|
|
+ env, err := p.Repo().GithubAppInstallation().ReadGithubAppInstallationByAccountID(int64(githubAccountID))
|
|
|
+ if err != nil {
|
|
|
+ return models.PorterAppEvent{}, telemetry.Error(ctx, span, err, "error reading github environment by owner repo name")
|
|
|
+ }
|
|
|
+
|
|
|
+ ghClient, err := getGithubClientFromEnvironment(p.Config(), env.InstallationID)
|
|
|
+ if err != nil {
|
|
|
+ return models.PorterAppEvent{}, telemetry.Error(ctx, span, err, "error getting github client using porter application")
|
|
|
+ }
|
|
|
+
|
|
|
+ actionRun, _, err := ghClient.Actions.GetWorkflowRunByID(ctx, repoOrg, repoName, int64(actionRunID))
|
|
|
+ if err != nil {
|
|
|
+ return models.PorterAppEvent{}, telemetry.Error(ctx, span, err, "error getting github action run by id")
|
|
|
+ }
|
|
|
+
|
|
|
+ if *actionRun.Status == "completed" {
|
|
|
+ if *actionRun.Conclusion == "success" {
|
|
|
+ event.Status = "SUCCESS"
|
|
|
+ } else {
|
|
|
+ event.Status = "FAILED"
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ fmt.Println("STEFAN", *actionRun.Status, actionRun.Conclusion, event.Status)
|
|
|
+
|
|
|
+ telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "porter-app-event-updated-status", Value: event.Status})
|
|
|
+
|
|
|
+ err = p.Repo().PorterAppEvent().UpdateEvent(ctx, &event)
|
|
|
+ if err != nil {
|
|
|
+ return models.PorterAppEvent{}, telemetry.Error(ctx, span, err, "error creating porter app event")
|
|
|
+ }
|
|
|
+
|
|
|
+ if event.ID == uuid.Nil {
|
|
|
+ return models.PorterAppEvent{}, telemetry.Error(ctx, span, nil, "porter app event not found")
|
|
|
+ }
|
|
|
+
|
|
|
+ return event, nil
|
|
|
+}
|
|
|
+
|
|
|
+func getGithubClientFromEnvironment(config *config.Config, installationID int64) (*github.Client, error) {
|
|
|
+ // get the github app client
|
|
|
+ ghAppId, err := strconv.Atoi(config.ServerConf.GithubAppID)
|
|
|
+ if err != nil {
|
|
|
+ return nil, fmt.Errorf("malformed GITHUB_APP_ID in server configuration: %w", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ // authenticate as github app installation
|
|
|
+ itr, err := ghinstallation.New(
|
|
|
+ http.DefaultTransport,
|
|
|
+ int64(ghAppId),
|
|
|
+ installationID,
|
|
|
+ config.ServerConf.GithubAppSecret,
|
|
|
+ )
|
|
|
+ if err != nil {
|
|
|
+ return nil, fmt.Errorf("error in creating github client from preview environment: %w", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ return github.NewClient(&http.Client{Transport: itr}), nil
|
|
|
+}
|