1
- name : Release
1
+ name : Python Automatic Release
2
2
3
3
on :
4
- schedule :
5
- # Run every day at 9:00 UTC
6
- - cron : ' 0 9 * * *'
7
- # Allow manual trigger for testing
8
4
workflow_dispatch :
9
5
10
6
jobs :
11
- prepare :
7
+ detect-last-release :
12
8
runs-on : ubuntu-latest
13
9
outputs :
14
- matrix : ${{ steps.set-matrix.outputs.matrix }}
15
10
last_release : ${{ steps.last-release.outputs.hash }}
16
11
steps :
17
12
- uses : actions/checkout@v4
18
13
with :
19
14
fetch-depth : 0
20
15
21
- - name : Find package directories
22
- id : set-matrix
23
- run : |
24
- # Find all package.json and pyproject.toml files, excluding root
25
- DIRS=$(git ls-tree -r HEAD --name-only | grep -E "package.json|pyproject.toml" | xargs dirname | grep -v "^.$" | jq -R -s -c 'split("\n")[:-1]')
26
- echo "matrix=${DIRS}" >> $GITHUB_OUTPUT
27
- echo "Found directories: ${DIRS}"
28
-
29
16
- name : Get last release hash
30
17
id : last-release
31
18
run : |
32
19
HASH=$(git rev-list --tags --max-count=1 || echo "HEAD~1")
33
20
echo "hash=${HASH}" >> $GITHUB_OUTPUT
34
21
echo "Using last release hash: ${HASH}"
35
22
36
- release :
37
- needs : prepare
23
+ create-tag-name :
38
24
runs-on : ubuntu-latest
39
- environment : release
40
- strategy :
41
- matrix :
42
- directory : ${{ fromJson(needs.prepare.outputs.matrix) }}
43
- fail-fast : false
44
- permissions :
45
- contents : write
46
- packages : write
25
+ outputs :
26
+ tag_name : ${{ steps.last-release.outputs.tag}}
27
+ steps :
28
+ - name : Get last release hash
29
+ id : last-release
30
+ run : |
31
+ DATE=$(date +%Y.%m.%d)
32
+ echo "tag=v${DATE}" >> $GITHUB_OUTPUT
33
+ echo "Using tag: v${DATE}"
47
34
35
+ detect-packages :
36
+ runs-on : ubuntu-latest
37
+ outputs :
38
+ packages : ${{ steps.find-packages.outputs.packages }}
48
39
steps :
49
40
- uses : actions/checkout@v4
50
- with :
51
- fetch-depth : 0
52
41
53
- - uses : astral-sh/setup-uv@v5
42
+ - name : Find packages
43
+ id : find-packages
44
+ working-directory : src
45
+ run : |
46
+ # Find all package.json and pyproject.toml files, excluding root
47
+ PACKAGES=$(find . -name "package.json" -o -name "pyproject.toml" -exec dirname {} \; | sed 's/^\.\///' | jq -R -s -c 'split("\n")[:-1]')
48
+ echo "packages=$PACKAGES" >> $GITHUB_OUTPUT
54
49
55
- - name : Setup Node.js
56
- if : endsWith(matrix.directory, '/package.json')
57
- uses : actions/setup-node@v4
50
+ detect-updates :
51
+ needs : [detect-packages, detect-last-release]
52
+ strategy :
53
+ matrix :
54
+ package : ${{ fromJson(needs.detect-packages.outputs.packages) }}
55
+ name : Build ${{ matrix.package }}
56
+ runs-on : ubuntu-latest
57
+ steps :
58
+ - uses : actions/checkout@v4
58
59
with :
59
- node-version : ' 18'
60
- registry-url : ' https://registry.npmjs.org'
61
-
62
- - name : Setup Python
63
- if : endsWith(matrix.directory, '/pyproject.toml')
64
- run : uv python install
60
+ fetch-depth : 0
65
61
66
- - name : Release package
67
- id : release
68
- env :
69
- NODE_AUTH_TOKEN : ${{ secrets.NPM_TOKEN }}
70
- UV_PUBLISH_TOKEN : ${{ secrets.PYPI_TOKEN }}
62
+ - name : Check updates
71
63
run : |
72
- # Create unique hash for this directory
73
- dir_hash=$(echo "${{ matrix.directory }}" | sha256sum | awk '{print $1}')
74
-
75
- # Run git diff first to show changes
76
- echo "Changes since last release:"
77
- git diff --name-only "${{ needs.prepare.outputs.last_release }}" -- "${{ matrix.directory }}" || true
78
-
79
- # Run the release
80
- output=$(uv run --script scripts/release.py "${{ matrix.directory }}" "${{ needs.prepare.outputs.last_release }}" 2>&1)
81
- exit_code=$?
82
-
83
- echo "Release output (exit code: $exit_code):"
84
- echo "$output"
85
-
86
- # Extract package info if successful
87
- if [ $exit_code -eq 0 ]; then
88
- pkg_info=$(echo "$output" | grep -o -E "[a-zA-Z0-9\-]+@[0-9]+\.[0-9]+\.[0-9]+" || true)
89
- else
90
- echo "Release failed"
91
- exit 1
64
+ mkdir -p '.info/${{ matrix.package }}'
65
+ if git diff --name-only ${{ needs.detect-last-release.outputs.last_release }}..HEAD "src/${{ matrix.package }}/**/*.{py,ts}" | grep -q .; then
66
+ echo "Changes detected in Python or TypeScript files for ${{ matrix.package }}"
67
+ echo "${{ matrix.package }}" > ".info/${{ matrix.package }}/changed"
92
68
fi
93
69
94
- if [ ! -z "$pkg_info" ]; then
95
- echo "Released package: $pkg_info"
96
-
97
- # Create outputs directory
98
- mkdir -p ./outputs
99
-
100
- # Save both package info and full changes
101
- echo "$pkg_info" > "./outputs/${dir_hash}_info"
102
- echo "dir_hash=${dir_hash}" >> $GITHUB_OUTPUT
103
-
104
- # Log what we're saving
105
- echo "Saved package info to ./outputs/${dir_hash}_info:"
106
- cat "./outputs/${dir_hash}_info"
107
- else
108
- echo "No release needed for this package"
109
- fi
110
-
111
- - name : Set artifact name
112
- if : steps.release.outputs.dir_hash
113
- id : artifact
114
- run : |
115
- # Replace forward slashes with dashes
116
- SAFE_DIR=$(echo "${{ matrix.directory }}" | tr '/' '-')
117
- echo "name=release-outputs-${SAFE_DIR}" >> $GITHUB_OUTPUT
118
-
119
- - uses : actions/upload-artifact@v4
120
- if : steps.release.outputs.dir_hash
70
+ - name : Upload artifacts
71
+ uses : actions/upload-artifact@v4
121
72
with :
122
- name : ${{ steps.artifact.outputs.name }}
123
- path : ./outputs/ ${{ steps.release.outputs.dir_hash }}*
73
+ name : release- ${{ matrix.package }}
74
+ path : .info/ ${{ matrix.package }}
124
75
125
76
create-tag :
126
- needs : [prepare, release ]
77
+ needs : [detect-updates, create-tag-name ]
127
78
runs-on : ubuntu-latest
128
79
permissions :
129
80
contents : write
@@ -132,25 +83,26 @@ jobs:
132
83
133
84
- uses : actions/download-artifact@v4
134
85
with :
135
- pattern : release-outputs-src- *
86
+ pattern : release-*
136
87
merge-multiple : true
137
88
path : outputs
138
89
139
- - name : Create tag and release
90
+ - name : Create release
140
91
env :
141
92
GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
142
93
run : |
143
94
if [ -d outputs ]; then
95
+ # Configure git
96
+ git config --global user.name "GitHub Actions"
97
+ git config --global user.email "[email protected] "
98
+
144
99
# Collect package info
145
- find outputs -name "*_info " -exec cat {} \; > packages.txt
100
+ find outputs -name "changed " -exec cat {} \; > packages.txt
146
101
147
102
if [ -s packages.txt ]; then
148
- DATE=$(date +%Y.%m.%d)
149
- echo "Creating tag v${DATE}"
150
-
151
103
# Generate comprehensive release notes
152
104
{
153
- echo "# Release ${DATE }"
105
+ echo "# Release ${{ needs.create-tag-name.outputs.tag_name } }"
154
106
echo ""
155
107
echo "## Updated Packages"
156
108
while IFS= read -r line; do
@@ -159,16 +111,16 @@ jobs:
159
111
} > notes.md
160
112
161
113
# Create and push tag
162
- git tag -a "v${DATE} " -m "Release ${DATE }"
163
- git push origin "v${DATE }"
114
+ git tag -a "${{ needs.create-tag-name.outputs.tag_name }} " -m "Release ${{ needs.create-tag-name.outputs.tag_name } }"
115
+ git push origin "${{ needs.create-tag-name.outputs.tag_name } }"
164
116
165
117
# Create GitHub release
166
- gh release create "v${DATE }" \
167
- --title "Release ${DATE }" \
118
+ gh release create "${{ needs.create-tag-name.outputs.tag_name } }" \
119
+ --title "Release ${{ needs.create-tag-name.outputs.tag_name } }" \
168
120
--notes-file notes.md
169
121
else
170
122
echo "No packages need release"
171
123
fi
172
124
else
173
125
echo "No release artifacts found"
174
- fi
126
+ fi
0 commit comments