Skip to content

Allow configurable release branch prefixes - #11

Merged
Eduardo Villalpando Mello (edvilme) merged 1 commit into
mainfrom
release-branch-prefix
Nov 9, 2026
Merged

Eduardo Villalpando Mello (edvilme) merged 1 commit into
mainfrom
release-branch-prefix

Conversation

@edvilme

@edvilme Eduardo Villalpando Mello (edvilme) commented Nov 9, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Add optional release-branch-prefix to release-pr, defaulting to release/ so existing consumers keep their current behavior. A prefix such as stable/v produces stable/v2026.8.0; callers cannot override the calculated stable version.
  • Expose branch in both modes. Plan reports the prospective stable release branch without creating it; ordinary PRs return an empty branch output.
  • Validate the literal refs/heads/<prefix><stable-version> with Git before modifying the manifest or creating a commit. Keep the empty-lease, create-only push and rejection of already-identical remote branches.
  • Document the contract, matching plan/release inputs, and Azure/bot branch-pattern prerequisites. No extension workflow, publishing activation, or branch-protection changes are included.
- uses: microsoft/vscode-python-ci/actions/release-pr@<reviewed-commit-sha>
  id: release
  with:
    mode: release
    release-branch-prefix: stable/v
# steps.release.outputs.branch: stable/v2026.8.0

Validation

  • 12 release-action tests and 7 version-action tests passed locally.
  • Git fixtures exercise default/custom plan output, read-only planning, custom branch creation, invalid prefixes in both modes before any write, and existing different/identical branch protection with both prefixes.
  • Existing smoke workflow now asserts that ordinary PRs return neither a version nor a branch.
  • Black, Prettier, and whitespace checks passed. Hosted Linux, Windows, and macOS tests passed on both push and PR runs; the version-action and read-only release-action smoke checks passed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 956d3afd-ae0b-486c-a60c-3a6276c23213

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟢 Approval recommended

The configurable release-branch naming change has no active review issues.

No open issues 🎉

What changed in this PR

This PR lets consumers configure release branch names while preserving the default release/ prefix and create-only push behavior.

Changes:

  • Add release-branch-prefix and a branch output for both plan and release modes.
  • Validate the calculated branch ref before modifying the manifest or creating a commit.
  • Expand tests and documentation for custom prefixes, invalid names, and ordinary PR outputs.
File Description
actions/​release-pr/​tests/​test_release_pr.py Tests custom prefixes, invalid-name rejection, and existing-branch protection.
actions/​release-pr/​README.md Documents inputs, outputs, validation, and branch-pattern prerequisites.
actions/​release-pr/​action.yml Adds prefix configuration, branch output, and ref validation; uses the calculated branch for pushes.
.github/​workflows/​smoke-release-pr-action.yml Checks that ordinary PRs return an empty branch output as well as an empty version.

Review effort: Balanced

@rchiodo

Copy link
Copy Markdown

🔒 Automated review in progress — Rich Chiodo (@rchiodo) is auto-reviewing this PR.

@rchiodo

Copy link
Copy Markdown

Reviewed commit: 30f5ef33388cb3fe759eca4d3264aeb49545ee0c

Result: ⚠️ partially-verified

Verification details

Verification: Automated verification is best effort. The PR author remains responsible for testing.

Summary: All 12 release-action tests and 7 version-action tests passed in the Linux container. An additional empty-prefix probe passed, including read-only planning, branch creation, manifest preservation, and identical-branch rejection. No product failures were observed; GitHub-hosted smoke execution and Windows/macOS coverage remain unverified.

Test runs: 4 passed, 2 not run

  • ⚠️ Not run | GitHub Actions ordinary-PR output smoke assertion | test -z "$VERSION"
    test -z "$BRANCH"
  • ⚠️ Not run | Windows and macOS workflow matrix | python -m unittest discover -s actions/get-extension-version/tests -v
    python -m unittest discover -s actions/release-pr/tests -v
  • ✅ Passed | Release-action tests | python -m unittest discover -s actions/release-pr/tests -v
  • ✅ Passed | Version-action tests | python -m unittest discover -s actions/get-extension-version/tests -v
  • ✅ Passed | Dependency and test discovery | printf 'Sandbox profile: %s\n' "${AUTOMATION_SANDBOX_PROFILE:-unset}"; uname -s; python --version; git --version; bash --version | head -n 1; git status --short; git log -3 --oneline; git diff HEAD^ HEAD --stat; python - <<'PY'
    import ast
    from pathlib import Path
    import unittest
    for directory in ('actions/release-pr', 'actions/get-extension-version'):
    print(f'\n{directory}:')
    for path in sorted(Path(directory).rglob('*.py')):
    tree = ast.parse(path.read_text(encoding='utf-8'))
    imports = sorted({node.module or '' for node in ast.walk(tree) if isinstance(node, ast.ImportFrom)} | {alias.name for node in ast.walk(tree) if isinstance(node, ast.Import) for alias in node.names})
    tests = [node.name for node in ast.walk(tree) if isinstance(node, ast.FunctionDef) and node.name.startswith('test_')]
    print(path, 'imports=', imports, 'tests=', tests)
    PY
  • ✅ Passed | Explicit empty-prefix workflow probe | python - <<'PY'
    import importlib.util
    from pathlib import Path

