Skip to content

Set up Snap and Winget distribution workflows#41

Merged
remcostoeten merged 1 commit intomasterfrom
packaging-release-workflows
Apr 5, 2026
Merged

Set up Snap and Winget distribution workflows#41
remcostoeten merged 1 commit intomasterfrom
packaging-release-workflows

Conversation

@remcostoeten
Copy link
Copy Markdown
Owner

@remcostoeten remcostoeten commented Apr 5, 2026

Summary

  • add release-ready Snap and Winget GitHub workflows
  • document the distribution flow and check in the initial 0.0.102 Winget manifests
  • update Snap packaging to derive the release version at build time

Verification

Summary by Sourcery

Add in-repo support for building and publishing Dora via Snap and Winget, including automation workflows, packaging metadata, and operator documentation.

New Features:

  • Introduce a Winget manifest generator script and initial versioned manifests for Dora.
  • Add Snap packaging configuration to build a distributable snap for Dora.

Enhancements:

  • Automate Winget manifest generation and optional update submissions via a dedicated GitHub Actions workflow tied to releases.
  • Automate Snap build, artifact upload, and optional Snap Store publishing through a GitHub Actions workflow that derives the release version at build time.
  • Document end-to-end distribution flows for Winget and Snap, including a one-machine packaging playbook and an interactive release guide script.

Summary by CodeRabbit

  • New Features

    • Added Snap package distribution support with automated build, upload, and Snap Store publishing.
    • Added Winget package distribution support with automated manifest generation and optional update submissions.
  • Documentation

    • Added comprehensive distribution guides for Snap and Winget.
    • Added release guide and single-machine playbook for packaging workflows.

@vercel
Copy link
Copy Markdown
Contributor

vercel bot commented Apr 5, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
dora Building Building Preview, Comment Apr 5, 2026 7:19pm

@sourcery-ai
Copy link
Copy Markdown

sourcery-ai bot commented Apr 5, 2026

Reviewer's Guide

Adds automated Snap and Winget distribution pipelines plus documentation, a Winget manifest generator script, and initial 0.0.102 Winget manifests, and updates Snap packaging to derive the release version at build time from tags/package.json.

Sequence diagram for Winget manifest generation and update submission

sequenceDiagram
  actor Dev
  participant GitHub as GitHub_Releases
  participant WingetWF as Workflow_winget_yml
  participant GenJob as Job_generate_manifests
  participant Script as generate_winget_manifest_ts
  participant Artifacts as GitHub_Artifacts
  participant UpdateJob as Job_submit_update
  participant WingetCreate as wingetcreate
  participant WingetPkgs as microsoft_winget_pkgs

  Dev->>GitHub: Publish tagged release vX_Y_Z
  GitHub-->>WingetWF: Trigger on release.published

  WingetWF->>GenJob: Start job generate-manifests
  GenJob->>GitHub: Resolve tag, version, installer_url, checksums_url
  GenJob->>GitHub: Download checksums-windows.txt

  GenJob->>Script: bun run release:winget -- version, installer-url, checksums-file, installer-file
  Script->>Script: Read checksum from file
  Script->>Script: Create version, locale, installer YAML manifests
  Script-->>GenJob: Write manifests under packaging/winget/manifests/version

  GenJob->>GenJob: Archive manifests to winget-manifests-<version>.tar.gz
  GenJob->>Artifacts: Upload artifact
  GenJob->>GitHub: Upload archive to release assets
  GenJob-->>WingetWF: Output tag, version, installer_url

  Note over WingetWF,UpdateJob: submit-update job is conditional on WINGET_PACKAGE_READY and WINGET_CREATE_GITHUB_TOKEN

  WingetWF->>UpdateJob: Start job submit-update
  UpdateJob->>WingetCreate: Install dependencies (VCLibs, wingetcreate)
  UpdateJob->>WingetCreate: wingetcreate update RemcoStoeten_Dora -u installer_url -v version -t WINGET_CREATE_GITHUB_TOKEN --submit
  WingetCreate->>WingetPkgs: Create update PR
  WingetPkgs-->>Dev: PR visible for review/merge
Loading

File-Level Changes

