Root causes of the remaining 5 CI PG failures (and the hidden flaky set):
1. All PG-integration packages shared ONE database under parallel package
execution - migrations/seeds/truncates raced (nondeterministic failure
sets, locally and in CI).
Fix: RequireTestDatabaseURL/SkipIfNoTestDatabaseURL now derive a
per-package database (<base>_<pkgHash>, advisory-lock-guarded
CREATE); 9 raw-env straggler tests funnelled through the helpers;
db-package tests call it unqualified (no import cycle).
2. Approval-chain fixtures were not production-shaped: freezeReviewSnapshot
only honors head_snapshot_id, fake content hashes never froze a
snapshot, so ApproverApprove rejected with 'approved requires frozen
review_snapshot_id'. Errors were swallowed (_, _ =) hiding this.
Fix (ownership-respecting, arch-enforced):
- docrevision.SeedContentSnapshotForTest seeds the ledger tables it owns
- docgov GovernanceEngine.FreezeHeadSnapshotForTest freezes head/review
pointers on document_records (docgov-owned) and clears engine cache
- all four integration fixtures use the pair; swallowed errors checked
3. Fixed-name fixtures collide once a package shares one DB (projects
uq_projects_name_global): uniquified in projectinstance + server tests.
4. CAS/ctxmgr tests never bootstrapped migrations (relied on other packages
having migrated the shared DB): explicit RunMigrationsOnceForTest.
Verified: full parallel short suite = 75 packages, 0 failures against an
isolated throwaway PG. CI skip list removed - short tests fully required.
79 lines
1.8 KiB
Go
79 lines
1.8 KiB
Go
package projectinstance
|
|
|
|
import "context"
|
|
|
|
// DocumentApprovedResult 文档批准后阶段就绪评估结果。
|
|
type DocumentApprovedResult struct {
|
|
StageReady bool
|
|
InstanceID int64
|
|
StageInstanceID int64
|
|
StageKey string
|
|
StageName string
|
|
ConfigRevision int
|
|
RequiredDocCount int
|
|
ApprovedDocCount int
|
|
}
|
|
|
|
// HandleDocumentApproved 同步文档任务状态并评估是否首次满足阶段推进条件。
|
|
func (s *Service) HandleDocumentApproved(ctx context.Context, projectID int64, taskKey string) (*DocumentApprovedResult, error) {
|
|
out := &DocumentApprovedResult{}
|
|
if s == nil || !s.Available() || projectID <= 0 || taskKey == "" {
|
|
return out, nil
|
|
}
|
|
|
|
if err := s.store.MarkDocTaskApproved(ctx, projectID, taskKey); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
live, err := s.store.GetLiveInstance(ctx, projectID)
|
|
if err != nil || live == nil {
|
|
return out, err
|
|
}
|
|
|
|
detail, err := s.store.GetInstanceByID(ctx, live.ID)
|
|
if err != nil || detail == nil || detail.ActiveStageKey == "" {
|
|
return out, err
|
|
}
|
|
|
|
readiness, err := s.GetStageReadiness(ctx, live.ID, detail.ActiveStageKey, 0, true)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if !readiness.Ready {
|
|
return out, nil
|
|
}
|
|
|
|
var stageInstID int64
|
|
for _, st := range detail.Stages {
|
|
if st.StageKey == detail.ActiveStageKey {
|
|
stageInstID = st.ID
|
|
break
|
|
}
|
|
}
|
|
if stageInstID <= 0 {
|
|
return out, nil
|
|
}
|
|
|
|
required := 0
|
|
approved := 0
|
|
for _, dt := range readiness.DocTasks {
|
|
if !dt.Enabled || !dt.Required {
|
|
continue
|
|
}
|
|
required++
|
|
if dt.Approved {
|
|
approved++
|
|
}
|
|
}
|
|
|
|
out.StageReady = true
|
|
out.InstanceID = live.ID
|
|
out.StageInstanceID = stageInstID
|
|
out.StageKey = readiness.StageKey
|
|
out.StageName = readiness.StageName
|
|
out.ConfigRevision = readiness.ConfigRevision
|
|
out.RequiredDocCount = required
|
|
out.ApprovedDocCount = approved
|
|
return out, nil
|
|
}
|