Skip to content

Commit fd3a3f9

Browse files
Copilotmrjf
andauthored
Merge origin/main: resolve score.go conflict, bring in workflow-disabled renames and plan.md
Co-authored-by: mrjf <180956+mrjf@users.noreply.github.com>
2 parents 47a3ee7 + dd8d7e8 commit fd3a3f9

29 files changed

Lines changed: 153 additions & 48 deletions
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Migration Plan: APM CLI Python to Go
2+
3+
## Strategy: Greenfield
4+
5+
The Go implementation is built in parallel alongside the existing Python codebase.
6+
The Python version stays runnable for benchmark parity testing throughout.
7+
End state is a clean Go binary with no Python in the shipping artifact.
8+
9+
## Milestones
10+
11+
| # | Milestone | Scope | Acceptance | Status |
12+
|---|-----------|-------|------------|--------|
13+
| 0 | Planning | Inventory, plan, scoring scaffold | Plan committed, score.go exists | done |
14+
| 1 | Build scaffolding | go.mod, go.sum, cmd/apm/main.go stub, CI | `go build ./...` passes, CI green | todo |
15+
| 2 | Go test/parity harness | acceptance tests calling Python binary, parity framework | score.go returns valid JSON, parity_total >= 10 | todo |
16+
| 3 | utils/ + constants + config | internal/utils, internal/constants, internal/config | parity tests pass for all util functions | todo |
17+
| 4 | models/ + primitives/ | internal/models, internal/primitives | parity tests pass for data structures | todo |
18+
| 5 | deps/ | internal/deps -- dependency resolution | parity tests pass for dep resolution | todo |
19+
| 6 | cache/ | internal/cache -- HTTP/git caching | parity tests pass for cache layer | todo |
20+
| 7 | core/ | internal/core -- auth, target detection, orchestration | parity tests pass for core | todo |
21+
| 8 | install/ | internal/install -- install pipeline and phases | parity tests pass for install | todo |
22+
| 9 | commands/ | internal/commands -- cobra replacing click | all commands respond correctly | todo |
23+
| 10 | integration/ | internal/integration -- file integrators | parity tests pass for integrators | todo |
24+
| 11 | compilation/ | internal/compilation -- compilation pipeline | parity tests pass for compilation | todo |
25+
| 12 | runtime/ | internal/runtime -- runtime adapters | parity tests pass | todo |
26+
| 13 | policy/ + security/ | internal/policy, internal/security | parity tests pass | todo |
27+
| 14 | marketplace/ + registry/ | internal/marketplace, internal/registry | parity tests pass | todo |
28+
| 15 | bundle/ + output/ | internal/bundle, internal/output | parity tests pass | todo |
29+
| 16 | CLI entry point wiring | cmd/apm/ final wiring | full CLI parity, migration_score = 1.0 | todo |
30+
31+
## Source Inventory Summary
32+
33+
- **302 Python files** across 20 modules
34+
- Largest modules: install (49), commands (44), marketplace (28), deps (25), utils (20)
35+
- Key external Python deps: click, rich, requests, pyyaml, gitpython, ruamel.yaml, watchdog
36+
37+
## Notes
38+
39+
- Never modify src/apm_cli/ (Python source) -- it is the parity reference
40+
- Never modify tests/ -- Python test suite is the parity oracle
41+
- The score.go script must not be modified after milestone 1 is accepted
42+
- Target: migration_score = 1.0 (all parity tests passing, all Go tests passing)

.crane/scripts/score.go

Lines changed: 52 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
//go:build ignore
22

3-
// score.go: Crane migration scoring script.
4-
// Usage: cd cmd/apm && go test -json ./... | go run ../../.crane/scripts/score.go
3+
// score.go -- migration scoring script for the APM CLI Python-to-Go migration.
4+
// Usage: go test -json ./... | go run .crane/scripts/score.go
5+
// Outputs JSON with migration_score and progress metrics.
56
//
6-
// Reads go test JSON output from stdin and emits a migration score JSON object.
7-
// migration_score = (parity_passing / parity_total) * correctness_gate
8-
// where correctness_gate = 1.0 if all target tests pass, 0.0 otherwise.
7+
// Scoring formula:
8+
// migration_score = (parity_passing / parity_total) * correctness_gate
9+
// correctness_gate = 1.0 if all target tests pass, 0.0 otherwise
10+
//
11+
// NOTE: This script must NOT be modified after milestone 1 is accepted.
912

1013
package main
1114

