Skip to content

Commit 36ca1c8

Browse files
ci: add pre-release workflow for per-PR dev builds
Add a GitHub Actions workflow that builds and publishes pre-release packages to Cloudsmith for manual testing on a per-PR basis. Trigger by either: - Adding the 'pre-release' label to a PR - Commenting '/pre-release' on a PR (collaborators only) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 2a47c30 commit 36ca1c8

File tree

1 file changed

+150
-0
lines changed

1 file changed

+150
-0
lines changed

.github/workflows/pre-release.yml

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
# Pre-release workflow: Build and publish dev packages to Cloudsmith for manual testing.
2+
#
3+
# Trigger by either:
4+
# 1. Adding the 'pre-release' label to a PR
5+
# 2. Commenting '/pre-release' on a PR (must be repo collaborator)
6+
#
7+
# The pre-release version is {base}.dev{pr_number}{epoch} (e.g. 1.13.0.dev421741712838).
8+
# Each re-trigger produces a unique version so previous pre-releases are preserved.
9+
10+
name: Pre-release
11+
12+
on:
13+
pull_request:
14+
types: [labeled]
15+
issue_comment:
16+
types: [created]
17+
18+
concurrency:
19+
group: pre-release-${{ github.event.pull_request.number || github.event.issue.number }}
20+
cancel-in-progress: true
21+
22+
jobs:
23+
pre-release:
24+
name: Build and publish pre-release
25+
# Trigger on 'pre-release' label OR '/pre-release' comment from a collaborator
26+
if: >-
27+
(github.event_name == 'pull_request' &&
28+
github.event.label.name == 'pre-release') ||
29+
(github.event_name == 'issue_comment' &&
30+
github.event.issue.pull_request &&
31+
startsWith(github.event.comment.body, '/pre-release') &&
32+
contains(fromJson('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association))
33+
runs-on: ubuntu-latest
34+
permissions:
35+
id-token: write
36+
contents: read
37+
issues: write
38+
pull-requests: write
39+
env:
40+
CLOUDSMITH_NAMESPACE: ${{ vars.CLOUDSMITH_NAMESPACE }}
41+
CLOUDSMITH_SVC_SLUG: ${{ vars.CLOUDSMITH_SVC_SLUG }}
42+
steps:
43+
- name: React to slash command
44+
if: github.event_name == 'issue_comment'
45+
env:
46+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
47+
COMMENT_ID: ${{ github.event.comment.id }}
48+
REPO: ${{ github.repository }}
49+
run: |
50+
gh api "repos/${REPO}/issues/comments/${COMMENT_ID}/reactions" \
51+
-f content=eyes --silent
52+
53+
- name: Resolve PR details
54+
id: pr
55+
env:
56+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
57+
EVENT_NAME: ${{ github.event_name }}
58+
ISSUE_NUMBER: ${{ github.event.issue.number }}
59+
PR_NUMBER_LABEL: ${{ github.event.pull_request.number }}
60+
REPO: ${{ github.repository }}
61+
run: |
62+
if [ "${EVENT_NAME}" = "issue_comment" ]; then
63+
PR_NUMBER="${ISSUE_NUMBER}"
64+
else
65+
PR_NUMBER="${PR_NUMBER_LABEL}"
66+
fi
67+
echo "number=${PR_NUMBER}" >> "${GITHUB_OUTPUT}"
68+
69+
PR_JSON=$(gh api "repos/${REPO}/pulls/${PR_NUMBER}")
70+
echo "sha=$(echo "${PR_JSON}" | jq -r .head.sha)" >> "${GITHUB_OUTPUT}"
71+
72+
# Block builds from forked PRs (the fork code would run with repo secrets)
73+
IS_FORK=$(echo "${PR_JSON}" | jq -r '.head.repo.fork // false')
74+
if [ "${IS_FORK}" = "true" ]; then
75+
echo "::error::Pre-release builds are not supported for PRs from forks"
76+
exit 1
77+
fi
78+
79+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
80+
with:
81+
ref: ${{ steps.pr.outputs.sha }}
82+
persist-credentials: false
83+
84+
- name: Set up Python 3.10
85+
uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # 6.1.0
86+
with:
87+
python-version: "3.10"
88+
89+
- name: Set pre-release version
90+
id: version
91+
env:
92+
PR_NUMBER: ${{ steps.pr.outputs.number }}
93+
run: |
94+
BASE_VERSION=$(cat VERSION)
95+
EPOCH=$(date +%s)
96+
PRE_VERSION="${BASE_VERSION}.dev${PR_NUMBER}${EPOCH}"
97+
echo "${PRE_VERSION}" > VERSION
98+
echo "${PRE_VERSION}" > cloudsmith_cli/data/VERSION
99+
echo "version=${PRE_VERSION}" >> "${GITHUB_OUTPUT}"
100+
101+
- name: Install build dependencies
102+
run: |
103+
python -m pip install --upgrade pip
104+
pip install setuptools wheel
105+
106+
- name: Build packages
107+
run: python setup.py sdist bdist_wheel
108+
109+
- name: Install and authenticate Cloudsmith CLI
110+
uses: cloudsmith-io/cloudsmith-cli-action@76c8ff51a34bea1036d9b7708f10a929624a1910 # v2.0.1
111+
with:
112+
oidc-namespace: ${{ vars.CLOUDSMITH_NAMESPACE }}
113+
oidc-service-slug: ${{ vars.CLOUDSMITH_SVC_SLUG }}
114+
115+
- name: Publish to Cloudsmith
116+
env:
117+
PKG_REPO: ${{ vars.CLOUDSMITH_NAMESPACE }}/cli
118+
run: |
119+
cloudsmith push python "${PKG_REPO}" dist/*.tar.gz
120+
cloudsmith push python "${PKG_REPO}" dist/*.whl
121+
122+
- name: Comment on PR with install instructions
123+
env:
124+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
125+
VERSION: ${{ steps.version.outputs.version }}
126+
PR_NUMBER: ${{ steps.pr.outputs.number }}
127+
HEAD_SHA: ${{ steps.pr.outputs.sha }}
128+
REPO: ${{ github.repository }}
129+
CS_NS: ${{ vars.CLOUDSMITH_NAMESPACE }}
130+
run: |
131+
cat > /tmp/comment.md << COMMENT
132+
🚀 **Pre-release \`${VERSION}\` published to Cloudsmith!**
133+
134+
Install with:
135+
\`\`\`
136+
pip install --extra-index-url https://dl.cloudsmith.io/public/${CS_NS}/cli/python/simple/ cloudsmith-cli==${VERSION}
137+
\`\`\`
138+
139+
_Built from ${HEAD_SHA}_
140+
COMMENT
141+
gh pr comment "${PR_NUMBER}" --repo "${REPO}" --body-file /tmp/comment.md
142+
143+
- name: Remove pre-release label
144+
if: github.event_name == 'pull_request'
145+
env:
146+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
147+
PR_NUMBER: ${{ steps.pr.outputs.number }}
148+
REPO: ${{ github.repository }}
149+
run: |
150+
gh pr edit "${PR_NUMBER}" --repo "${REPO}" --remove-label pre-release || true

0 commit comments

Comments
 (0)