From ed1009d6b8486b343e0127e5babf70ae07109f4f Mon Sep 17 00:00:00 2001 From: Kevin Tong Date: Mon, 24 Oct 2022 19:16:20 -0400 Subject: [PATCH 01/11] Fix HEAD promise method incorrectly calling DELETE --- src/Proyecto26.RestClient/RestClientPromise.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Proyecto26.RestClient/RestClientPromise.cs b/src/Proyecto26.RestClient/RestClientPromise.cs index b0e92f2..84ff3ae 100644 --- a/src/Proyecto26.RestClient/RestClientPromise.cs +++ b/src/Proyecto26.RestClient/RestClientPromise.cs @@ -381,7 +381,7 @@ public static IPromise Delete(RequestHelper options) /// A string containing the URL to which the request is sent. public static IPromise Head(string url) { - return Delete(new RequestHelper { Uri = url }); + return Head(new RequestHelper { Uri = url }); } /// From f93ab01a99aab5775ee10f28a70690bac8b407e5 Mon Sep 17 00:00:00 2001 From: Maifee Ul Asad <29339330+maifeeulasad@users.noreply.github.com> Date: Thu, 16 Feb 2023 16:08:05 +0600 Subject: [PATCH 02/11] added `maifeeulasad` to the list of contributors --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 17f1a48..4f7aadf 100644 --- a/README.md +++ b/README.md @@ -338,9 +338,9 @@ This project exists thanks to all the people who contribute. [[Contribute](CONTR ### Collaborators -[jdnichollsc](https://github.com/jdnichollsc) | [diegoossa](https://github.com/diegoossa) | [nasdull](https://github.com/nasdull) | -:---: | :---: | :---: | -[Juan Nicholls](mailto:jdnichollsc@hotmail.com) | [Diego Ossa](mailto:diegoossa@gmail.com) | [Nasdull](mailto:nasdull@hotmail.com) | +[jdnichollsc](https://github.com/jdnichollsc) | [diegoossa](https://github.com/diegoossa) | [nasdull](https://github.com/nasdull) | [nasdull](https://github.com/maifeeulasad) | +:---: | :---: | :---: | :---: | +[Juan Nicholls](mailto:jdnichollsc@hotmail.com) | [Diego Ossa](mailto:diegoossa@gmail.com) | [Nasdull](mailto:nasdull@hotmail.com) | [Maifee Ul Asad](mailto:maifeeulasad@gmail.com) | ## Supporting 🍻 From b6a44ab880bb70194315409277ee2cdf72b29e2e Mon Sep 17 00:00:00 2001 From: Maifee Ul Asad <29339330+maifeeulasad@users.noreply.github.com> Date: Thu, 16 Feb 2023 16:13:57 +0600 Subject: [PATCH 03/11] added on production usage https://github.com/proyecto26/RestClient/issues/138 --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 17f1a48..00c74d7 100644 --- a/README.md +++ b/README.md @@ -364,6 +364,12 @@ The maintainers of RestClient for Unity and thousands of other packages are work ## Security contact information 🚨 To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security). Tidelift will coordinate the fix and disclosure. +## Who is using RestClient ⚔️ +We are battle tested. There is a list of our usage in production: + - mainware. Ref: https://github.com/proyecto26/RestClient/issues/138#issuecomment-725552712 + - virsabi. Ref: https://github.com/proyecto26/RestClient/issues/138#issuecomment-863222899 + - type3studio. Ref: https://github.com/proyecto26/RestClient/issues/138#issuecomment-1415945883 + ## License ⚖️ This repository is available under the [MIT License](https://github.com/proyecto26/RestClient/blob/develop/LICENSE). From 1cfecf6d6116d10982d86500b88ae3acdbc77faf Mon Sep 17 00:00:00 2001 From: "J.D Nicholls" Date: Sun, 27 Oct 2024 12:04:50 -0400 Subject: [PATCH 04/11] Update README.md --- README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 4f7aadf..8cf1593 100644 --- a/README.md +++ b/README.md @@ -347,11 +347,9 @@ This project exists thanks to all the people who contribute. [[Contribute](CONTR I believe in Unicorns 🦄 Support [me](http://www.paypal.me/jdnichollsc/2), if you do too. -Donate **Ethereum**, **ADA**, **BNB**, **SHIBA**, **USDT**, **DOGE**: +Donate **Ethereum**, **ADA**, **BNB**, **SHIBA**, **USDT/USDC**, **DOGE**, etc: -![Wallet address](https://user-images.githubusercontent.com/2154886/123501719-84bf1900-d60c-11eb-882c-98a499cea323.png) - -> Wallet address: 0x3F9fA8021B43ACe578C2352861Cf335449F33427 +> Wallet address: jdnichollsc.eth Please let us know your contributions! 🙏 From a162b094c2806f7e5ea8715469ca184001d8a848 Mon Sep 17 00:00:00 2001 From: Maifee Ul Asad Date: Sat, 22 Nov 2025 12:16:08 +0600 Subject: [PATCH 05/11] [fix]: properly handle `ArgumentNullException` for abort controller; - ref #103 --- .../Helpers/RequestHelperExtension.cs | 58 +++++++++++++++++-- 1 file changed, 52 insertions(+), 6 deletions(-) diff --git a/src/Proyecto26.RestClient/Helpers/RequestHelperExtension.cs b/src/Proyecto26.RestClient/Helpers/RequestHelperExtension.cs index 7017a74..fadc6c3 100644 --- a/src/Proyecto26.RestClient/Helpers/RequestHelperExtension.cs +++ b/src/Proyecto26.RestClient/Helpers/RequestHelperExtension.cs @@ -20,7 +20,15 @@ public float UploadProgress float progress = 0; if (this.Request != null) { - progress = this.Request.uploadProgress; + try + { + progress = this.Request.uploadProgress; + } + catch (ArgumentNullException) + { + // Request was disposed - return 0 progress + progress = 0; + } } return progress; } @@ -36,7 +44,15 @@ public ulong UploadedBytes ulong bytes = 0; if (this.Request != null) { - bytes = this.Request.uploadedBytes; + try + { + bytes = this.Request.uploadedBytes; + } + catch (ArgumentNullException) + { + // Request was disposed - return 0 bytes + bytes = 0; + } } return bytes; } @@ -52,7 +68,15 @@ public float DownloadProgress float progress = 0; if (this.Request != null) { - progress = this.Request.downloadProgress; + try + { + progress = this.Request.downloadProgress; + } + catch (ArgumentNullException) + { + // Request was disposed - return 0 progress + progress = 0; + } } return progress; } @@ -68,7 +92,15 @@ public ulong DownloadedBytes ulong bytes = 0; if (this.Request != null) { - bytes = this.Request.downloadedBytes; + try + { + bytes = this.Request.downloadedBytes; + } + catch (ArgumentNullException) + { + // Request was disposed - return 0 bytes + bytes = 0; + } } return bytes; } @@ -81,10 +113,18 @@ public ulong DownloadedBytes /// The name of the header. public string GetHeader(string name) { - string headerValue; + string headerValue = null; if (this.Request != null) { - headerValue = this.Request.GetRequestHeader(name); + try + { + headerValue = this.Request.GetRequestHeader(name); + } + catch (ArgumentNullException) + { + // Request was disposed - fall back to headers dictionary + this.Headers.TryGetValue(name, out headerValue); + } } else { @@ -131,6 +171,12 @@ public void Abort() this.Request.Abort(); } } + catch (ArgumentNullException) + { + // Request was already disposed by UnityWebRequest's using block - this is expected behavior + // No need to log this as it's a normal part of the request lifecycle + HttpBase.DebugLog(this.EnableDebug, "Request was already disposed; abort skipped.", true); + } catch (Exception error) { HttpBase.DebugLog(this.EnableDebug, error.Message, true); } From be566ca2d6e881e892ae912fc78717e465e4ce2c Mon Sep 17 00:00:00 2001 From: Maifee Ul Asad Date: Sat, 22 Nov 2025 12:16:53 +0600 Subject: [PATCH 06/11] [version]: set to `2.6.3`; --- src/Proyecto26.RestClient/Proyecto26.RestClient.csproj | 2 +- src/Proyecto26.RestClient/RestClient.cs | 2 +- src/Proyecto26.RestClient/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Proyecto26.RestClient/Proyecto26.RestClient.csproj b/src/Proyecto26.RestClient/Proyecto26.RestClient.csproj index 9c255c1..edecf9f 100644 --- a/src/Proyecto26.RestClient/Proyecto26.RestClient.csproj +++ b/src/Proyecto26.RestClient/Proyecto26.RestClient.csproj @@ -9,7 +9,7 @@ Proyecto26.RestClient v3.5 Proyecto26.RestClient - 2.6.2 + 2.6.3 jdnichollsc https://github.com/proyecto26/RestClient/blob/master/img/icono.png?raw=true https://github.com/proyecto26/RestClient/blob/master/LICENSE diff --git a/src/Proyecto26.RestClient/RestClient.cs b/src/Proyecto26.RestClient/RestClient.cs index 82b0da5..2fbdd04 100644 --- a/src/Proyecto26.RestClient/RestClient.cs +++ b/src/Proyecto26.RestClient/RestClient.cs @@ -23,7 +23,7 @@ public static System.Version Version get { if (_version == null) { - _version = new System.Version("2.6.2"); + _version = new System.Version("2.6.3"); } return _version; } diff --git a/src/Proyecto26.RestClient/package.json b/src/Proyecto26.RestClient/package.json index 29f6577..e71dc6f 100644 --- a/src/Proyecto26.RestClient/package.json +++ b/src/Proyecto26.RestClient/package.json @@ -1,6 +1,6 @@ { "name": "com.proyecto26.restclient", - "version": "2.6.2", + "version": "2.6.3", "displayName": "RestClient for Unity", "description": "Simple HTTP and REST client for Unity based on Promises, also support Callbacks!", "unity": "2017.1", From 2f831dc323a2205235f5ecc18bea687d315617ac Mon Sep 17 00:00:00 2001 From: Maifee Ul Asad Date: Sat, 22 Nov 2025 12:18:00 +0600 Subject: [PATCH 07/11] [chores]: updated changelog w ref of #103; --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 68d69e6..57fd1f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [2.6.3] - 2025-11-22 + +### Fixed +- Fixed **ArgumentNullException** when calling `Abort()` or accessing properties on completed requests ([#103](https://github.com/proyecto26/RestClient/issues/103)). +- Enhanced disposal detection for UnityWebRequest objects to prevent crashes during cleanup scenarios. +- Added proper exception handling for all RequestHelper properties that access disposed UnityWebRequest instances. +- Improved thread safety for request cancellation in Unity's OnDestroy patterns. + ## [2.6.2] - 2021-12-26 ### Added From f0d0cdd30d9833f1d0a7c3f712105c391f3dc012 Mon Sep 17 00:00:00 2001 From: Juan David Nicholls Cardona Date: Sun, 15 Mar 2026 19:51:02 -0500 Subject: [PATCH 08/11] feat(ci): add automated release workflow with semantic versioning - Add release.yml: auto version bump, changelog generation, GitHub Release, NuGet publish, and UPM/NuGet branch splitting - Triggers on push to master + manual workflow_dispatch - Updates all 4 version files (package.json, .csproj, .nuspec, AssemblyInfo.cs) - Generates Keep a Changelog format entries with contributor credits - Creates GitHub Release named "Release X.Y.Z" with tag vX.Y.Z - Publishes NuGet package via NUGET_API_KEY secret - Sync version files on develop to 2.6.3 - Update ci.yml with paths-ignore to prevent race conditions --- .github/workflows/ci.yml | 4 + .github/workflows/release.yml | 338 ++++++++++++++++++ .../Properties/AssemblyInfo.cs | 2 +- .../Proyecto26.RestClient.nuspec | 2 +- 4 files changed, 344 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 82ba718..2157170 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,6 +3,10 @@ on: push: branches: - master + # Skip when the release workflow already handles branch splitting + paths-ignore: + - 'CHANGELOG.md' + - '.github/workflows/release.yml' jobs: split-upm: name: split upm branch diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..059c92f --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,338 @@ +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 }} + changelog_body: ${{ steps.changelog.outputs.body }} + 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 + # Parse conventional commits since last tag + 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 + echo "Detected: major (breaking change)" + elif echo "$COMMITS" | grep -qiE "^(feat|feature)(\(.+\))?:"; then + echo "type=minor" >> $GITHUB_OUTPUT + echo "Detected: minor (new feature)" + elif echo "$COMMITS" | grep -qiE "^(fix|perf|refactor)(\(.+\))?:"; then + echo "type=patch" >> $GITHUB_OUTPUT + echo "Detected: patch (fix/improvement)" + else + echo "type=patch" >> $GITHUB_OUTPUT + echo "Detected: patch (default)" + 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 }}" + + # Collect commits by type + ADDED="" + CHANGED="" + FIXED="" + REMOVED="" + + while IFS= read -r line; do + # Extract commit info + HASH=$(echo "$line" | cut -d'|' -f1) + MSG=$(echo "$line" | cut -d'|' -f2-) + SHORT_HASH=$(echo "$HASH" | cut -c1-7) + + # Get PR number and author if available + PR_NUM=$(echo "$MSG" | grep -oP '\(#\K[0-9]+(?=\))' | head -1) + AUTHOR=$(git log -1 --format='%an' "$HASH" 2>/dev/null) + GITHUB_USER=$(git log -1 --format='%(trailers:key=Co-authored-by,valueonly)' "$HASH" 2>/dev/null | grep -oP '@\K\S+' | head -1) + + # Build attribution + 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 message (remove conventional commit prefix and scope) + CLEAN_MSG=$(echo "$MSG" | sed -E 's/^(feat|fix|perf|refactor|chore|docs|style|test|build|ci)(\([^)]*\))?(!)?:\s*//') + # Remove PR reference from message if already captured + CLEAN_MSG=$(echo "$CLEAN_MSG" | sed -E 's/\s*\(#[0-9]+\)\s*$//') + + # Categorize + 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 + # Non-conventional commits go to Changed + CHANGED="${CHANGED}- ${CLEAN_MSG} ${ATTR}.\n" + fi + done < <(git log $RANGE --pretty=format:"%H|%s" --no-merges 2>/dev/null) + + # Add manual release notes if provided + if [ -n "${{ inputs.release_notes }}" ]; then + ADDED="${ADDED}- ${{ inputs.release_notes }}\n" + fi + + # Build changelog section + BODY="" + if [ -n "$ADDED" ]; then + BODY="${BODY}### Added\n${ADDED}\n" + fi + if [ -n "$CHANGED" ]; then + BODY="${BODY}### Changed\n${CHANGED}\n" + fi + if [ -n "$FIXED" ]; then + BODY="${BODY}### Fixed\n${FIXED}\n" + fi + if [ -n "$REMOVED" ]; then + BODY="${BODY}### Removed\n${REMOVED}\n" + fi + + # Fallback if no conventional commits found + if [ -z "$BODY" ]; then + BODY="### Changed\n- Release version ${NEW_VERSION}.\n" + fi + + # Save for GitHub Release body + echo -e "$BODY" > /tmp/release_body.md + echo "body<> $GITHUB_OUTPUT + echo -e "$BODY" >> $GITHUB_OUTPUT + echo "CHANGELOG_EOF" >> $GITHUB_OUTPUT + + # 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}" + + # Insert new version section after [Unreleased] line + sed -i "/^## \[Unreleased\]/a\\\\n${HEADER}\\n" CHANGELOG.md + # Insert the body after the new header + sed -i "/^## \[${NEW_VERSION}\]/r /tmp/release_body.md" CHANGELOG.md + # Update Unreleased comparison link + sed -i "s|\[Unreleased\]: .*|[Unreleased]: https://github.com/proyecto26/RestClient/compare/v${NEW_VERSION}...HEAD|" CHANGELOG.md + # Add new version comparison link before existing ones + sed -i "/^\[Unreleased\]:/a ${LINK}" CHANGELOG.md + + echo "Changelog updated for v${NEW_VERSION}" + + - name: Update version in package.json (UPM) + run: | + sed -i 's/"version": "[^"]*"/"version": "${{ steps.version.outputs.new_version }}"/' src/Proyecto26.RestClient/package.json + + - name: Update version in .csproj + run: | + sed -i 's/[^<]*${{ steps.version.outputs.new_version }}[^<]*${{ steps.version.outputs.new_version }} /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 + 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: src => root" + git push -u origin upm --force + env: + PKG_ROOT: src/Proyecto26.RestClient + UPM_ROOT: Release + + - name: Split NuGet branch + run: | + git checkout master + git pull origin master + git branch -d nuget &> /dev/null || echo "nuget branch not found" + git mv LICENSE $NUGET_ROOT + git mv README.md $NUGET_ROOT + git mv SECURITY.md $NUGET_ROOT + git mv CHANGELOG.md $NUGET_ROOT + git mv CONTRIBUTING.md $NUGET_ROOT + 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 diff --git a/src/Proyecto26.RestClient/Properties/AssemblyInfo.cs b/src/Proyecto26.RestClient/Properties/AssemblyInfo.cs index 5f14f0a..72a986b 100644 --- a/src/Proyecto26.RestClient/Properties/AssemblyInfo.cs +++ b/src/Proyecto26.RestClient/Properties/AssemblyInfo.cs @@ -17,7 +17,7 @@ // The form "{Major}.{Minor}.*" will automatically update the build and revision, // and "{Major}.{Minor}.{Build}.*" will update just the revision. -[assembly: AssemblyVersion ("2.6.2")] +[assembly: AssemblyVersion ("2.6.3")] // The following attributes are used to specify the signing key for the assembly, // if desired. See the Mono documentation for more information about signing. diff --git a/src/Proyecto26.RestClient/Proyecto26.RestClient.nuspec b/src/Proyecto26.RestClient/Proyecto26.RestClient.nuspec index 0a35221..4e9a26f 100644 --- a/src/Proyecto26.RestClient/Proyecto26.RestClient.nuspec +++ b/src/Proyecto26.RestClient/Proyecto26.RestClient.nuspec @@ -2,7 +2,7 @@ Proyecto26.RestClient - 2.6.2 + 2.6.3 RestClient for Unity Juan David Nicholls Cardona jdnichollsc From a513b6bfafd210c485e1485c2e74000e28ee5655 Mon Sep 17 00:00:00 2001 From: Juan David Nicholls Cardona Date: Sun, 15 Mar 2026 20:00:28 -0500 Subject: [PATCH 09/11] fix(ci): add .unitypackage artifact to releases, clean up .gitignore - Build and attach source tarball to GitHub Releases (no binaries in git) - Add .gitignore rules for Unity stub DLLs and build artifacts - Fix NuGet publish condition to use secrets context - Addresses issue #219 (missing meta files in UPM) --- .github/workflows/release.yml | 32 +++++++++++++++++++++++++++++--- src/.gitignore | 7 +++++++ 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 059c92f..0aff848 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -220,6 +220,32 @@ jobs: git tag "v${{ steps.version.outputs.new_version }}" git push origin master --follow-tags + - name: Build .unitypackage artifact + run: | + # Create a clean directory structure for the Unity package + PKG_DIR="/tmp/unity-package" + ASSET_DIR="$PKG_DIR/Assets/Proyecto26.RestClient" + mkdir -p "$ASSET_DIR" + # Copy only Unity-relevant source files (exclude build system files) + cp -r src/Proyecto26.RestClient/Helpers "$ASSET_DIR/" + cp src/Proyecto26.RestClient/RestClient.cs "$ASSET_DIR/" + cp src/Proyecto26.RestClient/RestClientPromise.cs "$ASSET_DIR/" + cp src/Proyecto26.RestClient/package.json "$ASSET_DIR/" + cp src/Proyecto26.RestClient/Proyecto26.RestClient.asmdef "$ASSET_DIR/" + # Copy meta files if they exist + find src/Proyecto26.RestClient -name "*.meta" -exec sh -c 'cp "$1" "'"$ASSET_DIR"'/$(basename "$1")" 2>/dev/null || true' _ {} \; + cp -r src/Proyecto26.RestClient/Helpers/*.meta "$ASSET_DIR/Helpers/" 2>/dev/null || true + cp src/Proyecto26.RestClient/RestClient.cs.meta "$ASSET_DIR/" 2>/dev/null || true + cp src/Proyecto26.RestClient/RestClientPromise.cs.meta "$ASSET_DIR/" 2>/dev/null || true + cp src/Proyecto26.RestClient/package.json.meta "$ASSET_DIR/" 2>/dev/null || true + cp src/Proyecto26.RestClient/Proyecto26.RestClient.asmdef.meta "$ASSET_DIR/" 2>/dev/null || true + cp LICENSE "$ASSET_DIR/" + cp README.md "$ASSET_DIR/" + # Create a tarball as the distributable (Unity .unitypackage format requires Unity Editor) + cd "$PKG_DIR" + tar -czf "/tmp/Proyecto26.RestClient-${{ steps.version.outputs.new_version }}.tar.gz" Assets/ + echo "Package built: Proyecto26.RestClient-${{ steps.version.outputs.new_version }}.tar.gz" + - name: Create GitHub Release uses: softprops/action-gh-release@v2 with: @@ -228,6 +254,8 @@ jobs: body_path: /tmp/release_body.md draft: false prerelease: false + files: | + /tmp/Proyecto26.RestClient-${{ steps.version.outputs.new_version }}.tar.gz publish-nuget: name: Publish to NuGet @@ -253,14 +281,12 @@ jobs: dotnet pack -c Release -o ../../artifacts - name: Publish to NuGet - if: ${{ env.NUGET_API_KEY != '' }} + if: ${{ secrets.NUGET_API_KEY != '' }} run: | dotnet nuget push artifacts/*.nupkg \ --api-key ${{ secrets.NUGET_API_KEY }} \ --source https://api.nuget.org/v3/index.json \ --skip-duplicate - env: - NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }} split-branches: name: Split UPM & NuGet branches diff --git a/src/.gitignore b/src/.gitignore index 1c2b85e..46d7d72 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -278,6 +278,13 @@ paket-files/ __pycache__/ *.pyc +# Unity stub DLLs (should be referenced from Unity installation, not committed) +dlls/ + +# Build artifacts (generated during CI/CD) +artifacts/ +*.unitypackage + # Cake - Uncomment if you are using it # tools/** # !tools/packages.config From 95880e1b6e6e8f7610e9aa981da07efbd15263ec Mon Sep 17 00:00:00 2001 From: Juan David Nicholls Cardona Date: Sun, 15 Mar 2026 20:17:58 -0500 Subject: [PATCH 10/11] fix(ci): proper .unitypackage build, NuGet CLI, UPM tagging MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Build real .unitypackage using Unity package format (GUID dirs with asset, asset.meta, pathname) — no Unity Editor required - Switch from dotnet pack to nuget pack (old-style .csproj is not SDK-compatible, dotnet pack would fail) - Tag UPM branch with upm/X.Y.Z for OpenUPM version detection - Clean UPM branch removes non-Unity files (fixes #219) - Attach .unitypackage to GitHub Release (matches README install docs) --- .github/workflows/release.yml | 186 ++++++++++++++-------------------- 1 file changed, 76 insertions(+), 110 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0aff848..abbdeea 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -29,7 +29,6 @@ jobs: runs-on: ubuntu-latest outputs: new_version: ${{ steps.version.outputs.new_version }} - changelog_body: ${{ steps.changelog.outputs.body }} steps: - uses: actions/checkout@v4 with: @@ -50,28 +49,19 @@ jobs: echo "type=${{ inputs.version_bump }}" >> $GITHUB_OUTPUT echo "Manual bump: ${{ inputs.version_bump }}" else - # Parse conventional commits since last tag 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 - echo "Detected: major (breaking change)" elif echo "$COMMITS" | grep -qiE "^(feat|feature)(\(.+\))?:"; then echo "type=minor" >> $GITHUB_OUTPUT - echo "Detected: minor (new feature)" - elif echo "$COMMITS" | grep -qiE "^(fix|perf|refactor)(\(.+\))?:"; then - echo "type=patch" >> $GITHUB_OUTPUT - echo "Detected: patch (fix/improvement)" else echo "type=patch" >> $GITHUB_OUTPUT - echo "Detected: patch (default)" fi fi @@ -92,45 +82,27 @@ jobs: 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 + 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 }}" - - # Collect commits by type - ADDED="" - CHANGED="" - FIXED="" - REMOVED="" + ADDED="" CHANGED="" FIXED="" REMOVED="" while IFS= read -r line; do - # Extract commit info HASH=$(echo "$line" | cut -d'|' -f1) MSG=$(echo "$line" | cut -d'|' -f2-) SHORT_HASH=$(echo "$HASH" | cut -c1-7) - - # Get PR number and author if available PR_NUM=$(echo "$MSG" | grep -oP '\(#\K[0-9]+(?=\))' | head -1) - AUTHOR=$(git log -1 --format='%an' "$HASH" 2>/dev/null) - GITHUB_USER=$(git log -1 --format='%(trailers:key=Co-authored-by,valueonly)' "$HASH" 2>/dev/null | grep -oP '@\K\S+' | head -1) - # Build attribution 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 message (remove conventional commit prefix and scope) CLEAN_MSG=$(echo "$MSG" | sed -E 's/^(feat|fix|perf|refactor|chore|docs|style|test|build|ci)(\([^)]*\))?(!)?:\s*//') - # Remove PR reference from message if already captured CLEAN_MSG=$(echo "$CLEAN_MSG" | sed -E 's/\s*\(#[0-9]+\)\s*$//') - # Categorize if echo "$MSG" | grep -qiE "^(feat|feature)(\(.+\))?:"; then ADDED="${ADDED}- ${CLEAN_MSG} ${ATTR}.\n" elif echo "$MSG" | grep -qiE "^fix(\(.+\))?:"; then @@ -140,73 +112,39 @@ jobs: elif echo "$MSG" | grep -qiE "^(revert)(\(.+\))?:"; then REMOVED="${REMOVED}- ${CLEAN_MSG} ${ATTR}.\n" else - # Non-conventional commits go to Changed CHANGED="${CHANGED}- ${CLEAN_MSG} ${ATTR}.\n" fi done < <(git log $RANGE --pretty=format:"%H|%s" --no-merges 2>/dev/null) - # Add manual release notes if provided if [ -n "${{ inputs.release_notes }}" ]; then ADDED="${ADDED}- ${{ inputs.release_notes }}\n" fi - # Build changelog section BODY="" - if [ -n "$ADDED" ]; then - BODY="${BODY}### Added\n${ADDED}\n" - fi - if [ -n "$CHANGED" ]; then - BODY="${BODY}### Changed\n${CHANGED}\n" - fi - if [ -n "$FIXED" ]; then - BODY="${BODY}### Fixed\n${FIXED}\n" - fi - if [ -n "$REMOVED" ]; then - BODY="${BODY}### Removed\n${REMOVED}\n" - fi + [ -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" - # Fallback if no conventional commits found - if [ -z "$BODY" ]; then - BODY="### Changed\n- Release version ${NEW_VERSION}.\n" - fi - - # Save for GitHub Release body echo -e "$BODY" > /tmp/release_body.md - echo "body<> $GITHUB_OUTPUT - echo -e "$BODY" >> $GITHUB_OUTPUT - echo "CHANGELOG_EOF" >> $GITHUB_OUTPUT # 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}" - - # Insert new version section after [Unreleased] line sed -i "/^## \[Unreleased\]/a\\\\n${HEADER}\\n" CHANGELOG.md - # Insert the body after the new header sed -i "/^## \[${NEW_VERSION}\]/r /tmp/release_body.md" CHANGELOG.md - # Update Unreleased comparison link sed -i "s|\[Unreleased\]: .*|[Unreleased]: https://github.com/proyecto26/RestClient/compare/v${NEW_VERSION}...HEAD|" CHANGELOG.md - # Add new version comparison link before existing ones sed -i "/^\[Unreleased\]:/a ${LINK}" CHANGELOG.md - echo "Changelog updated for v${NEW_VERSION}" - - - name: Update version in package.json (UPM) - run: | - sed -i 's/"version": "[^"]*"/"version": "${{ steps.version.outputs.new_version }}"/' src/Proyecto26.RestClient/package.json - - - name: Update version in .csproj - run: | - sed -i 's/[^<]*${{ steps.version.outputs.new_version }}[^<]*${{ steps.version.outputs.new_version }}[^<]*'"$VERSION"'[^<]*'"$VERSION"'/dev/null || true' _ {} \; - cp -r src/Proyecto26.RestClient/Helpers/*.meta "$ASSET_DIR/Helpers/" 2>/dev/null || true - cp src/Proyecto26.RestClient/RestClient.cs.meta "$ASSET_DIR/" 2>/dev/null || true - cp src/Proyecto26.RestClient/RestClientPromise.cs.meta "$ASSET_DIR/" 2>/dev/null || true - cp src/Proyecto26.RestClient/package.json.meta "$ASSET_DIR/" 2>/dev/null || true - cp src/Proyecto26.RestClient/Proyecto26.RestClient.asmdef.meta "$ASSET_DIR/" 2>/dev/null || true - cp LICENSE "$ASSET_DIR/" - cp README.md "$ASSET_DIR/" - # Create a tarball as the distributable (Unity .unitypackage format requires Unity Editor) - cd "$PKG_DIR" - tar -czf "/tmp/Proyecto26.RestClient-${{ steps.version.outputs.new_version }}.tar.gz" Assets/ - echo "Package built: Proyecto26.RestClient-${{ steps.version.outputs.new_version }}.tar.gz" + 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 + + # 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 @@ -255,7 +217,7 @@ jobs: draft: false prerelease: false files: | - /tmp/Proyecto26.RestClient-${{ steps.version.outputs.new_version }}.tar.gz + /tmp/Proyecto26.RestClient-${{ steps.version.outputs.new_version }}.unitypackage publish-nuget: name: Publish to NuGet @@ -270,23 +232,23 @@ jobs: - name: Pull latest (includes version bump commit) run: git pull origin master - - name: Setup .NET - uses: actions/setup-dotnet@v4 - with: - dotnet-version: '6.0.x' + # Use nuget CLI with .nuspec file (old-style .csproj is not compatible with dotnet pack) + - name: Install NuGet CLI + run: | + sudo apt-get update && sudo apt-get install -y nuget - name: Build NuGet package run: | cd src/Proyecto26.RestClient - dotnet pack -c Release -o ../../artifacts + nuget pack Proyecto26.RestClient.nuspec -Version ${{ needs.release.outputs.new_version }} -OutputDirectory ../../artifacts - name: Publish to NuGet if: ${{ secrets.NUGET_API_KEY != '' }} run: | - dotnet nuget push artifacts/*.nupkg \ - --api-key ${{ secrets.NUGET_API_KEY }} \ - --source https://api.nuget.org/v3/index.json \ - --skip-duplicate + 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 @@ -322,6 +284,7 @@ jobs: 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 @@ -338,8 +301,11 @@ jobs: git rm packages.config git rm packages.config.meta --ignore-unmatch fi - git commit -am "fix: src => root" + 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 From b003facf43297f3885a6d98be5a461f108305731 Mon Sep 17 00:00:00 2001 From: Juan David Nicholls Cardona Date: Sun, 15 Mar 2026 20:25:54 -0500 Subject: [PATCH 11/11] fix(ci): remove secrets context from if condition (not allowed in expressions) --- .github/workflows/release.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index abbdeea..29faf7d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -243,12 +243,13 @@ jobs: nuget pack Proyecto26.RestClient.nuspec -Version ${{ needs.release.outputs.new_version }} -OutputDirectory ../../artifacts - name: Publish to NuGet - if: ${{ secrets.NUGET_API_KEY != '' }} run: | nuget push artifacts/*.nupkg \ -ApiKey ${{ secrets.NUGET_API_KEY }} \ -Source https://api.nuget.org/v3/index.json \ -SkipDuplicate + env: + NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }} split-branches: name: Split UPM & NuGet branches