Change Details Files
Introduce a reusable Winget manifest generator script used by both local workflows and CI.
  • Add a TypeScript CLI that parses flags to build a Config object for Winget metadata and installer details
  • Implement checksum resolution from either an explicit SHA256 flag or a checksums file, supporting relative installer paths
  • Generate version, locale, and installer YAML manifests conforming to the Winget 1.9.0 schemas and write them into a versioned manifests directory
  • Log key metadata and write operations, exiting with a non‑zero code on error for CI‑friendliness
tools/scripts/generate-winget-manifest.ts
Add documentation for distribution flows and one-machine packaging, including release, Snap, and Winget steps.
  • Describe a one-machine packaging playbook, covering VM setup, release tagging, Winget bootstrap, AUR flow, and Snap flow
  • Document the Winget distribution pipeline, including manual first submission, repo-native manifest generation, CI automation, and local validation
  • Add a Snap distribution guide detailing local build commands, CI behavior, and Snapcraft credential setup
  • Introduce an interactive release-guide doc describing the release helper script and its checks and automation
docs/distribution/one-machine-playbook.md
docs/distribution/winget.md
docs/distribution/snap.md
docs/distribution/release-guide.md
Create a GitHub Actions workflow to generate and optionally submit Winget manifests on releases or manual runs.
  • On release or manual dispatch, resolve tag, version, installer URL, and checksums URL for the MSI installer
  • Download the Windows checksums file from the GitHub release and run the Winget manifest generator via bun
  • Archive the generated manifests into a tarball, upload it as an artifact, and attach it to the GitHub release
  • On Windows, optionally install WingetCreate and submit an update PR using wingetcreate update when repo variables/secrets are configured
.github/workflows/winget.yml
Add Snap packaging configuration and a CI workflow to build and optionally publish the snap.
  • Define snap metadata, confinement, plugs, and parts in snapcraft.yaml, including build dependencies and stage packages
  • In the Snap build, install Bun and Rust toolchains, derive the snap version from DORA_RELEASE_VERSION or package.json, and build the Tauri desktop app
  • Install the built binary, launcher script, desktop file, and icon into the snap filesystem layout
  • Add a GitHub Actions workflow that resolves release/tag metadata, builds the snap via snapcore/action-build, uploads it as an artifact, attaches it to releases, and optionally publishes to the Snap Store when credentials exist
snap/snapcraft.yaml
.github/workflows/snap.yml
Check in initial Winget manifests for version 0.0.102 and a packaging README describing their use.
  • Add version, default-locale, and installer manifests for Dora 0.0.102 pointing at the GitHub MSI and SHA256 hash
  • Document how to generate, validate, and use these manifests locally and in CI, including enabling automated update submissions
packaging/winget/README.md
packaging/winget/manifests/0.0.102/RemcoStoeten.Dora.yaml
packaging/winget/manifests/0.0.102/RemcoStoeten.Dora.locale.en-US.yaml
packaging/winget/manifests/0.0.102/RemcoStoeten.Dora.installer.yaml

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@remcostoeten remcostoeten merged commit b80a6cd into master Apr 5, 2026
4 of 8 checks passed
@remcostoeten remcostoeten deleted the packaging-release-workflows branch April 5, 2026 19:19
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 5, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2933b399-7c22-4a9b-a81e-0d1709e6efb4

📥 Commits

Reviewing files that changed from the base of the PR and between 5061220 and 12941f6.

📒 Files selected for processing (12)
  • .github/workflows/snap.yml
  • .github/workflows/winget.yml
  • docs/distribution/one-machine-playbook.md
  • docs/distribution/release-guide.md
  • docs/distribution/snap.md
  • docs/distribution/winget.md
  • packaging/winget/README.md
  • packaging/winget/manifests/0.0.102/RemcoStoeten.Dora.installer.yaml
  • packaging/winget/manifests/0.0.102/RemcoStoeten.Dora.locale.en-US.yaml
  • packaging/winget/manifests/0.0.102/RemcoStoeten.Dora.yaml
  • snap/snapcraft.yaml
  • tools/scripts/generate-winget-manifest.ts

📝 Walkthrough

Walkthrough

