Skip to content

Commit a8f36c0

Browse files
author
ulises-jeremias
committed
feat(dist): wire Homebrew notify and AUR publish flows
Implement release-tag fan-out to Create-Python-App/homebrew-tap and aur-package (PyPI sdist), document secrets, and extend distribution smoke. Closes #155. Closes #156.
1 parent 703850a commit a8f36c0

5 files changed

Lines changed: 319 additions & 53 deletions

File tree

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,51 @@
11
name: Notify Homebrew tap
2+
3+
# Triggers on release tags for the CLI package. Sends a
4+
# repository_dispatch event to Create-Python-App/homebrew-tap so its
5+
# update-formula workflow can bump the formula and push it.
26
on:
37
push:
48
tags:
59
- "create-awesome-python-app@*"
610
workflow_dispatch:
711
inputs:
812
version:
9-
description: "Package version"
13+
description: "Package version (e.g. 0.1.0)"
1014
required: true
15+
16+
permissions:
17+
contents: read
18+
1119
jobs:
1220
notify:
21+
name: Dispatch to homebrew-tap
1322
runs-on: ubuntu-latest
1423
steps:
15-
- name: Dispatch to homebrew-tap
24+
- name: Resolve version
25+
id: version
26+
env:
27+
TAG_REF: ${{ github.ref_name }}
28+
INPUT_VERSION: ${{ github.event.inputs.version }}
1629
run: |
17-
echo "Send repository_dispatch to Create-Python-App/homebrew-tap when it exists"
18-
echo "Secret: HOMEBREW_TAP_TOKEN"
30+
if [ -n "$INPUT_VERSION" ]; then
31+
VERSION="$INPUT_VERSION"
32+
else
33+
VERSION="${TAG_REF#create-awesome-python-app@}"
34+
fi
35+
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
36+
37+
- name: Dispatch repository event
38+
env:
39+
GH_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
40+
VERSION: ${{ steps.version.outputs.version }}
41+
run: |
42+
if [ -z "$GH_TOKEN" ]; then
43+
echo "::error::HOMEBREW_TAP_TOKEN secret is not set" >&2
44+
exit 1
45+
fi
46+
gh api \
47+
--method POST \
48+
-H "Accept: application/vnd.github+json" \
49+
/repos/Create-Python-App/homebrew-tap/dispatches \
50+
-f "event_type=new-release" \
51+
-f "client_payload[version]=$VERSION"

.github/workflows/publish-aur.yml

