diff --git a/api/internal/db/database.go b/api/internal/db/database.go index 4bce669e..30a9881c 100644 --- a/api/internal/db/database.go +++ b/api/internal/db/database.go @@ -1976,6 +1976,11 @@ func (d *Database) Migrate() error { return fmt.Errorf("failed to process password reset: %w", err) } + // Ensure default template repository is configured + if err := d.ensureDefaultRepository(); err != nil { + return fmt.Errorf("failed to configure default repository: %w", err) + } + return nil } @@ -2096,3 +2101,66 @@ func (d *Database) checkPasswordReset() error { return nil } + +// ensureDefaultRepository ensures the official StreamSpace templates repository is configured. +// This hardcodes the default repository URL: https://github.com/JoshuaAFerguson/streamspace-templates +// +// The repository will be automatically synced by the sync service on startup. +// +// Behavior: +// - If repository already exists (by name or URL), skip insertion +// - If not exists, insert with status 'pending' to trigger sync +// - Does not fail if repository already configured +// +// Default repository configuration: +// - Name: "streamspace-templates" +// - URL: https://github.com/JoshuaAFerguson/streamspace-templates +// - Branch: main +// - Auth: none (public repository) +// - Status: pending (will be synced automatically) +func (d *Database) ensureDefaultRepository() error { + const ( + defaultRepoName = "streamspace-templates" + defaultRepoURL = "https://github.com/JoshuaAFerguson/streamspace-templates" + defaultBranch = "main" + ) + + // Check if default repository already exists (by name or URL) + var existingID int + err := d.db.QueryRow(` + SELECT id FROM repositories + WHERE name = $1 OR url = $2 + LIMIT 1 + `, defaultRepoName, defaultRepoURL).Scan(&existingID) + + // Repository already exists - skip + if err == nil { + log.Printf("✓ Default template repository '%s' already configured (ID: %d)", defaultRepoName, existingID) + return nil + } + + // Error other than "not found" - report it + if err != sql.ErrNoRows { + return fmt.Errorf("failed to check existing repository: %w", err) + } + + // Repository doesn't exist - insert it + log.Println("📦 Adding default template repository...") + log.Printf(" Name: %s", defaultRepoName) + log.Printf(" URL: %s", defaultRepoURL) + log.Printf(" Branch: %s", defaultBranch) + + _, err = d.db.Exec(` + INSERT INTO repositories (name, url, branch, auth_type, status, created_at, updated_at) + VALUES ($1, $2, $3, 'none', 'pending', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) + `, defaultRepoName, defaultRepoURL, defaultBranch) + + if err != nil { + return fmt.Errorf("failed to insert default repository: %w", err) + } + + log.Println("✓ Default template repository added successfully") + log.Println(" The repository will be synced automatically on startup") + + return nil +} diff --git a/api/internal/sync/parser.go b/api/internal/sync/parser.go index 29e2343e..e7955cf1 100644 --- a/api/internal/sync/parser.go +++ b/api/internal/sync/parser.go @@ -25,7 +25,7 @@ import ( // // Validation: // - Required fields: name, displayName, baseImage -// - API version: stream.streamspace.io/v1alpha1 +// - API version: stream.space/v1alpha1 (or stream.streamspace.io/v1alpha1 for backward compatibility) // - App type inference: desktop (VNC) or webapp (HTTP) // // Example usage: @@ -119,7 +119,7 @@ type ParsedTemplate struct { // // Example YAML: // -// apiVersion: stream.streamspace.io/v1alpha1 +// apiVersion: stream.space/v1alpha1 // kind: Template // metadata: // name: firefox-browser @@ -293,8 +293,9 @@ func (p *TemplateParser) ParseTemplateFile(filePath string) (*ParsedTemplate, er return nil, fmt.Errorf("not a Template resource (kind: %s)", manifest.Kind) } - if manifest.APIVersion != "stream.streamspace.io/v1alpha1" { - return nil, fmt.Errorf("unsupported API version: %s", manifest.APIVersion) + // Support both old and new API versions for backward compatibility + if manifest.APIVersion != "stream.space/v1alpha1" && manifest.APIVersion != "stream.streamspace.io/v1alpha1" { + return nil, fmt.Errorf("unsupported API version: %s (expected stream.space/v1alpha1)", manifest.APIVersion) } // Validate required fields @@ -406,8 +407,9 @@ func (p *TemplateParser) ValidateTemplateManifest(yamlContent string) error { return fmt.Errorf("kind must be 'Template', got '%s'", manifest.Kind) } - if manifest.APIVersion != "stream.streamspace.io/v1alpha1" { - return fmt.Errorf("apiVersion must be 'stream.streamspace.io/v1alpha1', got '%s'", manifest.APIVersion) + // Support both old and new API versions + if manifest.APIVersion != "stream.space/v1alpha1" && manifest.APIVersion != "stream.streamspace.io/v1alpha1" { + return fmt.Errorf("apiVersion must be 'stream.space/v1alpha1', got '%s'", manifest.APIVersion) } if manifest.Metadata.Name == "" {