Introduces packaging and distribution infrastructure for multiple platforms. Adds GitHub Actions workflows for Snap and Winget packaging, corresponding configuration files, documentation guides, a utility script for generating Winget manifests, and example manifest files. Enables automated building, uploading, and publishing to distribution channels.

Changes

Cohort / File(s) Summary
GitHub Actions Workflows
.github/workflows/snap.yml, .github/workflows/winget.yml
New workflows for Snap package building/publishing and Winget manifest generation/submission on releases with configurable options via manual dispatch.
Snap Packaging Configuration
snap/snapcraft.yaml
Snapcraft manifest defining the dora snap application with strict confinement, required plugs, and multi-step build process including Node/Rust/Bun installation and Tauri app compilation.
Winget Manifest Utilities
tools/scripts/generate-winget-manifest.ts
TypeScript script to generate three Winget manifest YAML files (version, locale, installer) with CLI flag parsing, SHA-256 checksum resolution, and file I/O.
Winget Manifests
packaging/winget/manifests/0.0.102/*, packaging/winget/README.md
Example Winget manifest files for version 0.0.102 and README documenting the manifest structure and local/CI workflows.
Distribution Documentation
docs/distribution/one-machine-playbook.md, docs/distribution/release-guide.md, docs/distribution/snap.md, docs/distribution/winget.md
Guides covering single-machine packaging workflows, release automation script, Snap distribution setup, and Winget submission procedures.

Sequence Diagram(s)

sequenceDiagram
    participant GH as GitHub<br/>(Release)
    participant GA as GitHub<br/>Actions
    participant SC as Snapcraft<br/>Build
    participant GR as GitHub<br/>Release
    participant SS as Snap<br/>Store

    GH->>GA: Trigger on<br/>release.published
    GA->>GA: Resolve tag,<br/>version
    GA->>SC: Build snap<br/>(snapcore/action-build)
    SC-->>GA: .snap artifact
    GA->>GR: Upload .snap<br/>to release
    alt Credentials present
        GA->>SS: Publish snap<br/>to store
        SS-->>GA: Published
    end
    GA-->>GH: Workflow complete
Loading
sequenceDiagram
    participant GH as GitHub<br/>(Release/Dispatch)
    participant GA as GitHub<br/>Actions
    participant WM as Winget<br/>Manifest Gen
    participant GR as GitHub<br/>Release
    participant WP as Winget-pkgs<br/>(microsoft/repo)

    GH->>GA: Trigger on<br/>release.published
    GA->>GA: Resolve tag,<br/>version
    GA->>WM: Generate manifests<br/>(3 YAML files)
    WM-->>GA: Manifests
    GA->>GA: Archive to<br/>.tar.gz
    GA->>GR: Upload archive<br/>to release
    alt Submit enabled &<br/>credentials present
        GA->>WP: Submit update<br/>via wingetcreate
        WP-->>GA: PR created
    end
    GA-->>GH: Workflow complete
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 Hop, hop! What a day of distribution delight!
Snap builds sparkle, Winget manifests gleam so bright,
Workflows orchestrate the dance from source to store,
Our Dora now hops to platforms galore! ✨📦

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch packaging-release-workflows

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 2 issues, and left some high level feedback:

  • In snap/snapcraft.yaml the version: '0.0.102' field will quickly drift from the dynamically set version in the Snap workflow (craftctl set version=$DORA_RELEASE_VERSION); consider changing the manifest to use a placeholder (e.g. git) or a neutral value and rely solely on the workflow-set version to avoid mismatches between the snap metadata and the actual release tag.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `snap/snapcraft.yaml` the `version: '0.0.102'` field will quickly drift from the dynamically set version in the Snap workflow (`craftctl set version=$DORA_RELEASE_VERSION`); consider changing the manifest to use a placeholder (e.g. `git`) or a neutral value and rely solely on the workflow-set version to avoid mismatches between the snap metadata and the actual release tag.

## Individual Comments

### Comment 1
<location path="tools/scripts/generate-winget-manifest.ts" line_range="50-51" />
<code_context>
+		.map((line) => line.trim())
+		.filter(Boolean)
+
+	for (const line of lines) {
+		const [hash, relativePath] = line.split(/\s{2,}/)
+		if (!hash || !relativePath) {
+			continue
</code_context>
<issue_to_address>
**issue (bug_risk):** Splitting checksums on 2+ spaces may fail for common single-space checksum formats.

`sha256sum`-style files are often `HASH<space>FILENAME`, `HASH<space><space>FILENAME`, or include tabs. Requiring 2+ whitespace characters (`/\s{2,}/`) will miss valid single-space lines and incorrectly hit the `Could not find ...` path. Using a more flexible split (e.g. `line.split(/\s+/)` or `const [hash, ...rest] = line.split(/\s+/); const relativePath = rest.join(' ');`) would handle the common checksum formats reliably.
</issue_to_address>

### Comment 2
<location path=".github/workflows/winget.yml" line_range="82-85" />
<code_context>
+          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+        run: gh release upload ${{ steps.meta.outputs.tag }} winget-manifests-${{ steps.meta.outputs.version }}.tar.gz --clobber
+
+  submit-update:
+    needs: generate-manifests
+    if: ${{ (github.event_name == 'release' && vars.WINGET_PACKAGE_READY == 'true') || (github.event_name == 'workflow_dispatch' && inputs.submit_update) }}
+    runs-on: windows-latest
+    env:
+      WINGET_CREATE_GITHUB_TOKEN: ${{ secrets.WINGET_CREATE_GITHUB_TOKEN }}
</code_context>
<issue_to_address>
**suggestion (performance):** The submit-update job always allocates a Windows runner even when the Winget token is missing.

Because the job always runs on `windows-latest`, it still allocates a Windows runner even when `WINGET_CREATE_GITHUB_TOKEN` is empty and the first step exits immediately. Consider moving the token check into the job-level `if:` (e.g. append `&& secrets.WINGET_CREATE_GITHUB_TOKEN != ''`) so the job is entirely skipped when the token isn’t configured.

Suggested implementation:

```
  submit-update:
    needs: generate-manifests
    if: ${{ ((github.event_name == 'release' && vars.WINGET_PACKAGE_READY == 'true') || (github.event_name == 'workflow_dispatch' && inputs.submit_update)) && secrets.WINGET_CREATE_GITHUB_TOKEN != '' }}
    runs-on: windows-latest
    env:
      WINGET_CREATE_GITHUB_TOKEN: ${{ secrets.WINGET_CREATE_GITHUB_TOKEN }}

```

```
    steps:
      - name: Install WingetCreate dependencies

```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +50 to +51
for (const line of lines) {
const [hash, relativePath] = line.split(/\s{2,}/)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Splitting checksums on 2+ spaces may fail for common single-space checksum formats.

sha256sum-style files are often HASH<space>FILENAME, HASH<space><space>FILENAME, or include tabs. Requiring 2+ whitespace characters (/\s{2,}/) will miss valid single-space lines and incorrectly hit the Could not find ... path. Using a more flexible split (e.g. line.split(/\s+/) or const [hash, ...rest] = line.split(/\s+/); const relativePath = rest.join(' ');) would handle the common checksum formats reliably.

Comment on lines +82 to +85
submit-update:
needs: generate-manifests
if: ${{ (github.event_name == 'release' && vars.WINGET_PACKAGE_READY == 'true') || (github.event_name == 'workflow_dispatch' && inputs.submit_update) }}
runs-on: windows-latest
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (performance): The submit-update job always allocates a Windows runner even when the Winget token is missing.

Because the job always runs on windows-latest, it still allocates a Windows runner even when WINGET_CREATE_GITHUB_TOKEN is empty and the first step exits immediately. Consider moving the token check into the job-level if: (e.g. append && secrets.WINGET_CREATE_GITHUB_TOKEN != '') so the job is entirely skipped when the token isn’t configured.

Suggested implementation:

  submit-update:
    needs: generate-manifests
    if: ${{ ((github.event_name == 'release' && vars.WINGET_PACKAGE_READY == 'true') || (github.event_name == 'workflow_dispatch' && inputs.submit_update)) && secrets.WINGET_CREATE_GITHUB_TOKEN != '' }}
    runs-on: windows-latest
    env:
      WINGET_CREATE_GITHUB_TOKEN: ${{ secrets.WINGET_CREATE_GITHUB_TOKEN }}

    steps:
      - name: Install WingetCreate dependencies

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant