feat(cli): define plugin objects and basic plugin listing ability#154
Conversation
cb6219b to
ac3b7b9
Compare
4cdc89d to
bca8161
Compare
Downstream segments (convert, plugin list, plugin install) all need a way to find and parse installed plugins. This adds the shared foundation: a typed Plugin struct and a Discover() function that scans ~/.ossie/plugins/ for valid plugin.yaml files. Design decisions: - internal/plugin accepts pluginsDir as a parameter rather than calling ossiedir.PluginDir() internally — keeps the package testable without env var manipulation - plugin.yaml supports both ossie_* (preferred) and osi_* (deprecated fallback) key families to avoid breaking plugins written before the OSI → OSSIE rename; ossie_* wins when both are present - Malformed plugin dirs emit a warning to an io.Writer and are skipped; only an unreadable plugins directory is a hard error, matching the behavior specified in the architecture doc - Non-directory entries in the plugins dir are silently skipped (no warning); non-existent dir returns nil, nil Caveats: - Symlinked plugin directories are not yet handled — os.ReadDir reports symlinks with ModeSymlink, not IsDir(); a TODO comment marks the location for a future follow-up - cmd/plugin/list.go wiring is deferred to P1, which also requires the embedded registry before the full table output can be rendered
go.mod declares go 1.22 so slices.Equal (stdlib since 1.21) is available. Removes the hand-rolled utility in favour of the standard library equivalent.
os.IsNotExist does not handle wrapped errors correctly. Replace both occurrences with errors.Is(err, os.ErrNotExist), the modern idiom since Go 1.13.
Replace hardcoded /this/path/does/not/exist with a path derived from t.TempDir(). The parent is guaranteed to exist by the test harness but the child subdir does not, making the fixture deterministically nonexistent without relying on filesystem assumptions.
Adds two cases: setup path is correctly parsed when present, and setup is empty string when the field is absent from plugin.yaml. The setup path is consumed by the install segment (P2) when running the plugin's setup script.
Unknown fields in plugin.yaml are silently ignored by yaml.Unmarshal. Adding a comment to make clear this is a deliberate forward- compatibility choice, not an oversight.
…nd invoke args ConvertConfig.ToOSI/FromOSI and the plugin.yaml fields to_osi/from_osi were left using the old brand name. This sweeps them to ossie consistently with the rest of the CLI rename. to_ossie/from_ossie are now the canonical yaml keys. to_osi/from_osi are kept as deprecated fallbacks in rawPlugin, using the same ossie-wins merge pattern already established for ossie_plugin_spec/osi_plugin_spec. The invoke-arg convention (to-ossie, from-ossie) is updated in all canonical test fixtures; the two backward-compat tests (TestDiscover_ossieKeyPreferred, TestDiscover_osiKeyFallback) intentionally retain to_osi/from_osi since they exercise the deprecated-key path.
The preemptive osi_* fallback fields (osi_plugin_spec, osi_spec_version, to_osi, from_osi) were added in anticipation of backward compatibility, but no plugins exist yet using that format — the rename is happening before any external consumers. Carrying dead compatibility code with no real users adds noise and keeps osi in the codebase. Drops all deprecated fields and merge logic from rawPlugin, simplifying validate() and toPlugin() back to direct field access. TestDiscover_ossieKeyPreferred and TestDiscover_osiKeyFallback (which existed solely to exercise the now-removed paths) are replaced with TestDiscover_unknownFieldsIgnored, which covers the lenient-YAML behavior (future spec fields are silently tolerated) that discover.go explicitly documents.
Wires plugin list to the discovery infrastructure added in F2. Reads from the resolved plugin directory, prints a NAME/PLATFORM/SPEC table via tabwriter, and falls back to a "no plugins installed" message when the directory is empty or missing. This is a minimal first pass — the full P1 spec calls for cross-referencing against the embedded plugin registry (installed vs. available, latest version, update indicator), which depends on registry embedding (F4) not yet implemented.
go install . names the binary after the module path's last segment (cli) rather than the intended ossie. make install uses go build -o directly into $GOPATH/bin with the correct binary name.
bca8161 to
f2873b5
Compare
khush-bhatia
left a comment
There was a problem hiding this comment.
This is great, thanks.
One question, should we add a "name" field for plugin metadata ?
@khush-bhatia I agree that names are important! Also, thank you for calling this out 🙂 Right now the |
Agreed on having plugin name and vendor being top level. |
…atform
PR review on the plugin manifest schema concluded that plugins lack
their own identity: platform.name is documented as "matched against
--from/--to values" — i.e. it identifies the target platform, not the
plugin package itself. `ossie plugin list` papers over this by
displaying the install directory's basename as a stand-in "name",
which isn't stable across reinstalls/renames and gives a future
registry nothing durable to key on.
Considered adding a second, distinct field for the plugin's own
identity alongside platform.name/vendor, but with no existing
manifests to preserve, that just trades one problem for a schema with
two similarly-named concepts to document and keep straight. Settled on
reusing the existing required matching key as the plugin's identity
instead: top-level `name` (e.g. `dbt` vs a hypothetical `dbt-community`)
now does double duty, so official/community disambiguation happens by
naming convention at author time rather than needing runtime
conflict-resolution logic in discovery for two plugins that would
otherwise both claim `name: dbt`. `platform.vendor` collapses into a
plain top-level `platform` string, since nothing parses it — it's
freeform display text ("dbt Labs", "PowerBI") shown in `plugin list`,
not a second identifier.
`ossie plugin list` now shows the manifest's real name instead of the
directory basename.
Deferred: if two installed plugins do declare the same `name`,
discovery still has no conflict-resolution behavior. Not addressed
here — pre-existing gap, orthogonal to this schema change.
|
Summary
Define the basic structure of a plugin (plugin.yaml). In addition, add ability to list installed plugins. Note, this does not add the ability to install plugins, their associated setup, or convert invocations. This is simply the initial "how should a plugin be defined and found when it exists".
Screen.Recording.2026-06-23.at.16.59.01.mov