path = Path('actions/release-pr/tests/test_release_pr.py').resolve()
spec = importlib.util.spec_from_file_location('release_pr_verification_tests', path)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
case = module.GitWorkflowTests()
try:
case.setUp()
case.environment['RELEASE_BRANCH_PREFIX'] = ''
remote = ('--git-dir', str(case.remote))
refs_before = case.git(*remote, 'show-ref')
case.assertEqual(case.run_action('plan', case.head), '1.45.0')
case.assertEqual(case.branch, '1.44.0')
case.assertEqual(case.git('rev-parse', 'HEAD'), case.head)
case.assertEqual(case.git('status', '--porcelain'), '')
case.assertEqual(case.git(*remote, 'show-ref'), refs_before)
merged = case.merge()
case.assertEqual(case.run_action('release', merged), '1.44.0')
case.assertEqual(case.branch, '1.44.0')
ref = 'refs/heads/1.44.0'
prepared = case.git('rev-parse', 'HEAD')
case.assertEqual(case.git(*remote, 'rev-parse', ref), prepared)
case.assertEqual(case.git(*remote, 'rev-parse', f'{ref}^'), merged)
case.assertEqual(case.git(*remote, 'rev-parse', 'main'), merged)
case.assertEqual(module.json.loads(case.git(*remote, 'show', f'{ref}:package.json')), {**case.package, 'version': '1.44.0'})
with case.assertRaisesRegex(RuntimeError, 'Release branch already exists'):
case.step('Push the finished release branch')
case.assertEqual(case.git(*remote, 'rev-parse', ref), prepared)
print('PASS: explicit empty prefix produces 1.44.0; plan is read-only; release creates the version-only branch with the correct manifest and parent; target is unchanged; identical retry is rejected.')
finally:
case.doCleanups()
PY

⚠️ GitHub Actions ordinary-PR output smoke assertion diagnostic output
The changed smoke job requires GitHub pull_request context and composite-action execution. The offline container did not execute that job or produce its VERSION and BRANCH outputs.
⚠️ Windows and macOS workflow matrix diagnostic output
.github/workflows/smoke-release-pr-action.yml specifies ubuntu-latest, windows-latest, and macos-latest. Discovery reported Linux; Windows and macOS execution was unavailable.

@rchiodo Rich Chiodo (rchiodo) left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Approved via Review Center.

@rchiodo Rich Chiodo (rchiodo) added the review-auto:approved Automated review: no blocking findings (approval posted). label Nov 9, 2026
@edvilme
Eduardo Villalpando Mello (edvilme) merged commit f19aaaf into main Nov 9, 2026
12 checks passed
Eduardo Villalpando Mello (edvilme) added a commit to microsoft/vscode-python-environments that referenced this pull request Nov 10, 2026
## Summary

Adds a dedicated **Release PR / Plan** check to all PRs targeting
`main`, including edited/reopened PRs. Uses `contents: read`, no path
filters, and the shared `release-pr` action pinned to reviewed commit
`4e0c4335bbf6b1a274673e22d9c39cd7efb93ccf` in `mode: plan`.

Only PRs changing root `package.json` alone, with a different version,
are release candidates. Those must be version-only JSON changes with an
increasing SemVer, a positive odd development minor, supported
Marketplace bounds, and lossless serialization. Mixed-file changes and
unchanged versions pass as **not applicable**, explicitly distinguished
from validated candidates in the job summary. Other manifests, including
`api/package.json`, are outside this check's scope.

Existing CI and Azure publishing are unchanged. This does **not** create
release branches, enable release mode, or change branch protection. Make
the check required only after merging and observing it working;
publishing activation remains a separate rollout.

## Validation