Lines changed: 77 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,91 @@
11
name: Publish to AUR
2+
3+
# Triggers on release tags for the CLI package.
4+
# Publishes the updated PKGBUILD to aur.archlinux.org and keeps the
5+
# Create-Python-App/aur-package GitHub mirror in sync.
26
on:
37
push:
48
tags:
59
- "create-awesome-python-app@*"
610
workflow_dispatch:
711
inputs:
812
version:
9-
description: "Package version"
13+
description: "Package version (e.g. 0.1.0)"
1014
required: true
15+
16+
permissions:
17+
contents: read
18+
1119
jobs:
1220
aur:
21+
name: Update AUR package
1322
runs-on: ubuntu-latest
1423
steps:
15-
- uses: actions/checkout@v4
16-
- name: Placeholder
24+
- name: Resolve version
25+
id: version
26+
env:
27+
TAG_REF: ${{ github.ref_name }}
28+
INPUT_VERSION: ${{ github.event.inputs.version }}
1729
run: |
18-
echo "AUR publish requires AUR_SSH_PRIVATE_KEY + optional Create-Python-App/aur-package mirror"
19-
echo "See docs/DISTRIBUTION_SETUP.md"
30+
if [ -n "$INPUT_VERSION" ]; then
31+
VERSION="$INPUT_VERSION"
32+
else
33+
VERSION="${TAG_REF#create-awesome-python-app@}"
34+
fi
35+
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
36+
37+
- name: Checkout aur-package mirror repo
38+
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
39+
with:
40+
repository: Create-Python-App/aur-package
41+
token: ${{ secrets.AUR_REPO_TOKEN }}
42+
path: aur-package
43+
44+
- name: Update PKGBUILD (version + sha256 from PyPI)
45+
working-directory: aur-package
46+
env:
47+
NEW_VERSION: ${{ steps.version.outputs.version }}
48+
run: |
49+
set -euo pipefail
50+
# Reset pkgver and pkgrel; source URL already interpolates ${pkgver}.
51+
sed -i "s/^pkgver=.*/pkgver=${NEW_VERSION}/" PKGBUILD
52+
sed -i "s/^pkgrel=.*/pkgrel=1/" PKGBUILD
53+
54+
META=$(curl -sfL "https://pypi.org/pypi/create-awesome-python-app/${NEW_VERSION}/json")
55+
SHA=$(echo "$META" | jq -r '.urls[] | select(.packagetype=="sdist") | .digests.sha256')
56+
if [ -z "$SHA" ] || [ "$SHA" = "null" ]; then
57+
echo "::error::Failed to resolve PyPI sdist sha256 for v${NEW_VERSION}" >&2
58+
exit 1
59+
fi
60+
sed -i "s/^sha256sums=.*/sha256sums=('${SHA}')/" PKGBUILD
61+
62+
echo "----- Updated PKGBUILD -----"
63+
cat PKGBUILD
64+
65+
- name: Publish to AUR
66+
# Pushes to aur.archlinux.org via SSH. The action reads the
67+
# updated PKGBUILD, regenerates .SRCINFO, and pushes.
68+
uses: ulises-jeremias/github-actions-aur-publish@217e4e2abbbee9ecc942bdc0681302e233656d9f # v1
69+
with:
70+
pkgname: create-awesome-python-app
71+
pkgbuild: aur-package/PKGBUILD
72+
commit_username: "Create Python App Bot"
73+
commit_email: "ulisescf.24@gmail.com"
74+
commit_message: "Update to version ${{ steps.version.outputs.version }}"
75+
ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
76+
allow_empty_commits: "false"
77+
# dsa is no longer supported in modern OpenSSH; omit it to
78+
# avoid "Unknown key type" errors during keyscan.
79+
ssh_keyscan_types: "rsa,ecdsa,ed25519"
80+
81+
- name: Sync updated PKGBUILD to GitHub mirror
82+
# Keep the aur-package GitHub mirror in sync with what's live
83+
# on AUR. Only PKGBUILD needs to be committed here — .SRCINFO
84+
# is regenerated automatically by AUR from PKGBUILD.
85+
uses: stefanzweifel/git-auto-commit-action@4a55954c782fc1ea30b9056cd3e7a2b40ca8887d # v7.2.0
86+
with:
87+
repository: aur-package
88+
commit_message: "chore: sync PKGBUILD for v${{ steps.version.outputs.version }}"
89+
commit_user_name: "Create Python App Bot"
90+
commit_user_email: "ulisescf.24@gmail.com"
91+
file_pattern: "PKGBUILD"
Lines changed: 111 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,126 @@
11
name: Distribution smoke tests
2+
3+
# Smoke-tests each published distribution channel:
4+
# uvx — PyPI via uvx
5+
# homebrew — brew install on macos-latest
6+
# aur — makepkg inside an archlinux container
7+
# versions — cross-check channel versions against PyPI
8+
29
on:
310
schedule:
411
- cron: "0 6 * * *"
512
workflow_dispatch:
13+
614
permissions:
715
contents: read
16+
17+
concurrency:
18+
group: smoke-distribution
19+
cancel-in-progress: true
20+
821
jobs:
922
uvx:
23+
name: uvx (PyPI)
1024
runs-on: ubuntu-latest
1125
steps:
1226
- uses: astral-sh/setup-uv@v6
13-
- name: Smoke uvx (when published)
27+
- name: Smoke uvx
1428
run: |
15-
if uvx create-awesome-python-app@latest --help; then
16-
echo ok
17-
else
18-
echo "Package not on PyPI yet — soft fail"
19-
exit 0
20-
fi
21-
docker:
29+
set -euo pipefail
30+
uvx create-awesome-python-app@latest --version
31+
uvx create-awesome-python-app@latest --help | head -5
32+
33+
homebrew:
34+
name: Homebrew (Create-Python-App/tap)
35+
runs-on: macos-latest
36+
steps:
37+
- name: Tap and install
38+
run: |
39+
brew tap Create-Python-App/tap
40+
brew trust create-python-app/tap || true
41+
brew install create-awesome-python-app
42+
43+
- name: Verify --version
44+
run: |
45+
VERSION=$(create-awesome-python-app --version 2>&1)
46+
echo "homebrew version: $VERSION"
47+
echo "$VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$' || {
48+
echo "::error::Unexpected version output: $VERSION"
49+
exit 1
50+
}
51+
52+
- name: Verify --help
53+
run: create-awesome-python-app --help | head -5
54+
55+
aur:
56+
name: AUR (archlinux container)
2257
runs-on: ubuntu-latest
23-
continue-on-error: true
58+
container:
59+
image: archlinux:latest
2460
steps:
25-
- run: echo "Docker smoke activates after first image publish"
61+
- name: Bootstrap Arch system and non-root builder
62+
run: |
63+
pacman -Sy --noconfirm --needed \
64+
python python-pip python-build python-installer python-wheel \
65+
base-devel sudo git curl ca-certificates
66+
useradd -m -G wheel builder
67+
echo '%wheel ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers
68+
69+
- name: Clone AUR package and build
70+
run: |
71+
su builder -c "
72+
set -euo pipefail
73+
# Prefer live AUR; fall back to GitHub mirror during bootstrap.
74+
if git clone https://aur.archlinux.org/create-awesome-python-app.git /tmp/cpa 2>/dev/null; then
75+
cd /tmp/cpa
76+
else
77+
git clone https://github.com/Create-Python-App/aur-package.git /tmp/cpa
78+
cd /tmp/cpa
79+
fi
80+
makepkg -si --noconfirm
81+
"
82+
83+
- name: Verify --version
84+
run: |
85+
su builder -c "
86+
VERSION=\$(create-awesome-python-app --version 2>&1)
87+
echo \"aur version: \$VERSION\"
88+
echo \"\$VERSION\" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+\$' || exit 1
89+
"
90+
91+
- name: Verify --help
92+
run: su builder -c "create-awesome-python-app --help | head -5"
93+
94+
versions:
95+
name: Cross-check published versions
96+
runs-on: ubuntu-latest
97+
if: always()
98+
steps:
99+
- uses: astral-sh/setup-uv@v6
100+
- name: Gather versions from each channel
101+
run: |
102+
set -euo pipefail
103+
104+
PYPI=$(curl -sfL https://pypi.org/pypi/create-awesome-python-app/json | \
105+
python3 -c "import json,sys; print(json.load(sys.stdin)['info']['version'])")
106+
107+
HOMEBREW=$(curl -sfL \
108+
https://raw.githubusercontent.com/Create-Python-App/homebrew-tap/main/Formula/create-awesome-python-app.rb | \
109+
grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1 || echo "unavailable")
110+
111+
AUR=$(curl -sfL \
112+
"https://aur.archlinux.org/rpc/v5/info?arg=create-awesome-python-app" | \
113+
python3 -c "import json,sys; d=json.load(sys.stdin); r=d.get('results') or []; print(r[0]['Version'].split('-')[0] if r else 'unavailable')" \
114+
|| echo "unavailable")
115+
116+
echo "Channel versions:"
117+
echo " pypi: $PYPI"
118+
echo " homebrew: $HOMEBREW"
119+
echo " aur: $AUR"
120+
121+
if [ "$HOMEBREW" != "unavailable" ] && [ "$HOMEBREW" != "$PYPI" ]; then
122+
echo "::warning::Version mismatch: pypi=$PYPI homebrew=$HOMEBREW"
123+
fi
124+
if [ "$AUR" != "unavailable" ] && [ "$AUR" != "$PYPI" ]; then
125+
echo "::warning::Version mismatch: pypi=$PYPI aur=$AUR (AUR may lag)"
126+
fi

