Add errored builds api. fix package parsing of source version numbers
This commit is contained in:
parent
eaae782180
commit
6c31af0166
@ -3,6 +3,7 @@ package buildqueue
|
|||||||
import (
|
import (
|
||||||
"brunel/config"
|
"brunel/config"
|
||||||
"brunel/domain"
|
"brunel/domain"
|
||||||
|
"brunel/helpers"
|
||||||
"brunel/packages"
|
"brunel/packages"
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -30,7 +31,6 @@ func StartPackageQueueWorker(ctx context.Context) {
|
|||||||
packs.ForEach(func(k string, v domain.SourcePackage) bool {
|
packs.ForEach(func(k string, v domain.SourcePackage) bool {
|
||||||
needsBuild := false
|
needsBuild := false
|
||||||
buildVersion := ""
|
buildVersion := ""
|
||||||
buildAttempt := 0
|
|
||||||
v.Packages.ForEach(func(k string, v domain.PackageInfo) bool {
|
v.Packages.ForEach(func(k string, v domain.PackageInfo) bool {
|
||||||
if v.Status == domain.Current {
|
if v.Status == domain.Current {
|
||||||
return true
|
return true
|
||||||
@ -39,11 +39,6 @@ func StartPackageQueueWorker(ctx context.Context) {
|
|||||||
if vs == "" {
|
if vs == "" {
|
||||||
vs = v.Version
|
vs = v.Version
|
||||||
}
|
}
|
||||||
if v.LastBuildStatus == domain.Error {
|
|
||||||
if v.BuildAttempts > 0 {
|
|
||||||
buildAttempt = v.BuildAttempts
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if v.Status == domain.Missing || v.Status == domain.Stale {
|
if v.Status == domain.Missing || v.Status == domain.Stale {
|
||||||
needsBuild = true
|
needsBuild = true
|
||||||
}
|
}
|
||||||
@ -66,11 +61,17 @@ func StartPackageQueueWorker(ctx context.Context) {
|
|||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
if needsBuild {
|
if needsBuild {
|
||||||
if buildAttempt > 1 {
|
state, err := helpers.DBInst.GetBuildState(v.Name)
|
||||||
|
if err != nil {
|
||||||
|
state = domain.BuildState{
|
||||||
|
BuildNumber: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if state.BuildNumber > 1 {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
typ := domain.BuildTypeLTO
|
typ := domain.BuildTypeLTO
|
||||||
if buildAttempt == 1 {
|
if state.BuildNumber == 1 {
|
||||||
typ = domain.BuildTypeNormal
|
typ = domain.BuildTypeNormal
|
||||||
}
|
}
|
||||||
buildItem := domain.BuildQueueItem{
|
buildItem := domain.BuildQueueItem{
|
||||||
@ -79,10 +80,10 @@ func StartPackageQueueWorker(ctx context.Context) {
|
|||||||
Type: typ,
|
Type: typ,
|
||||||
Patch: false,
|
Patch: false,
|
||||||
Rebuild: false,
|
Rebuild: false,
|
||||||
BuildNumber: buildAttempt,
|
BuildNumber: state.BuildNumber,
|
||||||
BuildVersion: buildVersion,
|
BuildVersion: buildVersion,
|
||||||
}
|
}
|
||||||
err := Add(buildItem)
|
err = Add(buildItem)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Info("unable to add package to queue: " + err.Error())
|
slog.Info("unable to add package to queue: " + err.Error())
|
||||||
}
|
}
|
||||||
@ -113,10 +114,13 @@ func processQueueAndStatus(ctx context.Context) {
|
|||||||
slog.Error("unable to check if build is complete: " + err.Error())
|
slog.Error("unable to check if build is complete: " + err.Error())
|
||||||
}
|
}
|
||||||
if complete {
|
if complete {
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
updatePackageStatus(&item, domain.Error, domain.Error)
|
updateBuildState(item, domain.Error)
|
||||||
|
updatePackageStatus(&item, domain.Error)
|
||||||
} else {
|
} else {
|
||||||
updatePackageStatus(&item, domain.Current, domain.Built)
|
updateBuildState(item, domain.Built)
|
||||||
|
updatePackageStatus(&item, domain.Current)
|
||||||
}
|
}
|
||||||
packages.UpdateSourcePackage(item.Source)
|
packages.UpdateSourcePackage(item.Source)
|
||||||
itemsToRemove = append(itemsToRemove, k)
|
itemsToRemove = append(itemsToRemove, k)
|
||||||
@ -136,19 +140,16 @@ func processQueueAndStatus(ctx context.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
time.Sleep(1500 * time.Millisecond)
|
time.Sleep(10 * time.Second)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func updatePackageStatus(item *domain.BuildQueueItem, status domain.PackageStatus, buildStatus domain.PackageStatus) {
|
func updatePackageStatus(item *domain.BuildQueueItem, status domain.PackageStatus) {
|
||||||
item.Source.Packages.ForEach(func(k string, v domain.PackageInfo) bool {
|
item.Source.Packages.ForEach(func(k string, v domain.PackageInfo) bool {
|
||||||
v.Status = status
|
v.Status = status
|
||||||
v.BuildAttempts++
|
|
||||||
v.LastBuildStatus = domain.PackageStatus(buildStatus)
|
|
||||||
if status == domain.Current {
|
if status == domain.Current {
|
||||||
v.Version = item.BuildVersion
|
v.Version = item.BuildVersion
|
||||||
v.BuildAttempts = 0
|
|
||||||
v.NewVersion = ""
|
v.NewVersion = ""
|
||||||
}
|
}
|
||||||
item.Source.Packages.Set(k, v)
|
item.Source.Packages.Set(k, v)
|
||||||
@ -156,6 +157,22 @@ func updatePackageStatus(item *domain.BuildQueueItem, status domain.PackageStatu
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func updateBuildState(item domain.BuildQueueItem, buildStatus domain.PackageStatus) {
|
||||||
|
state, err := helpers.DBInst.GetBuildState(item.Source.Name)
|
||||||
|
if err != nil {
|
||||||
|
state = domain.BuildState{
|
||||||
|
Name: item.Source.Name,
|
||||||
|
Status: string(domain.Queued),
|
||||||
|
BuildVersion: item.BuildVersion,
|
||||||
|
BuildNumber: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state.Status = string(buildStatus)
|
||||||
|
state.BuildVersion = item.BuildVersion
|
||||||
|
state.BuildNumber++
|
||||||
|
helpers.DBInst.UpdateBuildState(state)
|
||||||
|
}
|
||||||
|
|
||||||
func StartQueueAndStatusWorker(ctx context.Context) {
|
func StartQueueAndStatusWorker(ctx context.Context) {
|
||||||
go processQueueAndStatus(ctx)
|
go processQueueAndStatus(ctx)
|
||||||
}
|
}
|
||||||
|
1
db/db.go
1
db/db.go
@ -32,6 +32,7 @@ func New() (*gorm.DB, error) {
|
|||||||
panic("failed to connect database")
|
panic("failed to connect database")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
db.AutoMigrate(&domain.BuildState{})
|
||||||
db.AutoMigrate(&domain.User{})
|
db.AutoMigrate(&domain.User{})
|
||||||
db.AutoMigrate(&domain.Session{})
|
db.AutoMigrate(&domain.Session{})
|
||||||
db.AutoMigrate(&domain.PackageInfo{})
|
db.AutoMigrate(&domain.PackageInfo{})
|
||||||
|
@ -138,6 +138,23 @@ func (r *Repository) UpdateLastUpdateTime(time time.Time) error {
|
|||||||
return tx.Error
|
return tx.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Repository) UpdateBuildState(state domain.BuildState) error {
|
||||||
|
tx := r.db.Save(&state)
|
||||||
|
return tx.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Repository) GetBuildState(name string) (domain.BuildState, error) {
|
||||||
|
var state domain.BuildState
|
||||||
|
tx := r.db.Where("name = ?", name).First(&state)
|
||||||
|
return state, tx.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Repository) GetFailedBuilds() ([]domain.BuildState, error) {
|
||||||
|
var states []domain.BuildState
|
||||||
|
tx := r.db.Where("status = ? AND build_number > 1", string(domain.Error)).Find(&states)
|
||||||
|
return states, tx.Error
|
||||||
|
}
|
||||||
|
|
||||||
func sourcePackageToDto(pkg domain.SourcePackage) domain.SourcePackageDTO {
|
func sourcePackageToDto(pkg domain.SourcePackage) domain.SourcePackageDTO {
|
||||||
dto := domain.SourcePackageDTO{
|
dto := domain.SourcePackageDTO{
|
||||||
Name: pkg.Name,
|
Name: pkg.Name,
|
||||||
|
@ -33,3 +33,10 @@ type BuildQueueCount struct {
|
|||||||
Queued int `json:"queued"`
|
Queued int `json:"queued"`
|
||||||
Building int `json:"building"`
|
Building int `json:"building"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type BuildState struct {
|
||||||
|
Name string `gorm:"primarykey"`
|
||||||
|
Status string
|
||||||
|
BuildVersion string
|
||||||
|
BuildNumber int
|
||||||
|
}
|
||||||
|
2
go.mod
2
go.mod
@ -13,6 +13,7 @@ require (
|
|||||||
github.com/samber/slog-fiber v1.16.0
|
github.com/samber/slog-fiber v1.16.0
|
||||||
github.com/ulikunitz/xz v0.5.12
|
github.com/ulikunitz/xz v0.5.12
|
||||||
golang.org/x/crypto v0.21.0
|
golang.org/x/crypto v0.21.0
|
||||||
|
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1
|
||||||
golang.org/x/net v0.22.0
|
golang.org/x/net v0.22.0
|
||||||
gorm.io/driver/sqlite v1.5.6
|
gorm.io/driver/sqlite v1.5.6
|
||||||
gorm.io/gorm v1.25.11
|
gorm.io/gorm v1.25.11
|
||||||
@ -50,7 +51,6 @@ require (
|
|||||||
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
||||||
go.opentelemetry.io/otel v1.19.0 // indirect
|
go.opentelemetry.io/otel v1.19.0 // indirect
|
||||||
go.opentelemetry.io/otel/trace v1.19.0 // indirect
|
go.opentelemetry.io/otel/trace v1.19.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect
|
|
||||||
golang.org/x/mod v0.12.0 // indirect
|
golang.org/x/mod v0.12.0 // indirect
|
||||||
golang.org/x/sys v0.18.0 // indirect
|
golang.org/x/sys v0.18.0 // indirect
|
||||||
golang.org/x/text v0.14.0 // indirect
|
golang.org/x/text v0.14.0 // indirect
|
||||||
|
29
handlers/build/errored.go
Normal file
29
handlers/build/errored.go
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package handlers_build
|
||||||
|
|
||||||
|
import (
|
||||||
|
"brunel/domain"
|
||||||
|
"brunel/helpers"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"golang.org/x/exp/slog"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ErroredResponse struct {
|
||||||
|
Total int `json:"total"`
|
||||||
|
Packages []domain.BuildState `json:"packages"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func Errored(c *fiber.Ctx) error {
|
||||||
|
states, err := helpers.DBInst.GetFailedBuilds()
|
||||||
|
if err != nil {
|
||||||
|
slog.Error(err.Error())
|
||||||
|
return c.Status(fiber.StatusInternalServerError).SendString("Internal Server Error")
|
||||||
|
}
|
||||||
|
|
||||||
|
response := ErroredResponse{
|
||||||
|
Total: len(states),
|
||||||
|
Packages: states,
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Status(fiber.StatusOK).JSON(response)
|
||||||
|
}
|
65
handlers/build/triggerBuild.go
Normal file
65
handlers/build/triggerBuild.go
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
package handlers_build
|
||||||
|
|
||||||
|
import (
|
||||||
|
"brunel/buildqueue"
|
||||||
|
"brunel/domain"
|
||||||
|
"brunel/packages"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TriggerBuild(c *fiber.Ctx) error {
|
||||||
|
var req struct {
|
||||||
|
PackageName string `json:"packageName"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
BuildType string `json:"buildType"`
|
||||||
|
Rebuild bool `json:"rebuild"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.BodyParser(&req); err != nil {
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||||
|
"error": "Invalid request body",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.PackageName == "" || req.Version == "" || req.BuildType == "" {
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||||
|
"error": "Missing required fields",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
packs := packages.GetPackages()
|
||||||
|
pack, ok := packs.Get(req.PackageName)
|
||||||
|
if !ok {
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||||
|
"error": "Package not found",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
buildItem := domain.BuildQueueItem{
|
||||||
|
Source: pack,
|
||||||
|
BuildVersion: req.Version,
|
||||||
|
Type: domain.BuildType(req.BuildType),
|
||||||
|
Rebuild: req.Rebuild,
|
||||||
|
Status: domain.Queued,
|
||||||
|
Patch: false,
|
||||||
|
BuildNumber: 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := buildqueue.Add(buildItem)
|
||||||
|
if err != nil {
|
||||||
|
if err.Error() == "package already in queue" {
|
||||||
|
return c.Status(fiber.StatusConflict).JSON(fiber.Map{
|
||||||
|
"error": "Package already in queue",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||||
|
"error": "Failed to add build to queue",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Status(fiber.StatusAccepted).JSON(fiber.Map{
|
||||||
|
"message": "Build job added to queue",
|
||||||
|
"package": req.PackageName,
|
||||||
|
})
|
||||||
|
}
|
@ -409,7 +409,25 @@ func fetchPackageFile(pkg config.PackageFile, selectedRepo string) (*haxmap.Map[
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
ver, err := version.Parse(stanza["Version"])
|
sourceSplit := strings.Split(stanza["Source"], " ")
|
||||||
|
source := sourceSplit[0]
|
||||||
|
if source == "" {
|
||||||
|
source = name
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract version from Source if available
|
||||||
|
sourceVersion := ""
|
||||||
|
if len(sourceSplit) > 1 {
|
||||||
|
sourceVersion = strings.Trim(sourceSplit[1], "()")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use sourceVersion if available, otherwise use stanza["Version"]
|
||||||
|
versionStr := stanza["Version"]
|
||||||
|
if sourceVersion != "" {
|
||||||
|
versionStr = sourceVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
ver, err := version.Parse(versionStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -423,12 +441,6 @@ func fetchPackageFile(pkg config.PackageFile, selectedRepo string) (*haxmap.Map[
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceSplit := strings.Split(stanza["Source"], " ")
|
|
||||||
source := sourceSplit[0]
|
|
||||||
if source == "" {
|
|
||||||
source = name
|
|
||||||
}
|
|
||||||
|
|
||||||
packages.Set(name, domain.PackageInfo{
|
packages.Set(name, domain.PackageInfo{
|
||||||
PackageName: name,
|
PackageName: name,
|
||||||
Version: ver.String(),
|
Version: ver.String(),
|
||||||
|
@ -93,8 +93,10 @@ func runServer(ctx context.Context) error {
|
|||||||
server.Get("/api/counts", handlers_packages.Counts)
|
server.Get("/api/counts", handlers_packages.Counts)
|
||||||
server.Get("/api/packages", handlers_packages.Packages)
|
server.Get("/api/packages", handlers_packages.Packages)
|
||||||
server.Get("/api/queue", handlers_build.Queue)
|
server.Get("/api/queue", handlers_build.Queue)
|
||||||
|
server.Get("/api/errored", handlers_build.Errored)
|
||||||
|
|
||||||
server.Post("/api/login", handlers_auth.Login)
|
server.Post("/api/login", handlers_auth.Login)
|
||||||
|
adminRoutes.Post("/triggerBuild", handlers_build.TriggerBuild)
|
||||||
adminRoutes.Post("/register", handlers_auth.Register)
|
adminRoutes.Post("/register", handlers_auth.Register)
|
||||||
adminRoutes.Post("/updatePassword", handlers_auth.UpdatePassword)
|
adminRoutes.Post("/updatePassword", handlers_auth.UpdatePassword)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user