feat: Add created_by field to issues (GH#748)
Add a created_by field to track who created each issue, similar to how comments have an author field. - Add CreatedBy string field to Issue struct - Add migration 029 to add created_by column to issues table - Update all SELECT/INSERT/Scan statements across storage layer - Populate created_by in bd create from actor chain - Display created_by in bd show output 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -268,6 +268,7 @@ var createCmd = &cobra.Command{
|
||||
ExternalRef: externalRefPtr,
|
||||
EstimatedMinutes: estimatedMinutes,
|
||||
Wisp: wisp,
|
||||
CreatedBy: getActorWithGit(), // GH#748: track who created the issue
|
||||
}
|
||||
|
||||
ctx := rootCtx
|
||||
|
||||
@@ -111,6 +111,7 @@ func CreateIssueFromFormValues(ctx context.Context, s storage.Storage, fv *creat
|
||||
IssueType: types.IssueType(fv.IssueType),
|
||||
Assignee: fv.Assignee,
|
||||
ExternalRef: externalRefPtr,
|
||||
CreatedBy: getActorWithGit(), // GH#748: track who created the issue
|
||||
}
|
||||
|
||||
// Check if any dependencies are discovered-from type
|
||||
|
||||
@@ -140,6 +140,9 @@ var showCmd = &cobra.Command{
|
||||
fmt.Printf("Estimated: %d minutes\n", *issue.EstimatedMinutes)
|
||||
}
|
||||
fmt.Printf("Created: %s\n", issue.CreatedAt.Format("2006-01-02 15:04"))
|
||||
if issue.CreatedBy != "" {
|
||||
fmt.Printf("Created by: %s\n", issue.CreatedBy)
|
||||
}
|
||||
fmt.Printf("Updated: %s\n", issue.UpdatedAt.Format("2006-01-02 15:04"))
|
||||
|
||||
// Show compaction status
|
||||
@@ -319,6 +322,9 @@ var showCmd = &cobra.Command{
|
||||
fmt.Printf("Estimated: %d minutes\n", *issue.EstimatedMinutes)
|
||||
}
|
||||
fmt.Printf("Created: %s\n", issue.CreatedAt.Format("2006-01-02 15:04"))
|
||||
if issue.CreatedBy != "" {
|
||||
fmt.Printf("Created by: %s\n", issue.CreatedBy)
|
||||
}
|
||||
fmt.Printf("Updated: %s\n", issue.UpdatedAt.Format("2006-01-02 15:04"))
|
||||
|
||||
// Show compaction status footer
|
||||
|
||||
@@ -247,7 +247,7 @@ func (s *SQLiteStorage) GetDependenciesWithMetadata(ctx context.Context, issueID
|
||||
rows, err := s.db.QueryContext(ctx, `
|
||||
SELECT i.id, i.content_hash, i.title, i.description, i.design, i.acceptance_criteria, i.notes,
|
||||
i.status, i.priority, i.issue_type, i.assignee, i.estimated_minutes,
|
||||
i.created_at, i.updated_at, i.closed_at, i.external_ref, i.source_repo,
|
||||
i.created_at, i.created_by, i.updated_at, i.closed_at, i.external_ref, i.source_repo,
|
||||
i.deleted_at, i.deleted_by, i.delete_reason, i.original_type,
|
||||
i.sender, i.ephemeral, i.pinned, i.is_template,
|
||||
i.await_type, i.await_id, i.timeout_ns, i.waiters,
|
||||
@@ -270,7 +270,7 @@ func (s *SQLiteStorage) GetDependentsWithMetadata(ctx context.Context, issueID s
|
||||
rows, err := s.db.QueryContext(ctx, `
|
||||
SELECT i.id, i.content_hash, i.title, i.description, i.design, i.acceptance_criteria, i.notes,
|
||||
i.status, i.priority, i.issue_type, i.assignee, i.estimated_minutes,
|
||||
i.created_at, i.updated_at, i.closed_at, i.external_ref, i.source_repo,
|
||||
i.created_at, i.created_by, i.updated_at, i.closed_at, i.external_ref, i.source_repo,
|
||||
i.deleted_at, i.deleted_by, i.delete_reason, i.original_type,
|
||||
i.sender, i.ephemeral, i.pinned, i.is_template,
|
||||
i.await_type, i.await_id, i.timeout_ns, i.waiters,
|
||||
@@ -484,7 +484,7 @@ func (s *SQLiteStorage) GetDependencyTree(ctx context.Context, issueID string, m
|
||||
SELECT
|
||||
i.id, i.title, i.status, i.priority, i.description, i.design,
|
||||
i.acceptance_criteria, i.notes, i.issue_type, i.assignee,
|
||||
i.estimated_minutes, i.created_at, i.updated_at, i.closed_at,
|
||||
i.estimated_minutes, i.created_at, i.created_by, i.updated_at, i.closed_at,
|
||||
i.external_ref,
|
||||
0 as depth,
|
||||
i.id as path,
|
||||
@@ -497,7 +497,7 @@ func (s *SQLiteStorage) GetDependencyTree(ctx context.Context, issueID string, m
|
||||
SELECT
|
||||
i.id, i.title, i.status, i.priority, i.description, i.design,
|
||||
i.acceptance_criteria, i.notes, i.issue_type, i.assignee,
|
||||
i.estimated_minutes, i.created_at, i.updated_at, i.closed_at,
|
||||
i.estimated_minutes, i.created_at, i.created_by, i.updated_at, i.closed_at,
|
||||
i.external_ref,
|
||||
t.depth + 1,
|
||||
t.path || '→' || i.id,
|
||||
@@ -525,7 +525,7 @@ func (s *SQLiteStorage) GetDependencyTree(ctx context.Context, issueID string, m
|
||||
SELECT
|
||||
i.id, i.title, i.status, i.priority, i.description, i.design,
|
||||
i.acceptance_criteria, i.notes, i.issue_type, i.assignee,
|
||||
i.estimated_minutes, i.created_at, i.updated_at, i.closed_at,
|
||||
i.estimated_minutes, i.created_at, i.created_by, i.updated_at, i.closed_at,
|
||||
i.external_ref,
|
||||
0 as depth,
|
||||
i.id as path,
|
||||
@@ -538,7 +538,7 @@ func (s *SQLiteStorage) GetDependencyTree(ctx context.Context, issueID string, m
|
||||
SELECT
|
||||
i.id, i.title, i.status, i.priority, i.description, i.design,
|
||||
i.acceptance_criteria, i.notes, i.issue_type, i.assignee,
|
||||
i.estimated_minutes, i.created_at, i.updated_at, i.closed_at,
|
||||
i.estimated_minutes, i.created_at, i.created_by, i.updated_at, i.closed_at,
|
||||
i.external_ref,
|
||||
t.depth + 1,
|
||||
t.path || '→' || i.id,
|
||||
@@ -839,7 +839,7 @@ func (s *SQLiteStorage) scanIssues(ctx context.Context, rows *sql.Rows) ([]*type
|
||||
&issue.ID, &contentHash, &issue.Title, &issue.Description, &issue.Design,
|
||||
&issue.AcceptanceCriteria, &issue.Notes, &issue.Status,
|
||||
&issue.Priority, &issue.IssueType, &assignee, &estimatedMinutes,
|
||||
&issue.CreatedAt, &issue.UpdatedAt, &closedAt, &externalRef, &sourceRepo, &closeReason,
|
||||
&issue.CreatedAt, &issue.CreatedBy, &issue.UpdatedAt, &closedAt, &externalRef, &sourceRepo, &closeReason,
|
||||
&deletedAt, &deletedBy, &deleteReason, &originalType,
|
||||
&sender, &wisp, &pinned, &isTemplate,
|
||||
&awaitType, &awaitID, &timeoutNs, &waiters,
|
||||
@@ -962,7 +962,7 @@ func (s *SQLiteStorage) scanIssuesWithDependencyType(ctx context.Context, rows *
|
||||
&issue.ID, &contentHash, &issue.Title, &issue.Description, &issue.Design,
|
||||
&issue.AcceptanceCriteria, &issue.Notes, &issue.Status,
|
||||
&issue.Priority, &issue.IssueType, &assignee, &estimatedMinutes,
|
||||
&issue.CreatedAt, &issue.UpdatedAt, &closedAt, &externalRef, &sourceRepo,
|
||||
&issue.CreatedAt, &issue.CreatedBy, &issue.UpdatedAt, &closedAt, &externalRef, &sourceRepo,
|
||||
&deletedAt, &deletedBy, &deleteReason, &originalType,
|
||||
&sender, &wisp, &pinned, &isTemplate,
|
||||
&awaitType, &awaitID, &timeoutNs, &waiters,
|
||||
|
||||
@@ -44,16 +44,16 @@ func insertIssue(ctx context.Context, conn *sql.Conn, issue *types.Issue) error
|
||||
INSERT OR IGNORE INTO issues (
|
||||
id, content_hash, title, description, design, acceptance_criteria, notes,
|
||||
status, priority, issue_type, assignee, estimated_minutes,
|
||||
created_at, updated_at, closed_at, external_ref, source_repo, close_reason,
|
||||
created_at, created_by, updated_at, closed_at, external_ref, source_repo, close_reason,
|
||||
deleted_at, deleted_by, delete_reason, original_type,
|
||||
sender, ephemeral, pinned, is_template,
|
||||
await_type, await_id, timeout_ns, waiters
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
`,
|
||||
issue.ID, issue.ContentHash, issue.Title, issue.Description, issue.Design,
|
||||
issue.AcceptanceCriteria, issue.Notes, issue.Status,
|
||||
issue.Priority, issue.IssueType, issue.Assignee,
|
||||
issue.EstimatedMinutes, issue.CreatedAt, issue.UpdatedAt,
|
||||
issue.EstimatedMinutes, issue.CreatedAt, issue.CreatedBy, issue.UpdatedAt,
|
||||
issue.ClosedAt, issue.ExternalRef, sourceRepo, issue.CloseReason,
|
||||
issue.DeletedAt, issue.DeletedBy, issue.DeleteReason, issue.OriginalType,
|
||||
issue.Sender, wisp, pinned, isTemplate,
|
||||
@@ -76,11 +76,11 @@ func insertIssues(ctx context.Context, conn *sql.Conn, issues []*types.Issue) er
|
||||
INSERT OR IGNORE INTO issues (
|
||||
id, content_hash, title, description, design, acceptance_criteria, notes,
|
||||
status, priority, issue_type, assignee, estimated_minutes,
|
||||
created_at, updated_at, closed_at, external_ref, source_repo, close_reason,
|
||||
created_at, created_by, updated_at, closed_at, external_ref, source_repo, close_reason,
|
||||
deleted_at, deleted_by, delete_reason, original_type,
|
||||
sender, ephemeral, pinned, is_template,
|
||||
await_type, await_id, timeout_ns, waiters
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
`)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to prepare statement: %w", err)
|
||||
@@ -110,7 +110,7 @@ func insertIssues(ctx context.Context, conn *sql.Conn, issues []*types.Issue) er
|
||||
issue.ID, issue.ContentHash, issue.Title, issue.Description, issue.Design,
|
||||
issue.AcceptanceCriteria, issue.Notes, issue.Status,
|
||||
issue.Priority, issue.IssueType, issue.Assignee,
|
||||
issue.EstimatedMinutes, issue.CreatedAt, issue.UpdatedAt,
|
||||
issue.EstimatedMinutes, issue.CreatedAt, issue.CreatedBy, issue.UpdatedAt,
|
||||
issue.ClosedAt, issue.ExternalRef, sourceRepo, issue.CloseReason,
|
||||
issue.DeletedAt, issue.DeletedBy, issue.DeleteReason, issue.OriginalType,
|
||||
issue.Sender, wisp, pinned, isTemplate,
|
||||
|
||||
@@ -157,7 +157,7 @@ func (s *SQLiteStorage) GetIssuesByLabel(ctx context.Context, label string) ([]*
|
||||
rows, err := s.db.QueryContext(ctx, `
|
||||
SELECT i.id, i.content_hash, i.title, i.description, i.design, i.acceptance_criteria, i.notes,
|
||||
i.status, i.priority, i.issue_type, i.assignee, i.estimated_minutes,
|
||||
i.created_at, i.updated_at, i.closed_at, i.external_ref, i.source_repo, i.close_reason,
|
||||
i.created_at, i.created_by, i.updated_at, i.closed_at, i.external_ref, i.source_repo, i.close_reason,
|
||||
i.deleted_at, i.deleted_by, i.delete_reason, i.original_type,
|
||||
i.sender, i.ephemeral, i.pinned, i.is_template,
|
||||
i.await_type, i.await_id, i.timeout_ns, i.waiters
|
||||
|
||||
@@ -45,6 +45,7 @@ var migrationsList = []Migration{
|
||||
{"additional_indexes", migrations.MigrateAdditionalIndexes},
|
||||
{"gate_columns", migrations.MigrateGateColumns},
|
||||
{"tombstone_closed_at", migrations.MigrateTombstoneClosedAt},
|
||||
{"created_by_column", migrations.MigrateCreatedByColumn},
|
||||
}
|
||||
|
||||
// MigrationInfo contains metadata about a migration for inspection
|
||||
|
||||
34
internal/storage/sqlite/migrations/029_created_by_column.go
Normal file
34
internal/storage/sqlite/migrations/029_created_by_column.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// MigrateCreatedByColumn adds the created_by column to the issues table.
|
||||
// This tracks who created the issue, using the same actor chain as comment authors
|
||||
// (--actor flag, BD_ACTOR env, or $USER). GH#748.
|
||||
func MigrateCreatedByColumn(db *sql.DB) error {
|
||||
// Check if column already exists
|
||||
var columnExists bool
|
||||
err := db.QueryRow(`
|
||||
SELECT COUNT(*) > 0
|
||||
FROM pragma_table_info('issues')
|
||||
WHERE name = 'created_by'
|
||||
`).Scan(&columnExists)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to check created_by column: %w", err)
|
||||
}
|
||||
|
||||
if columnExists {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Add the created_by column
|
||||
_, err = db.Exec(`ALTER TABLE issues ADD COLUMN created_by TEXT DEFAULT ''`)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to add created_by column: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -470,6 +470,7 @@ func TestMigrateContentHashColumn(t *testing.T) {
|
||||
assignee TEXT,
|
||||
estimated_minutes INTEGER,
|
||||
created_at DATETIME NOT NULL,
|
||||
created_by TEXT DEFAULT '',
|
||||
updated_at DATETIME NOT NULL,
|
||||
closed_at DATETIME,
|
||||
external_ref TEXT,
|
||||
@@ -497,7 +498,7 @@ func TestMigrateContentHashColumn(t *testing.T) {
|
||||
waiters TEXT DEFAULT '',
|
||||
CHECK ((status = 'closed') = (closed_at IS NOT NULL))
|
||||
);
|
||||
INSERT INTO issues SELECT id, title, description, design, acceptance_criteria, notes, status, priority, issue_type, assignee, estimated_minutes, created_at, updated_at, closed_at, external_ref, compaction_level, compacted_at, original_size, compacted_at_commit, source_repo, '', NULL, '', '', '', '', 0, 0, 0, '', '', '', '', '', '', 0, '' FROM issues_backup;
|
||||
INSERT INTO issues SELECT id, title, description, design, acceptance_criteria, notes, status, priority, issue_type, assignee, estimated_minutes, created_at, '', updated_at, closed_at, external_ref, compaction_level, compacted_at, original_size, compacted_at_commit, source_repo, '', NULL, '', '', '', '', 0, 0, 0, '', '', '', '', '', '', 0, '' FROM issues_backup;
|
||||
DROP TABLE issues_backup;
|
||||
`)
|
||||
if err != nil {
|
||||
|
||||
@@ -278,7 +278,7 @@ func (s *SQLiteStorage) GetIssue(ctx context.Context, id string) (*types.Issue,
|
||||
err := s.db.QueryRowContext(ctx, `
|
||||
SELECT id, content_hash, title, description, design, acceptance_criteria, notes,
|
||||
status, priority, issue_type, assignee, estimated_minutes,
|
||||
created_at, updated_at, closed_at, external_ref,
|
||||
created_at, created_by, updated_at, closed_at, external_ref,
|
||||
compaction_level, compacted_at, compacted_at_commit, original_size, source_repo, close_reason,
|
||||
deleted_at, deleted_by, delete_reason, original_type,
|
||||
sender, ephemeral, pinned, is_template,
|
||||
@@ -289,7 +289,7 @@ func (s *SQLiteStorage) GetIssue(ctx context.Context, id string) (*types.Issue,
|
||||
&issue.ID, &contentHash, &issue.Title, &issue.Description, &issue.Design,
|
||||
&issue.AcceptanceCriteria, &issue.Notes, &issue.Status,
|
||||
&issue.Priority, &issue.IssueType, &assignee, &estimatedMinutes,
|
||||
&issue.CreatedAt, &issue.UpdatedAt, &closedAt, &externalRef,
|
||||
&issue.CreatedAt, &issue.CreatedBy, &issue.UpdatedAt, &closedAt, &externalRef,
|
||||
&issue.CompactionLevel, &compactedAt, &compactedAtCommit, &originalSize, &sourceRepo, &closeReason,
|
||||
&deletedAt, &deletedBy, &deleteReason, &originalType,
|
||||
&sender, &wisp, &pinned, &isTemplate,
|
||||
@@ -491,7 +491,7 @@ func (s *SQLiteStorage) GetIssueByExternalRef(ctx context.Context, externalRef s
|
||||
err := s.db.QueryRowContext(ctx, `
|
||||
SELECT id, content_hash, title, description, design, acceptance_criteria, notes,
|
||||
status, priority, issue_type, assignee, estimated_minutes,
|
||||
created_at, updated_at, closed_at, external_ref,
|
||||
created_at, created_by, updated_at, closed_at, external_ref,
|
||||
compaction_level, compacted_at, compacted_at_commit, original_size, source_repo, close_reason,
|
||||
deleted_at, deleted_by, delete_reason, original_type,
|
||||
sender, ephemeral, pinned, is_template,
|
||||
@@ -502,7 +502,7 @@ func (s *SQLiteStorage) GetIssueByExternalRef(ctx context.Context, externalRef s
|
||||
&issue.ID, &contentHash, &issue.Title, &issue.Description, &issue.Design,
|
||||
&issue.AcceptanceCriteria, &issue.Notes, &issue.Status,
|
||||
&issue.Priority, &issue.IssueType, &assignee, &estimatedMinutes,
|
||||
&issue.CreatedAt, &issue.UpdatedAt, &closedAt, &externalRefCol,
|
||||
&issue.CreatedAt, &issue.CreatedBy, &issue.UpdatedAt, &closedAt, &externalRefCol,
|
||||
&issue.CompactionLevel, &compactedAt, &compactedAtCommit, &originalSize, &sourceRepo, &closeReason,
|
||||
&deletedAt, &deletedBy, &deleteReason, &originalType,
|
||||
&sender, &wisp, &pinned, &isTemplate,
|
||||
@@ -1699,7 +1699,7 @@ func (s *SQLiteStorage) SearchIssues(ctx context.Context, query string, filter t
|
||||
querySQL := fmt.Sprintf(`
|
||||
SELECT id, content_hash, title, description, design, acceptance_criteria, notes,
|
||||
status, priority, issue_type, assignee, estimated_minutes,
|
||||
created_at, updated_at, closed_at, external_ref, source_repo, close_reason,
|
||||
created_at, created_by, updated_at, closed_at, external_ref, source_repo, close_reason,
|
||||
deleted_at, deleted_by, delete_reason, original_type,
|
||||
sender, ephemeral, pinned, is_template,
|
||||
await_type, await_id, timeout_ns, waiters
|
||||
|
||||
@@ -137,7 +137,7 @@ func (s *SQLiteStorage) GetReadyWork(ctx context.Context, filter types.WorkFilte
|
||||
query := fmt.Sprintf(`
|
||||
SELECT i.id, i.content_hash, i.title, i.description, i.design, i.acceptance_criteria, i.notes,
|
||||
i.status, i.priority, i.issue_type, i.assignee, i.estimated_minutes,
|
||||
i.created_at, i.updated_at, i.closed_at, i.external_ref, i.source_repo, i.close_reason,
|
||||
i.created_at, i.created_by, i.updated_at, i.closed_at, i.external_ref, i.source_repo, i.close_reason,
|
||||
i.deleted_at, i.deleted_by, i.delete_reason, i.original_type,
|
||||
i.sender, i.ephemeral, i.pinned, i.is_template,
|
||||
i.await_type, i.await_id, i.timeout_ns, i.waiters
|
||||
@@ -476,7 +476,7 @@ func (s *SQLiteStorage) GetBlockedIssues(ctx context.Context, filter types.WorkF
|
||||
SELECT
|
||||
i.id, i.title, i.description, i.design, i.acceptance_criteria, i.notes,
|
||||
i.status, i.priority, i.issue_type, i.assignee, i.estimated_minutes,
|
||||
i.created_at, i.updated_at, i.closed_at, i.external_ref, i.source_repo,
|
||||
i.created_at, i.created_by, i.updated_at, i.closed_at, i.external_ref, i.source_repo,
|
||||
COALESCE(COUNT(d.depends_on_id), 0) as blocked_by_count,
|
||||
COALESCE(GROUP_CONCAT(d.depends_on_id, ','), '') as blocker_ids
|
||||
FROM issues i
|
||||
@@ -537,7 +537,7 @@ func (s *SQLiteStorage) GetBlockedIssues(ctx context.Context, filter types.WorkF
|
||||
&issue.ID, &issue.Title, &issue.Description, &issue.Design,
|
||||
&issue.AcceptanceCriteria, &issue.Notes, &issue.Status,
|
||||
&issue.Priority, &issue.IssueType, &assignee, &estimatedMinutes,
|
||||
&issue.CreatedAt, &issue.UpdatedAt, &closedAt, &externalRef, &sourceRepo, &issue.BlockedByCount,
|
||||
&issue.CreatedAt, &issue.CreatedBy, &issue.UpdatedAt, &closedAt, &externalRef, &sourceRepo, &issue.BlockedByCount,
|
||||
&blockerIDsStr,
|
||||
)
|
||||
if err != nil {
|
||||
@@ -665,7 +665,7 @@ func (s *SQLiteStorage) GetNewlyUnblockedByClose(ctx context.Context, closedIssu
|
||||
query := `
|
||||
SELECT i.id, i.content_hash, i.title, i.description, i.design, i.acceptance_criteria, i.notes,
|
||||
i.status, i.priority, i.issue_type, i.assignee, i.estimated_minutes,
|
||||
i.created_at, i.updated_at, i.closed_at, i.external_ref, i.source_repo, i.close_reason,
|
||||
i.created_at, i.created_by, i.updated_at, i.closed_at, i.external_ref, i.source_repo, i.close_reason,
|
||||
i.deleted_at, i.deleted_by, i.delete_reason, i.original_type,
|
||||
i.sender, i.ephemeral, i.pinned, i.is_template,
|
||||
i.await_type, i.await_id, i.timeout_ns, i.waiters
|
||||
|
||||
@@ -16,6 +16,7 @@ CREATE TABLE IF NOT EXISTS issues (
|
||||
assignee TEXT,
|
||||
estimated_minutes INTEGER,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
created_by TEXT DEFAULT '',
|
||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
closed_at DATETIME,
|
||||
external_ref TEXT,
|
||||
|
||||
@@ -310,7 +310,7 @@ func (t *sqliteTxStorage) GetIssue(ctx context.Context, id string) (*types.Issue
|
||||
row := t.conn.QueryRowContext(ctx, `
|
||||
SELECT id, content_hash, title, description, design, acceptance_criteria, notes,
|
||||
status, priority, issue_type, assignee, estimated_minutes,
|
||||
created_at, updated_at, closed_at, external_ref,
|
||||
created_at, created_by, updated_at, closed_at, external_ref,
|
||||
compaction_level, compacted_at, compacted_at_commit, original_size, source_repo, close_reason,
|
||||
deleted_at, deleted_by, delete_reason, original_type,
|
||||
sender, ephemeral, pinned, is_template,
|
||||
@@ -1127,7 +1127,7 @@ func (t *sqliteTxStorage) SearchIssues(ctx context.Context, query string, filter
|
||||
querySQL := fmt.Sprintf(`
|
||||
SELECT id, content_hash, title, description, design, acceptance_criteria, notes,
|
||||
status, priority, issue_type, assignee, estimated_minutes,
|
||||
created_at, updated_at, closed_at, external_ref,
|
||||
created_at, created_by, updated_at, closed_at, external_ref,
|
||||
compaction_level, compacted_at, compacted_at_commit, original_size, source_repo, close_reason,
|
||||
deleted_at, deleted_by, delete_reason, original_type,
|
||||
sender, ephemeral, pinned, is_template,
|
||||
@@ -1188,7 +1188,7 @@ func scanIssueRow(row scanner) (*types.Issue, error) {
|
||||
&issue.ID, &contentHash, &issue.Title, &issue.Description, &issue.Design,
|
||||
&issue.AcceptanceCriteria, &issue.Notes, &issue.Status,
|
||||
&issue.Priority, &issue.IssueType, &assignee, &estimatedMinutes,
|
||||
&issue.CreatedAt, &issue.UpdatedAt, &closedAt, &externalRef,
|
||||
&issue.CreatedAt, &issue.CreatedBy, &issue.UpdatedAt, &closedAt, &externalRef,
|
||||
&issue.CompactionLevel, &compactedAt, &compactedAtCommit, &originalSize, &sourceRepo, &closeReason,
|
||||
&deletedAt, &deletedBy, &deleteReason, &originalType,
|
||||
&sender, &wisp, &pinned, &isTemplate,
|
||||
|
||||
@@ -23,6 +23,7 @@ type Issue struct {
|
||||
Assignee string `json:"assignee,omitempty"`
|
||||
EstimatedMinutes *int `json:"estimated_minutes,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
CreatedBy string `json:"created_by,omitempty"` // Who created this issue (GH#748)
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
ClosedAt *time.Time `json:"closed_at,omitempty"`
|
||||
CloseReason string `json:"close_reason,omitempty"` // Reason provided when closing the issue
|
||||
@@ -97,7 +98,9 @@ func (i *Issue) ComputeContentHash() string {
|
||||
h.Write([]byte{0})
|
||||
h.Write([]byte(i.Assignee))
|
||||
h.Write([]byte{0})
|
||||
|
||||
h.Write([]byte(i.CreatedBy))
|
||||
h.Write([]byte{0})
|
||||
|
||||
if i.ExternalRef != nil {
|
||||
h.Write([]byte(*i.ExternalRef))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user