@@ -14,17 +17,17 @@ import (
1417
"encoding/json"
1518
"fmt"
1619
"os"
20+
"strings"
1721
)
1822

1923
type TestEvent struct {
20-
Action string `json:"Action"`
21-
Test string `json:"Test"`
22-
Package string `json:"Package"`
23-
Elapsed float64 `json:"Elapsed"`
24-
Output string `json:"Output"`
24+
Action string `json:"Action"`
25+
Package string `json:"Package"`
26+
Test string `json:"Test"`
27+
Output string `json:"Output"`
2528
}
2629

27-
type ScoreOutput struct {
30+
type Score struct {
2831
MigrationScore float64 `json:"migration_score"`
2932
Progress float64 `json:"progress"`
3033
ParityPassing int `json:"parity_passing"`
@@ -35,68 +38,69 @@ type ScoreOutput struct {
3538
}
3639

3740
func main() {
38-
var passed, failed int
3941
scanner := bufio.NewScanner(os.Stdin)
4042

43+
var parityPassing, parityTotal, targetPassing, targetTotal int
44+
4145
for scanner.Scan() {
42-
line := scanner.Bytes()
43-
if len(line) == 0 {
46+
line := scanner.Text()
47+
if !strings.HasPrefix(line, "{") {
4448
continue
4549
}
4650
var ev TestEvent
47-
if err := json.Unmarshal(line, &ev); err != nil {
51+
if err := json.Unmarshal([]byte(line), &ev); err != nil {
4852
continue
4953
}
5054
if ev.Test == "" {
51-
// package-level event
5255
continue
5356
}
54-
switch ev.Action {
55-
case "pass":
56-
passed++
57-
case "fail":
58-
failed++
57+
58+
isParity := strings.Contains(ev.Test, "Parity") || strings.Contains(ev.Package, "parity")
59+
isTarget := strings.HasPrefix(ev.Package, "github.com/githubnext/apm/")
60+
61+
if isParity {
62+
if ev.Action == "run" {
63+
parityTotal++
64+
} else if ev.Action == "pass" {
65+
parityPassing++
66+
}
67+
}
68+
if isTarget {
69+
if ev.Action == "run" {
70+
targetTotal++
71+
} else if ev.Action == "pass" {
72+
targetPassing++
73+
}
5974
}
6075
}
6176

62-
total := passed + failed
63-
// parity_total is the number of Python source modules (302).
64-
// Until parity tests are wired, this reflects Go test count.
65-
const parityTotal = 302
66-
parityPassing := 0
67-
if total > 0 {
68-
parityPassing = passed
77+
correctnessGate := 1.0
78+
if targetTotal > 0 && targetPassing < targetTotal {
79+
correctnessGate = 0.0
6980
}
7081

71-
correctnessGate := 0.0
72-
if total > 0 && failed == 0 {
73-
correctnessGate = 1.0
74-
} else if total == 0 {
75-
// No tests yet -- score is 0 but not a failure.
76-
correctnessGate = 0.0
82+
total := 302 // fixed: total Python modules/functions to port
83+
if parityTotal > total {
84+
total = parityTotal
7785
}
7886

79-
progress := 0.0
80-
if parityTotal > 0 {
81-
progress = float64(parityPassing) / float64(parityTotal)
87+
var migrationScore float64
88+
if total > 0 {
89+
migrationScore = (float64(parityPassing) / float64(total)) * correctnessGate
8290
}
8391

84-
migrationScore := progress * correctnessGate
92+
progress := float64(parityPassing) / float64(total)
8593

86-
out := ScoreOutput{
94+
score := Score{
8795
MigrationScore: migrationScore,
8896
Progress: progress,
8997
ParityPassing: parityPassing,
90-
ParityTotal: parityTotal,
91-
SourceTestsPassing: 247,
92-
TargetTestsPassing: passed,
98+
ParityTotal: total,
99+
SourceTestsPassing: 247, // stable Python baseline
100+
TargetTestsPassing: targetPassing,
93101
PerfRatio: 1.0,
94102
}
95103

96-
enc := json.NewEncoder(os.Stdout)
97-
enc.SetIndent("", " ")
98-
if err := enc.Encode(out); err != nil {
99-
fmt.Fprintf(os.Stderr, "score.go: encode error: %v\n", err)
100-
os.Exit(1)
101-
}
104+
out, _ := json.MarshalIndent(score, "", " ")
105+
fmt.Println(string(out))
102106
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

.github/workflows/cli-consistency-checker.lock.yml renamed to .github/workflows-disabled/cli-consistency-checker.lock.yml

File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)