Skip to content

feat: move actions-lock.json to .github/workflows/aw-lock.json#25110

Closed
Copilot wants to merge 4 commits intomainfrom
copilot/move-actions-lock-json
Closed

feat: move actions-lock.json to .github/workflows/aw-lock.json#25110
Copilot wants to merge 4 commits intomainfrom
copilot/move-actions-lock-json

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 7, 2026

Summary

Moves the action pin cache from .github/aw/actions-lock.json to .github/workflows/aw-lock.json and extends the schema for future extensibility, keeping the JSON format.

Changes

New file format (aw-lock.json)

{
  "version": "1",
  "actions": {
    "actions/checkout@v6.0.2": {
      "repo": "actions/checkout",
      "version": "v6.0.2",
      "sha": "de0fac2e4500dabe0009e67214ff5f5447ce83dd"
    }
  }
}

The new format adds:

  • version field for schema versioning
  • actions section (was entries in the old format)
  • containers section (new, for future container image pin support)

Core changes

  • pkg/workflow/action_cache.go: New constants (CacheFileName = "aw-lock.json", LegacyCacheFileName = "actions-lock.json"), new ContainerPinEntry struct, JSON marshaling with sorted keys, backward-compat Load() (falls back to legacy path), MarkDirty() method
  • pkg/cli/codemod_actions_lock_migration.go: New MigrateActionsLockFile() that moves and converts the old file to the new location/schema; wired into fix --write and the codemod registry
  • Makefile: Updated sync-action-pins to use a Go script that reads aw-lock.json and writes the embedded action_pins.json fallback (no external tooling required)
  • scripts/sync-action-pins/main.go: New Go script for syncing the action pin data

Backward compatibility

  • Load() automatically falls back to .github/aw/actions-lock.json if the new file doesn't exist
  • gh aw fix --write migrates the old file to the new location
  • UpdateActions checks both paths before deciding to skip

Files migrated in this PR

  • .github/aw/actions-lock.json.github/workflows/aw-lock.json
  • pkg/workflow/.github/aw/actions-lock.jsonpkg/workflow/.github/workflows/aw-lock.json

Tests updated

  • pkg/workflow/action_cache_test.go: new path, JSON format assertions
  • pkg/cli/update_command_test.go: new path, JSON content checks
  • pkg/cli/compile_integration_test.go: new path references
  • pkg/workflow/action_sha_validation_test.go: new path

Docs updated

All references to actions-lock.json in docs/, scratchpad, and code comments updated to aw-lock.json.

Copilot AI and others added 2 commits April 7, 2026 14:52
…w YAML format

- Change CacheFileName to aw-lock.yml in .github/workflows/ (was actions-lock.json in .github/aw/)
- Add LegacyCacheFileName constant for backward-compat loading
- Extend format: version, actions (was entries), containers sections
- Add ContainerPinEntry struct for future container pin support
- Keep backward compat: Load() falls back to old .github/aw/actions-lock.json
- Add MarkDirty() method to force save after legacy load
- Add codemod_actions_lock_migration.go: MigrateActionsLockFile() for fix --write
- Wire migration into fix_command.go and fix_codemods.go registry
- Update update_actions.go, update_command.go, upgrade_command.go references
- Update Makefile sync-action-pins to use Go script that converts YAML→JSON
- Add scripts/sync-action-pins/main.go for the conversion
- Migrate .github/aw/actions-lock.json → .github/workflows/aw-lock.yml
- Migrate pkg/workflow/.github/aw/actions-lock.json → pkg/workflow/.github/workflows/aw-lock.yml
- Update tests: action_cache_test.go, update_command_test.go, compile_integration_test.go
- Update docs and scratchpad references

Agent-Logs-Url: https://github.com/github/gh-aw/sessions/14c1b3fc-d16d-42e6-9307-d403b1bf6880

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

pelikhan commented Apr 7, 2026

@copilot keep format in JSON aw-lock.json , not YML

