Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Feb 12, 2026

Implementation Complete ✅

Successfully merged main branch and recompiled all workflows with both base-branch and footer fields working together.

Changes Made

Merge Conflicts Resolved:

  • ✅ Combined BaseBranch and Footer fields in CreatePullRequestsConfig struct
  • ✅ Updated handler config builder to support both fields
  • ✅ Updated JSON schema to include both properties
  • ✅ Updated documentation with both fields

Validation:

  • ✅ All unit tests pass (including new footer tests from main)
  • ✅ All integration tests pass
  • ✅ Manual compilation confirms both fields work together
  • ✅ All 148 workflows recompiled successfully

Usage Example

Both fields can now be used together:

safe-outputs:
  create-pull-request:
    target-repo: "microsoft/vscode-docs"
    base-branch: vnext    # NEW: Custom base branch
    footer: false         # NEW from main: Control footer visibility
    draft: true

Compiles to:

{
  "create_pull_request": {
    "base_branch": "vnext",
    "footer": false,
    "target-repo": "microsoft/vscode-docs",
    "draft": true
  }
}

Backward Compatibility

Both fields maintain backward compatibility:

  • base-branch defaults to ${{ github.ref_name }} when not specified
  • footer defaults to true when not specified
Original prompt

This section details on the original issue you should resolve

<issue_title>create-pull-request safe output: add base-branch field for cross-repo PRs targeting non-default branches</issue_title>
<issue_description>(note, AI generated and working with @benvillalobos on similar cross repo engineering flows)

Summary

The create-pull-request safe output hard-codes the base branch to ${{ github.ref_name }}, which is the branch of the workflow repository that the dispatch targets. For cross-repository PRs (via target-repo), there is no way to configure the base branch of the PR in the target repository.

This prevents workflows that need to create PRs targeting non-default branches in external repos (e.g., a workflow in org/engineering that creates a PR targeting the vnext branch in org/docs).

Expected Behavior

A base-branch field on create-pull-request that lets you specify the target branch for the PR:

safe-outputs:
  create-pull-request:
    draft: true
    target-repo: "microsoft/vscode-docs"
    base-branch: vnext

This should compile to base_branch: "vnext" in the handler config instead of base_branch: "${{ github.ref_name }}".

Actual Behavior

base-branch is not a recognized field — the compiler rejects it:

error: Unknown property: base-branch. Valid fields are: allow-empty, allowed-labels,
allowed-repos, auto-merge, draft, expires, github-token, if-no-changes, labels, reviewers, ...

The base branch is unconditionally set from github.ref_name in the compiled output:

// create_pull_request.go
customEnvVars = append(customEnvVars, "          GH_AW_BASE_BRANCH: \${{ github.ref_name }}\\n")

And the handler config in the lock file reflects this:

{
  "create_pull_request": {
    "base_branch": "${{ github.ref_name }}",
    "target-repo": "microsoft/vscode-docs"
  }
}

Since the workflow is dispatched with ref: main (the branch where the workflow file lives), all cross-repo PRs target main regardless of intent.

Use Case

We're building automation in microsoft/vscode-engineering that triggers when a feature-request issue is closed in microsoft/vscode. It should create two draft PRs in microsoft/vscode-docs:

  1. Insiders release notes → targeting main ✅ (works today)
  2. Feature documentation → targeting vnext ❌ (no way to configure this)

Both workflows use create-pull-request with target-repo: "microsoft/vscode-docs", but the second one needs to target vnext instead of main.

Source Reference

CreatePullRequestsConfig in pkg/workflow/create_pull_request.go has no BaseBranch field. The env var GH_AW_BASE_BRANCH is unconditionally set to github.ref_name.

Suggested Implementation

Add a BaseBranch field to CreatePullRequestsConfig:

type CreatePullRequestsConfig struct {
    // ...existing fields...
    BaseBranch string `yaml:"base-branch,omitempty"`
}

Then conditionally use it when building the env var:

