-
Notifications
You must be signed in to change notification settings - Fork 429
feat(codemods): rename allow-team-members → allowed-collaborators in safe-outputs.mentions
#40394
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
pelikhan
merged 7 commits into
main
from
copilot/add-codemod-rename-allowed-team-members
Jun 20, 2026
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
40f459d
feat(codemods): rename allow-team-members to allowed-collaborators in…
Copilot a9da635
fix: update stale field name in test comments
Copilot b44c3b3
docs(adr): add draft ADR-40394 for allowed-collaborators rename
github-actions[bot] 84149da
fix: address mentions rename review feedback
Copilot 676bc32
fix: handle flow-style mentions codemod safely
Copilot 8181b2f
refactor: simplify flow-style codemod replacement branch
Copilot 74e14df
refactor: streamline flow-style mentions key rewrite
Copilot File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
38 changes: 38 additions & 0 deletions
38
docs/adr/40394-rename-allow-team-members-to-allowed-collaborators.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| # ADR-40394: Rename `allow-team-members` to `allowed-collaborators` in `safe-outputs.mentions` | ||
|
|
||
| **Date**: 2026-06-19 | ||
| **Status**: Draft | ||
|
|
||
| ## Context | ||
|
|
||
| The `safe-outputs.mentions` configuration historically exposed a boolean field named `allow-team-members` to control whether repository collaborators could be @mentioned. The rest of the mentions configuration uses an `allowed-*` naming family (`allowed`, `allowed-teams`), so `allow-team-members` was inconsistent with the surrounding vocabulary and described its subject ("collaborators with any permission level") imprecisely. Because workflow frontmatter is authored by users in repositories outside this codebase, any rename must avoid silently breaking existing workflows that still set the old key. This decision concerns how to evolve a public configuration field name without a breaking change. | ||
|
|
||
| ## Decision | ||
|
|
||
| We will rename the field to `allowed-collaborators` as the canonical name and retain `allow-team-members` as a backward-compatible deprecated alias. Concretely: `MentionsConfig.AllowTeamMembers` becomes `AllowedCollaborators` (YAML tag `allowed-collaborators`, runtime JSON key `allowedCollaborators`); `parseMentionsConfig` reads `allowed-collaborators` first and falls back to `allow-team-members`; the JSON schema marks the old key `deprecated` with an `x-deprecation-message`; and a `gh aw fix` codemod (`mentions-allow-team-members-to-allowed-collaborators`) rewrites the old key to the new one in-place while preserving indentation, inline comments, and the markdown body. The codemod is a no-op when the key is absent, when `mentions` is a bare boolean, or when the field is already migrated. | ||
|
|
||
| ## Alternatives Considered | ||
|
|
||
| ### Alternative 1: Hard rename with no alias | ||
| Remove `allow-team-members` entirely and accept only `allowed-collaborators`. Rejected because it would immediately break every existing workflow that still sets the old key, with no migration path, violating the non-negotiable backward-compatibility constraint. | ||
|
|
||
| ### Alternative 2: Leave the field named `allow-team-members` | ||
| Keep the existing name to avoid any migration work. Rejected because it perpetuates the naming inconsistency with the `allowed-*` family and the imprecise "team-members" terminology, and the cost of a backward-compatible rename plus an automated codemod is low. | ||
|
|
||
| ## Consequences | ||
|
|
||
| ### Positive | ||
| - The field name is consistent with the `allowed-*` configuration family and more accurately describes repository collaborators. | ||
| - Existing workflows continue to compile unchanged via the deprecated-alias fallback, and `gh aw fix` migrates them automatically. | ||
|
|
||
| ### Negative | ||
| - The parser and schema must carry two keys for the same setting until the deprecated alias is removed, increasing maintenance surface. | ||
| - The deprecated `allow-team-members` entry lingers in the schema and documentation, which can confuse new authors about which key to use. | ||
|
|
||
| ### Neutral | ||
| - The runtime JSON key emitted to the handler changes from `allowTeamMembers` to `allowedCollaborators`; downstream consumers read the new key. | ||
| - A future ADR will be required to schedule and execute removal of the deprecated alias once adoption is confirmed. | ||
|
|
||
| --- | ||
|
|
||
| *This is a DRAFT ADR generated by the [Design Decision Gate](https://github.com/github/gh-aw/actions/runs/27852098024) workflow. The PR author must review, complete, and finalize this document before the PR can merge.* |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,151 @@ | ||
| package cli | ||
|
|
||
| import ( | ||
| "strings" | ||
|
|
||
| "github.com/github/gh-aw/pkg/logger" | ||
| ) | ||
|
|
||
| var mentionsAllowTeamMembersCodemodLog = logger.New("cli:codemod_mentions_allow_team_members") | ||
|
|
||
| func getMentionsAllowTeamMembersCodemod() Codemod { | ||
| return Codemod{ | ||
| ID: "mentions-allow-team-members-to-allowed-collaborators", | ||
| Name: "Rename allow-team-members to allowed-collaborators in mentions", | ||
| Description: "Renames allow-team-members to allowed-collaborators in safe-outputs.mentions.", | ||
| IntroducedIn: "1.0.0", | ||
| Apply: func(content string, frontmatter map[string]any) (string, bool, error) { | ||
| if !mentionsAllowTeamMembersNeedsMigration(frontmatter) { | ||
| return content, false, nil | ||
| } | ||
|
|
||
| newContent, applied, err := applyFrontmatterLineTransform(content, func(lines []string) ([]string, bool) { | ||
| return renameMentionsAllowTeamMembers(lines) | ||
| }) | ||
| if applied { | ||
| mentionsAllowTeamMembersCodemodLog.Print("Renamed allow-team-members to allowed-collaborators in safe-outputs.mentions") | ||
| } | ||
| return newContent, applied, err | ||
| }, | ||
| } | ||
| } | ||
|
|
||
| func mentionsAllowTeamMembersNeedsMigration(frontmatter map[string]any) bool { | ||
| safeOutputsAny, ok := frontmatter["safe-outputs"] | ||
| if !ok { | ||
| return false | ||
| } | ||
| safeOutputsMap, ok := safeOutputsAny.(map[string]any) | ||
| if !ok { | ||
| return false | ||
| } | ||
| mentionsAny, ok := safeOutputsMap["mentions"] | ||
| if !ok { | ||
| return false | ||
| } | ||
| mentionsMap, ok := mentionsAny.(map[string]any) | ||
| if !ok { | ||
| return false | ||
| } | ||
|
|
||
| _, hasOld := mentionsMap["allow-team-members"] | ||
| _, hasNew := mentionsMap["allowed-collaborators"] | ||
| return hasOld && !hasNew | ||
| } | ||
|
|
||
| func renameMentionsAllowTeamMembers(lines []string) ([]string, bool) { | ||
| result := make([]string, 0, len(lines)) | ||
| modified := false | ||
|
|
||
| inSafeOutputs := false | ||
| safeOutputsIndent := "" | ||
| safeOutputsChildIndent := "" | ||
| inMentions := false | ||
| mentionsIndent := "" | ||
| mentionsChildIndent := "" | ||
|
|
||
| for i, line := range lines { | ||
| trimmed := strings.TrimSpace(line) | ||
| indent := getIndentation(line) | ||
|
|
||
| if !strings.HasPrefix(trimmed, "#") { | ||
| if inSafeOutputs && hasExitedBlock(line, safeOutputsIndent) { | ||
| inSafeOutputs = false | ||
| safeOutputsChildIndent = "" | ||
| inMentions = false | ||
| mentionsIndent = "" | ||
| mentionsChildIndent = "" | ||
| } | ||
| if inMentions && hasExitedBlock(line, mentionsIndent) { | ||
| inMentions = false | ||
| mentionsIndent = "" | ||
| mentionsChildIndent = "" | ||
| } | ||
| } | ||
|
|
||
| if strings.HasPrefix(trimmed, "safe-outputs:") { | ||
| inSafeOutputs = true | ||
| safeOutputsIndent = indent | ||
| safeOutputsChildIndent = "" | ||
| inMentions = false | ||
| mentionsIndent = "" | ||
| mentionsChildIndent = "" | ||
| result = append(result, line) | ||
| continue | ||
| } | ||
|
|
||
| if inSafeOutputs && isDescendant(indent, safeOutputsIndent) && !strings.HasPrefix(trimmed, "#") { | ||
| if (safeOutputsChildIndent == "" || indent == safeOutputsChildIndent) && strings.HasPrefix(trimmed, "mentions:") { | ||
| if safeOutputsChildIndent == "" { | ||
| safeOutputsChildIndent = indent | ||
| } | ||
| if strings.HasSuffix(trimmed, ":") { | ||
| inMentions = true | ||
| mentionsIndent = indent | ||
| mentionsChildIndent = "" | ||
| } else { | ||
| inMentions = false | ||
| mentionsIndent = "" | ||
| mentionsChildIndent = "" | ||
| if strings.Contains(trimmed, "allow-team-members:") { | ||
| newLine := strings.Replace(line, "allow-team-members:", "allowed-collaborators:", 1) | ||
| result = append(result, newLine) | ||
| modified = true | ||
| mentionsAllowTeamMembersCodemodLog.Printf("Renamed allow-team-members to allowed-collaborators in safe-outputs.mentions on line %d", i+1) | ||
| continue | ||
| } | ||
| } | ||
| result = append(result, line) | ||
| continue | ||
| } | ||
| if strings.HasSuffix(trimmed, ":") && (safeOutputsChildIndent == "" || indent == safeOutputsChildIndent) { | ||
| if safeOutputsChildIndent == "" { | ||
| safeOutputsChildIndent = indent | ||
| } | ||
| inMentions = false | ||
| mentionsIndent = "" | ||
| mentionsChildIndent = "" | ||
| result = append(result, line) | ||
| continue | ||
| } | ||
| } | ||
|
|
||
| if inMentions && mentionsChildIndent == "" && isDescendant(indent, mentionsIndent) && trimmed != "" && !strings.HasPrefix(trimmed, "#") { | ||
| mentionsChildIndent = indent | ||
| } | ||
|
|
||
| if inMentions && indent == mentionsChildIndent && strings.HasPrefix(trimmed, "allow-team-members:") { | ||
| newLine, replaced := findAndReplaceInLine(line, "allow-team-members", "allowed-collaborators") | ||
| if replaced { | ||
| result = append(result, newLine) | ||
| modified = true | ||
| mentionsAllowTeamMembersCodemodLog.Printf("Renamed allow-team-members to allowed-collaborators in safe-outputs.mentions on line %d", i+1) | ||
| continue | ||
| } | ||
| } | ||
|
|
||
| result = append(result, line) | ||
| } | ||
|
|
||
| return result, modified | ||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[/tdd] When both
allow-team-membersandallowed-collaboratorsare present simultaneously,mentionsAllowTeamMembersNeedsMigrationreturnsfalseand the codemod silently skips. The old deprecated key stays in the file even after the user runsgh aw fix.The
TestMentionsAllowTeamMembersCodemod_NoOp_AlreadyMigratedtest only covers the case whereallow-team-membersis absent — not the "both keys present" case. A user who hand-edited their YAML to addallowed-collaboratorsbut forgot to remove the old key would be surprised thatgh aw fixdoes nothing.💡 Suggested additional test
This documents the intended no-op and prevents a future refactor from accidentally "fixing" both-key documents in unexpected ways.