Per feedback, keep the lock file in JSON format (not YAML).
- CacheFileName = "aw-lock.json" (was "aw-lock.yml")
- Save/Load use JSON marshaling, new schema has version + actions + containers fields
- Convert .github/workflows/aw-lock.yml → aw-lock.json
- Convert pkg/workflow/.github/workflows/aw-lock.yml → aw-lock.json
- Update all docs, comments, and tests accordingly

Agent-Logs-Url: https://github.com/github/gh-aw/sessions/648f89f3-a5e5-4dc2-96c1-aea60ffa8be3

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 7, 2026

@copilot keep format in JSON aw-lock.json , not YML

Done — reverted to JSON format. The file is now .github/workflows/aw-lock.json with the new schema (version, actions, containers fields). Commit 0ab2b6c.

Copilot AI changed the title feat: move actions-lock.json to .github/workflows/aw-lock.yml feat: move actions-lock.json to .github/workflows/aw-lock.json Apr 7, 2026
@pelikhan pelikhan marked this pull request as ready for review April 7, 2026 15:30
Copilot AI review requested due to automatic review settings April 7, 2026 15:30
Copy link
Copy Markdown
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

Moves the action pin cache to a new canonical location (.github/workflows/aw-lock.json), introduces a versioned/extendable JSON schema, and adds migration + tooling updates to keep embedded fallback pins in sync.

Changes:

  • Relocates actions-lock.json to .github/workflows/aw-lock.json and updates the on-disk schema (version, actions, future containers).
  • Adds backward-compatible loading + a fix --write codemod to migrate legacy caches.
  • Updates build tooling to regenerate the embedded pkg/workflow/data/action_pins.json from the lock file via a Go script.
Show a summary per file
File Description
scripts/sync-action-pins/main.go New Go sync tool to generate embedded action_pins.json from aw-lock.json/legacy cache.
Makefile Switches sync-action-pins to run the new Go sync tool.
pkg/workflow/action_cache.go Implements new cache filename/location, versioned schema, container pins scaffold, sorted JSON marshaling, and legacy fallback loading.
pkg/workflow/action_cache_test.go Updates tests for new cache path and schema (actions map).
pkg/workflow/action_sha_validation_test.go Updates expected cache path under .github/workflows/.
pkg/workflow/.github/workflows/aw-lock.json Migrates fixture lock file to new schema (version + actions).
.github/workflows/aw-lock.json Migrates repository lock file to new schema (version + actions).
pkg/cli/update_actions.go Updates action-update logic to prefer new path and recognize legacy path.
pkg/cli/update_command.go Updates user-facing messaging to reference aw-lock.json.
pkg/cli/update_command_test.go Updates tests to read new cache path and assert new JSON keys.
pkg/cli/upgrade_command.go Updates command help text to reference new lock location.
pkg/cli/fix_command.go Runs the migration step during fix --write.
pkg/cli/fix_codemods.go Registers the new actions-lock migration codemod.
pkg/cli/codemod_actions_lock_migration.go New migration implementation for legacy → new cache location/schema.
pkg/cli/compile_integration_test.go Updates integration tests to use new cache filename constant and new path.
pkg/workflow/compiler_types.go Updates comments around action cache creation behavior.
pkg/workflow/safe_outputs_actions.go Updates comments about safe-outputs action input caching location.
pkg/workflow/data/action_pins.json Updates embedded pins JSON content to match regenerated format (e.g., removes descriptions).
docs/src/content/docs/setup/cli.md Updates docs references from actions-lock.json to aw-lock.json.
docs/src/content/docs/reference/releases.md Updates docs references and example commands for new lock file name/location.
docs/src/content/docs/reference/faq.md Updates FAQ wording and paths for the new lock file.
docs/src/content/docs/reference/compilation-process.md Updates compilation/pinning docs to reference new cache file.
docs/src/content/docs/introduction/architecture.mdx Updates architecture diagram label to aw-lock.json.
scratchpad/layout.md Updates scratchpad layout references to the new filename.
scratchpad/debugging-action-pinning.md Updates debugging guide paths to the new cache location.

