Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ jobs:
sudo apt-get update
sudo apt-get install -y libxcb1-dev libx11-xcb-dev libxkbcommon-dev libxkbcommon-x11-dev \
libwayland-dev libvulkan-dev libfontconfig-dev libfreetype-dev libasound2-dev libzstd-dev
- name: Homebrew cask style
if: runner.os == 'macOS' && matrix.suite == 'core'
run: bash scripts/release/check-homebrew-cask.sh
- run: cargo fmt --all --check
if: runner.os == 'Linux'
- name: Clippy (core)
Expand Down
28 changes: 28 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -180,3 +180,31 @@ jobs:
fi
gh release create "v$RELEASE_VERSION" release/* --target "$GITHUB_SHA" \
--title "convt $RELEASE_VERSION" --notes-file "$RUNNER_TEMP/release-notes.md"
# Never blocks publication. Missing tap repo, branch protection, or a
# stale sha256 fetch must not fail the Release workflow.
homebrew:
name: Update Homebrew cask
if: always() && needs.preflight.outputs.publish == 'true' && needs.publish.result == 'success'
needs: [preflight, publish]
runs-on: ubuntu-24.04
timeout-minutes: 15
continue-on-error: true
permissions:
contents: write
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
ref: main
- uses: actions/setup-python@v6
with:
python-version: "3.12"
- name: Bump Casks/convt.rb from the published manifest
env:
HOMEBREW_TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
RELEASE_VERSION: ${{ needs.preflight.outputs.version }}
run: |
python3 scripts/release/update-homebrew-cask.py \
--cask Casks/convt.rb \
--from-manifest-url "https://github.com/${GITHUB_REPOSITORY}/releases/download/v${RELEASE_VERSION}/release-manifest.json" \
--commit --push --tap opencoredev/homebrew-tap
32 changes: 32 additions & 0 deletions Casks/convt.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
cask "convt" do
version "0.2.0"
sha256 "8fc47f8b9873adbf4ad6df1db9e050d74205c26cff7e8c7e919ce0d398ae2ea3"

url "https://github.com/opencoredev/convt/releases/download/v#{version}/convt-macos-arm64.dmg",
verified: "github.com/opencoredev/convt/"
name "convt"
desc "Convert files locally without uploading"
homepage "https://convt.app/"

livecheck do
url :url
strategy :github_latest
end

depends_on arch: :arm64
depends_on macos: :ventura

app "convt.app"
binary "#{appdir}/convt.app/Contents/MacOS/convt"

uninstall quit: "app.convt.desktop"

zap trash: [
"~/Library/Application Support/convt",
"~/Library/Caches/app.convt.desktop",
"~/Library/HTTPStorages/app.convt.desktop",
"~/Library/Logs/convt",
"~/Library/Preferences/app.convt.desktop.plist",
"~/Library/Saved Application State/app.convt.desktop.savedState",
]
end
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,14 @@ Local file conversion for your own machine. Right-click a file, pick a format, a

## Install

Download the app from [convt.app/download](https://convt.app/download). Release 0.2.0 has a disk image for macOS on Apple silicon and an MSI installer for Windows x86_64. The Linux packages (AppImage, .deb, .rpm and a tarball) build from `packaging/linux` but are not in a release yet. Packaged builds start a 7-day trial on the first conversion.
macOS (Apple silicon) with Homebrew:

```bash
brew tap opencoredev/convt https://github.com/opencoredev/convt
brew install --cask convt
```

That installs the signed app and puts the `convt` CLI on your `PATH`. Download the app from [convt.app/download](https://convt.app/download) for a disk image, Windows MSI, or Linux packages. There is no Linux Homebrew formula yet; use the `.deb`, `.rpm` or AppImage. Packaged builds start a 7-day trial on the first conversion.

To build from source:

Expand Down
12 changes: 12 additions & 0 deletions apps/web/src/components/site/download.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,15 @@ export function Sha({ value }: { value: string }) {
</div>
);
}

export function HomebrewInstall() {
return (
<div className="flex flex-col gap-1.5">
<p className="text-[13px]/5 text-ink-2">Or install with Homebrew (Apple silicon):</p>
<pre className="overflow-x-auto rounded-lg bg-sunken px-3 py-2 font-mono text-[12px]/5">
{`brew tap opencoredev/convt https://github.com/opencoredev/convt
brew install --cask convt`}
</pre>
</div>
);
}
4 changes: 3 additions & 1 deletion apps/web/src/routes/_site/download.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { createFileRoute } from "@tanstack/react-router";
import { createServerFn } from "@tanstack/react-start";

import { cx } from "#/components/app/ui";
import { DownloadButton, Sha } from "#/components/site/download";
import { DownloadButton, HomebrewInstall, Sha } from "#/components/site/download";
import { PageHeader, TextLink, siteColumn } from "#/components/site/layout";
import {
isOs,
Expand Down Expand Up @@ -125,6 +125,7 @@ function Recommended({ os }: { os: Os }) {
</div>
<DownloadButton artifact={slot?.artifact ?? null} large />
{slot?.artifact && <Sha value={slot.artifact.sha256} />}
{os === "macos" && <HomebrewInstall />}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔍 Homebrew instructions remain visible without downloads

When the macOS download says “Shipping today,” HomebrewInstall still offers an install command. Confirm whether that fallback is intended before the first published release or during manifest outages.

Devin Review


Was this helpful? React with 👍 or 👎 to provide feedback.

<p className="text-[13px]/5 text-ink-2">
Not your system?{" "}
<TextLink href="#platforms" className="font-normal">
Expand Down Expand Up @@ -187,6 +188,7 @@ function PlatformCard({ os, current }: { os: Os; current: boolean }) {
</li>
))}
</ul>
{os === "macos" && <HomebrewInstall />}
</section>
);
}
9 changes: 8 additions & 1 deletion apps/web/test/unit/download.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { expect, test } from "bun:test";
import { readFileSync } from "node:fs";
import { renderToStaticMarkup } from "react-dom/server";

import { DownloadButton } from "../../src/components/site/download";
import { DownloadButton, HomebrewInstall } from "../../src/components/site/download";

const page = readFileSync(new URL("../../src/routes/_site/download.tsx", import.meta.url), "utf8");

Expand Down Expand Up @@ -39,4 +39,11 @@ test("/download has no checksum or source Coming soon sections", () => {
expect(page).not.toContain("verify-title");
expect(page).toContain("DownloadButton");
expect(page).toContain("For your computer");
expect(page).toContain("HomebrewInstall");
});

test("Homebrew install block renders the tap commands", () => {
const html = renderToStaticMarkup(<HomebrewInstall />);
expect(html).toContain("brew tap opencoredev/convt");
expect(html).toContain("brew install --cask convt");
});
2 changes: 1 addition & 1 deletion docs/release.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ The envelope contains `payload` and `signature`, both unpadded base64url. Payloa

## Signing and publishing

Compare unsigned artifacts first. `scripts/release/sign-linux.sh UNSIGNED SIGNED` signs copies with `debsigs` and `rpmsign`, using `CONVT_REPO_SIGNING_KEY_ID`. Regenerate checksums and manifests from signed copies because signatures change bytes. The apt layout has pool packages, Packages, Packages.gz and Release; sign Release into InRelease and Release.gpg. The dnf template signs packages, creates deterministic repodata with `createrepo_c`, then signs repomd.xml. Homebrew and winget manifests are rendered only when the matching Mac or Windows artifact exists. Their unfilled templates live in `packaging/release`.
Compare unsigned artifacts first. `scripts/release/sign-linux.sh UNSIGNED SIGNED` signs copies with `debsigs` and `rpmsign`, using `CONVT_REPO_SIGNING_KEY_ID`. Regenerate checksums and manifests from signed copies because signatures change bytes. The apt layout has pool packages, Packages, Packages.gz and Release; sign Release into InRelease and Release.gpg. The dnf template signs packages, creates deterministic repodata with `createrepo_c`, then signs repomd.xml. Homebrew and winget manifests are rendered only when the matching Mac or Windows artifact exists. Their unfilled templates live in `packaging/release`. The tap users install is `Casks/convt.rb` in this repository (`brew tap opencoredev/convt https://github.com/opencoredev/convt`). After a successful GitHub release, the `Update Homebrew cask` job rewrites that file from `release-manifest.json` and pushes it. The job is `continue-on-error: true`, so a tap or branch-protection failure never blocks publication. Set repository secret `HOMEBREW_TAP_TOKEN` (a PAT that can write `opencoredev/homebrew-tap`) to also publish `brew install --cask opencoredev/tap/convt`.

`bun run release:upload --dry-run VERSION_DIRECTORY` makes no network writes. `--upload` is a separate operation, rejects failed source gates and mismatched artifact bytes, and needs a bucket created by Leo plus account ID and scoped R2 S3 credentials. Account and bucket management use the `cf` CLI. Object transfer uses the S3-compatible endpoint and an atomic If-None-Match precondition, with a 5 GiB single-object limit, instead of the cf REST object's 300 MB limit. Split larger corresponding-source deliveries before publication. This upload path has not been exercised against an account.

Expand Down
29 changes: 25 additions & 4 deletions packaging/release/convt.rb.in
Original file line number Diff line number Diff line change
@@ -1,11 +1,32 @@
cask "convt" do
version "@version@"
sha256 "@macos-arm64.dmg.sha256@"
url "@macos-arm64.dmg.url@"

url "https://github.com/opencoredev/convt/releases/download/v#{version}/convt-macos-arm64.dmg",
verified: "github.com/opencoredev/convt/"
name "convt"
desc "Local file conversion"
homepage "https://convt.app"
desc "Convert files locally without uploading"
homepage "https://convt.app/"

livecheck do
url :url
strategy :github_latest
end

depends_on arch: :arm64
depends_on macos: ">= :ventura"
depends_on macos: :ventura

app "convt.app"
binary "#{appdir}/convt.app/Contents/MacOS/convt"

uninstall quit: "app.convt.desktop"

zap trash: [
"~/Library/Application Support/convt",
"~/Library/Caches/app.convt.desktop",
"~/Library/HTTPStorages/app.convt.desktop",
"~/Library/Logs/convt",
"~/Library/Preferences/app.convt.desktop.plist",
"~/Library/Saved Application State/app.convt.desktop.savedState",
]
end
24 changes: 24 additions & 0 deletions scripts/release/check-homebrew-cask.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/bin/bash
# Validate Casks/convt.rb with `brew style` and `brew audit`. Homebrew only
# accepts casks that live in a tap, so this copies the file into a throwaway
# local tap and removes it afterwards.
set -euo pipefail
root=$(cd "$(dirname "$0")/../.." && pwd)
cask="$root/Casks/convt.rb"
test -f "$cask"
command -v brew >/dev/null

tap=convt/cask-audit
# brew tap-new writes into $(brew --repository)/Library/Taps/convt/homebrew-cask-audit
if brew tap-info "$tap" >/dev/null 2>&1; then
brew untap "$tap"
fi
brew tap-new --no-git "$tap" >/dev/null
repo=$(brew --repository "$tap")
mkdir -p "$repo/Casks"
cp "$cask" "$repo/Casks/convt.rb"
cleanup() { brew untap "$tap" >/dev/null 2>&1 || true; }
trap cleanup EXIT

brew style --cask "$tap/convt"
brew audit --cask "$tap/convt"
Loading
Loading