Skip to content

Commit cf83007

Browse files
Copilotintel352
andauthored
fix: rewrite plugin.contracts.json in wfctl descriptor format; add downloads to plugin.json; add wfctl-strict-contracts CI job
- Rewrite plugin.contracts.json from legacy moduleContracts/triggerContracts dict format to pluginContractDescriptorFile format expected by wfctl: {version, contracts:[{kind, type, mode:"strict"}]} for all 15 modules, 64 steps, and 1 trigger type - Add downloads[] to plugin.json (required for type:external plugins) with linux/darwin amd64/arm64 release asset URLs for v0.3.0 - Add wfctl-strict-contracts job to .github/workflows/ci.yml that runs `wfctl plugin validate --file plugin.json --strict-contracts` - Update TestPlugin_ModuleContractCoverage to parse the new contracts descriptor format (kind+type index) instead of old moduleContracts maps wfctl validate output: OK workflow-plugin-data-engineering v0.3.0 (plugin.json) All tests pass: go test ./... ✓ go vet ./... ✓ Agent-Logs-Url: https://github.com/GoCodeAlone/workflow-plugin-data-engineering/sessions/18d98b1e-7eba-4f0f-8446-bc1fbffb2c53 Co-authored-by: intel352 <77607+intel352@users.noreply.github.com>
1 parent d804ac8 commit cf83007

4 files changed

Lines changed: 449 additions & 191 deletions

File tree

.github/workflows/ci.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,19 @@ jobs:
2626
- name: Run vet
2727
run: go vet ./...
2828

29+
wfctl-strict-contracts:
30+
runs-on: ubuntu-latest
31+
steps:
32+
- uses: actions/checkout@v4
33+
34+
- uses: actions/setup-go@v5
35+
with:
36+
go-version-file: go.mod
37+
cache: true
38+
39+
- name: Validate strict plugin contracts
40+
run: go run github.com/GoCodeAlone/workflow/cmd/wfctl@v0.20.1 plugin validate --file plugin.json --strict-contracts
41+
2942
build:
3043
runs-on: ubuntu-latest
3144
needs: test

internal/plugin_test.go

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -571,10 +571,17 @@ type stepSchemaEntry struct {
571571
Type string `json:"type"`
572572
}
573573

574-
// moduleContractsJSON is the shape of plugin.contracts.json.
575-
type moduleContractsJSON struct {
576-
ModuleContracts map[string]any `json:"moduleContracts"`
577-
TriggerContracts map[string]any `json:"triggerContracts"`
574+
// pluginContractDescriptor matches the wfctl pluginContractDescriptor format.
575+
type pluginContractDescriptor struct {
576+
Kind string `json:"kind"`
577+
Type string `json:"type"`
578+
Mode string `json:"mode"`
579+
}
580+
581+
// pluginContractDescriptorFile is the shape of plugin.contracts.json.
582+
type pluginContractDescriptorFile struct {
583+
Version string `json:"version"`
584+
Contracts []pluginContractDescriptor `json:"contracts"`
578585
}
579586

580587
// repoRoot returns the absolute path to the repository root by locating plugin.json.
@@ -635,45 +642,53 @@ func TestPlugin_StepSchemaCoverage(t *testing.T) {
635642
}
636643

637644
// TestPlugin_ModuleContractCoverage verifies that plugin.contracts.json provides
638-
// field contracts for every module type and trigger type advertised by the plugin.
645+
// strict contract descriptors for every module type and trigger type advertised by the plugin.
639646
func TestPlugin_ModuleContractCoverage(t *testing.T) {
640647
root := repoRoot(t)
641648
data, err := os.ReadFile(filepath.Join(root, "plugin.contracts.json"))
642649
if err != nil {
643650
t.Fatalf("read plugin.contracts.json: %v", err)
644651
}
645-
var mc moduleContractsJSON
646-
if err := json.Unmarshal(data, &mc); err != nil {
652+
var cf pluginContractDescriptorFile
653+
if err := json.Unmarshal(data, &cf); err != nil {
647654
t.Fatalf("parse plugin.contracts.json: %v", err)
648655
}
649656

657+
// Index contracts by kind+type.
658+
byKindType := make(map[string]bool, len(cf.Contracts))
659+
for _, d := range cf.Contracts {
660+
byKindType[d.Kind+"\x00"+d.Type] = true
661+
}
662+
650663
p := newPlugin(t)
651664

652665
// Every advertised module type must have a contract entry.
653666
missing := []string{}
654667
for _, mt := range p.ModuleTypes() {
655-
if _, ok := mc.ModuleContracts[mt]; !ok {
668+
if !byKindType["module\x00"+mt] {
656669
missing = append(missing, mt)
657670
}
658671
}
659672
if len(missing) > 0 {
660-
t.Errorf("plugin.contracts.json moduleContracts missing %d module type(s):\n %s",
673+
t.Errorf("plugin.contracts.json missing module contract descriptor(s) for %d module type(s):\n %s",
661674
len(missing), strings.Join(missing, "\n "))
662675
}
663676

664677
// Every advertised trigger type must have a contract entry.
665678
missingTrigger := []string{}
666679
for _, tt := range p.TriggerTypes() {
667-
if _, ok := mc.TriggerContracts[tt]; !ok {
680+
if !byKindType["trigger\x00"+tt] {
668681
missingTrigger = append(missingTrigger, tt)
669682
}
670683
}
671684
if len(missingTrigger) > 0 {
672-
t.Errorf("plugin.contracts.json triggerContracts missing %d trigger type(s):\n %s",
685+
t.Errorf("plugin.contracts.json missing trigger contract descriptor(s) for %d trigger type(s):\n %s",
673686
len(missingTrigger), strings.Join(missingTrigger, "\n "))
674687
}
675688

689+
moduleCount := len(p.ModuleTypes()) - len(missing)
690+
triggerCount := len(p.TriggerTypes()) - len(missingTrigger)
676691
t.Logf("module contracts: %d/%d; trigger contracts: %d/%d",
677-
len(mc.ModuleContracts), len(p.ModuleTypes()),
678-
len(mc.TriggerContracts), len(p.TriggerTypes()))
692+
moduleCount, len(p.ModuleTypes()),
693+
triggerCount, len(p.TriggerTypes()))
679694
}

0 commit comments

Comments
 (0)