Merge pull request #97 from Brain-Modulation-Lab/fix/fix-linux-dir-build #8
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CD | |
| on: | |
| push: | |
| tags: | |
| - "v*" | |
| workflow_dispatch: | |
| inputs: | |
| publish_release: | |
| description: "Publish a GitHub Release (manual runs only)" | |
| required: false | |
| default: false | |
| type: boolean | |
| sign_artifacts: | |
| description: "Enable code-signing steps if signing secrets are present" | |
| required: false | |
| default: false | |
| type: boolean | |
| permissions: | |
| contents: write | |
| jobs: | |
| # --------------------------------------------------------------------------- | |
| # Pre-flight gates. These run on every invocation and block all build jobs | |
| # from starting if the release artifact would be inconsistent with the | |
| # sources. Both gates are skipped for `workflow_dispatch` runs where | |
| # `publish_release=false`, so maintainers can still dry-run the build matrix | |
| # without a tag. | |
| # --------------------------------------------------------------------------- | |
| changelog-gate: | |
| name: CHANGELOG.md has section for tag | |
| runs-on: ubuntu-latest | |
| if: ${{ github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.publish_release) }} | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| - name: Verify CHANGELOG.md contains the tagged version | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| ref="${GITHUB_REF_NAME}" | |
| # Strip leading `v` (tags are `vX.Y.Z`; CHANGELOG uses `[X.Y.Z]`). | |
| version="${ref#v}" | |
| if ! grep -qE "^## \[${version}\]( - [0-9]{4}-[0-9]{2}-[0-9]{2})?$" CHANGELOG.md; then | |
| echo "::error file=CHANGELOG.md::Missing '## [${version}]' section in CHANGELOG.md" >&2 | |
| echo "Expected a heading like '## [${version}] - YYYY-MM-DD' (Keep a Changelog)." >&2 | |
| exit 1 | |
| fi | |
| echo "CHANGELOG.md contains a section for ${version}." | |
| - name: Ensure no unreleased Towncrier fragments remain | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| shopt -s nullglob | |
| fragments=(newsfragments/*.added.md newsfragments/*.changed.md newsfragments/*.deprecated.md newsfragments/*.removed.md newsfragments/*.fixed.md newsfragments/*.security.md) | |
| if [ "${#fragments[@]}" -gt 0 ]; then | |
| echo "::error::Unreleased Towncrier fragments remain. Build CHANGELOG.md before tagging:" >&2 | |
| printf ' - %s\n' "${fragments[@]}" >&2 | |
| exit 1 | |
| fi | |
| version-consistency: | |
| name: Version is consistent across sources | |
| runs-on: ubuntu-latest | |
| if: ${{ github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.publish_release) }} | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| - name: Set up uv with Python | |
| uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b | |
| with: | |
| python-version: "3.12" | |
| enable-cache: true | |
| - name: Verify __version__, [tool.briefcase].version, and git tag agree | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| ref="${GITHUB_REF_NAME}" | |
| tag_version="${ref#v}" | |
| pkg_version=$(uv run --no-sync --no-project python -c "import re, pathlib; \ | |
| src = pathlib.Path('src/dbs_annotator/__init__.py').read_text(); \ | |
| m = re.search(r'^__version__\\s*=\\s*[\"\\'](?P<v>[^\"\\']+)[\"\\']', src, re.MULTILINE); \ | |
| print(m.group('v') if m else '')") | |
| briefcase_version=$(uv run --no-sync --no-project python -c "import tomllib, pathlib; \ | |
| data = tomllib.loads(pathlib.Path('pyproject.toml').read_text()); \ | |
| print(data['tool']['briefcase'].get('version', ''))") | |
| echo "git tag : ${tag_version}" | |
| echo "__version__ : ${pkg_version}" | |
| echo "[tool.briefcase].ver : ${briefcase_version}" | |
| fail=0 | |
| if [ "${pkg_version}" != "${tag_version}" ]; then | |
| echo "::error file=src/dbs_annotator/__init__.py::__version__ (${pkg_version}) != tag (${tag_version})" >&2 | |
| fail=1 | |
| fi | |
| if [ "${briefcase_version}" != "${tag_version}" ]; then | |
| echo "::error file=pyproject.toml::[tool.briefcase].version (${briefcase_version}) != tag (${tag_version})" >&2 | |
| fail=1 | |
| fi | |
| exit "${fail}" | |
| build-python-dist: | |
| name: Build Python distribution | |
| runs-on: ubuntu-latest | |
| needs: | |
| - changelog-gate | |
| - version-consistency | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| - name: Set up uv with Python | |
| uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b | |
| with: | |
| python-version: "3.12" | |
| enable-cache: true | |
| - name: Build distribution | |
| run: | | |
| uv build | |
| - name: Upload Python dist artifacts | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: python-dist | |
| path: dist/* | |
| if-no-files-found: error | |
| publish-docs: | |
| name: Trigger Read the Docs tag build | |
| runs-on: ubuntu-latest | |
| needs: | |
| - changelog-gate | |
| - version-consistency | |
| if: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') }} | |
| steps: | |
| - name: Trigger RTD build for this tag version | |
| shell: bash | |
| env: | |
| READTHEDOCS_TOKEN: ${{ secrets.READTHEDOCS_TOKEN }} | |
| # Update if your RTD slug differs. | |
| READTHEDOCS_PROJECT_SLUG: app-clinicaldbsannot | |
| run: | | |
| set -euo pipefail | |
| if [ -z "${READTHEDOCS_TOKEN:-}" ]; then | |
| echo "READTHEDOCS_TOKEN is not configured; skipping RTD trigger." | |
| exit 0 | |
| fi | |
| version="${GITHUB_REF_NAME}" | |
| echo "Triggering RTD build for project=${READTHEDOCS_PROJECT_SLUG}, version=${version}" | |
| curl -fsS -X POST \ | |
| -H "Authorization: Token ${READTHEDOCS_TOKEN}" \ | |
| "https://readthedocs.org/api/v3/projects/${READTHEDOCS_PROJECT_SLUG}/versions/${version}/builds/" | |
| build-briefcase-msi: | |
| name: Build Briefcase MSI (Windows) | |
| runs-on: windows-latest | |
| needs: | |
| - changelog-gate | |
| - version-consistency | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| - name: Set up uv | |
| uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b | |
| with: | |
| python-version: "3.12" | |
| enable-cache: true | |
| - name: Set up .NET SDK | |
| uses: actions/setup-dotnet@v5 | |
| with: | |
| dotnet-version: "8.0.x" | |
| - name: Install WiX CLI (prefer modern toolchain) | |
| shell: pwsh | |
| run: | | |
| dotnet tool install --global wix --version "5.*" | |
| "$env:USERPROFILE\.dotnet\tools" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append | |
| wix --version | |
| # Briefcase can use WIX env var; point it at the known-good CLI install. | |
| $wixExe = Join-Path $env:USERPROFILE ".dotnet\tools\wix.exe" | |
| if (-not (Test-Path $wixExe)) { | |
| throw "WiX executable not found at expected path: $wixExe" | |
| } | |
| "WIX=$wixExe" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append | |
| - name: Sync dependencies (incl. build / Briefcase) | |
| run: | | |
| uv sync --locked --dev --group build | |
| - name: Export lock-derived constraints for Briefcase (Windows) | |
| run: | | |
| uv export --locked --format requirements.txt --no-dev --no-hashes --no-emit-project --no-emit-workspace --output-file constraints-briefcase.txt | |
| - name: Briefcase create / build / package (msi + zip raw) | |
| env: | |
| QT_QPA_PLATFORM: offscreen | |
| PIP_INDEX_URL: https://pypi.org/simple | |
| PIP_EXTRA_INDEX_URL: "" | |
| PIP_NO_CACHE_DIR: "1" | |
| run: | | |
| uv run briefcase create --no-input | |
| uv run briefcase build --no-input | |
| uv run briefcase package --no-input -p msi | |
| uv run briefcase package --no-input -p zip | |
| - name: Name Windows raw portable archive | |
| shell: pwsh | |
| run: | | |
| $v = $env:GITHUB_REF_NAME -replace '^v','' | |
| $z = Get-ChildItem -Path dist -Filter *.zip -File -ErrorAction SilentlyContinue | Select-Object -First 1 | |
| if (-not $z) { throw "No .zip in dist/ after briefcase package -p zip" } | |
| $raw = "DBSAnnotator-$v-windows-x86_64-raw.zip" | |
| if ($z.Name -ne $raw) { | |
| Move-Item -LiteralPath $z.FullName -Destination (Join-Path "dist" $raw) -Force | |
| } | |
| Write-Host "Windows raw: dist/$raw" | |
| # step.if cannot use secrets.* (actionlint / GHA); probe via env then gate signing. | |
| - name: Detect Windows signing secrets | |
| id: win_signing | |
| shell: bash | |
| env: | |
| WINDOWS_SIGN_PFX_BASE64: ${{ secrets.WINDOWS_SIGN_PFX_BASE64 }} | |
| WINDOWS_SIGN_PFX_PASSWORD: ${{ secrets.WINDOWS_SIGN_PFX_PASSWORD }} | |
| run: | | |
| if [ -n "${WINDOWS_SIGN_PFX_BASE64}" ] && [ -n "${WINDOWS_SIGN_PFX_PASSWORD}" ]; then | |
| echo "ready=true" >> "${GITHUB_OUTPUT}" | |
| else | |
| echo "ready=false" >> "${GITHUB_OUTPUT}" | |
| fi | |
| - name: Validate Windows signing secrets (optional gate) | |
| if: ${{ github.event_name == 'workflow_dispatch' && inputs.sign_artifacts }} | |
| shell: pwsh | |
| env: | |
| WINDOWS_SIGN_PFX_BASE64: ${{ secrets.WINDOWS_SIGN_PFX_BASE64 }} | |
| WINDOWS_SIGN_PFX_PASSWORD: ${{ secrets.WINDOWS_SIGN_PFX_PASSWORD }} | |
| run: | | |
| if ([string]::IsNullOrWhiteSpace($env:WINDOWS_SIGN_PFX_BASE64) -or [string]::IsNullOrWhiteSpace($env:WINDOWS_SIGN_PFX_PASSWORD)) { | |
| throw "sign_artifacts=true but Windows signing secrets are missing." | |
| } | |
| - name: Sign MSI (optional) | |
| if: >- | |
| ${{ | |
| (github.event_name == 'workflow_dispatch' && inputs.sign_artifacts) || | |
| (github.event_name == 'push' && steps.win_signing.outputs.ready == 'true') | |
| }} | |
| shell: pwsh | |
| env: | |
| WINDOWS_SIGN_PFX_BASE64: ${{ secrets.WINDOWS_SIGN_PFX_BASE64 }} | |
| WINDOWS_SIGN_PFX_PASSWORD: ${{ secrets.WINDOWS_SIGN_PFX_PASSWORD }} | |
| run: | | |
| $pfxPath = Join-Path $env:RUNNER_TEMP "codesign.pfx" | |
| [IO.File]::WriteAllBytes($pfxPath, [Convert]::FromBase64String($env:WINDOWS_SIGN_PFX_BASE64)) | |
| $secure = ConvertTo-SecureString $env:WINDOWS_SIGN_PFX_PASSWORD -AsPlainText -Force | |
| Import-PfxCertificate -FilePath $pfxPath -Password $secure -CertStoreLocation Cert:\CurrentUser\My | Out-Null | |
| $msis = Get-ChildItem -Path dist -Filter *.msi -Recurse | |
| if (-not $msis) { throw "No MSI found under dist/ to sign." } | |
| foreach ($msi in $msis) { | |
| signtool sign /fd SHA256 /td SHA256 /tr http://timestamp.digicert.com /a "$($msi.FullName)" | |
| } | |
| - name: Upload Briefcase MSI artifacts | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: briefcase-msi | |
| path: dist/* | |
| if-no-files-found: error | |
| build-briefcase-macos-arm: | |
| name: Build Briefcase macOS DMG (arm64) | |
| runs-on: macos-14 | |
| needs: | |
| - changelog-gate | |
| - version-consistency | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| - name: Set up uv | |
| uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b | |
| with: | |
| python-version: "3.12" | |
| enable-cache: true | |
| - name: Sync dependencies (incl. build / Briefcase) | |
| run: | | |
| uv sync --locked --dev --group build | |
| - name: Export lock-derived constraints for Briefcase (macOS) | |
| run: | | |
| uv export --locked --format requirements.txt --no-dev --no-hashes --no-emit-project --no-emit-workspace --output-file constraints-briefcase.txt | |
| - name: Briefcase create / build / package (dmg) | |
| env: | |
| QT_QPA_PLATFORM: offscreen | |
| PIP_INDEX_URL: https://pypi.org/simple | |
| PIP_EXTRA_INDEX_URL: "" | |
| PIP_NO_CACHE_DIR: "1" | |
| run: | | |
| set -euo pipefail | |
| uv run briefcase create --no-input | |
| uv run briefcase build --no-input | |
| # --adhoc-sign keeps `briefcase package` non-interactive when no Apple Developer | |
| # ID is configured. When signing secrets ARE provided, the dedicated | |
| # "Sign and notarize DMG" step below re-signs and notarizes the artifact. | |
| uv run briefcase package --no-input --adhoc-sign -p dmg | |
| - name: Detect macOS signing secrets | |
| id: mac_signing | |
| shell: bash | |
| env: | |
| APPLE_IDENTITY: ${{ secrets.APPLE_IDENTITY }} | |
| APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }} | |
| APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }} | |
| APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }} | |
| run: | | |
| if [ -n "${APPLE_IDENTITY}" ] && [ -n "${APPLE_API_ISSUER}" ] && \ | |
| [ -n "${APPLE_API_KEY_ID}" ] && [ -n "${APPLE_API_KEY}" ]; then | |
| echo "ready=true" >> "${GITHUB_OUTPUT}" | |
| else | |
| echo "ready=false" >> "${GITHUB_OUTPUT}" | |
| fi | |
| - name: Validate macOS signing secrets (optional gate) | |
| if: ${{ github.event_name == 'workflow_dispatch' && inputs.sign_artifacts }} | |
| shell: bash | |
| env: | |
| APPLE_IDENTITY: ${{ secrets.APPLE_IDENTITY }} | |
| APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }} | |
| APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }} | |
| APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }} | |
| run: | | |
| for var in APPLE_IDENTITY APPLE_API_ISSUER APPLE_API_KEY_ID APPLE_API_KEY; do | |
| if [ -z "${!var}" ]; then | |
| echo "sign_artifacts=true but missing secret: $var" >&2 | |
| exit 1 | |
| fi | |
| done | |
| - name: Sign and notarize DMG (optional) | |
| if: >- | |
| ${{ | |
| (github.event_name == 'workflow_dispatch' && inputs.sign_artifacts) || | |
| (github.event_name == 'push' && steps.mac_signing.outputs.ready == 'true') | |
| }} | |
| shell: bash | |
| env: | |
| APPLE_IDENTITY: ${{ secrets.APPLE_IDENTITY }} | |
| APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }} | |
| APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }} | |
| APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }} | |
| run: | | |
| KEY_PATH="$RUNNER_TEMP/AuthKey_${APPLE_API_KEY_ID}.p8" | |
| printf '%s' "$APPLE_API_KEY" > "$KEY_PATH" | |
| mapfile -t DMGS < <(find dist -name '*.dmg' -type f) | |
| if [ "${#DMGS[@]}" -eq 0 ]; then | |
| echo "No DMG found under dist/ to sign." >&2 | |
| exit 1 | |
| fi | |
| for dmg in "${DMGS[@]}"; do | |
| codesign --force --sign "$APPLE_IDENTITY" "$dmg" | |
| xcrun notarytool submit "$dmg" --key "$KEY_PATH" --key-id "$APPLE_API_KEY_ID" --issuer "$APPLE_API_ISSUER" --wait | |
| xcrun stapler staple "$dmg" | |
| done | |
| - name: Create macOS raw .app bundle archive (no DMG) | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| v="${GITHUB_REF_NAME#v}" | |
| app_path=$(find build/dbs_annotator/macos -name "DBSAnnotator.app" -type d 2>/dev/null | head -1) | |
| if [ -z "$app_path" ]; then | |
| echo "::error::DBSAnnotator.app not found under build/dbs_annotator/macos" >&2 | |
| exit 1 | |
| fi | |
| parent=$(dirname "$app_path") | |
| out="${GITHUB_WORKSPACE}/dist/DBSAnnotator-${v}-macos-arm64-raw.tar.gz" | |
| (cd "$parent" && tar -czf "$out" "DBSAnnotator.app") | |
| echo "macOS raw: dist/DBSAnnotator-${v}-macos-arm64-raw.tar.gz" | |
| - name: Upload Briefcase macOS artifacts | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: briefcase-macos-arm64 | |
| path: dist/* | |
| if-no-files-found: error | |
| build-briefcase-linux-x86: | |
| name: Build Briefcase Linux package (x86_64) | |
| runs-on: ubuntu-latest | |
| needs: | |
| - changelog-gate | |
| - version-consistency | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| - name: Set up uv | |
| uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b | |
| with: | |
| python-version: "3.12" | |
| enable-cache: true | |
| # PySide6 links libEGL even for offscreen; ubuntu-latest images omit it by default. | |
| - name: Install Qt EGL/XCB dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y --no-install-recommends \ | |
| libegl1 \ | |
| libgl1 \ | |
| libxkbcommon0 \ | |
| libdbus-1-3 | |
| - name: Sync dependencies (incl. build / Briefcase) | |
| run: | | |
| uv sync --locked --dev --group build | |
| - name: Export lock-derived constraints for Briefcase (Linux) | |
| run: | | |
| uv export --locked --format requirements.txt --no-dev --no-hashes --no-emit-project --no-emit-workspace --output-file constraints-briefcase.txt | |
| - name: Briefcase create / build / package (linux system) | |
| env: | |
| QT_QPA_PLATFORM: offscreen | |
| PIP_INDEX_URL: https://pypi.org/simple | |
| PIP_EXTRA_INDEX_URL: "" | |
| PIP_NO_CACHE_DIR: "1" | |
| run: | | |
| uv run briefcase create linux system --no-input | |
| uv run briefcase build linux system --no-input | |
| uv run briefcase package linux system --no-input | |
| - name: Create Linux raw app tree archive (no .deb) | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| v="${GITHUB_REF_NAME#v}" | |
| # Briefcase linux system: build/<app>/<vendor>/<codename>/... (not .../linux/...). | |
| # Raw tar must include usr/bin launcher + usr/lib payload. | |
| root="build/dbs_annotator" | |
| if [ ! -d "${root}" ]; then | |
| echo "::error::Missing Briefcase build tree at ${root}" >&2 | |
| find build -maxdepth 3 -type d 2>/dev/null | head -40 >&2 || true | |
| exit 1 | |
| fi | |
| # Find candidate package roots that contain usr/bin (launcher) and usr/lib/*/app. | |
| pkg_root="" | |
| if largest=$(find "${root}" -type d -name usr 2>/dev/null | while read -r d; do | |
| p="$(dirname "$d")" | |
| [ -d "${p}/usr/bin" ] || continue | |
| [ -n "$(find "${p}/usr/bin" -mindepth 1 -maxdepth 1 -type f 2>/dev/null | head -n 1)" ] || continue | |
| [ -d "${p}/usr/lib/dbs_annotator/app" ] || continue | |
| du -sk "$p" 2>/dev/null | |
| done | sort -n | tail -1); then | |
| pkg_root=${largest#*[[:space:]]} | |
| fi | |
| if [ -z "${pkg_root}" ]; then | |
| echo "::error::No Briefcase Linux package root with non-empty usr/bin under ${root}. Listing usr candidates:" >&2 | |
| find "${root}" -type d -name usr 2>/dev/null | while read -r d; do | |
| p="$(dirname "$d")" | |
| echo "--- $p" >&2 | |
| du -sh "$p" 2>/dev/null || true | |
| find "${p}/usr/bin" -mindepth 1 -maxdepth 1 2>/dev/null | head -20 >&2 || true | |
| find "${p}/usr/lib/dbs_annotator/app" -mindepth 1 -maxdepth 1 2>/dev/null | head -5 >&2 || true | |
| done | |
| exit 1 | |
| fi | |
| # Also verify app payload exists so raw tar isn't launcher-only. | |
| if [ ! -d "${pkg_root}/usr/lib/dbs_annotator/app" ] || [ -z "$(find "${pkg_root}/usr/lib/dbs_annotator/app" -mindepth 1 -maxdepth 1 2>/dev/null | head -n 1)" ]; then | |
| echo "::error::Selected package root lacks non-empty usr/lib/dbs_annotator/app payload: ${pkg_root}" >&2 | |
| exit 1 | |
| fi | |
| out="${GITHUB_WORKSPACE}/dist/dbs-annotator_${v}_linux_x86_64-raw.tar.gz" | |
| (cd "${pkg_root}" && tar -czf "${out}" usr) | |
| echo "Linux raw: dist/dbs-annotator_${v}_linux_x86_64-raw.tar.gz" | |
| echo "Included launcher files:" | |
| find "${pkg_root}/usr/bin" -mindepth 1 -maxdepth 1 -type f 2>/dev/null | sed "s#^${pkg_root}/##" | head -20 | |
| - name: Upload Briefcase Linux artifacts | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: briefcase-linux-x86_64 | |
| path: dist/* | |
| if-no-files-found: error | |
| release: | |
| name: Create GitHub Release and upload artifacts | |
| runs-on: ubuntu-latest | |
| needs: | |
| - build-python-dist | |
| - build-briefcase-msi | |
| - build-briefcase-macos-arm | |
| - build-briefcase-linux-x86 | |
| if: ${{ github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.publish_release) }} | |
| steps: | |
| - name: Download build artifacts | |
| uses: actions/download-artifact@v8 | |
| with: | |
| path: release-assets | |
| merge-multiple: true | |
| - name: Create GitHub Release and upload artifacts | |
| uses: softprops/action-gh-release@v3 | |
| with: | |
| tag_name: ${{ github.ref_name }} | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| fail_on_unmatched_files: false | |
| generate_release_notes: true | |
| working_directory: release-assets | |
| files: | | |
| **/* |