tauri-action icon indicating copy to clipboard operation
tauri-action copied to clipboard

Option to change base URL in latest.json

Open betamos opened this issue 1 year ago • 9 comments

I use a private Github repo for my app and want to host the binaries outside of Github (in my case Cloudflare R2).

I currently:

  • Use this Github action to build the app and publish to my private repo's packages
  • Transfer the directory with all assets to a directory named after the current version in R2
  • Modify the links in latest.json manually to point to a public R2 URL, e.g. https://releases.example.com/v0.2.0/App_universal.tar.gz
  • Upload latest.json to R2

Currently, the generated latest.json file contains github URLs for the releases. I would like it to point to my host's path ( etc) instead (note this includes the version).

However, I am open to other options. Perhaps I should be not be using static files at all. Or perhaps, there should be an option to upload to S3-compatible stores instead of Github. Feel free to suggest something better.

betamos avatar Aug 10 '24 14:08 betamos

Thanks for your request! ~~Since uploading to other targets than github is currently considered out of scope for this action i will mark this as wontfix for now.~~

I'd love to write the latest.json file into the job output like the build artifacts but that's not possible with how the file is (currently) getting generated. 🤔

Edit: Hmm, maybe providing a (potentionally undocumented) option for a base url wouldn't be too bad. Should be simple enough.

FabianLars avatar Aug 10 '24 18:08 FabianLars

Thanks for the swift response.

I do think all options should be documented, Github Actions is difficult enough to use as it is.

That said, to prevent XY problems: my FR is I want to host my stuff elsewhere, and that part should be common (even if Cloudflare R2 may be niche). I do want to have a full CD pipeline eventually, but I don't expect this repo to anticipate all weird use cases, like mine.

My Actions knowledge is minimal, but here's an idea:

  • Add an option to disable uploading artifacts to Github Packages
  • Add an option for base URL
  • For users like me: add a custom step after the Tauri action which uses artifactPaths output to invoke a custom upload, using e.g. FTP, S3 etc

Would something like that make sense?

betamos avatar Aug 10 '24 18:08 betamos

Uploading the packages to a release is optional if you're okay with the action not creating a github release at all. The problem is that if the action does not upload the packages, it won't be able to create a json file either because it needs to collect the packages across the different runners and it currently relies on the release for that.

At that point creating the json file from scratch yourself would probably be easier for you and us.

FabianLars avatar Aug 10 '24 19:08 FabianLars

Ah, right. Multiple jobs makes it more complicated.

The main issue is that the artifact file names (of zip and tar files) are not deterministic within stable Tauri. They've changed in the past and might change in the future, or simply based on config changes (say MSI to NSIS).

As a result, both steps (uploading & referencing them for the updater) benefit from a single source of truth for CD purposes. So to be safe(r) I'm trusting latest.json for now (at least more than me hard-coding them). So, an optional base URL arg would be helpful. For now, I'm using sed to replace it:

sed -i -e 's#https:.*\/#https://releases.example.com/v0.2.0/#' latest.json

betamos avatar Aug 11 '24 12:08 betamos

Maybe the action can output found artifacts names (or full paths) so any following steps can generate requires fields on their own?

JokerQyou avatar Nov 09 '24 14:11 JokerQyou

it already does https://github.com/tauri-apps/tauri-action#outputs

FabianLars avatar Nov 09 '24 16:11 FabianLars

I trigger a separate workflow when the tauri workflow completes. You can also dispatch an S3 upload (R2 in this case) manually by specifying the release tag. Useful as you don't need to rebuild if just the transfer fails.

This way you have the full release as all jobs in the previous workflow are complete. Simply gh release download to download all assets, aws s3 cp to upload them, and sed to replace links in latest.json

name: 'Upload Release to R2'

on:
  workflow_run:
    workflows: ["Release Tauri App"]
    types:
      - completed
  workflow_dispatch:
    inputs:
      release-tag:
        description: 'Release tag (e.g., v1.0.0 or v1.0.0-pre)'
        required: true
        type: string

