-
-
Notifications
You must be signed in to change notification settings - Fork 176
364 lines (325 loc) · 14.4 KB
/
release.yml
File metadata and controls
364 lines (325 loc) · 14.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
name: Release
on:
push:
branches:
- master
workflow_dispatch:
inputs:
version_bump:
description: 'Version bump type'
required: true
default: 'patch'
type: choice
options:
- patch
- minor
- major
release_notes:
description: 'Additional release notes (optional)'
required: false
type: string
permissions:
contents: write
jobs:
release:
name: Create Release
runs-on: ubuntu-latest
outputs:
new_version: ${{ steps.version.outputs.new_version }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- name: Get current version
id: current
run: |
CURRENT=$(grep -oP '"version":\s*"\K[^"]+' src/Proyecto26.RestClient/package.json)
echo "version=$CURRENT" >> $GITHUB_OUTPUT
echo "Current version: $CURRENT"
- name: Determine version bump from commits
id: bump
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
echo "type=${{ inputs.version_bump }}" >> $GITHUB_OUTPUT
echo "Manual bump: ${{ inputs.version_bump }}"
else
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
if [ -z "$LAST_TAG" ]; then
RANGE="HEAD"
else
RANGE="${LAST_TAG}..HEAD"
fi
COMMITS=$(git log $RANGE --pretty=format:"%s" 2>/dev/null || echo "")
if echo "$COMMITS" | grep -qiE "^(feat|feature)(\(.+\))?!:|BREAKING CHANGE"; then
echo "type=major" >> $GITHUB_OUTPUT
elif echo "$COMMITS" | grep -qiE "^(feat|feature)(\(.+\))?:"; then
echo "type=minor" >> $GITHUB_OUTPUT
else
echo "type=patch" >> $GITHUB_OUTPUT
fi
fi
- name: Calculate new version
id: version
run: |
IFS='.' read -r MAJOR MINOR PATCH <<< "${{ steps.current.outputs.version }}"
case "${{ steps.bump.outputs.type }}" in
major) MAJOR=$((MAJOR + 1)); MINOR=0; PATCH=0 ;;
minor) MINOR=$((MINOR + 1)); PATCH=0 ;;
patch) PATCH=$((PATCH + 1)) ;;
esac
NEW_VERSION="${MAJOR}.${MINOR}.${PATCH}"
echo "new_version=$NEW_VERSION" >> $GITHUB_OUTPUT
echo "New version: $NEW_VERSION"
- name: Generate changelog entry
id: changelog
run: |
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
if [ -z "$LAST_TAG" ]; then RANGE="HEAD"; else RANGE="${LAST_TAG}..HEAD"; fi
TODAY=$(date +%Y-%m-%d)
NEW_VERSION="${{ steps.version.outputs.new_version }}"
ADDED="" CHANGED="" FIXED="" REMOVED=""
while IFS= read -r line; do
HASH=$(echo "$line" | cut -d'|' -f1)
MSG=$(echo "$line" | cut -d'|' -f2-)
SHORT_HASH=$(echo "$HASH" | cut -c1-7)
PR_NUM=$(echo "$MSG" | grep -oP '\(#\K[0-9]+(?=\))' | head -1)
if [ -n "$PR_NUM" ]; then
ATTR="([#${PR_NUM}](https://github.com/proyecto26/RestClient/pull/${PR_NUM}))"
else
ATTR="([${SHORT_HASH}](https://github.com/proyecto26/RestClient/commit/${HASH}))"
fi
CLEAN_MSG=$(echo "$MSG" | sed -E 's/^(feat|fix|perf|refactor|chore|docs|style|test|build|ci)(\([^)]*\))?(!)?:\s*//')
CLEAN_MSG=$(echo "$CLEAN_MSG" | sed -E 's/\s*\(#[0-9]+\)\s*$//')
if echo "$MSG" | grep -qiE "^(feat|feature)(\(.+\))?:"; then
ADDED="${ADDED}- ${CLEAN_MSG} ${ATTR}.\n"
elif echo "$MSG" | grep -qiE "^fix(\(.+\))?:"; then
FIXED="${FIXED}- ${CLEAN_MSG} ${ATTR}.\n"
elif echo "$MSG" | grep -qiE "^(perf|refactor|chore|docs|style|build|ci)(\(.+\))?:"; then
CHANGED="${CHANGED}- ${CLEAN_MSG} ${ATTR}.\n"
elif echo "$MSG" | grep -qiE "^(revert)(\(.+\))?:"; then
REMOVED="${REMOVED}- ${CLEAN_MSG} ${ATTR}.\n"
else
CHANGED="${CHANGED}- ${CLEAN_MSG} ${ATTR}.\n"
fi
done < <(git log $RANGE --pretty=format:"%H|%s" --no-merges 2>/dev/null)
if [ -n "${{ inputs.release_notes }}" ]; then
ADDED="${ADDED}- ${{ inputs.release_notes }}\n"
fi
BODY=""
[ -n "$ADDED" ] && BODY="${BODY}### Added\n${ADDED}\n"
[ -n "$CHANGED" ] && BODY="${BODY}### Changed\n${CHANGED}\n"
[ -n "$FIXED" ] && BODY="${BODY}### Fixed\n${FIXED}\n"
[ -n "$REMOVED" ] && BODY="${BODY}### Removed\n${REMOVED}\n"
[ -z "$BODY" ] && BODY="### Changed\n- Release version ${NEW_VERSION}.\n"
echo -e "$BODY" > /tmp/release_body.md
# Update CHANGELOG.md
PREV_VERSION="${{ steps.current.outputs.version }}"
HEADER="## [${NEW_VERSION}] - ${TODAY}"
LINK="[${NEW_VERSION}]: https://github.com/proyecto26/RestClient/compare/v${PREV_VERSION}...v${NEW_VERSION}"
sed -i "/^## \[Unreleased\]/a\\\\n${HEADER}\\n" CHANGELOG.md
sed -i "/^## \[${NEW_VERSION}\]/r /tmp/release_body.md" CHANGELOG.md
sed -i "s|\[Unreleased\]: .*|[Unreleased]: https://github.com/proyecto26/RestClient/compare/v${NEW_VERSION}...HEAD|" CHANGELOG.md
sed -i "/^\[Unreleased\]:/a ${LINK}" CHANGELOG.md
- name: Update version in all files
run: |
VERSION="${{ steps.version.outputs.new_version }}"
sed -i 's/"version": "[^"]*"/"version": "'"$VERSION"'"/' src/Proyecto26.RestClient/package.json
sed -i 's/<PackageVersion>[^<]*</<PackageVersion>'"$VERSION"'</' src/Proyecto26.RestClient/Proyecto26.RestClient.csproj
sed -i 's/<version>[^<]*</<version>'"$VERSION"'</' src/Proyecto26.RestClient/Proyecto26.RestClient.nuspec
sed -i 's/AssemblyVersion ("[^"]*")/AssemblyVersion ("'"$VERSION"'")/' src/Proyecto26.RestClient/Properties/AssemblyInfo.cs
- name: Commit version bump
run: |
git config --global user.name 'github-actions[bot]'
git config --global user.email 'github-actions[bot]@users.noreply.github.com'
git add -A
git commit -m "chore(release): v${{ steps.version.outputs.new_version }}
- Updated package.json, .csproj, .nuspec, AssemblyInfo.cs
- Updated CHANGELOG.md"
git tag "v${{ steps.version.outputs.new_version }}"
git push origin master --follow-tags
# Build proper .unitypackage using the Unity package format
# Format: tar.gz of GUID directories, each containing asset, asset.meta, pathname
- name: Build .unitypackage
run: |
PKG_SRC="src/Proyecto26.RestClient"
STAGING="/tmp/unitypackage_staging"
UNITY_ROOT="Assets/Proyecto26.RestClient"
VERSION="${{ steps.version.outputs.new_version }}"
mkdir -p "$STAGING"
add_asset() {
local file="$1" meta="$2" unity_path="$3"
GUID=$(grep 'guid:' "$meta" | awk '{print $2}')
[ -z "$GUID" ] && return
mkdir -p "$STAGING/$GUID"
cp "$file" "$STAGING/$GUID/asset"
cp "$meta" "$STAGING/$GUID/asset.meta"
echo "$unity_path" > "$STAGING/$GUID/pathname"
}
add_folder_meta() {
local meta="$1" unity_path="$2"
GUID=$(grep 'guid:' "$meta" | awk '{print $2}')
[ -z "$GUID" ] && return
mkdir -p "$STAGING/$GUID"
cp "$meta" "$STAGING/$GUID/asset.meta"
echo "$unity_path" > "$STAGING/$GUID/pathname"
}
# Add source files (.cs, .asmdef, package.json) — exclude build system files
for f in $(find "$PKG_SRC" -type f \( -name "*.cs" -o -name "*.asmdef" -o -name "package.json" \) \
! -path "*/Properties/*" ! -path "*/bin/*" ! -path "*/obj/*"); do
META="${f}.meta"
if [ -f "$META" ]; then
REL_PATH="${f#$PKG_SRC/}"
add_asset "$f" "$META" "$UNITY_ROOT/$REL_PATH"
fi
done
# Add folder .meta files (e.g., Helpers.meta)
if [ -f "$PKG_SRC/Helpers.meta" ]; then
add_folder_meta "$PKG_SRC/Helpers.meta" "$UNITY_ROOT/Helpers"
fi
# Add demo scene and sample scripts (matching old manual package)
DEMO_ROOT="Assets/RestClient/DemoScene"
if [ -d "demo/Assets" ]; then
for f in $(find "demo/Assets" -type f \( -name "*.cs" -o -name "*.unity" -o -name "*.asmdef" \)); do
META="${f}.meta"
if [ -f "$META" ]; then
REL_PATH="${f#demo/Assets/}"
add_asset "$f" "$META" "$DEMO_ROOT/$REL_PATH"
fi
done
# Add demo folder .meta files
for f in $(find "demo/Assets" -maxdepth 2 -name "*.meta" -type f); do
BASENAME=$(basename "$f" .meta)
DIR=$(dirname "$f")
if [ -d "$DIR/$BASENAME" ]; then
REL_PATH="${f#demo/Assets/}"
FOLDER_PATH="${REL_PATH%.meta}"
add_folder_meta "$f" "$DEMO_ROOT/$FOLDER_PATH"
fi
done
fi
# Add documentation PDF
if [ -f "doc/RestClient.pdf" ]; then
# Generate a stable GUID for the PDF (no .meta file exists)
PDF_GUID="d0c5f3a1e2b4c6d8f0a1b2c3d4e5f6a7"
mkdir -p "$STAGING/$PDF_GUID"
cp "doc/RestClient.pdf" "$STAGING/$PDF_GUID/asset"
echo "Assets/RestClient/RestClient.pdf" > "$STAGING/$PDF_GUID/pathname"
fi
# Create the .unitypackage
cd "$STAGING"
ASSET_COUNT=$(ls -d */ 2>/dev/null | wc -l)
tar -czf "/tmp/Proyecto26.RestClient-${VERSION}.unitypackage" */
echo "Built .unitypackage with ${ASSET_COUNT} assets"
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: v${{ steps.version.outputs.new_version }}
name: Release ${{ steps.version.outputs.new_version }}
body_path: /tmp/release_body.md
draft: false
prerelease: false
files: |
/tmp/Proyecto26.RestClient-${{ steps.version.outputs.new_version }}.unitypackage
publish-nuget:
name: Publish to NuGet
needs: release
runs-on: windows-latest
if: needs.release.outputs.new_version != ''
steps:
- uses: actions/checkout@v4
with:
ref: master
- name: Pull latest (includes version bump commit)
run: git pull origin master
- name: Setup NuGet
uses: nuget/setup-nuget@v2
- name: Build NuGet package
run: |
cd src/Proyecto26.RestClient
nuget pack Proyecto26.RestClient.nuspec -Version ${{ needs.release.outputs.new_version }} -OutputDirectory ../../artifacts
- name: Publish to NuGet
run: |
nuget push artifacts\*.nupkg -ApiKey ${{ secrets.NUGET_API_KEY }} -Source https://api.nuget.org/v3/index.json -SkipDuplicate
split-branches:
name: Split UPM & NuGet branches
needs: release
runs-on: ubuntu-latest
if: needs.release.outputs.new_version != ''
steps:
- uses: actions/checkout@v4
with:
ref: master
fetch-depth: 0
- name: Pull latest
run: git pull origin master
- name: Split UPM branch
run: |
git branch -d upm &> /dev/null || echo "upm branch not found"
git mv "$PKG_ROOT" "src/$UPM_ROOT"
git mv "src/$UPM_ROOT" .
git mv demo/Assets demo/Samples~
git mv demo/Samples~ $UPM_ROOT
git mv doc Docs
git mv Docs $UPM_ROOT
git mv LICENSE $UPM_ROOT
git mv README.md $UPM_ROOT
git mv SECURITY.md $UPM_ROOT
git mv CHANGELOG.md $UPM_ROOT
git mv CONTRIBUTING.md $UPM_ROOT
git config --global user.name 'github-actions[bot]'
git config --global user.email 'github-actions[bot]@users.noreply.github.com'
git add "$UPM_ROOT"
git commit -m "create release folder"
git subtree split -P "$UPM_ROOT" -b upm
git checkout upm
# Remove non-Unity files that cause missing .meta warnings (fixes #219)
if [[ -d "Samples~/Packages" ]]; then
git rm -rf Samples~/Packages
git rm Samples~/Packages.meta --ignore-unmatch
git rm Samples~/packages.config
git rm Samples~/packages.config.meta --ignore-unmatch
fi
if [[ -d "Properties" ]]; then
git rm -rf Properties
git rm Properties.meta --ignore-unmatch
git rm Proyecto26.RestClient.csproj
git rm Proyecto26.RestClient.csproj.meta --ignore-unmatch
git rm Proyecto26.RestClient.nuspec
git rm Proyecto26.RestClient.nuspec.meta --ignore-unmatch
git rm packages.config
git rm packages.config.meta --ignore-unmatch
fi
git commit -am "fix: clean UPM branch (remove non-Unity files)"
git push -u origin upm --force
# Tag UPM branch for OpenUPM version detection
git tag "upm/${{ needs.release.outputs.new_version }}"
git push origin "upm/${{ needs.release.outputs.new_version }}"
env:
PKG_ROOT: src/Proyecto26.RestClient
UPM_ROOT: Release
# Fresh checkout needed because UPM split modified the working tree
- name: Fresh checkout for NuGet split
uses: actions/checkout@v4
with:
ref: master
fetch-depth: 0
clean: true
- name: Pull latest for NuGet
run: git pull origin master
- name: Split NuGet branch
run: |
git branch -d nuget &> /dev/null || echo "nuget branch not found"
git mv LICENSE $NUGET_ROOT 2>/dev/null || true
git mv README.md $NUGET_ROOT 2>/dev/null || true
git mv SECURITY.md $NUGET_ROOT 2>/dev/null || true
git mv CHANGELOG.md $NUGET_ROOT 2>/dev/null || true
git mv CONTRIBUTING.md $NUGET_ROOT 2>/dev/null || true
git config --global user.name 'github-actions[bot]'
git config --global user.email 'github-actions[bot]@users.noreply.github.com'
git subtree split -P "$NUGET_ROOT" -b nuget
git checkout nuget
git commit -am "fix: src => root" --allow-empty
git push -u origin nuget --force
env:
NUGET_ROOT: src