Conversation
|
| persist-credentials: false | ||
| - uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 | ||
| @@UV_SETUP_WITH@@ | ||
| - run: @@CLI@@ sync --check |
There was a problem hiding this comment.
Manual headings trigger deployments
This app-mode pull request workflow only runs sync --check. An ordinary pull request can therefore add a valid ## YYYY.W.S heading without using the release dispatch flow. After that pull request is merged, release_from_changelog.yml treats the heading as an unpublished release and starts the staging-to-production deployment pipeline. Add the existing heading-provenance check, adapted for app release branches, so hand-written headings cannot initiate deployments.
Knowledge Base Used:
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | ||
| with: | ||
| ref: "@@MAIN_BRANCH@@" | ||
| fetch-depth: 0 | ||
| persist-credentials: false | ||
| submodules: recursive |
There was a problem hiding this comment.
Private submodule checkout fails
If the source is a private cross-repository submodule, recursive checkout uses the action's default repository token before app-materialize can install the GitHub CLI credential helper. The checkout then fails before the release PR can be created. The generated configuration also has no token or secret setting through which consumers can provide the appropriately scoped credential described in the README. The same issue affects the recursive checkout in deploy_dev.yml.
| missing = inputs - workflow_call_inputs(target.read_text(encoding="utf-8")) | ||
| if missing: | ||
| fail( | ||
| f"app workflow {workflow} must declare workflow_call inputs: {', '.join(sorted(missing))}" | ||
| ) |
There was a problem hiding this comment.
App hook validation checks only whether the expected input names exist, even though the documented contract requires string inputs. A hook can declare version, ref, or environment as an incompatible type and still pass sync --check, leaving the generated reusable-workflow call to fail when GitHub validates or executes it. Parse and verify each input's type: string contract instead of comparing names alone.
Knowledge Base Used: Release command and workflow automation
Merging this PR will not alter performance
Comparing Footnotes
|
There was a problem hiding this comment.
6 issues found across 16 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="packages/reflex-release/src/reflex_release/scaffold.py">
<violation number="1" location="packages/reflex-release/src/reflex_release/scaffold.py:807">
P2: When an app hook declares a required input with a non-string or missing `type`, `sync --check` still passes because it checks names only, and the release then fails when GitHub validates the reusable-workflow call. Validate each hook's input type (and required declaration) against the documented contract before accepting it.</violation>
</file>
<file name="packages/reflex-release/src/reflex_release/config.py">
<violation number="1" location="packages/reflex-release/src/reflex_release/config.py:948">
P2: When an app repository retains package-only settings such as `changelog-exempt-packages`, `_load_app` accepts them even though app workflows ignore them. Reject all package-only keys consistently to enforce the documented app-versus-package configuration boundary.</violation>
<violation number="2" location="packages/reflex-release/src/reflex_release/config.py:1077">
P2: When app configuration contains an invalid `release-timezone`, `app-materialize` raises an uncaught `ZoneInfoNotFoundError` instead of the CLI’s normal configuration error. Validate the timezone while loading app configuration so the workflow fails clearly before allocation.
(Based on your team's feedback about validating release configuration early.)</violation>
</file>
<file name="packages/reflex-release/src/reflex_release/templates/workflows/app/changelog.yml">
<violation number="1" location="packages/reflex-release/src/reflex_release/templates/workflows/app/changelog.yml:4">
P2: The app changelog check only runs `sync --check`; unlike the package `changelog.yml`, it has no guard rejecting hand-written CHANGELOG version headings. A PR that hand-adds an untagged `YYYY.W.sequence` heading passes this check and, once merged to `main`, `release_from_changelog.yml` → `app-detect` treats it as a release and automatically deploys to staging (production still requires approval). Add the same heading rejection (and the release-branch/author exemption) to the app workflow if the 'same reviewed changelog flow' claim is to hold.</violation>
</file>
<file name="tests/units/reflex_release/test_app.py">
<violation number="1" location="tests/units/reflex_release/test_app.py:94">
P2: These capsys assertions are fragile: `write_outputs`/`write_summary` (actions._append_lines) write to stdout only when `$GITHUB_OUTPUT`/`$GITHUB_STEP_SUMMARY` are unset, and otherwise append to those files leaving stdout empty. GitHub Actions sets GITHUB_OUTPUT for the whole job, so in the project's CI every `capsys.readouterr().out` here (this detect test, `test_detect_empty_and_stale`, `test_dev_never_changes_changelog_or_tags`, `test_app_cli_materialize_and_detect`) would assert against empty output and fail. The rest of the suite avoids this via the `outputs`/`summary` fixtures that monkeypatch GITHUB_OUTPUT to a temp file; these app tests should do the same instead of depending on the variable being absent.</violation>
</file>
<file name="packages/reflex-release/README.md">
<violation number="1" location="packages/reflex-release/README.md:1073">
P2: Private cross-repository submodules cannot use the documented app configuration because generated checkouts expose no scoped token or SSH credential. Add a configurable checkout credential to the generated workflows, or document private cross-repository submodules as unsupported.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| fail( | ||
| f"app workflow {workflow} must be an existing, repository-owned workflow" | ||
| ) | ||
| missing = inputs - workflow_call_inputs(target.read_text(encoding="utf-8")) |
There was a problem hiding this comment.
P2: When an app hook declares a required input with a non-string or missing type, sync --check still passes because it checks names only, and the release then fails when GitHub validates the reusable-workflow call. Validate each hook's input type (and required declaration) against the documented contract before accepting it.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/reflex-release/src/reflex_release/scaffold.py, line 807:
<comment>When an app hook declares a required input with a non-string or missing `type`, `sync --check` still passes because it checks names only, and the release then fails when GitHub validates the reusable-workflow call. Validate each hook's input type (and required declaration) against the documented contract before accepting it.</comment>
<file context>
@@ -768,8 +794,24 @@ def sync(config: Config, check: bool = False, force: bool = False) -> None:
+ fail(
+ f"app workflow {workflow} must be an existing, repository-owned workflow"
+ )
+ missing = inputs - workflow_call_inputs(target.read_text(encoding="utf-8"))
+ if missing:
+ fail(
</file context>
| "never-publish-packages", | ||
| "latest-release-package", | ||
| "post-release-workflow", | ||
| "tag-prefix", |
There was a problem hiding this comment.
P2: When an app repository retains package-only settings such as changelog-exempt-packages, _load_app accepts them even though app workflows ignore them. Reject all package-only keys consistently to enforce the documented app-versus-package configuration boundary.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/reflex-release/src/reflex_release/config.py, line 948:
<comment>When an app repository retains package-only settings such as `changelog-exempt-packages`, `_load_app` accepts them even though app workflows ignore them. Reject all package-only keys consistently to enforce the documented app-versus-package configuration boundary.</comment>
<file context>
@@ -849,6 +877,85 @@ def _default_root_source_dirs(root: Path, root_package: str | None) -> tuple[str
+ "never-publish-packages",
+ "latest-release-package",
+ "post-release-workflow",
+ "tag-prefix",
+ )
+ )
</file context>
| ) | ||
|
|
||
| if "app" in table: | ||
| return dataclasses.replace( |
There was a problem hiding this comment.
P2: When app configuration contains an invalid release-timezone, app-materialize raises an uncaught ZoneInfoNotFoundError instead of the CLI’s normal configuration error. Validate the timezone while loading app configuration so the workflow fails clearly before allocation.
(Based on your team's feedback about validating release configuration early.)
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/reflex-release/src/reflex_release/config.py, line 1077:
<comment>When app configuration contains an invalid `release-timezone`, `app-materialize` raises an uncaught `ZoneInfoNotFoundError` instead of the CLI’s normal configuration error. Validate the timezone while loading app configuration so the workflow fails clearly before allocation.
(Based on your team's feedback about validating release configuration early.) </comment>
<file context>
@@ -966,6 +1073,11 @@ def load_config(root: Path) -> Config:
)
+ if "app" in table:
+ return dataclasses.replace(
+ config, app=_load_app(table, towncrier), packages_dir=None
+ )
</file context>
| @@ -0,0 +1,20 @@ | |||
| @@HEADER@@ | |||
There was a problem hiding this comment.
P2: The app changelog check only runs sync --check; unlike the package changelog.yml, it has no guard rejecting hand-written CHANGELOG version headings. A PR that hand-adds an untagged YYYY.W.sequence heading passes this check and, once merged to main, release_from_changelog.yml → app-detect treats it as a release and automatically deploys to staging (production still requires approval). Add the same heading rejection (and the release-branch/author exemption) to the app workflow if the 'same reviewed changelog flow' claim is to hold.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/reflex-release/src/reflex_release/templates/workflows/app/changelog.yml, line 4:
<comment>The app changelog check only runs `sync --check`; unlike the package `changelog.yml`, it has no guard rejecting hand-written CHANGELOG version headings. A PR that hand-adds an untagged `YYYY.W.sequence` heading passes this check and, once merged to `main`, `release_from_changelog.yml` → `app-detect` treats it as a release and automatically deploys to staging (production still requires approval). Add the same heading rejection (and the release-branch/author exemption) to the app workflow if the 'same reviewed changelog flow' claim is to hold.</comment>
<file context>
@@ -0,0 +1,20 @@
+@@HEADER@@
+name: Check release workflows
+
+on:
+ pull_request:
+ workflow_dispatch:
</file context>
| version = app.materialize(app_repo, "", "Release") | ||
| capsys.readouterr() | ||
| app.detect(app_repo, "main") | ||
| assert "any=true" in capsys.readouterr().out |
There was a problem hiding this comment.
P2: These capsys assertions are fragile: write_outputs/write_summary (actions._append_lines) write to stdout only when $GITHUB_OUTPUT/$GITHUB_STEP_SUMMARY are unset, and otherwise append to those files leaving stdout empty. GitHub Actions sets GITHUB_OUTPUT for the whole job, so in the project's CI every capsys.readouterr().out here (this detect test, test_detect_empty_and_stale, test_dev_never_changes_changelog_or_tags, test_app_cli_materialize_and_detect) would assert against empty output and fail. The rest of the suite avoids this via the outputs/summary fixtures that monkeypatch GITHUB_OUTPUT to a temp file; these app tests should do the same instead of depending on the variable being absent.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At tests/units/reflex_release/test_app.py, line 94:
<comment>These capsys assertions are fragile: `write_outputs`/`write_summary` (actions._append_lines) write to stdout only when `$GITHUB_OUTPUT`/`$GITHUB_STEP_SUMMARY` are unset, and otherwise append to those files leaving stdout empty. GitHub Actions sets GITHUB_OUTPUT for the whole job, so in the project's CI every `capsys.readouterr().out` here (this detect test, `test_detect_empty_and_stale`, `test_dev_never_changes_changelog_or_tags`, `test_app_cli_materialize_and_detect`) would assert against empty output and fail. The rest of the suite avoids this via the `outputs`/`summary` fixtures that monkeypatch GITHUB_OUTPUT to a temp file; these app tests should do the same instead of depending on the variable being absent.</comment>
<file context>
@@ -0,0 +1,271 @@
+ version = app.materialize(app_repo, "", "Release")
+ capsys.readouterr()
+ app.detect(app_repo, "main")
+ assert "any=true" in capsys.readouterr().out
+ git(app_repo.root, "tag", version)
+ app.detect(app_repo, "main")
</file context>
| section, and opens a PR against main. Omitting `source-submodule` supports apps | ||
| whose source lives entirely in the deployment repository; in that case leave | ||
| `revision` empty. The source repository URL comes from `.gitmodules`. The default | ||
| checkout/token must be able to read it; private cross-repository submodules need |
There was a problem hiding this comment.
P2: Private cross-repository submodules cannot use the documented app configuration because generated checkouts expose no scoped token or SSH credential. Add a configurable checkout credential to the generated workflows, or document private cross-repository submodules as unsupported.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/reflex-release/README.md, line 1073:
<comment>Private cross-repository submodules cannot use the documented app configuration because generated checkouts expose no scoped token or SSH credential. Add a configurable checkout credential to the generated workflows, or document private cross-repository submodules as unsupported.</comment>
<file context>
@@ -1029,3 +1029,105 @@ The same shape recovers a final version: seed `## 1.2.3 (<date>)` and dispatch
+section, and opens a PR against main. Omitting `source-submodule` supports apps
+whose source lives entirely in the deployment repository; in that case leave
+`revision` empty. The source repository URL comes from `.gitmodules`. The default
+checkout/token must be able to read it; private cross-repository submodules need
+an appropriately scoped checkout credential configured by the consumer.
+
</file context>
Application deployments need the same reviewed changelog and post-publish tagging flow as package releases. Add an opt-in
[tool.reflex-release.app]mode that generates the orchestration while repository-owned reusable workflows handle builds and deployments. Existing package publishing keeps its current templates.Dispatch accepts an optional source revision and reason, pins a configured Git submodule, allocates an ISO-year.week.sequence version, and opens a release PR. After merge, the generated workflow builds the captured commit, queues staging through production approval, and creates the tag and GitHub release only after the production hook succeeds. Existing tags make detection a no-op. Optional scheduled dev builds resolve upstream independently without committing release metadata.
The app mode documents and validates hook inputs, checks generated workflow drift, reserves versions across pending release branches, and rejects stale releases. Includes user documentation and a news fragment.
Type of change
Validation
sync --checkfor both package and app configurations.Workflow validation from implementation passed except for actionlint 1.7.12's unsupported
concurrency.queuekey;queue: maxis documented by GitHub and is intentionally retained. No live deployment was run.Companion consumer migration: https://github.com/reflex-dev/reflex-docs/pull/27. That PR stays draft until this support is published in the pinned reflex-release version.