Skip to content

Add object form of imports with aw and apm-packages subfields; deprecate dependencies#22727

Merged
pelikhan merged 3 commits intomainfrom
copilot/add-support-object-form-imports
Mar 24, 2026
Merged

Add object form of imports with aw and apm-packages subfields; deprecate dependencies#22727
pelikhan merged 3 commits intomainfrom
copilot/add-support-object-form-imports

Conversation

Copy link
Contributor

Copilot AI commented Mar 24, 2026

imports previously only accepted an array. This adds an object form that consolidates agentic workflow imports (aw) and APM packages (apm-packages) under a single key, and deprecates the top-level dependencies field in favour of imports.apm-packages.

New object form of imports

imports:
  aw:
    - shared/common-tools.md
    - shared/mcp/tavily.md
  apm-packages:
    - microsoft/apm-sample-package
    # or object form:
    # packages: [...]
    # github-app: { app-id: ..., private-key: ... }

Both aw and apm-packages are optional — the object form works with either or both subfields.

Deprecation of dependencies

Using dependencies alone emits a deprecation warning at compile time directing users to migrate to imports.apm-packages. Specifying both imports.apm-packages and dependencies simultaneously is a compilation error:

cannot use both 'imports.apm-packages' and 'dependencies' simultaneously.
Remove 'dependencies' and use 'imports.apm-packages' exclusively.
Run 'gh aw fix --write' to automatically migrate.

Migration codemod

gh aw fix --write automatically migrates dependenciesimports.apm-packages, handling three cases:

  • No imports: creates imports: { apm-packages: ... }
  • Array imports: converts to imports: { aw: [...], apm-packages: ... }
  • Object imports: appends apm-packages to the existing object

The codemod skips files that already have imports.apm-packages to avoid overwriting existing configuration.

Changes

  • Schema (main_workflow_schema.json): imports is now oneOf [array, object]
  • Parser (import_bfs.go): handles map[string]any imports by processing aw as import specs; extracted parseImportSpecsFromArray helper
  • APM extraction (frontmatter_extraction_metadata.go): returns an error if both imports.apm-packages and dependencies are set; uses imports.apm-packages when present alone; falls back to dependencies with deprecation warning; extracted extractAPMDependenciesFromValue helper
  • Import injection (compiler_orchestrator_engine.go): addImportToFrontmatter appends to imports.aw when imports is already in object form
  • CLI consumers (imports.go, run_push.go, dependency_graph.go): all imports-field consumers handle the object form, extracting paths from aw only
  • Hash extraction (frontmatter_hash.go): text-based hash parser handles object form, extracting only aw items (not apm-packages slugs) as import paths
  • Codemod (codemod_dependencies.go): new dependencies-to-imports-apm-packages codemod registered in the codemod registry

🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.

@github-actions
Copy link
Contributor

Hey @Copilot 👋 — thanks for working on object-form imports support! Unifying imports and dependencies under a single frontmatter key is a nice ergonomic improvement and the codemod for dependenciesimports.apm-packages will make migration smooth for existing workflows.

A couple of things worth addressing before this leaves draft:

  • Add a description — the PR body is a tasklist of what needs doing, but doesn't explain why this feature is needed (e.g. the use-case for imports.apm-packages, why the object form is preferred over keeping dependencies as a top-level field). A short prose paragraph above the checklist would help reviewers understand the motivation.
  • Complete the test coverage — the checklist already tracks the test tasks (Add tests for imports.apm-packages and Add tests for the new codemod), which is great. Make sure pkg/workflow/apm_dependencies_test.go covers the new imports.apm-packages extraction path, and that the new pkg/cli/codemod_dependencies.go has a _test.go companion following the pattern used by codemod_expires_integer_test.go and others in pkg/cli/.
  • Run make agent-finish before marking ready for review — this validates build, tests, lint, and recompile in one shot.

Generated by Contribution Check ·

…elds, deprecate dependencies

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Agent-Logs-Url: https://github.com/github/gh-aw/sessions/aa3ac404-4800-44eb-87ba-46e012289e85
Copilot AI changed the title [WIP] Add support for object form of imports frontmatter field Add object form of imports with aw and apm-packages subfields; deprecate dependencies Mar 24, 2026
Copilot AI requested a review from pelikhan March 24, 2026 17:35
@pelikhan
Copy link
Contributor