README.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44
[![Lint](https://github.com/Create-Python-App/create-python-app/actions/workflows/lint.yml/badge.svg)](https://github.com/Create-Python-App/create-python-app/actions/workflows/lint.yml)
55
[![Typecheck](https://github.com/Create-Python-App/create-python-app/actions/workflows/type-check.yml/badge.svg)](https://github.com/Create-Python-App/create-python-app/actions/workflows/type-check.yml)
66
[![PyPI](https://img.shields.io/pypi/v/create-awesome-python-app.svg)](https://pypi.org/project/create-awesome-python-app/)
7+
[![AUR](https://img.shields.io/aur/version/create-awesome-python-app?label=AUR&logo=archlinux)](https://aur.archlinux.org/packages/create-awesome-python-app)
8+
[![Homebrew](https://img.shields.io/badge/homebrew-Create--Python--App%2Ftap-orange?logo=homebrew)](https://github.com/Create-Python-App/homebrew-tap)
79
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)
810

9-
<!-- PyPI / coverage badges activate after first publish -->
10-
1111
Composable scaffolding CLI for production-ready Python apps.
1212

1313
> **Status:** CLI monorepo bootstrapped. Template bank: [`cpa-templates`](https://github.com/Create-Python-App/cpa-templates). Roadmap: [#1](https://github.com/Create-Python-App/create-python-app/issues/1).
@@ -18,6 +18,8 @@ Composable scaffolding CLI for production-ready Python apps.
1818
|------------|------|
1919
| [create-python-app](https://github.com/Create-Python-App/create-python-app) (this repo) | CLI (`create-awesome-python-app`) and scaffolding engine (`create-python-app-core`) |
2020
| [cpa-templates](https://github.com/Create-Python-App/cpa-templates) | Official templates and extensions (`templates.json` catalog) |
21+
| [homebrew-tap](https://github.com/Create-Python-App/homebrew-tap) | Homebrew formula |
22+
| [aur-package](https://github.com/Create-Python-App/aur-package) | AUR PKGBUILD mirror |
2123

2224
The CLI fetches the catalog from:
2325

@@ -28,7 +30,15 @@ Override with `CPA_CATALOG_URL` for forks or local testing (`file://` supported)
2830
## Install
2931

3032
```bash
33+
# PyPI / uv
3134
uvx create-awesome-python-app@latest my-app
35+
36+
# Homebrew
37+
brew tap Create-Python-App/tap
38+
brew install create-awesome-python-app
39+
40+
# AUR
41+
yay -S create-awesome-python-app
3242
```
3343

3444
Or pin a version:

0 commit comments

Comments
 (0)