Copilot's findings

Tip

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

Comments suppressed due to low confidence (5)

pkg/cli/compile_integration_test.go:75

  • These test comments and log strings mention aw-lock.yml, but the cache file is aw-lock.json. Updating these strings will keep the test output and documentation aligned with the actual filename.

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

	}

	// Clean up any action cache files created during tests
	// Tests may create .github/workflows/aw-lock.yml in the pkg/cli directory
	actionCacheDir := filepath.Join(wd, ".github")
	if _, err := os.Stat(actionCacheDir); err == nil {
		_ = os.RemoveAll(actionCacheDir)
	}

pkg/cli/compile_integration_test.go:1293

  • The assertions here are correct (they use workflow.CacheFileName), but the surrounding comments and log strings say aw-lock.yml even though the file is aw-lock.json. Please update the wording to match the real filename to reduce confusion when reading test failures/logs.
	// Verify aw-lock.yml is created at the repository root (.github/workflows/aw-lock.yml)
	// NOT at .github/workflows/.github/workflows/aw-lock.yml
	expectedLockPath := filepath.Join(setup.tempDir, ".github", "workflows", workflow.CacheFileName)
	wrongLockPath := filepath.Join(setup.workflowsDir, ".github", "workflows", workflow.CacheFileName)

	// Check if aw-lock.yml exists (it may or may not, depending on whether actions were pinned)
	// The important part is that if it exists, it's in the right place
	if _, err := os.Stat(expectedLockPath); err == nil {
		t.Logf("aw-lock.yml correctly created at repo root: %s", expectedLockPath)
	} else if !os.IsNotExist(err) {
		t.Fatalf("Failed to check for aw-lock.yml at expected path: %v", err)
	}

