diff --git a/.github/workflows/merge-demo-feature.yml b/.github/workflows/merge-demo-feature.yml index 95cb946..ab20739 100644 --- a/.github/workflows/merge-demo-feature.yml +++ b/.github/workflows/merge-demo-feature.yml @@ -21,6 +21,7 @@ jobs: - "robust-maturin-demo" with: demo_name: ${{ matrix.demo_name }} + branch: ${{ github.ref_name }} merge-demo-feature: name: Merge Demo Feature @@ -30,11 +31,13 @@ jobs: demo_name: - "robust-python-demo" - "robust-maturin-demo" + env: + GH_TOKEN: ${{ secrets.DEMO_TOKEN }} steps: - name: Checkout Template uses: actions/checkout@v4 with: - repository: ${{ github.repository }} + repository: "${{ github.repository_owner }}/cookiecutter-robust-python" - name: Checkout Demo uses: actions/checkout@v4 @@ -42,6 +45,7 @@ jobs: repository: "${{ github.repository_owner }}/${{ inputs.demo_name }}" path: ${{ inputs.demo_name }} ref: develop + token: ${{ secrets.DEMO_TOKEN }} - name: Set up uv uses: astral-sh/setup-uv@v6 diff --git a/.github/workflows/sync-demos.yml b/.github/workflows/sync-demos.yml index 04fcb30..a9c0c56 100644 --- a/.github/workflows/sync-demos.yml +++ b/.github/workflows/sync-demos.yml @@ -1,8 +1,10 @@ name: sync-demo.yml on: - pull_request: - branches: - - develop + push: + branches-ignore: + - "main" + - "develop" + - "release/*" jobs: update-demo: @@ -15,3 +17,6 @@ jobs: - "robust-maturin-demo" with: demo_name: ${{ matrix.demo_name }} + branch: ${{ github.ref_name }} + secrets: + DEMO_TOKEN: ${{ secrets.DEMO_TOKEN }} diff --git a/.github/workflows/update-demo.yml b/.github/workflows/update-demo.yml index 93a933f..3801530 100644 --- a/.github/workflows/update-demo.yml +++ b/.github/workflows/update-demo.yml @@ -5,12 +5,19 @@ on: demo_name: required: true type: string + branch: + required: true + type: string + secrets: + DEMO_TOKEN: + required: true env: COOKIECUTTER_ROBUST_PYTHON__DEMOS_CACHE_FOLDER: ${{ github.workspace }} COOKIECUTTER_ROBUST_PYTHON__APP_AUTHOR: ${{ github.repository_owner }} ROBUST_PYTHON_DEMO__APP_AUTHOR: ${{ github.repository_owner }} ROBUST_MATURIN_DEMO__APP_AUTHOR: ${{ github.repository_owner }} + GH_TOKEN: ${{ secrets.DEMO_TOKEN }} jobs: update-demo: @@ -19,15 +26,24 @@ jobs: - name: Checkout Template uses: actions/checkout@v4 with: + fetch-depth: 0 repository: ${{ github.repository }} path: "${{ github.workspace }}/cookiecutter-robust-python" + - name: Configure Git + working-directory: "${{ github.workspace }}/cookiecutter-robust-python" + run: | + git config --global user.name "github-actions[bot]" + git config --global user.email "github-actions[bot]@users.noreply.github.com" + - name: Checkout Demo uses: actions/checkout@v4 with: + fetch-depth: 0 repository: "${{ github.repository_owner }}/${{ inputs.demo_name }}" path: ${{ inputs.demo_name }} ref: develop + token: ${{ secrets.DEMO_TOKEN }} - name: Set up uv uses: astral-sh/setup-uv@v6 @@ -39,4 +55,4 @@ jobs: - name: Update Demo working-directory: "${{ github.workspace }}/cookiecutter-robust-python" - run: "uvx nox -s 'update-demo(${{ inputs.demo_name }})' -- --branch-override ${{ github.head_ref }}" + run: "uvx nox -s 'update-demo(${{ inputs.demo_name }})' -- --branch-override ${{ inputs.branch }}" diff --git a/CHANGELOG.md b/CHANGELOG.md index 38b2f0f..7363b72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,36 @@ +## v2025.12.1 (2025-12-08) + +### Feat + +- improve the initial description and add a small blurb linking to the tooling rationale +- add pin image for use in readme +- add additional note pointing toward newly made PR url +- remove extra url marker for stability temporarily +- add debugging logs marking the location of demo PR's made +- add GH_TOKEN adjacent to DEMO_TOKEN usages +- add passthrough of DEMO_TOKEN wherever needed +- add workflow_call secrets passthrough +- replace default github token with premade PAT named DEMO_TOKEN + +### Fix + +- adjust inversed returncode chec +- swap to just checking return code +- shrink the scope of text checked for to ensure differing gh cli versions don't differ wording +- remove decodes that aren't relevant +- add utf-8 decodes where missing +- add --global kwargs to git config calls to see if that fixes the error +- add passthrough for branch name to differentiate branch name source for pull requests and straight pushes +- adjust syntax to use branches-ignore in sync-demos workflow +- add git config to update-demo workflow +- try removing ancestry check to see if it actually matters +- replace check against commit hash to instead check against HEAD in update-demo workflow +- remove backup creation of develop branch due to more purposeful checkout existing +- add two additional fetches that ensure branch actually exists locally so CICD doesn't error on update demo workflow +- move fetch depth adjustment to the demo instead of the template checkout in the update-demo workflow +- ensure enough history is fetched in update-demo workflow to verify branch is in sync with remote during CI +- adjust repository reference in merge-demo-feature.yml + ## v2025.12.0 (2025-12-01) ### Feat diff --git a/README.md b/README.md index 8f35f63..4a97062 100644 --- a/README.md +++ b/README.md @@ -7,34 +7,97 @@ +[![User Guide][user-guide-badge]][user-guide-page] +[![uv][uv-badge]][uv-page] +[![Python Versions][python-versions-badge]][python-versions-page] +[![Python demo status][robust-python-demo-status-badge]][robust-python-demo-status-page] +[![Maturin demo status][robust-maturin-demo-status-badge]][robust-maturin-demo-status-page] +[![Discord][discord-badge]][discord-page] + +[user-guide-badge]: https://img.shields.io/badge/user-guide-brightgreen?logo=readthedocs&style=flat-square +[user-guide-page]: https://cookiecutter-robust-python.readthedocs.io/ +[uv-badge]: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json&style=flat-square +[uv-page]: https://github.com/astral-sh/uv +[python-versions-badge]: https://img.shields.io/pypi/pyversions/robust-python-demo?style=flat-square +[python-versions-page]: https://github.com/robust-python/cookiecutter-robust-python +[discord-badge]: https://img.shields.io/badge/Discord-%235865F2.svg?logo=discord&logoColor=white&style=flat-square +[discord-page]: https://discord.gg/XZAHSBgqXU + -[![Maturin User Guide](https://img.shields.io/badge/user-guide-brightgreen?logo=readthedocs&style=flat-square)](https://robust-python.dev/cookiecutter) -[![uv](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json&style=flat-square)](https://github.com/astral-sh/uv) -[![Python Versions](https://img.shields.io/pypi/pyversions/robust-python-demo?style=flat-square)](https://github.com/robust-python/cookiecutter-robust-python) -[![Python demo status](https://github.com/robust-python/cookiecutter-robust-python/actions/workflows/python-demo.yml/badge.svg?style=flat-square)](https://github.com/robust-python/robust-python-demo/actions) -[![Maturin demo status](https://github.com/robust-python/cookiecutter-robust-python/actions/workflows/maturin-demo.yml/badge.svg)](https://github.com/robust-python/robust-maturin-demo/actions) -[![Discord](https://img.shields.io/badge/Discord-%235865F2.svg?logo=discord&logoColor=white&style=flat-square)](https://discord.gg/XZAHSBgqXU) +

