Skip to content

Add checkout field and manager for agent job - #18223

Merged
pelikhan merged 5 commits into
mainfrom
copilot/add-checkout-field-and-manager
Feb 25, 2026
Merged

Add checkout field and manager for agent job#18223
pelikhan merged 5 commits into
mainfrom
copilot/add-checkout-field-and-manager

Conversation

Copilot AI commented Feb 24, 2026

Copy link
Copy Markdown
Contributor

Adds a top-level checkout frontmatter field that controls how actions/checkout is emitted in the agent job.

Changes Made

  • checkout_manager.go: New CheckoutManager that collects and deduplicates checkout configs. Merging rules: deepest fetch-depth wins, sparse-checkout patterns are unioned, LFS/submodules are OR-ed. persist-credentials: false is always enforced. Token and ref use first-seen-wins when merging duplicate targets.
  • frontmatter_types.go: Added Checkout any (JSON round-trip) and CheckoutConfigs []*CheckoutConfig (parsed) fields to FrontmatterConfig.
  • compiler_types.go: Added CheckoutConfigs []*CheckoutConfig to WorkflowData.
  • compiler_orchestrator_workflow.go: Populate CheckoutConfigs from parsed frontmatter, with a fallback to extract checkout directly from the raw frontmatter map when full frontmatter parsing fails (e.g. for non-standard tool configs like bash: ["*"]).
  • compiler_yaml_main_job.go: Use CheckoutManager for checkout step generation instead of inline YAML.
  • main_workflow_schema.json: Added checkout property and checkoutConfig definition.
  • checkout_manager_test.go: Unit tests covering all merging and generation behaviors.
  • smoke-codex.md: Added checkout: fetch-depth: 2 as a usage example and smoke test.

Usage

# Single checkout override — full history + custom token
checkout:
  fetch-depth: 0
  github-token: ${{ secrets.MY_PAT }}

# Multiple checkouts — primary + secondary repo
checkout:
  - path: .
    fetch-depth: 0
  - repository: owner/other-repo
    path: ./libs/other
    ref: main
    sparse-checkout: |
      src/
      docs/

Key Design Decisions

  • persist-credentials: false is always enforced regardless of user input
  • The token field is named github-token (mapped to actions/checkout's token input)
  • Token and ref use first-seen-wins when merging duplicate targets (same repository + path)
  • The "default" checkout (empty path + empty repository) applies user overrides on top of the automatic workspace checkout; trial-mode overrides take precedence
  • Additional checkouts are emitted after the default step
  • fetch-depth integer values are handled for all YAML numeric types (int, int64, uint64, float64); fractional float values are rejected

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
@pelikhan

Copy link
Copy Markdown
Collaborator

@copilot add checkout entry in the smoke-codex with fetch depth 2

…ack parsing

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>

Copilot AI commented Feb 25, 2026

Copy link
Copy Markdown
Contributor Author

@copilot add checkout entry in the smoke-codex with fetch depth 2

Done in 62e65ce. Added checkout: fetch-depth: 2 to smoke-codex.md. Also fixed two underlying bugs discovered along the way:

  1. YAML parses integer literals as uint64 — the fetch-depth type switch now handles uint64 and int64 in addition to int/float64.
  2. When ParseFrontmatterConfig fails (e.g. for bash: ["*"] tool config), the checkout field is now extracted directly from the raw frontmatter as a fallback.

Copilot AI changed the title [WIP] Add checkout field and manager for agent job Add checkout field and manager for agent job Feb 25, 2026
@pelikhan
pelikhan marked this pull request as ready for review February 25, 2026 03:30
Copilot AI review requested due to automatic review settings February 25, 2026 03:30

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds a top-level checkout frontmatter field to control how actions/checkout steps are emitted for the agent job, including support for multiple checkouts and merged/deduped configs.

Changes:

  • Introduces CheckoutManager + CheckoutConfig parsing/merging and uses it to generate checkout steps in the main job.
  • Extends frontmatter/workflow data types to carry raw + parsed checkout configs, including a fallback raw parse path when typed frontmatter parsing fails.
  • Updates the JSON schema and smoke-test workflow example/lock output to include checkout.fetch-depth.

Reviewed changes

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

Show a summary per file
File Description
pkg/workflow/checkout_manager.go Implements checkout config parsing, merging, and YAML step generation
pkg/workflow/checkout_manager_test.go Adds unit tests for parsing/merge/generation behavior
pkg/workflow/frontmatter_types.go Adds checkout fields to frontmatter config and parses them into typed configs
pkg/workflow/compiler_types.go Plumbs checkout configs through WorkflowData
pkg/workflow/compiler_orchestrator_workflow.go Populates WorkflowData.CheckoutConfigs from parsed or raw frontmatter
pkg/workflow/compiler_yaml_main_job.go Switches checkout step generation to CheckoutManager
pkg/parser/schemas/main_workflow_schema.json Adds schema support for checkout and checkoutConfig
.github/workflows/smoke-codex.md Adds checkout.fetch-depth as a smoke-test example
.github/workflows/smoke-codex.lock.yml Reflects generated workflow output including fetch-depth: 2
.github/agents/agentic-workflows.agent.md Updates agent routing documentation (report prompt)
Comments suppressed due to low confidence (2)

pkg/workflow/checkout_manager.go:88

  • The comment says merged checkouts are keyed by (repository, ref, path, token), but the actual grouping key is only (repository, path) (and ref/token are merged settings). Please update the doc comment to match the implemented behavior to avoid misleading future changes/debugging.
// Merging rules:
//   - Checkouts with the same (repository, ref, path, token) are merged into one.
//   - The deepest fetch-depth wins: 0 (full history) overrides any shallower value.
//   - Sparse-checkout patterns are unioned across merged configs.
//   - LFS and submodules are OR-ed (if any request enables them, the result enables them).

pkg/workflow/checkout_manager.go:138

  • Submodules merging is not actually OR-ed/unioned: if the first config sets submodules (including "false"), subsequent configs for the same repo/path can never enable submodules/recursive mode because entry.submodules is only set when empty. If the intended behavior is “enable if any config enables it”, implement a precedence/merge function (e.g., recursive > true > false > empty) instead of “first non-empty wins”.
			entry.lfs = true
		}
		if cfg.Submodules != "" && entry.submodules == "" {
			entry.submodules = cfg.Submodules
		}

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

