Files
onyx-prebootstrap/internal/models/workstream.go

215 lines
6.4 KiB
Go

package models
import (
"encoding/json"
"fmt"
"time"
)
// Workstream represents a stacked-diff workflow
type Workstream struct {
// Name is the unique identifier for the workstream
Name string `json:"name"`
// Description provides context about the workstream
Description string `json:"description"`
// BaseBranch is the Git branch this workstream is based on
BaseBranch string `json:"base_branch"`
// Commits is an ordered list of commits in this workstream
Commits []WorkstreamCommit `json:"commits"`
// Created is when the workstream was created
Created time.Time `json:"created"`
// Updated is when the workstream was last modified
Updated time.Time `json:"updated"`
// Status indicates the current state (active, merged, abandoned)
Status WorkstreamStatus `json:"status"`
// Metadata contains additional workstream-specific data
Metadata map[string]string `json:"metadata,omitempty"`
}
// WorkstreamCommit represents a single commit in a workstream
type WorkstreamCommit struct {
// SHA is the Git commit hash
SHA string `json:"sha"`
// Message is the commit message
Message string `json:"message"`
// Author is the commit author
Author string `json:"author"`
// Timestamp is when the commit was created
Timestamp time.Time `json:"timestamp"`
// ParentSHA is the parent commit in the workstream (empty for first commit)
ParentSHA string `json:"parent_sha,omitempty"`
// BaseSHA is the base commit from the base branch
BaseSHA string `json:"base_sha"`
// BranchRef is the Git reference for this commit (e.g., refs/onyx/workstreams/name/commit-1)
BranchRef string `json:"branch_ref"`
}
// WorkstreamStatus represents the state of a workstream
type WorkstreamStatus string
const (
// WorkstreamStatusActive indicates the workstream is being actively developed
WorkstreamStatusActive WorkstreamStatus = "active"
// WorkstreamStatusMerged indicates the workstream has been merged
WorkstreamStatusMerged WorkstreamStatus = "merged"
// WorkstreamStatusAbandoned indicates the workstream has been abandoned
WorkstreamStatusAbandoned WorkstreamStatus = "abandoned"
// WorkstreamStatusArchived indicates the workstream has been archived
WorkstreamStatusArchived WorkstreamStatus = "archived"
)
// WorkstreamCollection represents the collection of all workstreams
type WorkstreamCollection struct {
// Workstreams is a map of workstream name to Workstream
Workstreams map[string]*Workstream `json:"workstreams"`
// CurrentWorkstream is the name of the active workstream
CurrentWorkstream string `json:"current_workstream,omitempty"`
}
// NewWorkstream creates a new workstream
func NewWorkstream(name, description, baseBranch string) *Workstream {
now := time.Now()
return &Workstream{
Name: name,
Description: description,
BaseBranch: baseBranch,
Commits: []WorkstreamCommit{},
Created: now,
Updated: now,
Status: WorkstreamStatusActive,
Metadata: make(map[string]string),
}
}
// AddCommit adds a commit to the workstream
func (w *Workstream) AddCommit(commit WorkstreamCommit) {
w.Commits = append(w.Commits, commit)
w.Updated = time.Now()
}
// GetLatestCommit returns the latest commit in the workstream
func (w *Workstream) GetLatestCommit() (*WorkstreamCommit, error) {
if len(w.Commits) == 0 {
return nil, fmt.Errorf("workstream has no commits")
}
return &w.Commits[len(w.Commits)-1], nil
}
// GetCommitCount returns the number of commits in the workstream
func (w *Workstream) GetCommitCount() int {
return len(w.Commits)
}
// IsEmpty returns true if the workstream has no commits
func (w *Workstream) IsEmpty() bool {
return len(w.Commits) == 0
}
// NewWorkstreamCommit creates a new workstream commit
func NewWorkstreamCommit(sha, message, author, parentSHA, baseSHA, branchRef string) WorkstreamCommit {
return WorkstreamCommit{
SHA: sha,
Message: message,
Author: author,
Timestamp: time.Now(),
ParentSHA: parentSHA,
BaseSHA: baseSHA,
BranchRef: branchRef,
}
}
// NewWorkstreamCollection creates a new workstream collection
func NewWorkstreamCollection() *WorkstreamCollection {
return &WorkstreamCollection{
Workstreams: make(map[string]*Workstream),
}
}
// AddWorkstream adds a workstream to the collection
func (wc *WorkstreamCollection) AddWorkstream(workstream *Workstream) error {
if _, exists := wc.Workstreams[workstream.Name]; exists {
return fmt.Errorf("workstream '%s' already exists", workstream.Name)
}
wc.Workstreams[workstream.Name] = workstream
return nil
}
// GetWorkstream retrieves a workstream by name
func (wc *WorkstreamCollection) GetWorkstream(name string) (*Workstream, error) {
workstream, exists := wc.Workstreams[name]
if !exists {
return nil, fmt.Errorf("workstream '%s' not found", name)
}
return workstream, nil
}
// RemoveWorkstream removes a workstream from the collection
func (wc *WorkstreamCollection) RemoveWorkstream(name string) error {
if _, exists := wc.Workstreams[name]; !exists {
return fmt.Errorf("workstream '%s' not found", name)
}
delete(wc.Workstreams, name)
return nil
}
// ListWorkstreams returns all workstreams
func (wc *WorkstreamCollection) ListWorkstreams() []*Workstream {
workstreams := make([]*Workstream, 0, len(wc.Workstreams))
for _, ws := range wc.Workstreams {
workstreams = append(workstreams, ws)
}
return workstreams
}
// SetCurrentWorkstream sets the active workstream
func (wc *WorkstreamCollection) SetCurrentWorkstream(name string) error {
if _, exists := wc.Workstreams[name]; !exists {
return fmt.Errorf("workstream '%s' not found", name)
}
wc.CurrentWorkstream = name
return nil
}
// GetCurrentWorkstream returns the current workstream
func (wc *WorkstreamCollection) GetCurrentWorkstream() (*Workstream, error) {
if wc.CurrentWorkstream == "" {
return nil, fmt.Errorf("no current workstream set")
}
return wc.GetWorkstream(wc.CurrentWorkstream)
}
// Serialize converts the workstream collection to JSON
func (wc *WorkstreamCollection) Serialize() ([]byte, error) {
data, err := json.MarshalIndent(wc, "", " ")
if err != nil {
return nil, fmt.Errorf("failed to marshal workstream collection: %w", err)
}
return data, nil
}
// DeserializeWorkstreamCollection converts JSON data to a workstream collection
func DeserializeWorkstreamCollection(data []byte) (*WorkstreamCollection, error) {
wc := &WorkstreamCollection{}
if err := json.Unmarshal(data, wc); err != nil {
return nil, fmt.Errorf("failed to unmarshal workstream collection: %w", err)
}
return wc, nil
}