pkg/workflow/safe_outputs_actions.go:224

  • This comment references aw-lock.yml, but the cache file is aw-lock.json (see workflow.CacheFileName). Please update the extension to avoid confusion.
			// Check the ActionCache for previously-fetched inputs before going to the network.
			// The cache key uses the original version tag from the `uses:` field (ref.Ref, e.g.
			// "v1") which matches the key stored in aw-lock.yml.
			if data.ActionCache != nil {

scratchpad/layout.md:387

  • This directory tree still shows aw-lock.json under .github/aw/, but the canonical path is now .github/workflows/aw-lock.json (with .github/aw/actions-lock.json as legacy). Please update the tree so it matches the new layout.
.github/
├── agents/                     # Custom agent definitions
│   └── test-agent.md
├── aw/                         # Workflow configuration
│   └── aw-lock.json
└── workflows/                  # Workflow files
    ├── *.md                    # Source workflows

scratchpad/debugging-action-pinning.md:381

  • These jq commands still reference .entries, but aw-lock.json now uses .actions as the top-level map. Please update the filters (and any nearby examples) so they work with the new schema.
Check for unexpected cache entries:

```bash
# List all SHAs with their version tags
jq -r '.entries | to_entries[] | "\(.value.sha) \(.value.version) \(.key)"' .github/workflows/aw-lock.json | sort

# Find duplicate SHAs
jq -r '.entries | to_entries[] | .value.sha' .github/workflows/aw-lock.json | sort | uniq -d
</details>


- **Files reviewed:** 25/25 changed files
- **Comments generated:** 6


// Resolution priority (highest wins):
// 1. Inputs already specified in the frontmatter (config.Inputs != nil)
// 2. Inputs cached in the ActionCache (actions-lock.json)
// 2. Inputs cached in the ActionCache (aw-lock.yml)
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

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

The comments/log strings here refer to aw-lock.yml, but the cache file is aw-lock.json (see workflow.CacheFileName). This should be updated to avoid confusing users and to match the actual on-disk filename.

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

Suggested change
// 2. Inputs cached in the ActionCache (aw-lock.yml)
// 2. Inputs cached in the ActionCache (aw-lock.json)

Copilot uses AI. Check for mistakes.

// Auto-detect git repository root for action cache path resolution
// This ensures actions-lock.json is created at repo root regardless of CWD
// This ensures aw-lock.yml is created at repo root regardless of CWD
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

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

This inline comment says aw-lock.yml, but the action cache file is JSON (aw-lock.json). Please update the filename/extension in the comment to match the new cache location and format.

Suggested change
// This ensures aw-lock.yml is created at repo root regardless of CWD
// This ensures aw-lock.json is created at repo root regardless of CWD

Copilot uses AI. Check for mistakes.
Comment on lines +20 to +23
cache := workflow.NewActionCache(".")
if err := cache.Load(); err != nil {
fmt.Fprintf(os.Stderr, "Warning: failed to load action cache: %v\n", err)
// Continue with empty cache — action_pins.json will be written empty.
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

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

If the action cache file is missing, ActionCache.Load() returns nil and cache.Entries stays empty, so this script will overwrite pkg/workflow/data/action_pins.json with an empty entries object without warning. Consider explicitly checking for the presence of either .github/workflows/aw-lock.json or .github/aw/actions-lock.json and skipping (or failing) instead of clobbering the embedded fallback data.

Suggested change
cache := workflow.NewActionCache(".")
if err := cache.Load(); err != nil {
fmt.Fprintf(os.Stderr, "Warning: failed to load action cache: %v\n", err)
// Continue with empty cache — action_pins.json will be written empty.
sourcePaths := []string{
".github/workflows/aw-lock.json",
".github/aw/actions-lock.json",
}
foundSource := false
for _, path := range sourcePaths {
if _, err := os.Stat(path); err == nil {
foundSource = true
break
} else if !os.IsNotExist(err) {
fmt.Fprintf(os.Stderr, "Error checking %s: %v\n", path, err)
os.Exit(1)
}
}
if !foundSource {
fmt.Fprintf(os.Stderr, "Error: no action cache source file found; expected one of %q or %q\n", sourcePaths[0], sourcePaths[1])
os.Exit(1)
}
cache := workflow.NewActionCache(".")
if err := cache.Load(); err != nil {
fmt.Fprintf(os.Stderr, "Error: failed to load action cache: %v\n", err)
os.Exit(1)

Copilot uses AI. Check for mistakes.
Comment on lines +72 to 83
The action cache is stored at `.github/workflows/aw-lock.json`. Examine it for duplicate entries:

```bash
# Pretty-print the cache
cat .github/aw/actions-lock.json | jq .
cat .github/workflows/aw-lock.json | jq .

# Find entries for a specific action
cat .github/aw/actions-lock.json | jq '.entries | to_entries[] | select(.value.repo == "actions/github-script")'
cat .github/workflows/aw-lock.json | jq '.entries | to_entries[] | select(.value.repo == "actions/github-script")'

# Check for duplicate SHAs
cat .github/aw/actions-lock.json | jq -r '.entries | to_entries[] | "\(.value.sha) \(.key)"' | sort | uniq -d -w 40
cat .github/workflows/aw-lock.json | jq -r '.entries | to_entries[] | "\(.value.sha) \(.key)"' | sort | uniq -d -w 40
```
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

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

The jq filters still reference .entries, but the new aw-lock.json schema uses top-level actions (and version). These commands should be updated to query .actions so the debugging guide works with the migrated file.

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

See below for a potential fix:

cat .github/workflows/aw-lock.json | jq '.actions | to_entries[] | select(.value.repo == "actions/github-script")'

# Check for duplicate SHAs
cat .github/workflows/aw-lock.json | jq -r '.actions | to_entries[] | "\(.value.sha) \(.key)"' | sort | uniq -d -w 40

Copilot uses AI. Check for mistakes.
|------|------|-------------|---------------|
| `.github/workflows/` | Directory | Workflow definition directory | Contains all `.md` and `.lock.yml` workflow files |
| `.github/aw/` | Directory | Agentic workflow configuration | Contains `actions-lock.json` and other configs |
| `.github/aw/` | Directory | Agentic workflow configuration | Contains `aw-lock.json` and other configs |
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

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

This table/tree still describes aw-lock.json as living under .github/aw/, but the PR moves it to .github/workflows/aw-lock.json (with .github/aw/actions-lock.json only as a legacy path). Please update this layout doc to reflect the new canonical location.

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

Suggested change
| `.github/aw/` | Directory | Agentic workflow configuration | Contains `aw-lock.json` and other configs |
| `.github/workflows/aw-lock.json` | File | Canonical actions lock file | Primary location for the workflow lock configuration |
| `.github/aw/` | Directory | Agentic workflow configuration | Contains other configs and legacy `.github/aw/actions-lock.json` path |

Copilot uses AI. Check for mistakes.
Comment on lines +53 to +61
// If the new file already exists, skip migration to avoid overwriting.
if _, err := os.Stat(newPath); err == nil {
// Both files exist: warn and remove the legacy file.
fmt.Fprintf(os.Stderr, "%s\n", console.FormatWarningMessage(
fmt.Sprintf("%s already exists; removing legacy %s", newPath, legacyPath)))
if err := os.Remove(legacyPath); err != nil {
return false, fmt.Errorf("removing legacy %s: %w", legacyPath, err)
}
return true, nil
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

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

When the new file already exists, this migration path deletes the legacy file unconditionally. That can lose data if the new file is stale/partial (or created by a newer tool with different contents). Safer options: keep the legacy file and return a warning, or compare/merge contents before deleting, or rename the legacy file to a backup instead of removing it.

Suggested change
// If the new file already exists, skip migration to avoid overwriting.
if _, err := os.Stat(newPath); err == nil {
// Both files exist: warn and remove the legacy file.
fmt.Fprintf(os.Stderr, "%s\n", console.FormatWarningMessage(
fmt.Sprintf("%s already exists; removing legacy %s", newPath, legacyPath)))
if err := os.Remove(legacyPath); err != nil {
return false, fmt.Errorf("removing legacy %s: %w", legacyPath, err)
}
return true, nil
// If the new file already exists, skip migration to avoid overwriting or
// discarding the legacy file without verifying the contents match.
if _, err := os.Stat(newPath); err == nil {
fmt.Fprintf(os.Stderr, "%s\n", console.FormatWarningMessage(
fmt.Sprintf("%s already exists; leaving legacy %s in place and skipping migration", newPath, legacyPath)))
return false, nil

Copilot uses AI. Check for mistakes.
@pelikhan
Copy link
Copy Markdown
Collaborator

pelikhan commented Apr 7, 2026

@copilot review comments

…ers, layout doc, safe migration

- pkg/workflow/safe_outputs_actions.go: fix two comments still saying 'aw-lock.yml'
- pkg/workflow/compiler_types.go: fix comment saying 'aw-lock.yml'
- scratchpad/debugging-action-pinning.md: update jq filters from .entries to .actions (x4)
- scratchpad/layout.md: update table and directory tree to show aw-lock.json in .github/workflows/
- pkg/cli/codemod_actions_lock_migration.go: when new file already exists, skip migration instead of deleting the legacy file
- scripts/sync-action-pins/main.go: fail with error when no source cache file is found (instead of silently writing empty action_pins.json)

Agent-Logs-Url: https://github.com/github/gh-aw/sessions/1c9e14dd-0ab3-48a8-8390-a4ce974fd972

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 7, 2026

@copilot review comments

All review comments addressed in commit 830862e:

  • Fixed stale aw-lock.yml references in safe_outputs_actions.go (×2) and compiler_types.go
  • Updated jq filters in scratchpad/debugging-action-pinning.md from .entries to .actions (×4)
  • Updated scratchpad/layout.md table and directory tree to reflect the new canonical location (.github/workflows/aw-lock.json)
  • Migration codemod now skips with a warning (instead of deleting the legacy file) when aw-lock.json already exists
  • sync-action-pins script now exits with an error when neither source cache file is found, preventing silent overwrite of the embedded fallback with empty data

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