@copilot make it an error to mom dependencies and apm-packages

Copy link
Contributor Author

Copilot AI commented Mar 24, 2026

@copilot make it an error to mom dependencies and apm-packages

Done in e71d63c. extractAPMDependenciesFromFrontmatter now returns an error if both imports.apm-packages and dependencies are present at the same time:

cannot use both 'imports.apm-packages' and 'dependencies' simultaneously. Remove 'dependencies' and use 'imports.apm-packages' exclusively. Run 'gh aw fix --write' to automatically migrate.

@pelikhan
Copy link
Contributor

@copilot update docs on dependencies with new syntax . use tech-writer agent.

@pelikhan pelikhan marked this pull request as ready for review March 24, 2026 18:04
Copilot AI review requested due to automatic review settings March 24, 2026 18:04
@pelikhan pelikhan merged commit 4f2dc9a into main Mar 24, 2026
1 check failed
@pelikhan pelikhan deleted the copilot/add-support-object-form-imports branch March 24, 2026 18:04
Copilot stopped work on behalf of pelikhan due to an error March 24, 2026 18:04
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an object form for the imports frontmatter key to support both agentic workflow imports (imports.aw) and APM packages (imports.apm-packages), and deprecates the top-level dependencies field in favor of imports.apm-packages (including a migration codemod).

Changes:

  • Extend imports parsing/consumers to support { aw: ..., apm-packages: ... } while treating only aw as workflow import paths.
  • Implement dependenciesimports.apm-packages behavior (error on conflict, warning on deprecated usage) and add a codemod to migrate files.
  • Update schema + hashing + CLI utilities and add tests for new extraction/migration flows.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
pkg/workflow/frontmatter_extraction_metadata.go Prefer imports.apm-packages, warn on deprecated dependencies, and error when both are set.
pkg/workflow/compiler_orchestrator_engine.go Ensure import injection appends to imports.aw when imports is object form.
pkg/workflow/apm_dependencies_test.go Add tests covering imports.apm-packages extraction and conflict behavior.
pkg/parser/schemas/main_workflow_schema.json Allow imports to be oneOf array/object, including apm-packages config.
pkg/parser/import_bfs.go Parse object-form imports by extracting and BFS-processing only imports.aw.
pkg/parser/frontmatter_hash.go Update text-based import-path hashing to support object-form imports (intended to hash aw only).
pkg/cli/run_push.go Update import collection to read paths from imports.aw when object form is used.
pkg/cli/imports.go Update workflowspec conversion logic to process imports.aw for object form.
pkg/cli/fix_codemods_test.go Update codemod count/order expectations to include the new codemod.
pkg/cli/fix_codemods.go Register the new dependencies-to-imports-apm-packages codemod.
pkg/cli/dependency_graph.go Update dependency graph import extraction to read from imports.aw when object form is used.
pkg/cli/codemod_dependencies_test.go Add tests for the new migration codemod across multiple frontmatter shapes.
pkg/cli/codemod_dependencies.go Implement codemod that moves dependencies into imports.apm-packages, converting imports shape as needed.
Comments suppressed due to low confidence (1)