+⭐ Star us on GitHub — it motivates us a lot and helps to pay the rent! +

- +--- + +**[cookiecutter-robust-python]** is a template made with the understanding that **project needs change over time**. + +The **[Robust Python Cookiecutter]** aims to provide **best practice tooling/CICD** within a structure designed for **future adaptability**. Meaning that important decisions like whether to use [maturin] may be delayed **without breaking the docs, CICD, etc.** during transition. + +--- + +## Table of Contents[![](./docs/_static/pin.svg)](#table-of-contents) + +- [About](#about) + - [Key Features](#key-features) +- [Getting Started](#getting-started) + - [Prerequisites](#prerequisites) + - [Usage](#usage) + - [Project Setup](#project-setup) +- [Roadmap](#roadmap) + - [Current Status](#current-status) +- [Why does this project exist?](#why-does-this-project-exist) +- [Contributing](#contributing) + +## About[![](./docs/_static/pin.svg)](#about) + +### Key Features +- Uses [cruft] to allow for easily transitioning between: + - Using [maturin] vs not + - repository/CICD provider ([github], [gitlab], [bitbucket]) + - Supported Python Versions +- Out of the box support/testing for major OS's (windows, linux, macos) and all currently supported [python] versions +- Automated template demos for integration testing generated CICD +- Rich documentation explaining [tooling decisions] and rationale +- and just about any other typical CI workflow you can think of (linting, release process, security, etc.) + +### Tooling Summary +- [cruft] for project generation/update +- [uv] for dependency management +- [nox] for CI execution +- [commitizen] for version/changelog management +- [ruff] for linting/formatting +- [basedpyright] for type checking +- [pip-audit] for security vulnerability checking +- [maturin] (optional) for rust integration when needed -# cookiecutter-robust-python +> 💡 For more information on tools evaluated and why choices were made, please visit our docs on [tooling decisions] -**A template making robust design the default** -**[📚 View Documentation](https://cookiecutter-robust-python.readthedocs.io/)** | **[🐛 Report a Bug](https://github.com/robust-python/cookiecutter-robust-python/issues)** | **[✨ Request a Feature](https://github.com/robust-python/cookiecutter-robust-python/issues)** + +
↑ Back to top ↑
--- -## Quick Start +## Getting Started[![](./docs/_static/pin.svg)](#getting-started) ### Prerequisites -The only requirement is [uv]. +The only requirement is installing [uv]. + +Besides that, it may be useful to install the following to avoid `uvx` installing dependencies at unexpected times: +```terminaloutput +uv tool install nox +uv tool install cruft +uv tool install ruff +uv tool install basedpyright +uv tool install maturin +``` -### Create Your Project +### Usage Navigate to where you want to create your project and run: ```bash -uvx cruft create https://github.com/robust-python/cookiecutter-robust-python.git +uvx cruft create https://github.com/robust-python/cookiecutter-robust-python ``` This will prompt you for a few inputs to customize your project: @@ -52,34 +115,21 @@ After generating your project, set it up for development: ```bash cd my-awesome-project -# Set up virtual environment and install dependencies uvx nox -s setup-venv - -# Initialize git repository with main/develop branches uvx nox -s setup-git - -# Set up remote repository (requires empty remote repo to exist) +gh repo create my-awesome-project uvx nox -s setup-remote ``` -**Quick setup:** Run `uvx nox -t env` to execute all environment setup tasks at once. - +> ⚠️ Scripts and nox sessions prefixed with "setup-" are usually not idempotent, although some will try to warn you if misused. -## Most Notable Features -- Modern tooling with [uv], [ruff], [cruft], etc. -- Built for supporting most OS's (windows, linux, macos) and all currently supported [python] versions -- Platform agnostic CI/CD ([github], [gitlab], [bitbucket]) -- CI/CD that parities local [nox] sessions for all [python] -- [maturin] support that can be added at any time during the project's lifecycle -- Designed to be a maintainable template over time through the use of automated demos and integration tests -- Rich documentation explaining tooling decisions and rationale +From there all that is left is setting up various integrations like Pypi publishing and Readthedocs as desired. -For a general overview of where we are at with this template, please see the [roadmap](#roadmap) section. +
↑ Back to top ↑
-## Example Output -For an example of this template's output, please visit the [demo](https://github.com/robust-python/robust-python-demo) which is kept up to date with the current state of this template. +--- -## Roadmap +## Roadmap[![](./docs/_static/pin.svg)](#roadmap) This is a really brief/condensed idea of what is planned for this template, and where it stands currently:
@@ -95,18 +145,29 @@ This is a really brief/condensed idea of what is planned for this template, and - [ ] Ensure maturin template works locally - [ ] Add modified CI/CD for the maturin version - [ ] Add CI/CD for the cookiecutter itself -- [ ] Add github actions to automate demo publishing on merge to main or develop in cookiecutter -- [ ] Better define out templates for issues, pull requests, etc. +- [x] Add github actions to automate demo publishing on merge to main or develop in cookiecutter +- [x] Better define out templates for issues, pull requests, etc. - [ ] Improve generated changelogs - [ ] Clean up documentation and make it readable - [ ] Possibly swap documentation to follow MADR (Maybe during clean up process, but low priority for the time being) -- [ ] Move to an organization (Will be done whenever there are other users besides myself) +- [x] Move to an organization (Will be done whenever there are other users besides myself) - [ ] Add any missing automation for administrative tasks - [ ] Designate backup plans for the projects lifecycle over time
+### Current Status -# Why does this project exist? +| vendor | Demo Statuses | +|-------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| [github] | [![Python demo status][robust-python-demo-status-badge]][robust-python-demo-status-page][![Maturin demo status][robust-maturin-demo-status-badge]][robust-maturin-demo-status-page] | +| [gitlab] | [![Python demo status][robust-gitlab-python-demo-status-badge]][robust-gitlab-python-demo-status-page][![Maturin demo status][robust-gitlab-maturin-demo-status-badge]][robust-gitlab-maturin-demo-status-page] | +| [bitbucket] | [![Python demo status][robust-bitbucket-python-demo-status-badge]][robust-bitbucket-python-demo-status-page][![Maturin demo status][robust-bitbucket-maturin-demo-status-badge]][robust-bitbucket-maturin-demo-status-page] | + +
↑ Back to top ↑
+ +--- + +## Why does this project exist?[![](./docs/_static/pin.svg)](#why-does-this-project-exist) Unfortunately, the [Hypermodern Python Cookiecutter] is no longer maintained nor modern. While it will always have a place in my heart, there have been far too many improvements in Python tooling to keep using it as is. @@ -117,86 +178,22 @@ to new tooling such as [ruff], [uv], [maturin], etc., I found the process of upd The [Hypermodern Python Cookiecutter] remains as a fantastic sendoff point for devs interested in building a 2021-style Python Package. However, there were a handful of issues with it that prevented it from being able to adapt to new Python developments over the years. -# Okay, so what's different this time? - -The [Robust Python Cookiecutter] exists to solve a few main concerns +The goal is for [cookiecutter-robust-python] to fill the gap that exists for a best practices template that is structured to be adaptable from the start. -- [Template Update Propagation](#template-update-propagation) -- [Project Domain Expansion](#project-domain-expansion) -- [Documenting Tooling Decisions](#documenting-tooling-decisions) -- [CI/CD Vendor Lock](#cicd-vendor-lock) -- [Project Neglect](#project-neglect) +
↑ Back to top ↑
-## Template Update Propagation - -One of the main issues I encountered with [my personal fork] of the [Hypermodern Python Cookiecutter] was that any change -I made to my repos would mean a later conflict if I tried to rerun [cookiecutter] to sync a change from a different project. - -Thankfully, [cruft] exists specifically to help with this issue. It enables us to periodically create PR's to add in any fixes -the [Robust Python Cookiecutter] may have added. - -Additionally, extra care is put in to use tooling specific config files whenever possible to help reduce merge conflicts occurring -in the pyproject.toml. - -## Project Domain Expansion - -Now, I'm not one to advocate for mixing languages in a project. However, there is a unique case that has arisen with the creation of [maturin]. - -There are a plethora of great projects such as [ruff], [uv], [polars], [just], etc. all making use of [maturin] to get the performance improvements of [rust] while -submitting their package to both pypi and crates.io - -Now, this definitely is not required by any means to make a good Python package, however this pattern only seems to be picking up momentum and has honestly been a massive boon -to Python's ecosystem overall. - -That being said, it's generally good practice to avoid the complexity of this dual language system unless you actually need the performance bump for your use case. However knowing ahead of time if performance -will be an issue is rather tricky, and a much easier route is to just prepare as though you _might_ swap to it some day. - -The [Robust Python Cookiecutter] includes an `add_rust_extension` flag that not only toggles [maturin] vs a traditional Python package, -but that can be used in combination with [cruft] to swap to [maturin] at any time with just about no risk to CI/CD / etc. - -Additionally, the [Robust Python Cookiecutter] is designed with both normal and [monorepos] in mind. So whether you need to just add -a quick [rust] module for performance or you are trying to publish a series of crates and packages, either case will be handled using a setup inspired by [polars]. - -## Documenting Tooling Decisions - -One of the really stand out features of the [Hypermodern Python Cookiecutter] was its incredibly detailed documentation. -It did a pretty great job of describing the tooling to use, but there was a distinct lack of **_why_** these decisions were made. - -It may seem like a small detail, but detailing why a decision was made has an incredibly important effect on the maintainablity of the template. - -#### **It allows maintainers to check if a decision should change in one click.** - -Rather than having to go through a mini crusade to determine whether we use [poetry] or [uv], we can just point to the -[existing reasoning](https://cookiecutter-robust-python.readthedocs.io/en/latest/topics/02_dependency_management.md#option-2--term--poetry) to see if it still is true or not. - -Overall, it's rather rare that people debate over tooling for no reason. Most things have merit in some cases, and a large goal of this template is identifying the tools that have the most merit in almost all cases. - -## CI/CD Vendor Lock - -Now don't get me wrong, I love [github-actions] and do pretty much everything in my power to avoid [bitbucket-pipelines]. -However, not all jobs have the luxury of GitHub, and I would love to be able to just use the same template for both my personal and professional projects. - -The [Robust Python Cookiecutter] focuses on being as modular as possible for areas that connect to the CI/CD pipeline. Additionally, there will always be either alternative -CI/CD options or at a minimum basic examples of what the translated CI/CD pipeline would look like. - -Finally, the main reason that this task is even possible is that the [Robust Python Cookiecutter] mirrors all of the CI/CD steps in it's local dev tooling. -The local [noxfile] is designed to match up directly with the CI/CD each step of the way. - -The [Hypermodern Python Cookiecutter] did this where it could afford to also, however the lack of [uv] meant it would significantly increase CI/CD times if done everywhere. -Thankfully now we can spin up a venv with a tiny fraction of the overhead that used to exist. - -## Project Neglect +--- -This is most certainly not a knock against claudio. The work they did on [cookiecutter-hypermodern-python] laid the way for countless other devs to start -implementing best practices in their python packages. +## Contributing[![](./docs/_static/pin.svg)](#contributing) -However, Open Source work is draining, and is especially so for a project template including metacode. +For more information on contributing to the [Robust Python Cookiecutter], please visit the [contributing] docs. -I can guarantee that if the [Robust Python Cookiecutter] ever sees any number of users, I will immediately transfer it to an organization to enable at least a handful -of trusted individuals to ensure the project is taken care of. +[basedpyright]: https://github.com/DetachHead/basedpyright [bitbucket]: https://bitbucket.org [bitbucket-pipelines]: https://support.atlassian.com/bitbucket-cloud/docs/write-a-pipe-for-bitbucket-pipelines/ +[commitizen]: https://commitizen-tools.github.io/commitizen/ +[contributing]: CONTRIBUTING.md [cookiecutter]: https://cookiecutter.readthedocs.io/en/stable/ [cookiecutter-hypermodern-python]: https://github.com/cjolowicz/cookiecutter-hypermodern-python [cookiecutter-robust-python]: https://github.com/robust-python/cookiecutter-robust-python @@ -211,12 +208,26 @@ of trusted individuals to ensure the project is taken care of. [my personal fork]: https://github.com/56kyle/cookiecutter-hypermodern-python [nox]: https://nox.thea.codes/ [noxfile]: https://github.com/robust-python/cookiecutter-robust-python/blob/main/%7B%7Bcookiecutter.project_name%7D%7D/noxfile.py +[pip-audit]: https://github.com/pypa/pip-audit [poetry]: https://python-poetry.org/docs/ [polars]: https://github.com/pola-rs/polars [python]: https://www.python.org/ +[robust-bitbucket-maturin-demo-status-badge]: https://img.shields.io/bitbucket/pipelines/robust-python/robust-maturin-demo/main?style=flat-square +[robust-bitbucket-maturin-demo-status-page]: https://bitbucket.org/robust-python/robust-maturin-demo/src +[robust-bitbucket-python-demo-status-badge]: https://img.shields.io/bitbucket/pipelines/robust-python/robust-python-demo/main?style=flat-square +[robust-bitbucket-python-demo-status-page]: https://bitbucket.org/robust-python/robust-python-demo/src [robust python cookiecutter]: https://github.com/robust-python/cookiecutter-robust-python +[robust-gitlab-python-demo-status-badge]: https://img.shields.io/gitlab/pipeline-status/robust-python%2Frobust-python-demo?branch=main&style=flat-square +[robust-gitlab-python-demo-status-page]: https://gitlab.com/robust-python/robust-python-demo +[robust-gitlab-maturin-demo-status-badge]: https://img.shields.io/gitlab/pipeline-status/robust-python%2Frobust-maturin-demo?branch=main&style=flat-square +[robust-gitlab-maturin-demo-status-page]: https://gitlab.com/robust-python/robust-maturin-demo +[robust-maturin-demo-status-badge]: https://img.shields.io/github/actions/workflow/status/robust-python/robust-maturin-demo/release-python.yml?branch=main&style=flat-square&label=robust-maturin-demo +[robust-maturin-demo-status-page]: https://github.com/robust-python/robust-maturin-demo +[robust-python-demo-status-badge]: https://img.shields.io/github/actions/workflow/status/robust-python/robust-python-demo/release-python.yml?branch=main&style=flat-square&label=robust-python-demo +[robust-python-demo-status-page]: https://gitlab.com/robust-python/robust-python-demo [ruff]: https://docs.astral.sh/ruff/ [rust]: https://www.rust-lang.org/learn [rye]: https://rye.astral.sh/ +[tooling decisions]: https://cookiecutter-robust-python.readthedocs.io/en/latest/our-chosen-toolchain.html [install uv]: https://docs.astral.sh/uv/getting-started/installation/ [uv]: https://docs.astral.sh/uv/ diff --git a/docs/_static/pin.svg b/docs/_static/pin.svg new file mode 100644 index 0000000..d3ef87e --- /dev/null +++ b/docs/_static/pin.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index ada6c7a..7266d45 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "cookiecutter-robust-python" -version = "2025.12.0" +version = "2025.12.1" description = "Add your description here" readme = "README.md" requires-python = ">=3.10,<4.0" diff --git a/scripts/update-demo.py b/scripts/update-demo.py index d9a151f..397af93 100644 --- a/scripts/update-demo.py +++ b/scripts/update-demo.py @@ -50,6 +50,7 @@ def update_demo( demo_name: str = get_demo_name(add_rust_extension=add_rust_extension) demo_path: Path = demos_cache_folder / demo_name + typer.secho(f"template:\n\tcurrent_branch: {get_current_branch()}\n\tcurrent_commit: {get_current_commit()}") if branch_override is not None: typer.secho(f"Overriding current branch name for demo reference. Using '{branch_override}' instead.") desired_branch_name: str = branch_override @@ -76,6 +77,7 @@ def update_demo( typer.secho(f"Updating demo project at {demo_path=}.", fg="yellow") with work_in(demo_path): + typer.secho(f"demo:\n\tcurrent_branch: {get_current_branch()}\n\tcurrent_commit: {get_current_commit()}") if get_current_branch() != desired_branch_name: git("checkout", "-b", desired_branch_name, DEMO.develop_branch) @@ -146,8 +148,10 @@ def _create_demo_pr(demo_path: Path, branch: str, commit_start: str) -> None: """Creates a PR to merge the given branch into develop.""" gh("repo", "set-default", f"{DEMO.app_author}/{DEMO.app_name}") search_results: subprocess.CompletedProcess = gh("pr", "list", "--state", "open", "--search", branch) - if "no pull requests match your search" not in search_results.stdout: - typer.secho(f"Skipping PR creation due to existing PR found for branch {branch}") + + if search_results.returncode == 0: + url: str = _get_pr_url(branch=branch) + typer.secho(f"Skipping PR creation due to existing PR found for branch {branch} at {url}") return body: str = _get_demo_feature_pr_body(demo_path=demo_path, commit_start=commit_start) @@ -160,6 +164,16 @@ def _create_demo_pr(demo_path: Path, branch: str, commit_start: str) -> None: "--repo": f"{DEMO.app_author}/{DEMO.app_name}", } gh("pr", "create", *itertools.chain.from_iterable(pr_kwargs.items())) + url: str = _get_pr_url(branch=branch) + typer.secho(f"Created PR for branch '{branch}' at '{url}'.") + + +def _get_pr_url(branch: str) -> str: + """Returns the url of the current branch's PR.""" + result: subprocess.CompletedProcess = gh("pr", "view", branch, "--json", "url", "--jq", ".url") + if result.returncode != 0: + raise ValueError(f"Failed to find a PR URL for branch {branch}.") + return result.stdout.strip() def _get_demo_feature_pr_body(demo_path: Path, commit_start: str) -> str: diff --git a/scripts/util.py b/scripts/util.py index d09b47d..9cc862e 100644 --- a/scripts/util.py +++ b/scripts/util.py @@ -131,6 +131,7 @@ def require_clean_and_up_to_date_demo_repo(demo_path: Path) -> None: try: with work_in(demo_path): git("fetch") + git("fetch", "origin", f"{DEMO.main_branch}:{DEMO.main_branch}") git("status", "--porcelain") validate_is_synced_ancestor(ancestor=DEMO.main_branch, descendent=DEMO.develop_branch) except Exception as e: diff --git a/uv.lock b/uv.lock index aa6e894..a30bc78 100644 --- a/uv.lock +++ b/uv.lock @@ -356,7 +356,7 @@ wheels = [ [[package]] name = "cookiecutter-robust-python" -version = "2025.12.0" +version = "2025.12.1" source = { virtual = "." } dependencies = [ { name = "cookiecutter" },