jobs:
  upload-to-r2:
    if: ${{ github.event.workflow_run.conclusion == 'success' || github.event_name == 'workflow_dispatch' }}
    runs-on: ubuntu-latest
    permissions:
      contents: read
      actions: read

    steps:
      - uses: actions/checkout@v4

      - name: Get release and download assets
        id: download-assets
        run: |
          if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
            # Manual trigger - use provided release tag
            TAG_NAME="${{ github.event.inputs.release-tag }}"
            echo "Manual trigger: Looking for release with tag: $TAG_NAME"
          else
            # Automatic trigger from workflow_run
            echo "Automatic trigger: Finding release created by workflow run..."

            # Get the commit SHA from the triggering workflow run
            HEAD_SHA="${{ github.event.workflow_run.head_sha }}"
            echo "Looking for release with commit SHA: $HEAD_SHA"

            # Find the release that matches this commit SHA
            RELEASE_DATA=$(gh api repos/${{ github.repository }}/releases | \
              jq -r --arg sha "$HEAD_SHA" '.[] | select(.target_commitish == $sha)')

            if [[ -z "$RELEASE_DATA" || "$RELEASE_DATA" == "null" ]]; then
              echo "❌ No release found for commit SHA: $HEAD_SHA"
              echo "This might indicate the release workflow failed or the release was created with a different commit."
              exit 1
            fi

            TAG_NAME=$(echo "$RELEASE_DATA" | jq -r '.tag_name')
          fi

          echo "Found release: $TAG_NAME"
          echo "tag-name=$TAG_NAME" >> $GITHUB_OUTPUT

          # Create directory for assets
          mkdir -p release-assets

          # Download all assets for the release using GitHub CLI
          echo "Downloading all assets for release $TAG_NAME..."
          cd release-assets

          if gh release download "$TAG_NAME" --repo ${{ github.repository }}; then
            echo "✅ Successfully downloaded all assets"

            # List downloaded files with sizes
            echo "Downloaded files:"
            ls -lah
          else
            echo "❌ Failed to download assets for release $TAG_NAME"
            exit 1
          fi
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Configure AWS CLI for Cloudflare R2
        run: |
          aws configure set aws_access_key_id ${{ secrets.R2_ACCESS_KEY_ID }}
          aws configure set aws_secret_access_key ${{ secrets.R2_SECRET_ACCESS_KEY }}

      - name: Upload artifacts to Cloudflare R2
        run: |
          TAG_NAME="${{ steps.download-assets.outputs.tag-name }}"

          for file in release-assets/*; do
            if [[ -f "$file" ]]; then
              filename=$(basename "$file")

              # Skip latest.json - it will be handled separately
              if [[ "$filename" == "latest.json" ]]; then
                echo "Skipping $filename for separate processing"
                continue
              fi

              echo "Uploading $filename to $TAG_NAME/"
              aws s3 cp "$file" s3://${{ secrets.R2_BUCKET_PREFIX }}/$TAG_NAME/ --endpoint-url ${{ secrets.R2_ENDPOINT_URL }} --checksum-algorithm CRC32
            fi
          done

          echo "✅ All artifacts uploaded to R2 successfully!"

      - name: Process and upload latest.json
        if: ${{ !contains(steps.download-assets.outputs.tag-name, 'pre') }}
        run: |
          TAG_NAME="${{ steps.download-assets.outputs.tag-name }}"

          if [[ -f "release-assets/latest.json" ]]; then
            echo "Processing latest.json..."

            # Replace GitHub URLs with R2 URLs
            sed "s|https://github.com/${{ github.repository }}/releases/download/[^/]*/|${{ secrets.R2_BASE_URL }}/$TAG_NAME/|g" \
              release-assets/latest.json > release-assets/latest-processed.json

            echo "Uploading latest.json to bucket root..."
            aws s3 cp release-assets/latest-processed.json s3://${{ secrets.R2_BUCKET_PREFIX }}/latest.json --endpoint-url ${{ secrets.R2_ENDPOINT_URL }} --checksum-algorithm CRC32

            echo "✅ latest.json processed and uploaded successfully!"
          else
            echo "⚠️ latest.json not found in release assets"
          fi

TheUltDev avatar Jun 04 '25 07:06 TheUltDev

how ya'll handle the weird file names (all kind of characters replaced with . by github)? Do you keep the github names?

if i were to add an option for this (still not fond of the idea) in v1 (so a breaking change) should the urls rather keep the original file name when there's a baseUrl set?

FabianLars avatar Nov 17 '25 21:11 FabianLars

Hmm i'll put this on the backburner again. Since it'd be opt-in we can add it after v1 as well.

Another question would be how much customization we should offer, should it have a syntax similar to releaseAssetNamePattern? I think that'd only make sense without the filename modification since we'd may have to rename the files on disk for that to really make sense.

FabianLars avatar Nov 18 '25 10:11 FabianLars