pkg/cli/imports.go:126

  • In the object-form imports.aw case, collectStringImports drops any {path: ..., inputs: ...} entries and then rewrites aw as a []string, losing inputs/config. Update this to preserve object import specs and only rewrite their path values.
			switch aw := awAny.(type) {
			case []any:
				awImports := collectStringImports(aw)
				importsLog.Printf("Found %d imports (object form, aw subfield) to process", len(awImports))
				v["aw"] = processImportPaths(awImports)
			case []string:

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +161 to +165
"type": "object",
"description": "Object format with packages and optional configuration.",
"properties": {
"packages": {
"type": "array",
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extractAPMDependenciesFromValue supports an version field in the object config, but the imports.apm-packages object schema doesn’t allow version. This will make schema validation reject valid configs. Add a version property (with appropriate pattern/description) to this object schema.

Copilot uses AI. Check for mistakes.
Comment on lines +326 to +339
// Detect the 'aw:' subfield (object form)
if lineIndent == baseIndent+2 && strings.HasPrefix(trimmed, "aw:") {
isObjectForm = true
inAwSubfield = true
awIndent = lineIndent
continue
}

// Detect other object-form subfields (e.g. 'apm-packages:') — skip their contents
if isObjectForm && lineIndent == baseIndent+2 && strings.Contains(trimmed, ":") && !strings.HasPrefix(trimmed, "-") {
inAwSubfield = false
continue
}

Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Object-form detection in extractImportsFromText only flips isObjectForm=true when it sees aw:. If a workflow uses object form with only imports.apm-packages (no aw), isObjectForm stays false and - ... items under apm-packages will be incorrectly treated as import paths (hash changes). Detect object form when encountering any subkey under imports: (e.g. apm-packages:), and only collect - items when inside aw:.

Suggested change
// Detect the 'aw:' subfield (object form)
if lineIndent == baseIndent+2 && strings.HasPrefix(trimmed, "aw:") {
isObjectForm = true
inAwSubfield = true
awIndent = lineIndent
continue
}
// Detect other object-form subfields (e.g. 'apm-packages:') — skip their contents
if isObjectForm && lineIndent == baseIndent+2 && strings.Contains(trimmed, ":") && !strings.HasPrefix(trimmed, "-") {
inAwSubfield = false
continue
}
// Detect object-form subfields under imports: (e.g. 'aw:', 'apm-packages:')
if lineIndent == baseIndent+2 && strings.Contains(trimmed, ":") && !strings.HasPrefix(trimmed, "-") {
// Any subkey under imports: indicates object form
isObjectForm = true
if strings.HasPrefix(trimmed, "aw:") {
// We are entering the 'aw:' subfield; only its items are import paths
inAwSubfield = true
awIndent = lineIndent
} else {
// Other subfields (e.g. 'apm-packages:') are not import paths
inAwSubfield = false
}
continue
}

Copilot uses AI. Check for mistakes.
Comment on lines +111 to +114
case []any:
imports := collectStringImports(v)
importsLog.Printf("Found %d imports (array form) to process", len(imports))
result.Frontmatter["imports"] = processImportPaths(imports)
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the []any imports case, this code extracts only string items and then overwrites imports with a []string. If the list contains object import specs (e.g. {path: ..., inputs: ...}), those entries will be silently dropped when rewriting the file. Preserve object items and rewrite only the path field (or round-trip via []any without discarding non-strings).

This issue also appears on line 121 of the same file.

Copilot uses AI. Check for mistakes.
Comment on lines +124 to +134

for i, line := range lines {
if i == importsEnd {
result = append(result, " apm-packages:")
result = append(result, reindentBlock(depsBodyRaw, depsBodyItemIndent, " ")...)
}
if i >= depsIdx && i < depsEnd {
continue
}
result = append(result, line)
}
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When imports is already an object, insertion of apm-packages happens only when i == importsEnd. If importsEnd == len(lines) (imports block is last in frontmatter), that condition is never hit, so the codemod will remove dependencies but never insert imports.apm-packages (data loss). Add a post-loop insertion when the apm-packages block hasn’t been inserted yet.

Suggested change
for i, line := range lines {
if i == importsEnd {
result = append(result, " apm-packages:")
result = append(result, reindentBlock(depsBodyRaw, depsBodyItemIndent, " ")...)
}
if i >= depsIdx && i < depsEnd {
continue
}
result = append(result, line)
}
insertedAPMPackages := false
for i, line := range lines {
if i == importsEnd {
result = append(result, " apm-packages:")
result = append(result, reindentBlock(depsBodyRaw, depsBodyItemIndent, " ")...)
insertedAPMPackages = true
}
if i >= depsIdx && i < depsEnd {
continue
}
result = append(result, line)
}
// If importsEnd == len(lines), the loop never hits i == importsEnd,
// so we need to append apm-packages after processing all lines.
if !insertedAPMPackages {
result = append(result, " apm-packages:")
result = append(result, reindentBlock(depsBodyRaw, depsBodyItemIndent, " ")...)
}

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants