Skip to content

Commit 4c1cea7

Browse files
committed
Add gitignore and action
1 parent 896bcba commit 4c1cea7

3 files changed

Lines changed: 218 additions & 0 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.claude/

README.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,52 @@
11
# plugin-release
2+
23
GitHub Action for automatically bump FastAPI Best Architecture plugin version after a release.
4+
5+
When a plugin repository pushes a new tag, this Action automatically creates a pull request
6+
to update the corresponding submodule in [fastapi-practices/plugins](https://github.com/fastapi-practices/plugins).
7+
8+
## Usage
9+
10+
Add the following workflow file to your plugin repository (e.g. `.github/workflows/release.yml`):
11+
12+
```yaml
13+
name: Plugin Release
14+
15+
on:
16+
push:
17+
tags:
18+
- "v*"
19+
20+
jobs:
21+
update-submodule:
22+
runs-on: ubuntu-latest
23+
steps:
24+
- name: Update plugin submodule
25+
uses: fastapi-practices/plugin-release@v1
26+
with:
27+
push-to: your-username/plugins
28+
```
29+
30+
## Inputs
31+
32+
| Input | Required | Default | Description |
33+
| ------------- | -------- | ----------------------------- | ---------------------------------------------------------------------------------------- |
34+
| `push-to` | Yes | — | The repository to push the update branch to (`owner/repo`), e.g. `your-username/plugins` |
35+
| `plugin-name` | No | Repository name of the caller | Plugin name, must match the submodule directory name in `fastapi-practices/plugins` |
36+
37+
## How it works
38+
39+
1. Validates that the version in `plugin.toml` matches the pushed tag
40+
2. Checks out the push-to repository with all submodules
41+
3. Syncs with the upstream `fastapi-practices/plugins` repository
42+
4. Validates that the specified plugin submodule exists
43+
5. Creates a new branch in the push-to repository
44+
6. Updates the submodule to the latest commit via `git submodule update --remote`
45+
7. Commits and pushes the changes
46+
8. Opens a pull request against the upstream plugins repository
47+
48+
If the submodule is already up to date, no PR is created.
49+
50+
## License
51+
52+
[MIT](./LICENSE)

action.yml

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
name: FBA Plugin Release
2+
description: Automatically update FastAPI Best Architecture plugin version after a release
3+
author: fastapi-practices
4+
5+
branding:
6+
icon: package
7+
color: gray-dark
8+
9+
inputs:
10+
plugin-name:
11+
description: >
12+
The name of the plugin, must match the submodule directory name in fastapi-practices/plugins.
13+
Defaults to the repository name of the caller.
14+
required: false
15+
default: ${{ github.event.repository.name }}
16+
push-to:
17+
description: >
18+
The repository to push the update branch to (owner/repo).
19+
e.g. "your-username/plugins"
20+
required: true
21+
22+
runs:
23+
using: composite
24+
steps:
25+
- name: Checkout plugin repository
26+
uses: actions/checkout@v4
27+
with:
28+
path: _plugin
29+
30+
- name: Validate plugin version
31+
shell: bash
32+
run: |
33+
TOML="_plugin/plugin.toml"
34+
if [ ! -f "${TOML}" ]; then
35+
echo "::error::plugin.toml not found in the plugin repository"
36+
exit 1
37+
fi
38+
TOML_VERSION=$(awk -F'=' '/^\[plugin\]/{found=1} found && /^version/{gsub(/[ \t"'"'"']/, "", $2); print $2; exit}' "${TOML}")
39+
if [ -z "${TOML_VERSION}" ]; then
40+
echo "::error::version field not found in plugin.toml"
41+
exit 1
42+
fi
43+
RELEASE_VERSION="${{ github.ref_name }}"
44+
if [ "${TOML_VERSION}" != "${RELEASE_VERSION}" ]; then
45+
echo "::error::Version mismatch: plugin.toml has '${TOML_VERSION}' but release tag is '${RELEASE_VERSION}'"
46+
exit 1
47+
fi
48+
echo "Version '${RELEASE_VERSION}' matches plugin.toml"
49+
50+
- name: Checkout push-to repository
51+
uses: actions/checkout@v4
52+
with:
53+
repository: ${{ inputs.push-to }}
54+
token: ${{ github.token }}
55+
submodules: true
56+
fetch-depth: 0
57+
58+
- name: Sync fork with upstream
59+
shell: bash
60+
run: |
61+
git remote add upstream https://github.com/fastapi-practices/plugins.git
62+
git fetch upstream
63+
UPSTREAM_BRANCH=$(git remote show upstream | awk '/HEAD branch/ {print $NF}')
64+
echo "UPSTREAM_BRANCH=${UPSTREAM_BRANCH}" >> "$GITHUB_ENV"
65+
git checkout "${UPSTREAM_BRANCH}"
66+
git merge "upstream/${UPSTREAM_BRANCH}" --ff-only
67+
68+
- name: Validate plugin exists
69+
shell: bash
70+
run: |
71+
PLUGIN_PATH="plugins/${{ inputs.plugin-name }}"
72+
if [ ! -f ".gitmodules" ]; then
73+
echo "::error::No .gitmodules file found in the plugins repository"
74+
exit 1
75+
fi
76+
if ! grep -q "path = ${PLUGIN_PATH}" .gitmodules; then
77+
echo "::error::Plugin '${PLUGIN_PATH}' not found in .gitmodules"
78+
exit 1
79+
fi
80+
echo "Plugin '${PLUGIN_PATH}' found in .gitmodules"
81+
82+
- name: Configure git
83+
shell: bash
84+
run: |
85+
git config user.name "github-actions[bot]"
86+
git config user.email "github-actions[bot]@users.noreply.github.com"
87+
88+
- name: Create update branch
89+
shell: bash
90+
id: create-branch
91+
run: |
92+
BRANCH_NAME="update-plugin/${{ inputs.plugin-name }}-${{ github.ref_name }}"
93+
echo "branch-name=${BRANCH_NAME}" >> "$GITHUB_OUTPUT"
94+
git checkout -b "${BRANCH_NAME}"
95+
96+
- name: Update submodule
97+
shell: bash
98+
run: |
99+
git submodule update --remote "plugins/${{ inputs.plugin-name }}"
100+
git add "plugins/${{ inputs.plugin-name }}"
101+
102+
- name: Check for changes
103+
shell: bash
104+
id: check-changes
105+
run: |
106+
if git diff --cached --quiet; then
107+
echo "has-changes=false" >> "$GITHUB_OUTPUT"
108+
echo "::notice::Submodule 'plugins/${{ inputs.plugin-name }}' is already up to date. Skipping PR creation."
109+
else
110+
echo "has-changes=true" >> "$GITHUB_OUTPUT"
111+
NEW_SHA=$(git diff --cached --submodule=short | grep "^+Subproject" | awk '{print $3}')
112+
OLD_SHA=$(git diff --cached --submodule=short | grep "^-Subproject" | awk '{print $3}')
113+
echo "new-sha=${NEW_SHA}" >> "$GITHUB_OUTPUT"
114+
echo "old-sha=${OLD_SHA}" >> "$GITHUB_OUTPUT"
115+
echo "Updated from ${OLD_SHA} to ${NEW_SHA}"
116+
fi
117+
118+
- name: Commit changes
119+
shell: bash
120+
if: steps.check-changes.outputs.has-changes == 'true'
121+
run: |
122+
git commit -m "Update ${{ inputs.plugin-name }} plugin to ${{ github.ref_name }}"
123+
124+
- name: Push branch
125+
shell: bash
126+
if: steps.check-changes.outputs.has-changes == 'true'
127+
run: |
128+
git push origin "${{ steps.create-branch.outputs.branch-name }}"
129+
130+
- name: Create pull request
131+
shell: bash
132+
if: steps.check-changes.outputs.has-changes == 'true'
133+
id: create-pr
134+
run: |
135+
FORK_OWNER=$(echo "${{ inputs.push-to }}" | cut -d'/' -f1)
136+
137+
PR_URL=$(gh pr create \
138+
--repo fastapi-practices/plugins \
139+
--base "${UPSTREAM_BRANCH}" \
140+
--head "${FORK_OWNER}:${{ steps.create-branch.outputs.branch-name }}" \
141+
--title "Update ${{ inputs.plugin-name }} plugin to ${{ github.ref_name }}" \
142+
--body "$(cat <<'EOF'
143+
## Summary
144+
145+
Automated submodule update for plugin **${{ inputs.plugin-name }}** to `${{ github.ref_name }}`.
146+
147+
| Field | Value |
148+
|-------|-------|
149+
| Plugin | `${{ inputs.plugin-name }}` |
150+
| Triggered by | ${{ github.repository }}@${{ github.ref_name }} |
151+
| Workflow run | ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} |
152+
153+
## Changes
154+
155+
This PR updates the `plugins/${{ inputs.plugin-name }}` submodule to `${{ github.ref_name }}`.
156+
157+
---
158+
*This PR was automatically created by [plugin-release](https://github.com/fastapi-practices/plugin-release) action.*
159+
EOF
160+
)")
161+
162+
echo "pr-url=${PR_URL}" >> "$GITHUB_OUTPUT"
163+
PR_NUMBER=$(echo "${PR_URL}" | grep -oE '[0-9]+$')
164+
echo "pr-number=${PR_NUMBER}" >> "$GITHUB_OUTPUT"
165+
echo "::notice::Pull request created: ${PR_URL}"
166+
env:
167+
GH_TOKEN: ${{ github.token }}

0 commit comments

Comments
 (0)