if data.SafeOutputs.CreatePullRequests.BaseBranch != "" {
    customEnvVars = append(customEnvVars, fmt.Sprintf("          GH_AW_BASE_BRANCH: %q\\n", data.SafeOutputs.CreatePullRequests.BaseBranch))
} else {
    customEnvVars = append(customEnvVars, "          GH_AW_BASE_BRANCH: \${{ github.ref_name }}\\n")
}
```</issue_description>

## Comments on the Issue (you are @copilot in this section)

<comments>
</comments>

💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Copilot AI and others added 2 commits February 12, 2026 05:35
Copilot AI changed the title [WIP] Add base-branch field for create-pull-request safe output Add base-branch field for cross-repo PRs targeting non-default branches Feb 12, 2026
Copilot AI requested a review from pelikhan February 12, 2026 05:44
@pelikhan pelikhan marked this pull request as ready for review February 12, 2026 05:51
Copilot AI review requested due to automatic review settings February 12, 2026 05:51
@pelikhan
Copy link
Contributor

@copilot Merge main and recompile

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 support for configuring the base branch used by the create-pull-request safe output, enabling cross-repo PR creation targeting non-default branches while keeping the existing ${{ github.ref_name }} default.

Changes:

  • Added base-branch to CreatePullRequestsConfig and propagate it into the create PR job env (GH_AW_BASE_BRANCH) and handler-manager config (base_branch).
  • Extended the workflow JSON schema to accept the new base-branch field.
  • Added unit + integration coverage to validate default vs custom base branch compilation.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
pkg/workflow/create_pull_request_base_branch_integration_test.go New integration tests that compile workflows and assert base_branch output for custom/default/slash-containing branches.
pkg/workflow/create_pull_request.go Adds BaseBranch config field and uses it to set GH_AW_BASE_BRANCH, falling back to ${{ github.ref_name }}.
pkg/workflow/compiler_safe_outputs_config_test.go Adds unit test verifying handler-manager config JSON includes the expected base_branch.
pkg/workflow/compiler_safe_outputs_config.go Updates create_pull_request handler config builder to emit custom base_branch or default ${{ github.ref_name }}.
pkg/parser/schemas/main_workflow_schema.json Adds base-branch to the create-pull-request schema definition.
docs/src/content/docs/reference/frontmatter-full.md Documents the new base-branch option under safe-outputs.create-pull-request.

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

Comment on lines +784 to +805
for _, step := range steps {
if strings.Contains(step, "GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG") {
parts := strings.Split(step, "GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: ")
if len(parts) == 2 {
jsonStr := strings.TrimSpace(parts[1])
jsonStr = strings.Trim(jsonStr, "\"")
jsonStr = strings.ReplaceAll(jsonStr, "\\\"", "\"")

var config map[string]map[string]any
err := json.Unmarshal([]byte(jsonStr), &config)
require.NoError(t, err, "Config JSON should be valid")

prConfig, ok := config["create_pull_request"]
require.True(t, ok, "create_pull_request config should exist")

baseBranch, ok := prConfig["base_branch"]
require.True(t, ok, "base_branch should be in config")

assert.Equal(t, tt.expectedBaseBranch, baseBranch, "base_branch should match expected value")
}
}
}
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

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

In TestCreatePullRequestBaseBranch, the JSON extraction loop doesn’t assert that it actually found/parses the GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG line. If the env var generation regresses (or the string format changes), the test can pass without validating anything. Track a found boolean (or extract once with SplitN) and require.True(t, found, ...) after the loop, and consider failing if len(parts) != 2 to avoid silent success.

Suggested change
for _, step := range steps {
if strings.Contains(step, "GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG") {
parts := strings.Split(step, "GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: ")
if len(parts) == 2 {
jsonStr := strings.TrimSpace(parts[1])
jsonStr = strings.Trim(jsonStr, "\"")
jsonStr = strings.ReplaceAll(jsonStr, "\\\"", "\"")
var config map[string]map[string]any
err := json.Unmarshal([]byte(jsonStr), &config)
require.NoError(t, err, "Config JSON should be valid")
prConfig, ok := config["create_pull_request"]
require.True(t, ok, "create_pull_request config should exist")
baseBranch, ok := prConfig["base_branch"]
require.True(t, ok, "base_branch should be in config")
assert.Equal(t, tt.expectedBaseBranch, baseBranch, "base_branch should match expected value")
}
}
}
found := false
for _, step := range steps {
if strings.Contains(step, "GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG") {
parts := strings.SplitN(step, "GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: ", 2)
require.Len(t, parts, 2, "GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG line should contain key and value")
found = true
jsonStr := strings.TrimSpace(parts[1])
jsonStr = strings.Trim(jsonStr, "\"")
jsonStr = strings.ReplaceAll(jsonStr, "\\\"", "\"")
var config map[string]map[string]any
err := json.Unmarshal([]byte(jsonStr), &config)
require.NoError(t, err, "Config JSON should be valid")
prConfig, ok := config["create_pull_request"]
require.True(t, ok, "create_pull_request config should exist")
baseBranch, ok := prConfig["base_branch"]
require.True(t, ok, "base_branch should be in config")
assert.Equal(t, tt.expectedBaseBranch, baseBranch, "base_branch should match expected value")
}
}
require.True(t, found, "GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG should be present in steps")

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Copilot AI commented Feb 12, 2026

@copilot Merge main and recompile

Merged main and recompiled all 148 workflows successfully. The merge combined the base-branch field with the new footer field from main, and all tests pass. Commit: 729952f

Copilot AI requested a review from pelikhan February 12, 2026 06:05
@pelikhan pelikhan merged commit 9513a84 into main Feb 12, 2026
87 checks passed
@pelikhan pelikhan deleted the copilot/add-base-branch-field branch February 12, 2026 06:11
github-actions bot added a commit that referenced this pull request Feb 12, 2026
Add documentation for the new base-branch configuration option in the
create-pull-request safe output. This field allows workflows to specify
which branch a pull request should target, particularly useful for
cross-repository workflows targeting non-default branches.

Changes:
- Add base-branch field to create-pull-request YAML example
- Document default behavior (defaults to github.ref_name)
- Include use case example for cross-repo PR targeting vnext branch

Related: #15089

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
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.

create-pull-request safe output: add base-branch field for cross-repo PRs targeting non-default branches

2 participants