179 lines
5.5 KiB
Go
179 lines
5.5 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"cmr-backend/internal/apperr"
|
|
"cmr-backend/internal/store/postgres"
|
|
)
|
|
|
|
type AdminPipelineService struct {
|
|
store *postgres.Store
|
|
configService *ConfigService
|
|
}
|
|
|
|
type AdminReleaseView struct {
|
|
ID string `json:"id"`
|
|
ReleaseNo int `json:"releaseNo"`
|
|
ConfigLabel string `json:"configLabel"`
|
|
ManifestURL string `json:"manifestUrl"`
|
|
ManifestChecksumSha256 *string `json:"manifestChecksumSha256,omitempty"`
|
|
RouteCode *string `json:"routeCode,omitempty"`
|
|
BuildID *string `json:"buildId,omitempty"`
|
|
Status string `json:"status"`
|
|
PublishedAt string `json:"publishedAt"`
|
|
}
|
|
|
|
type AdminEventPipelineView struct {
|
|
EventID string `json:"eventId"`
|
|
CurrentRelease *AdminReleaseView `json:"currentRelease,omitempty"`
|
|
Sources []EventConfigSourceView `json:"sources"`
|
|
Builds []EventConfigBuildView `json:"builds"`
|
|
Releases []AdminReleaseView `json:"releases"`
|
|
}
|
|
|
|
type AdminRollbackReleaseInput struct {
|
|
ReleaseID string `json:"releaseId"`
|
|
}
|
|
|
|
func NewAdminPipelineService(store *postgres.Store, configService *ConfigService) *AdminPipelineService {
|
|
return &AdminPipelineService{
|
|
store: store,
|
|
configService: configService,
|
|
}
|
|
}
|
|
|
|
func (s *AdminPipelineService) GetEventPipeline(ctx context.Context, eventPublicID string, limit int) (*AdminEventPipelineView, error) {
|
|
event, err := s.store.GetEventByPublicID(ctx, strings.TrimSpace(eventPublicID))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if event == nil {
|
|
return nil, apperr.New(http.StatusNotFound, "event_not_found", "event not found")
|
|
}
|
|
|
|
sources, err := s.configService.ListEventConfigSources(ctx, event.PublicID, limit)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
buildRecords, err := s.store.ListEventConfigBuildsByEventID(ctx, event.ID, limit)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
releaseRecords, err := s.store.ListEventReleasesByEventID(ctx, event.ID, limit)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
builds := make([]EventConfigBuildView, 0, len(buildRecords))
|
|
for i := range buildRecords {
|
|
item, err := buildEventConfigBuildView(&buildRecords[i])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
builds = append(builds, *item)
|
|
}
|
|
releases := make([]AdminReleaseView, 0, len(releaseRecords))
|
|
for _, item := range releaseRecords {
|
|
releases = append(releases, buildAdminReleaseView(item))
|
|
}
|
|
|
|
result := &AdminEventPipelineView{
|
|
EventID: event.PublicID,
|
|
Sources: sources,
|
|
Builds: builds,
|
|
Releases: releases,
|
|
}
|
|
if event.CurrentReleasePubID != nil {
|
|
result.CurrentRelease = &AdminReleaseView{
|
|
ID: *event.CurrentReleasePubID,
|
|
ConfigLabel: derefStringOrEmpty(event.ConfigLabel),
|
|
ManifestURL: derefStringOrEmpty(event.ManifestURL),
|
|
ManifestChecksumSha256: event.ManifestChecksum,
|
|
RouteCode: event.RouteCode,
|
|
Status: "published",
|
|
}
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
func (s *AdminPipelineService) BuildSource(ctx context.Context, sourceID string) (*EventConfigBuildView, error) {
|
|
return s.configService.BuildPreview(ctx, BuildPreviewInput{SourceID: sourceID})
|
|
}
|
|
|
|
func (s *AdminPipelineService) GetBuild(ctx context.Context, buildID string) (*EventConfigBuildView, error) {
|
|
return s.configService.GetEventConfigBuild(ctx, buildID)
|
|
}
|
|
|
|
func (s *AdminPipelineService) PublishBuild(ctx context.Context, buildID string) (*PublishedReleaseView, error) {
|
|
return s.configService.PublishBuild(ctx, PublishBuildInput{BuildID: buildID})
|
|
}
|
|
|
|
func (s *AdminPipelineService) RollbackRelease(ctx context.Context, eventPublicID string, input AdminRollbackReleaseInput) (*AdminReleaseView, error) {
|
|
event, err := s.store.GetEventByPublicID(ctx, strings.TrimSpace(eventPublicID))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if event == nil {
|
|
return nil, apperr.New(http.StatusNotFound, "event_not_found", "event not found")
|
|
}
|
|
|
|
input.ReleaseID = strings.TrimSpace(input.ReleaseID)
|
|
if input.ReleaseID == "" {
|
|
return nil, apperr.New(http.StatusBadRequest, "invalid_params", "releaseId is required")
|
|
}
|
|
|
|
release, err := s.store.GetEventReleaseByPublicID(ctx, input.ReleaseID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if release == nil {
|
|
return nil, apperr.New(http.StatusNotFound, "release_not_found", "release not found")
|
|
}
|
|
if release.EventID != event.ID {
|
|
return nil, apperr.New(http.StatusConflict, "release_not_belong_to_event", "release does not belong to event")
|
|
}
|
|
if release.Status != "published" {
|
|
return nil, apperr.New(http.StatusConflict, "release_not_publishable", "release is not published")
|
|
}
|
|
|
|
tx, err := s.store.Begin(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer tx.Rollback(ctx)
|
|
|
|
if err := s.store.SetCurrentEventRelease(ctx, tx, event.ID, release.ID); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := tx.Commit(ctx); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
view := buildAdminReleaseView(*release)
|
|
return &view, nil
|
|
}
|
|
|
|
func buildAdminReleaseView(item postgres.EventRelease) AdminReleaseView {
|
|
return AdminReleaseView{
|
|
ID: item.PublicID,
|
|
ReleaseNo: item.ReleaseNo,
|
|
ConfigLabel: item.ConfigLabel,
|
|
ManifestURL: item.ManifestURL,
|
|
ManifestChecksumSha256: item.ManifestChecksum,
|
|
RouteCode: item.RouteCode,
|
|
BuildID: item.BuildID,
|
|
Status: item.Status,
|
|
PublishedAt: item.PublishedAt.Format(timeRFC3339),
|
|
}
|
|
}
|
|
|
|
func derefStringOrEmpty(value *string) string {
|
|
if value == nil {
|
|
return ""
|
|
}
|
|
return *value
|
|
}
|