docs/plans/2026-01-06-remove-redundant-task-proto-fields.md
For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
Goal: Remove redundant fields from task proto messages and retrieve them from plan specs instead
Architecture: Currently, task payload duplicates information already stored in plan specs. We'll remove these duplicate fields from storepb.Task and v1pb.Task.DatabaseUpdate, and modify converters and executors to retrieve this data from the plan spec using the spec_id field.
Tech Stack: Protocol Buffers, Go, PostgreSQL JSONB
From proto/store/store/task.proto (storepb.Task):
environment_id (line 32)database_name (line 34)table_name (line 36)character_set (line 38)collation (line 40)password (line 58)format (line 60)From proto/v1/v1/rollout_service.proto (v1pb.Task.DatabaseUpdate):
schema_version (line 427)Keep in proto/v1/v1/rollout_service.proto:
v1pb.Task.DatabaseCreate message (lines 398-415) - part of public APIv1pb.Task.DatabaseDataExport message (lines 430-443) - part of public APITasks are linked to plan specs via task.payload.spec_id. Each spec contains the authoritative configuration:
PlanConfig_Spec.CreateDatabaseConfig has database, table, character_set, collation, environmentPlanConfig_Spec.ExportDataConfig has format, passwordThe converters and executors will look up the spec and extract these fields when needed.
Files:
proto/store/store/task.protoproto/v1/v1/rollout_service.protoStep 1: Remove fields from storepb.Task
Edit proto/store/store/task.proto and remove lines 31-40 and 57-60:
// REMOVE these lines (31-40):
// The environment where the database will be created.
string environment_id = 5;
// Name of the database to create.
string database_name = 6;
// Optional table name to create (required for some databases like MongoDB).
string table_name = 7;
// Character set for the new database.
string character_set = 8;
// Collation for the new database.
string collation = 9;
// REMOVE these lines (57-60):
// Password to encrypt the exported data archive.
string password = 14;
// Format of the exported data (SQL, CSV, JSON, etc).
ExportFormat format = 15;
Step 2: Remove schema_version from v1pb.Task.DatabaseUpdate
Edit proto/v1/v1/rollout_service.proto and remove lines 426-427:
message DatabaseUpdate {
oneof source {
string sheet = 1;
string release = 4;
}
// REMOVE this line:
// string schema_version = 2;
}
Step 3: Generate proto code
Run: cd proto && buf generate
Step 4: Format proto files
Run: buf format -w proto
Step 5: Commit proto changes
git add proto/store/store/task.proto proto/v1/v1/rollout_service.proto backend/generated-go
git commit -m "refactor: remove redundant task proto fields
Remove duplicate fields from Task proto that are already stored in PlanConfig specs:
- environment_id, database_name, table_name, character_set, collation
- password, format
- schema_version from DatabaseUpdate
These fields will be retrieved from the plan spec using spec_id.
Breaking change: stored Task payloads no longer contain these fields."
Files:
backend/api/v1/rollout_service_task.go:153-173backend/api/v1/rollout_service_task.go:301-326Step 1: Remove field assignments from getTaskCreatesFromCreateDatabaseConfig
Edit backend/api/v1/rollout_service_task.go lines 153-173:
v := &store.TaskMessage{
InstanceID: instance.ResourceID,
DatabaseName: &databaseName,
Environment: effectiveEnvironmentID,
Type: storepb.Task_DATABASE_CREATE,
Payload: &storepb.Task{
SpecId: spec.Id,
// REMOVE these lines:
// CharacterSet: c.CharacterSet,
// TableName: c.Table,
// Collation: c.Collation,
// EnvironmentId: dbEnvironmentID,
// DatabaseName: databaseName,
Source: &storepb.Task_SheetSha256{
SheetSha256: sheet.Sha256,
},
},
}
Step 2: Remove field assignments from getTaskCreatesFromExportDataConfig
Edit backend/api/v1/rollout_service_task.go lines 301-326:
payload := &storepb.Task{
SpecId: spec.Id,
Source: &storepb.Task_SheetSha256{
SheetSha256: c.SheetSha256,
},
// REMOVE these lines:
// Format: c.Format,
}
// REMOVE these lines:
// if c.Password != nil {
// payload.Password = *c.Password
// }
Step 3: Run Go formatter
Run: gofmt -w backend/api/v1/rollout_service_task.go
Step 4: Run linter
Run: golangci-lint run --allow-parallel-runners
Expected: PASS (no new issues)
Step 5: Commit
git add backend/api/v1/rollout_service_task.go
git commit -m "refactor: stop setting redundant fields in task creation
Task payloads no longer duplicate data from plan specs."
Files:
backend/api/v1/rollout_service_converter.goStep 1: Add getSpecFromPlan helper function
Add this function after line 17 in backend/api/v1/rollout_service_converter.go:
// getSpecFromPlan retrieves a spec by ID from a plan's configuration.
func getSpecFromPlan(plan *store.PlanMessage, specID string) (*storepb.PlanConfig_Spec, error) {
if plan.Config == nil {
return nil, errors.Errorf("plan config is nil")
}
for _, spec := range plan.Config.Specs {
if spec.Id == specID {
return spec, nil
}
}
return nil, errors.Errorf("spec %q not found in plan", specID)
}
Step 2: Run Go formatter
Run: gofmt -w backend/api/v1/rollout_service_converter.go
Step 3: Run linter
Run: golangci-lint run --allow-parallel-runners backend/api/v1/rollout_service_converter.go
Expected: PASS
Step 4: Commit
git add backend/api/v1/rollout_service_converter.go
git commit -m "feat: add helper to retrieve spec from plan by ID"
Files:
backend/api/v1/rollout_service_converter.go:151-220backend/api/v1/rollout_service_converter.go:239-267backend/api/v1/rollout_service_converter.go:310-341Step 1: Update convertToRollout to pass plan to converters
Modify convertToRollout function signature and calls (lines 151-220):
func convertToRollout(project *store.ProjectMessage, plan *store.PlanMessage, tasks []*store.TaskMessage, environmentOrderMap map[string]int) (*v1pb.Rollout, error) {
// ... existing code ...
// Update this section (lines 200-208):
var v1Tasks []*v1pb.Task
for _, task := range envTasks {
v1Task, err := convertToTask(project, plan, task) // ADD plan parameter
if err != nil {
return nil, connect.NewError(connect.CodeInternal, errors.Wrapf(err, "failed to convert task"))
}
v1Tasks = append(v1Tasks, v1Task)
}
// ... rest of function ...
}
Step 2: Update convertToTask signature and dispatch
Modify lines 222-237:
func convertToTask(project *store.ProjectMessage, plan *store.PlanMessage, task *store.TaskMessage) (*v1pb.Task, error) {
//exhaustive:enforce
switch task.Type {
case storepb.Task_DATABASE_CREATE:
return convertToTaskFromDatabaseCreate(project, plan, task) // ADD plan
case storepb.Task_DATABASE_MIGRATE:
return convertToTaskFromSchemaUpdate(project, task) // No change
case storepb.Task_DATABASE_EXPORT:
return convertToTaskFromDatabaseDataExport(project, plan, task) // ADD plan
case storepb.Task_TASK_TYPE_UNSPECIFIED:
return nil, errors.Errorf("task type %v is not supported", task.Type)
default:
return nil, errors.Errorf("task type %v is not supported", task.Type)
}
}
Step 3: Update convertToTaskFromDatabaseCreate to get fields from spec
Modify lines 239-267:
func convertToTaskFromDatabaseCreate(project *store.ProjectMessage, plan *store.PlanMessage, task *store.TaskMessage) (*v1pb.Task, error) {
// Retrieve the spec to get configuration details
spec, err := getSpecFromPlan(plan, task.Payload.GetSpecId())
if err != nil {
return nil, errors.Wrapf(err, "failed to get spec for task")
}
createConfig := spec.GetCreateDatabaseConfig()
if createConfig == nil {
return nil, errors.Errorf("spec does not contain create database config")
}
stageID := common.FormatStageID(task.Environment)
v1pbTask := &v1pb.Task{
Name: common.FormatTask(project.ResourceID, task.PlanID, stageID, task.ID),
SpecId: task.Payload.GetSpecId(),
Type: convertToTaskType(task),
Status: convertToTaskStatus(task.LatestTaskRunStatus, task.Payload.GetSkipped()),
SkippedReason: task.Payload.GetSkippedReason(),
Target: common.FormatInstance(task.InstanceID),
Payload: &v1pb.Task_DatabaseCreate_{
DatabaseCreate: &v1pb.Task_DatabaseCreate{
Project: "",
Database: createConfig.Database, // FROM SPEC
Table: createConfig.Table, // FROM SPEC
Sheet: common.FormatSheet(project.ResourceID, task.Payload.GetSheetSha256()),
CharacterSet: createConfig.CharacterSet, // FROM SPEC
Collation: createConfig.Collation, // FROM SPEC
Environment: createConfig.Environment, // FROM SPEC
},
},
}
if task.UpdatedAt != nil {
v1pbTask.UpdateTime = timestamppb.New(*task.UpdatedAt)
}
if task.RunAt != nil {
v1pbTask.RunTime = timestamppb.New(*task.RunAt)
}
return v1pbTask, nil
}
Step 4: Update convertToTaskFromDatabaseDataExport to get fields from spec
Modify lines 310-341:
func convertToTaskFromDatabaseDataExport(project *store.ProjectMessage, plan *store.PlanMessage, task *store.TaskMessage) (*v1pb.Task, error) {
if task.DatabaseName == nil {
return nil, errors.Errorf("data export task database is nil")
}
// Retrieve the spec to get configuration details
spec, err := getSpecFromPlan(plan, task.Payload.GetSpecId())
if err != nil {
return nil, errors.Wrapf(err, "failed to get spec for task")
}
exportConfig := spec.GetExportDataConfig()
if exportConfig == nil {
return nil, errors.Errorf("spec does not contain export data config")
}
targetDatabaseName := fmt.Sprintf("%s%s/%s%s", common.InstanceNamePrefix, task.InstanceID, common.DatabaseIDPrefix, *(task.DatabaseName))
sheet := common.FormatSheet(project.ResourceID, task.Payload.GetSheetSha256())
var password *string
if exportConfig.Password != nil {
password = exportConfig.Password // FROM SPEC
}
v1pbTaskPayload := v1pb.Task_DatabaseDataExport_{
DatabaseDataExport: &v1pb.Task_DatabaseDataExport{
Target: targetDatabaseName,
Sheet: sheet,
Format: convertExportFormat(exportConfig.Format), // FROM SPEC
Password: password, // FROM SPEC
},
}
stageID := common.FormatStageID(task.Environment)
v1pbTask := &v1pb.Task{
Name: common.FormatTask(project.ResourceID, task.PlanID, stageID, task.ID),
SpecId: task.Payload.GetSpecId(),
Type: convertToTaskType(task),
Status: convertToTaskStatus(task.LatestTaskRunStatus, false),
Target: targetDatabaseName,
Payload: &v1pbTaskPayload,
}
if task.UpdatedAt != nil {
v1pbTask.UpdateTime = timestamppb.New(*task.UpdatedAt)
}
if task.RunAt != nil {
v1pbTask.RunTime = timestamppb.New(*task.RunAt)
}
return v1pbTask, nil
}
Step 5: Find and update all calls to convertToRollout
Run: grep -n "convertToRollout" backend/api/v1/rollout_service.go
Update each call site to ensure all parameters are correct.
Step 6: Run Go formatter
Run: gofmt -w backend/api/v1/rollout_service_converter.go backend/api/v1/rollout_service.go
Step 7: Run linter
Run: golangci-lint run --allow-parallel-runners
Expected: PASS (fix any issues)
Step 8: Commit
git add backend/api/v1/rollout_service_converter.go backend/api/v1/rollout_service.go
git commit -m "refactor: get task display fields from plan spec
Converters now retrieve database_name, table_name, character_set,
collation, environment, format, and password from plan specs instead
of task payloads."
Files:
backend/runner/taskrun/database_create_executor.go:36-121Step 1: Update RunOnce to retrieve spec and get environment_id and database_name
Modify the RunOnce method (lines 36-121):
func (exec *DatabaseCreateExecutor) RunOnce(ctx context.Context, driverCtx context.Context, task *store.TaskMessage, _ int) (*storepb.TaskRunResult, error) {
sheet, err := exec.store.GetSheetFull(ctx, task.Payload.GetSheetSha256())
if err != nil {
return nil, errors.Wrapf(err, "failed to get sheet: %s", task.Payload.GetSheetSha256())
}
if sheet == nil {
return nil, errors.Errorf("sheet not found: %s", task.Payload.GetSheetSha256())
}
statement := sheet.Statement
statement = strings.TrimSpace(statement)
if statement == "" {
return nil, errors.Errorf("empty create database statement")
}
instance, err := exec.store.GetInstance(ctx, &store.FindInstanceMessage{ResourceID: &task.InstanceID})
if err != nil {
return nil, err
}
if !common.EngineSupportCreateDatabase(instance.Metadata.GetEngine()) {
return nil, errors.Errorf("creating database is not supported for engine %v", instance.Metadata.GetEngine().String())
}
plan, err := exec.store.GetPlan(ctx, &store.FindPlanMessage{UID: &task.PlanID})
if err != nil {
return nil, errors.Wrapf(err, "failed to get plan %v", task.PlanID)
}
if plan == nil {
return nil, errors.Errorf("plan %v not found", task.PlanID)
}
// NEW: Retrieve the spec to get configuration details
spec, err := getSpecFromPlan(plan, task.Payload.GetSpecId())
if err != nil {
return nil, errors.Wrapf(err, "failed to get spec for task")
}
createConfig := spec.GetCreateDatabaseConfig()
if createConfig == nil {
return nil, errors.Errorf("spec does not contain create database config")
}
// Create database.
slog.Debug("Start creating database...",
slog.String("instance", instance.Metadata.GetTitle()),
slog.String("database", createConfig.Database), // FROM SPEC
slog.String("statement", statement),
)
// NEW: Get environment_id from spec
envID := ""
if createConfig.Environment != "" {
envID = strings.TrimPrefix(createConfig.Environment, common.EnvironmentNamePrefix)
}
var environmentID *string
if envID != "" {
environmentID = &envID
}
database, err := exec.store.UpsertDatabase(ctx, &store.DatabaseMessage{
ProjectID: plan.ProjectID,
InstanceID: instance.ResourceID,
DatabaseName: createConfig.Database, // FROM SPEC
EnvironmentID: environmentID,
Metadata: &storepb.DatabaseMetadata{},
})
if err != nil {
return nil, err
}
var defaultDBDriver db.Driver
switch instance.Metadata.GetEngine() {
case storepb.Engine_MONGODB:
defaultDBDriver, err = exec.dbFactory.GetAdminDatabaseDriver(ctx, instance, database, db.ConnectionContext{})
if err != nil {
return nil, err
}
default:
defaultDBDriver, err = exec.dbFactory.GetAdminDatabaseDriver(ctx, instance, nil /* database */, db.ConnectionContext{})
if err != nil {
return nil, err
}
}
defer defaultDBDriver.Close(ctx)
if _, err := defaultDBDriver.Execute(driverCtx, statement, db.ExecuteOptions{CreateDatabase: true}); err != nil {
return nil, err
}
if err := exec.schemaSyncer.SyncDatabaseSchema(ctx, database); err != nil {
slog.Error("failed to sync database schema",
slog.String("instanceName", instance.ResourceID),
slog.String("databaseName", database.DatabaseName),
log.BBError(err),
)
}
return &storepb.TaskRunResult{}, nil
}
Step 2: Add getSpecFromPlan helper function
Add this function at the top of the file after imports:
// getSpecFromPlan retrieves a spec by ID from a plan's configuration.
func getSpecFromPlan(plan *store.PlanMessage, specID string) (*storepb.PlanConfig_Spec, error) {
if plan.Config == nil {
return nil, errors.Errorf("plan config is nil")
}
for _, spec := range plan.Config.Specs {
if spec.Id == specID {
return spec, nil
}
}
return nil, errors.Errorf("spec %q not found in plan", specID)
}
Step 3: Add import for strings package if not already present
Check if strings is imported, add if needed.
Step 4: Run Go formatter
Run: gofmt -w backend/runner/taskrun/database_create_executor.go
Step 5: Run linter
Run: golangci-lint run --allow-parallel-runners
Expected: PASS (fix any issues)
Step 6: Commit
git add backend/runner/taskrun/database_create_executor.go
git commit -m "refactor: get database create fields from plan spec
DatabaseCreateExecutor now retrieves environment_id and database_name
from the plan spec instead of task payload."
Files:
backend/runner/taskrun/data_export_executor.go:47-106Step 1: Update RunOnce to retrieve spec and get format
Modify the RunOnce method (lines 47-106):
func (exec *DataExportExecutor) RunOnce(ctx context.Context, _ context.Context, task *store.TaskMessage, _ int) (*storepb.TaskRunResult, error) {
issue, err := exec.store.GetIssue(ctx, &store.FindIssueMessage{PlanUID: &task.PlanID})
if err != nil {
return nil, errors.Wrapf(err, "failed to get issue")
}
database, err := exec.store.GetDatabase(ctx, &store.FindDatabaseMessage{InstanceID: &task.InstanceID, DatabaseName: task.DatabaseName, ShowDeleted: true})
if err != nil {
return nil, errors.Wrapf(err, "failed to get database")
}
if database == nil {
return nil, errors.Errorf("database not found")
}
instance, err := exec.store.GetInstance(ctx, &store.FindInstanceMessage{ResourceID: &database.InstanceID, ShowDeleted: true})
if err != nil {
return nil, errors.Wrapf(err, "failed to get instance")
}
if instance == nil {
return nil, errors.Errorf("instance not found")
}
sheet, err := exec.store.GetSheetFull(ctx, task.Payload.GetSheetSha256())
if err != nil {
return nil, err
}
if sheet == nil {
return nil, errors.Errorf("sheet not found: %s", task.Payload.GetSheetSha256())
}
statement := sheet.Statement
// NEW: Get plan and spec to retrieve export configuration
plan, err := exec.store.GetPlan(ctx, &store.FindPlanMessage{UID: &task.PlanID})
if err != nil {
return nil, errors.Wrapf(err, "failed to get plan %v", task.PlanID)
}
if plan == nil {
return nil, errors.Errorf("plan %v not found", task.PlanID)
}
spec, err := getSpecFromPlan(plan, task.Payload.GetSpecId())
if err != nil {
return nil, errors.Wrapf(err, "failed to get spec for task")
}
exportConfig := spec.GetExportDataConfig()
if exportConfig == nil {
return nil, errors.Errorf("spec does not contain export data config")
}
dataSource := apiv1.GetQueriableDataSource(instance)
creatorUser, err := exec.store.GetUserByEmail(ctx, issue.CreatorEmail)
if err != nil {
return nil, errors.Wrapf(err, "failed to get creator user for issue %d", issue.UID)
}
if creatorUser == nil {
return nil, errors.Errorf("creator user not found for issue %d", issue.UID)
}
// Execute the export without masking.
// For approved DATABASE_EXPORT tasks, the approval itself authorizes access to the data.
bytes, exportErr := exec.executeExport(ctx, instance, database, dataSource, statement, exportConfig.Format, creatorUser) // FROM SPEC
if exportErr != nil {
return nil, errors.Wrap(exportErr, "failed to export data")
}
exportArchive, err := exec.store.CreateExportArchive(ctx, &store.ExportArchiveMessage{
Bytes: bytes,
Payload: &storepb.ExportArchivePayload{
FileFormat: exportConfig.Format, // FROM SPEC
},
})
if err != nil {
return nil, errors.Wrap(err, "failed to create export archive")
}
return &storepb.TaskRunResult{
ExportArchiveUid: int32(exportArchive.UID),
}, nil
}
Step 2: Add getSpecFromPlan helper function (if not already present)
Add this function at the top of the file after imports (only if it doesn't already exist from a previous task):
// getSpecFromPlan retrieves a spec by ID from a plan's configuration.
func getSpecFromPlan(plan *store.PlanMessage, specID string) (*storepb.PlanConfig_Spec, error) {
if plan.Config == nil {
return nil, errors.Errorf("plan config is nil")
}
for _, spec := range plan.Config.Specs {
if spec.Id == specID {
return spec, nil
}
}
return nil, errors.Errorf("spec %q not found in plan", specID)
}
Step 3: Run Go formatter
Run: gofmt -w backend/runner/taskrun/data_export_executor.go
Step 4: Run linter
Run: golangci-lint run --allow-parallel-runners
Expected: PASS (fix any issues)
Step 5: Commit
git add backend/runner/taskrun/data_export_executor.go
git commit -m "refactor: get data export format from plan spec
DataExportExecutor now retrieves export format from the plan spec
instead of task payload."
Files:
backend/common/plan_utils.gobackend/api/v1/rollout_service_converter.gobackend/runner/taskrun/database_create_executor.gobackend/runner/taskrun/data_export_executor.goStep 1: Create plan_utils.go with shared helper
Create backend/common/plan_utils.go:
package common
import (
"github.com/pkg/errors"
storepb "github.com/bytebase/bytebase/backend/generated-go/store"
"github.com/bytebase/bytebase/backend/store"
)
// GetSpecFromPlan retrieves a spec by ID from a plan's configuration.
func GetSpecFromPlan(plan *store.PlanMessage, specID string) (*storepb.PlanConfig_Spec, error) {
if plan.Config == nil {
return nil, errors.Errorf("plan config is nil")
}
for _, spec := range plan.Config.Specs {
if spec.Id == specID {
return spec, nil
}
}
return nil, errors.Errorf("spec %q not found in plan", specID)
}
Step 2: Replace local getSpecFromPlan in rollout_service_converter.go
Edit backend/api/v1/rollout_service_converter.go:
getSpecFromPlan functiongetSpecFromPlan with common.GetSpecFromPlanStep 3: Replace local getSpecFromPlan in database_create_executor.go
Edit backend/runner/taskrun/database_create_executor.go:
getSpecFromPlan functiongetSpecFromPlan with common.GetSpecFromPlanStep 4: Replace local getSpecFromPlan in data_export_executor.go
Edit backend/runner/taskrun/data_export_executor.go:
getSpecFromPlan functiongetSpecFromPlan with common.GetSpecFromPlanStep 5: Run Go formatter
Run: gofmt -w backend/common/plan_utils.go backend/api/v1/rollout_service_converter.go backend/runner/taskrun/database_create_executor.go backend/runner/taskrun/data_export_executor.go
Step 6: Run linter
Run: golangci-lint run --allow-parallel-runners
Expected: PASS
Step 7: Commit
git add backend/common/plan_utils.go backend/api/v1/rollout_service_converter.go backend/runner/taskrun/database_create_executor.go backend/runner/taskrun/data_export_executor.go
git commit -m "refactor: extract GetSpecFromPlan to common utility
Consolidate duplicate getSpecFromPlan implementations into a single
shared utility function in the common package."
Files:
Step 1: Run backend tests
Run: go test -v -count=1 github.com/bytebase/bytebase/backend/api/v1 -run TestRollout
Expected: Tests may fail due to proto changes
Step 2: Identify failing tests
Review test output and identify tests that fail due to:
Step 3: Update test fixtures and mocks
For each failing test:
Step 4: Run executor tests
Run: go test -v -count=1 github.com/bytebase/bytebase/backend/runner/taskrun
Expected: Tests should pass after executor changes
Step 5: Fix any remaining test failures
Iterate on test fixes until all tests pass.
Step 6: Run full linter
Run: golangci-lint run --allow-parallel-runners
Expected: PASS
Step 7: Commit test fixes
git add backend/api/v1/*_test.go backend/runner/taskrun/*_test.go
git commit -m "test: update tests for removed task proto fields
Update test fixtures and assertions to work with new architecture
where fields are retrieved from plan specs."
Files:
backend/migrator/migrator_test.goStep 1: Check TestLatestVersion test
The CLAUDE.md instructions state that TestLatestVersion needs update after migration file changes. Since we're changing stored proto structure, check if this test needs updating.
Run: go test -v -count=1 github.com/bytebase/bytebase/backend/migrator -run TestLatestVersion
Step 2: Update test if needed
If the test fails, update the test expectations to match the new proto structure.
Step 3: Run test again
Run: go test -v -count=1 github.com/bytebase/bytebase/backend/migrator -run TestLatestVersion
Expected: PASS
Step 4: Commit if changes made
git add backend/migrator/migrator_test.go
git commit -m "test: update migrator test for proto changes"
Files:
Step 1: Build backend
Run: go build -ldflags "-w -s" -p=16 -o ./bytebase-build/bytebase ./backend/bin/server/main.go
Expected: Build succeeds
Step 2: Run all linters
Run: golangci-lint run --allow-parallel-runners
Expected: PASS (run multiple times until no issues)
Step 3: Run full backend test suite
Run: go test -v -count=1 github.com/bytebase/bytebase/backend/...
Expected: All tests pass
Step 4: Verify proto formatting
Run: buf format -w proto && buf lint proto
Expected: No changes, no lint errors
Step 5: Final commit if any formatting changes
git add -A
git commit -m "chore: final cleanup and formatting"
Files:
Step 1: Push branch
Run: git push -u origin main
Step 2: Verify all commits
Run: git log --oneline -15
Review commit history to ensure all changes are properly committed.
Step 3: Run final verification
# Ensure build works
go build -ldflags "-w -s" -p=16 -o ./bytebase-build/bytebase ./backend/bin/server/main.go
# Ensure tests pass
go test -v -count=1 github.com/bytebase/bytebase/backend/api/v1
go test -v -count=1 github.com/bytebase/bytebase/backend/runner/taskrun
# Ensure linter passes
golangci-lint run --allow-parallel-runners
Expected: All commands succeed
This plan removes redundant fields from task proto messages and updates all code to retrieve these fields from plan specs instead. The changes include:
storepb.Task and 1 field from v1pb.Task.DatabaseUpdatespec_idspec_idGetSpecFromPlan helperBreaking Changes:
Benefits: