Check / check (pull_request) Successful in 4m23s
A build whose output ends in Docker's error line now fails with that error, instead of going on to inspect a tag that was never created. The build output is written to the deployment log before the failure is recorded, so the log ends in order. Before building, upaas compares the daemon's API version with 1.39 (Docker Engine 18.09), the first that builds with BuildKit without experimental mode, and fails the deploy on an older daemon instead of letting it use the legacy builder. The README's Compose section gives the update command and the Docker Engine versions builds need. Disclosure: merged after a rebase that changed only TODO.md; the review gated this tree on the current next. Model: opus-5-5 Co-authored-by: clawbot <sneak+clawbot@sneak.cloud>
120 lines
2.9 KiB
Go
120 lines
2.9 KiB
Go
package deploy
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log/slog"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"sneak.berlin/go/upaas/internal/config"
|
|
"sneak.berlin/go/upaas/internal/docker"
|
|
"sneak.berlin/go/upaas/internal/models"
|
|
)
|
|
|
|
// NewTestService creates a Service with minimal dependencies for testing.
|
|
func NewTestService(log *slog.Logger) *Service {
|
|
return &Service{
|
|
log: log,
|
|
}
|
|
}
|
|
|
|
// CancelActiveDeploy exposes cancelActiveDeploy for testing.
|
|
func (svc *Service) CancelActiveDeploy(appID string) {
|
|
svc.cancelActiveDeploy(appID)
|
|
}
|
|
|
|
// RegisterActiveDeploy registers an active deploy for testing.
|
|
func (svc *Service) RegisterActiveDeploy(
|
|
appID string,
|
|
cancel context.CancelFunc,
|
|
done chan struct{},
|
|
) {
|
|
svc.activeDeploys.Store(appID, &activeDeploy{cancel: cancel, done: done})
|
|
}
|
|
|
|
// TryLockApp exposes tryLockApp for testing.
|
|
func (svc *Service) TryLockApp(appID string) bool {
|
|
return svc.tryLockApp(appID)
|
|
}
|
|
|
|
// UnlockApp exposes unlockApp for testing.
|
|
func (svc *Service) UnlockApp(appID string) {
|
|
svc.unlockApp(appID)
|
|
}
|
|
|
|
// NewTestServiceWithConfig creates a Service with config and docker client for testing.
|
|
func NewTestServiceWithConfig(
|
|
log *slog.Logger,
|
|
cfg *config.Config,
|
|
dockerClient *docker.Client,
|
|
) *Service {
|
|
return &Service{
|
|
log: log,
|
|
config: cfg,
|
|
docker: dockerClient,
|
|
}
|
|
}
|
|
|
|
// CleanupCancelledDeploy exposes the build directory cleanup portion of
|
|
// cleanupCancelledDeploy for testing. It removes build directories matching
|
|
// the deployment ID prefix.
|
|
func (svc *Service) CleanupCancelledDeploy(
|
|
_ context.Context,
|
|
appName string,
|
|
deploymentID int64,
|
|
_ string,
|
|
) {
|
|
// We can't create real models.App/Deployment in tests easily,
|
|
// so we test the build dir cleanup portion directly.
|
|
buildDir := svc.GetBuildDir(appName)
|
|
|
|
entries, err := os.ReadDir(buildDir)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
prefix := fmt.Sprintf("%d-", deploymentID)
|
|
|
|
for _, entry := range entries {
|
|
if entry.IsDir() && strings.HasPrefix(entry.Name(), prefix) {
|
|
dirPath := filepath.Join(buildDir, entry.Name())
|
|
_ = os.RemoveAll(dirPath)
|
|
}
|
|
}
|
|
}
|
|
|
|
// GetBuildDirExported exposes GetBuildDir for testing.
|
|
func (svc *Service) GetBuildDirExported(appName string) string {
|
|
return svc.GetBuildDir(appName)
|
|
}
|
|
|
|
// RecordDeployedImage exposes recordDeployedImage for testing.
|
|
func (svc *Service) RecordDeployedImage(
|
|
ctx context.Context,
|
|
app *models.App,
|
|
deployment *models.Deployment,
|
|
imageID docker.ImageID,
|
|
) error {
|
|
return svc.recordDeployedImage(ctx, app, deployment, imageID)
|
|
}
|
|
|
|
// BuildImage exposes buildImage for testing.
|
|
func (svc *Service) BuildImage(
|
|
ctx context.Context,
|
|
app *models.App,
|
|
deployment *models.Deployment,
|
|
) (docker.ImageID, error) {
|
|
return svc.buildImage(ctx, app, deployment)
|
|
}
|
|
|
|
// BuildContainerOptionsExported exposes buildContainerOptions for testing.
|
|
func (svc *Service) BuildContainerOptionsExported(
|
|
ctx context.Context,
|
|
app *models.App,
|
|
imageID docker.ImageID,
|
|
) (docker.CreateContainerOptions, error) {
|
|
return svc.buildContainerOptions(ctx, app, imageID)
|
|
}
|