Comment thread pkg/workflow/checkout_manager.go Outdated

// ParseCheckoutConfigs converts a raw frontmatter value (single map or array of maps)
// into a slice of CheckoutConfig entries.
// Returns nil if the value is nil or cannot be parsed.

Copilot AI Feb 25, 2026

Copy link

Choose a reason for hiding this comment

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

The docstring for ParseCheckoutConfigs says it returns nil when the value “cannot be parsed”, but the function actually returns a non-nil error for invalid types/shapes. Update the comment to reflect the real contract (nil only when raw is nil; otherwise errors are returned on invalid input).

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

Suggested change
// Returns nil if the value is nil or cannot be parsed.
// Returns (nil, nil) if the value is nil; for non-nil values, invalid types or shapes
// result in a non-nil error.

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 4ad61d6 — updated to: "Returns (nil, nil) if the value is nil; for non-nil values, invalid types or shapes result in a non-nil error."

Comment thread pkg/workflow/checkout_manager.go Outdated
Comment on lines +1 to +2
//go:build !integration

Copilot AI Feb 25, 2026

Copy link

Choose a reason for hiding this comment

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

This file is guarded by //go:build !integration, but NewCheckoutManager, CheckoutConfig, and ParseCheckoutConfigs are referenced from non-tagged production code (e.g., compiler YAML generation and frontmatter parsing). Building/tests with the integration tag will exclude this file and fail to compile. Remove the build tag (or provide an integration-compatible implementation) so the workflow package builds under -tags=integration.

Suggested change
//go:build !integration

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The //go:build !integration tag was only on checkout_manager_test.go (the test file), not on checkout_manager.go itself — the production code has no build tag and compiles under all build configurations.

Comment thread pkg/workflow/checkout_manager.go Outdated
Comment on lines +124 to +129
if cfg.Ref != "" {
entry.ref = cfg.Ref // last non-empty ref wins
}
if cfg.Token != "" {
entry.token = cfg.Token // last non-empty token wins
}

Copilot AI Feb 25, 2026

Copy link

Choose a reason for hiding this comment

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

Token merging currently uses “last non-empty token wins”, but the PR description states “token is excluded from the grouping key (first-seen wins when merging duplicate targets)”. Please align the implementation with the intended behavior (e.g., only set entry.token if it is empty) or update the PR description/spec so users get predictable results when multiple configs target the same repo/path.

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

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 4ad61d6. Both ref and token now use first-seen-wins: if cfg.Ref != "" && entry.ref == "" / if cfg.GitHubToken != "" && entry.token == "". Updated the test that previously asserted last-ref-wins.

case uint64:
depth := int(n)
cfg.FetchDepth = &depth
case float64:

Copilot AI Feb 25, 2026

Copy link

Choose a reason for hiding this comment

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

For fetch-depth values parsed as float64, the code does depth := int(n) without validating that n is a whole number. This will silently truncate fractional values (e.g. 1.9 → 1) even though the error message says it must be an integer. Add a check that the float is integral before converting (similar to other parsers in this repo).

Suggested change
case float64:
case float64:
if n != float64(int64(n)) {
return nil, errors.New("checkout.fetch-depth must be an integer")
}

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 4ad61d6. Added if n != float64(int64(n)) { return nil, errors.New("checkout.fetch-depth must be an integer") } before the conversion.

@pelikhan

Copy link
Copy Markdown
Collaborator

@copilot rename checkout.token to checkout.github-token

…string, float validation

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>

Copilot AI commented Feb 25, 2026

Copy link
Copy Markdown
Contributor Author

@copilot rename checkout.token to checkout.github-token

Done in 4ad61d6. Renamed tokengithub-token throughout: CheckoutConfig.GitHubToken field (json:"github-token"), YAML step output (github-token: key), JSON schema, and tests.

@pelikhan
pelikhan merged commit 5c49c3c into main Feb 25, 2026
106 checks passed
@pelikhan
pelikhan deleted the copilot/add-checkout-field-and-manager branch February 25, 2026 04:29
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