- Prettier, whitespace, YAML contract, Bash syntax, and both summary
outcomes pass.
- Real external-consumer pilot:
microsoft/vscode-black-formatter#839
(disposable; never merged).
- [Valid version-only
bump](https://github.com/microsoft/vscode-black-formatter/actions/runs/42701669435):
passed with exact candidate output, nested stable-version action
resolution, and an unchanged worktree.
- [Invalid even-minor
bump](https://github.com/microsoft/vscode-black-formatter/actions/runs/42701753358):
failed as expected with "The development minor must be positive and
odd".
- [Mixed-file
bump](https://github.com/microsoft/vscode-black-formatter/actions/runs/42701874256)
and [unchanged-version manifest
edit](https://github.com/microsoft/vscode-black-formatter/actions/runs/42702002023):
passed with empty candidate output and an unchanged worktree.

This adoption PR changes only the workflow. Its [Release PR / Plan
check](https://github.com/microsoft/vscode-python-environments/actions/runs/42724187188)
passed on head `7649eedcc247217d9835af154e5e3e106c081d3f` as **not
applicable**. This workflow-only diff does not exercise candidate
authorization; shared-action tests and hosted API smoke cover that
behavior.


## Latest shared action

Updated to merged commit `4e0c4335bbf6b1a274673e22d9c39cd7efb93ccf`,
including microsoft/vscode-python-ci#11 and
microsoft/vscode-python-ci#12. Release candidates now require the PR
creator to have write/maintain/admin repository access; permission
lookups fail closed. Configurable branch prefixes and the branch output
are available, with the existing `release/` default. This workflow
remains read-only plan mode. The linked disposable pilot covers the
original baseline; shared-action CI covers the added
prefix/authorization behavior.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 956d3afd-ae0b-486c-a60c-3a6276c23213
Eduardo Villalpando Mello (edvilme) added a commit to microsoft/vscode-python that referenced this pull request Nov 12, 2026
## Summary

Adds a dedicated **Release PR / Plan** check to all PRs targeting
`main`, including edited/reopened PRs. Uses `contents: read`, no path
filters, and the shared `release-pr` action pinned to reviewed commit
`4e0c4335bbf6b1a274673e22d9c39cd7efb93ccf` in `mode: plan`.

Only PRs changing root `package.json` alone, with a different version,
are release candidates. Those must be version-only JSON changes with an
increasing SemVer, a positive odd development minor, supported
Marketplace bounds, and lossless serialization. Mixed-file changes and
unchanged versions pass as **not applicable**, explicitly distinguished
from validated candidates in the job summary. Other manifests, including
`api/package.json`, are outside this check's scope.

Existing CI and Azure publishing are unchanged. This does **not** create
release branches, enable release mode, or change branch protection. Make
the check required only after merging and observing it working;
publishing activation remains a separate rollout.

## Validation

- Prettier, whitespace, YAML contract, Bash syntax, and both summary
outcomes pass.
- Real external-consumer pilot:
microsoft/vscode-black-formatter#839
(disposable; never merged).
- [Valid version-only
bump](https://github.com/microsoft/vscode-black-formatter/actions/runs/42701669435):
passed with exact candidate output, nested stable-version action
resolution, and an unchanged worktree.
- [Invalid even-minor
bump](https://github.com/microsoft/vscode-black-formatter/actions/runs/42701753358):
failed as expected with "The development minor must be positive and
odd".
- [Mixed-file
bump](https://github.com/microsoft/vscode-black-formatter/actions/runs/42701874256)
and [unchanged-version manifest
edit](https://github.com/microsoft/vscode-black-formatter/actions/runs/42702002023):
passed with empty candidate output and an unchanged worktree.

This adoption PR changes only the workflow. Its [Release PR / Plan
check](https://github.com/microsoft/vscode-python/actions/runs/42724186665)
passed on head `fa1d9b2bcd5bbdba5caabab74832e0b385a94ed9` as **not
applicable**. This workflow-only diff does not exercise candidate
authorization; shared-action tests and hosted API smoke cover that
behavior.


Issue tracking: this is workflow-only maintenance from the shared CI
rollout, with no separate product issue. Uses the repository's existing
`skip-issue-check` label for that case.

## Latest shared action

Updated to merged commit `4e0c4335bbf6b1a274673e22d9c39cd7efb93ccf`,
including microsoft/vscode-python-ci#11 and
microsoft/vscode-python-ci#12. Release candidates now require the PR
creator to have write/maintain/admin repository access; permission
lookups fail closed. Configurable branch prefixes and the branch output
are available, with the existing `release/` default. This workflow
remains read-only plan mode. The linked disposable pilot covers the
original baseline; shared-action CI covers the added
prefix/authorization behavior.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 956d3afd-ae0b-486c-a60c-3a6276c23213
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request review-auto:approved Automated review: no blocking findings (approval posted).

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants