Compare commits
4 commits
main
...
feat/flatp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
00d1420e30 | ||
|
|
916c19b2cc | ||
|
|
a0fe809d3a | ||
|
|
dd0d5efda0 |
30 changed files with 12431 additions and 53 deletions
89
.github/workflows/build-release-artifacts.yml
vendored
89
.github/workflows/build-release-artifacts.yml
vendored
|
|
@ -199,6 +199,7 @@ jobs:
|
|||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y \
|
||||
appstream \
|
||||
desktop-file-utils \
|
||||
pkg-config \
|
||||
libxcb1-dev \
|
||||
|
|
@ -218,9 +219,9 @@ jobs:
|
|||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p dist
|
||||
# Backward compatibility for older tags that used non-standard categories.
|
||||
sed 's/VersionControl;/RevisionControl;/g' assets/linux/gitcomet.desktop > dist/gitcomet.desktop
|
||||
desktop-file-validate dist/gitcomet.desktop
|
||||
cp assets/linux/dev.gitcomet.GitComet.desktop dist/dev.gitcomet.GitComet.desktop
|
||||
desktop-file-validate dist/dev.gitcomet.GitComet.desktop
|
||||
appstreamcli validate --no-net flatpak/dev.gitcomet.GitComet.metainfo.xml
|
||||
|
||||
- name: Package tar.gz
|
||||
run: |
|
||||
|
|
@ -246,8 +247,8 @@ jobs:
|
|||
mkdir -p "${pkg_root}/usr/share/icons/hicolor/512x512/apps"
|
||||
|
||||
install -m755 target/release/gitcomet-app "${pkg_root}/usr/bin/gitcomet-app"
|
||||
install -m644 dist/gitcomet.desktop "${pkg_root}/usr/share/applications/gitcomet.desktop"
|
||||
install -m644 assets/gitcomet-512.png "${pkg_root}/usr/share/icons/hicolor/512x512/apps/gitcomet.png"
|
||||
install -m644 dist/dev.gitcomet.GitComet.desktop "${pkg_root}/usr/share/applications/dev.gitcomet.GitComet.desktop"
|
||||
install -m644 assets/gitcomet-512.png "${pkg_root}/usr/share/icons/hicolor/512x512/apps/dev.gitcomet.GitComet.png"
|
||||
|
||||
{
|
||||
echo "Package: gitcomet"
|
||||
|
|
@ -268,8 +269,8 @@ jobs:
|
|||
appdir="dist/AppDir"
|
||||
mkdir -p "${appdir}/usr/bin"
|
||||
install -m755 target/release/gitcomet-app "${appdir}/usr/bin/gitcomet-app"
|
||||
install -m644 dist/gitcomet.desktop "${appdir}/gitcomet.desktop"
|
||||
install -m644 assets/gitcomet-512.png "${appdir}/gitcomet.png"
|
||||
install -m644 dist/dev.gitcomet.GitComet.desktop "${appdir}/dev.gitcomet.GitComet.desktop"
|
||||
install -m644 assets/gitcomet-512.png "${appdir}/dev.gitcomet.GitComet.png"
|
||||
|
||||
{
|
||||
echo '#!/usr/bin/env bash'
|
||||
|
|
@ -298,6 +299,45 @@ jobs:
|
|||
if-no-files-found: error
|
||||
retention-days: 7
|
||||
|
||||
build_flatpak:
|
||||
name: Build Flatpak artifact
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 120
|
||||
needs: prepare
|
||||
container:
|
||||
image: ghcr.io/flathub-infra/flatpak-github-actions:freedesktop-24.08
|
||||
options: --privileged
|
||||
env:
|
||||
TAG: ${{ needs.prepare.outputs.tag }}
|
||||
VERSION: ${{ needs.prepare.outputs.version }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
ref: ${{ needs.prepare.outputs.tag }}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Build Flatpak bundle
|
||||
uses: flatpak/flatpak-github-actions/flatpak-builder@v6
|
||||
with:
|
||||
bundle: dev.gitcomet.GitComet.flatpak
|
||||
manifest-path: flatpak/dev.gitcomet.GitComet.local.yaml
|
||||
cache-key: flatpak-builder-${{ needs.prepare.outputs.tag }}
|
||||
upload-artifact: false
|
||||
|
||||
- name: Stage Flatpak artifact
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p dist
|
||||
mv dev.gitcomet.GitComet.flatpak "dist/gitcomet-v${VERSION}-linux-x86_64.flatpak"
|
||||
|
||||
- name: Upload Flatpak artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: flatpak-release-artifacts
|
||||
path: dist/*.flatpak
|
||||
if-no-files-found: error
|
||||
retention-days: 7
|
||||
|
||||
build_macos:
|
||||
name: Build macOS artifacts (${{ matrix.arch }})
|
||||
runs-on: ${{ matrix.runs_on }}
|
||||
|
|
@ -350,13 +390,18 @@ jobs:
|
|||
name: Attach assets and checksums to GitHub release
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
needs: [prepare, build_windows, build_linux, build_macos]
|
||||
needs: [prepare, build_windows, build_linux, build_flatpak, build_macos]
|
||||
env:
|
||||
TAG: ${{ needs.prepare.outputs.tag }}
|
||||
VERSION: ${{ needs.prepare.outputs.version }}
|
||||
RELEASE_ID: ${{ needs.prepare.outputs.release_id }}
|
||||
ENABLE_KEYLESS_SIGNING: ${{ vars.ENABLE_KEYLESS_SIGNING }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
ref: ${{ env.TAG }}
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: windows-release-artifacts
|
||||
|
|
@ -367,6 +412,11 @@ jobs:
|
|||
name: linux-release-artifacts
|
||||
path: dist/linux
|
||||
|
||||
- uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: flatpak-release-artifacts
|
||||
path: dist/flatpak
|
||||
|
||||
- uses: actions/download-artifact@v8
|
||||
with:
|
||||
pattern: macos-release-artifacts-*
|
||||
|
|
@ -379,6 +429,7 @@ jobs:
|
|||
mkdir -p dist/release
|
||||
find dist/windows -maxdepth 1 -type f -exec cp -f {} dist/release/ \;
|
||||
find dist/linux -maxdepth 1 -type f -exec cp -f {} dist/release/ \;
|
||||
find dist/flatpak -maxdepth 1 -type f -exec cp -f {} dist/release/ \;
|
||||
find dist/macos -maxdepth 1 -type f -exec cp -f {} dist/release/ \;
|
||||
file_count="$(find dist/release -maxdepth 1 -type f | wc -l | tr -d '[:space:]')"
|
||||
if [ "${file_count}" = "0" ]; then
|
||||
|
|
@ -387,6 +438,28 @@ jobs:
|
|||
fi
|
||||
ls -lah dist/release
|
||||
|
||||
- name: Generate source tarball
|
||||
run: |
|
||||
set -euo pipefail
|
||||
git archive \
|
||||
--format=tar.gz \
|
||||
--prefix="gitcomet-v${VERSION}-source/" \
|
||||
"$TAG" \
|
||||
-o "dist/release/gitcomet-v${VERSION}-source.tar.gz"
|
||||
|
||||
- name: Render Flathub manifest assets
|
||||
run: |
|
||||
set -euo pipefail
|
||||
source_tar="dist/release/gitcomet-v${VERSION}-source.tar.gz"
|
||||
source_sha256="$(sha256sum "$source_tar" | awk '{print $1}')"
|
||||
source_url="https://github.com/${GITHUB_REPOSITORY}/releases/download/${TAG}/gitcomet-v${VERSION}-source.tar.gz"
|
||||
scripts/render-flathub-manifest.sh \
|
||||
--source-url "$source_url" \
|
||||
--source-sha256 "$source_sha256" \
|
||||
--output "dist/release/dev.gitcomet.GitComet.yaml"
|
||||
cp flatpak/cargo-sources.json dist/release/cargo-sources.json
|
||||
cp flatpak/flathub.json dist/release/flathub.json
|
||||
|
||||
- name: Generate Homebrew formula
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
|
|
|||
317
.github/workflows/deploy-flathub.yml
vendored
Normal file
317
.github/workflows/deploy-flathub.yml
vendored
Normal file
|
|
@ -0,0 +1,317 @@
|
|||
name: Deploy Flathub Manifest
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
tag:
|
||||
required: true
|
||||
type: string
|
||||
version:
|
||||
required: true
|
||||
type: string
|
||||
flathub_repo:
|
||||
required: false
|
||||
type: string
|
||||
default: ""
|
||||
flathub_branch:
|
||||
required: false
|
||||
type: string
|
||||
default: ""
|
||||
mode:
|
||||
required: false
|
||||
type: string
|
||||
default: "pull_request"
|
||||
dry_run:
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
secrets:
|
||||
FLATHUB_TOKEN:
|
||||
required: false
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: "Release version (e.g. 0.2.0 or v0.2.0)"
|
||||
required: true
|
||||
type: string
|
||||
tag:
|
||||
description: "Optional tag override (e.g. v0.2.0). Defaults to v<version>."
|
||||
required: false
|
||||
type: string
|
||||
flathub_repo:
|
||||
description: "Target Flathub packaging repo in OWNER/REPO form"
|
||||
required: false
|
||||
default: ""
|
||||
type: string
|
||||
flathub_branch:
|
||||
description: "Target branch in the Flathub packaging repo (defaults to that repo's default branch)"
|
||||
required: false
|
||||
default: ""
|
||||
type: string
|
||||
mode:
|
||||
description: "Update mode: pull_request or push"
|
||||
required: false
|
||||
default: "pull_request"
|
||||
type: string
|
||||
dry_run:
|
||||
description: "Validate and report manifest deployment without pushing"
|
||||
required: true
|
||||
default: false
|
||||
type: boolean
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: deploy-flathub-${{ inputs.tag || github.event.inputs.tag || inputs.version || github.event.inputs.version || github.run_id }}
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
name: Publish manifest to Flathub packaging repo
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 20
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
steps:
|
||||
- name: Normalize inputs
|
||||
id: norm
|
||||
env:
|
||||
INPUT_TAG: ${{ inputs.tag }}
|
||||
DISPATCH_TAG: ${{ github.event.inputs.tag }}
|
||||
INPUT_VERSION: ${{ inputs.version }}
|
||||
DISPATCH_VERSION: ${{ github.event.inputs.version }}
|
||||
INPUT_FLATHUB_REPO: ${{ inputs.flathub_repo }}
|
||||
DISPATCH_FLATHUB_REPO: ${{ github.event.inputs.flathub_repo }}
|
||||
INPUT_FLATHUB_BRANCH: ${{ inputs.flathub_branch }}
|
||||
DISPATCH_FLATHUB_BRANCH: ${{ github.event.inputs.flathub_branch }}
|
||||
INPUT_MODE: ${{ inputs.mode }}
|
||||
DISPATCH_MODE: ${{ github.event.inputs.mode }}
|
||||
INPUT_DRY_RUN: ${{ inputs.dry_run }}
|
||||
DISPATCH_DRY_RUN: ${{ github.event.inputs.dry_run }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
tag="${INPUT_TAG:-${DISPATCH_TAG:-}}"
|
||||
version="${INPUT_VERSION:-${DISPATCH_VERSION:-}}"
|
||||
flathub_repo="${INPUT_FLATHUB_REPO:-${DISPATCH_FLATHUB_REPO:-}}"
|
||||
flathub_branch="${INPUT_FLATHUB_BRANCH:-${DISPATCH_FLATHUB_BRANCH:-}}"
|
||||
mode="${INPUT_MODE:-${DISPATCH_MODE:-pull_request}}"
|
||||
dry_run="${INPUT_DRY_RUN:-${DISPATCH_DRY_RUN:-false}}"
|
||||
|
||||
tag="$(echo "$tag" | tr -d '[:space:]')"
|
||||
version="$(echo "$version" | tr -d '[:space:]')"
|
||||
flathub_repo="$(echo "$flathub_repo" | tr -d '[:space:]')"
|
||||
flathub_branch="$(echo "$flathub_branch" | tr -d '[:space:]')"
|
||||
mode="$(echo "$mode" | tr -d '[:space:]' | tr '[:upper:]' '[:lower:]')"
|
||||
dry_run="$(echo "$dry_run" | tr -d '[:space:]' | tr '[:upper:]' '[:lower:]')"
|
||||
|
||||
if [ -z "$version" ]; then
|
||||
echo "::error title=Missing version::Version is required."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
version="${version#v}"
|
||||
if [ -z "$tag" ]; then
|
||||
tag="v${version}"
|
||||
fi
|
||||
|
||||
if [[ "$tag" != v* ]]; then
|
||||
tag="v${tag}"
|
||||
fi
|
||||
|
||||
if [ "$tag" != "v${version}" ]; then
|
||||
echo "::error title=Tag/version mismatch::Tag '$tag' does not match version '$version'."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! [[ "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-rc\.[0-9]+)?$ ]]; then
|
||||
echo "::error title=Invalid version::Expected semver like 1.2.3 or 1.2.3-rc.1."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$flathub_repo" ]; then
|
||||
flathub_repo="flathub/dev.gitcomet.GitComet"
|
||||
fi
|
||||
|
||||
if ! [[ "$flathub_repo" =~ ^[^/]+/[^/]+$ ]]; then
|
||||
echo "::error title=Invalid Flathub repo::flathub_repo must be OWNER/REPO."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$mode" != "pull_request" && "$mode" != "push" ]]; then
|
||||
echo "::error title=Invalid mode::mode must be pull_request or push."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$dry_run" != "true" && "$dry_run" != "false" ]]; then
|
||||
echo "::error title=Invalid dry_run::dry_run must be true or false."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "tag=$tag" >> "$GITHUB_OUTPUT"
|
||||
echo "version=$version" >> "$GITHUB_OUTPUT"
|
||||
echo "flathub_repo=$flathub_repo" >> "$GITHUB_OUTPUT"
|
||||
echo "flathub_branch=$flathub_branch" >> "$GITHUB_OUTPUT"
|
||||
echo "mode=$mode" >> "$GITHUB_OUTPUT"
|
||||
echo "dry_run=$dry_run" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Download Flathub assets from GitHub release
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p dist
|
||||
gh release view "${{ steps.norm.outputs.tag }}" --repo "$GITHUB_REPOSITORY" >/dev/null
|
||||
gh release download "${{ steps.norm.outputs.tag }}" \
|
||||
--repo "$GITHUB_REPOSITORY" \
|
||||
--pattern "dev.gitcomet.GitComet.yaml" \
|
||||
--pattern "cargo-sources.json" \
|
||||
--pattern "flathub.json" \
|
||||
--dir dist \
|
||||
--clobber
|
||||
test -f dist/dev.gitcomet.GitComet.yaml
|
||||
test -f dist/cargo-sources.json
|
||||
test -f dist/flathub.json
|
||||
|
||||
- name: Emit dry-run summary
|
||||
if: ${{ steps.norm.outputs.dry_run == 'true' }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
branch_display="${{ steps.norm.outputs.flathub_branch }}"
|
||||
if [ -z "$branch_display" ]; then
|
||||
branch_display="default branch"
|
||||
fi
|
||||
|
||||
{
|
||||
echo "### Flathub deployment dry run"
|
||||
echo ""
|
||||
echo "- Source release: \`${{ steps.norm.outputs.tag }}\`"
|
||||
echo "- Target repo: \`${{ steps.norm.outputs.flathub_repo }}\`"
|
||||
echo "- Target branch: \`${branch_display}\`"
|
||||
echo "- Mode: \`${{ steps.norm.outputs.mode }}\`"
|
||||
echo ""
|
||||
echo "Manifest SHA256: \`$(sha256sum dist/dev.gitcomet.GitComet.yaml | awk '{print $1}')\`"
|
||||
echo "Cargo sources SHA256: \`$(sha256sum dist/cargo-sources.json | awk '{print $1}')\`"
|
||||
echo "flathub.json SHA256: \`$(sha256sum dist/flathub.json | awk '{print $1}')\`"
|
||||
} >> "$GITHUB_STEP_SUMMARY"
|
||||
|
||||
- name: Publish manifest to Flathub packaging repo
|
||||
if: ${{ steps.norm.outputs.dry_run != 'true' }}
|
||||
env:
|
||||
FLATHUB_TOKEN: ${{ secrets.FLATHUB_TOKEN }}
|
||||
FLATHUB_REPO: ${{ steps.norm.outputs.flathub_repo }}
|
||||
FLATHUB_BRANCH: ${{ steps.norm.outputs.flathub_branch }}
|
||||
FLATHUB_MODE: ${{ steps.norm.outputs.mode }}
|
||||
TAG: ${{ steps.norm.outputs.tag }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
if [ -z "${FLATHUB_TOKEN:-}" ]; then
|
||||
echo "::error title=Missing secret::Set FLATHUB_TOKEN to push to ${FLATHUB_REPO}."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
clone_args=()
|
||||
if [ -n "$FLATHUB_BRANCH" ]; then
|
||||
clone_args+=(--branch "$FLATHUB_BRANCH")
|
||||
fi
|
||||
|
||||
rm -rf flathub-repo
|
||||
git clone "${clone_args[@]}" "https://x-access-token:${FLATHUB_TOKEN}@github.com/${FLATHUB_REPO}.git" flathub-repo
|
||||
|
||||
cp dist/dev.gitcomet.GitComet.yaml flathub-repo/dev.gitcomet.GitComet.yaml
|
||||
cp dist/cargo-sources.json flathub-repo/cargo-sources.json
|
||||
cp dist/flathub.json flathub-repo/flathub.json
|
||||
|
||||
pushd flathub-repo >/dev/null
|
||||
base_branch="$(git branch --show-current)"
|
||||
if [ -z "$base_branch" ]; then
|
||||
echo "::error title=Unknown branch::Could not determine the checked out branch for ${FLATHUB_REPO}."
|
||||
popd >/dev/null
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "FLATHUB_BASE_BRANCH=${base_branch}" >> "$GITHUB_ENV"
|
||||
echo "FLATHUB_MODE_RESOLVED=${FLATHUB_MODE}" >> "$GITHUB_ENV"
|
||||
|
||||
if [ -z "$(git status --porcelain -- dev.gitcomet.GitComet.yaml cargo-sources.json flathub.json)" ]; then
|
||||
echo "No Flathub manifest changes detected; packaging repo already up to date."
|
||||
popd >/dev/null
|
||||
exit 0
|
||||
fi
|
||||
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
|
||||
if [ "$FLATHUB_MODE" = "push" ]; then
|
||||
git add dev.gitcomet.GitComet.yaml cargo-sources.json flathub.json
|
||||
git commit -m "dev.gitcomet.GitComet ${TAG}"
|
||||
git push origin "HEAD:${base_branch}"
|
||||
echo "FLATHUB_TARGET_BRANCH=${base_branch}" >> "$GITHUB_ENV"
|
||||
else
|
||||
pr_branch="gitcomet/release-${TAG}"
|
||||
git checkout -B "$pr_branch"
|
||||
git add dev.gitcomet.GitComet.yaml cargo-sources.json flathub.json
|
||||
git commit -m "dev.gitcomet.GitComet ${TAG}"
|
||||
|
||||
if git ls-remote --exit-code --heads origin "$pr_branch" >/dev/null 2>&1; then
|
||||
git push --force-with-lease -u origin "$pr_branch"
|
||||
else
|
||||
git push -u origin "$pr_branch"
|
||||
fi
|
||||
|
||||
{
|
||||
printf 'Update GitComet to %s.\n\n' "$TAG"
|
||||
printf 'Generated by `.github/workflows/deploy-flathub.yml` from GitHub release assets in %s.\n\n' "$GITHUB_REPOSITORY"
|
||||
printf 'Assets:\n- `dev.gitcomet.GitComet.yaml`\n- `cargo-sources.json`\n- `flathub.json`\n'
|
||||
} > /tmp/flathub-pr-body.md
|
||||
|
||||
existing_pr="$(GH_TOKEN="$FLATHUB_TOKEN" gh pr list \
|
||||
--repo "$FLATHUB_REPO" \
|
||||
--head "$pr_branch" \
|
||||
--base "$base_branch" \
|
||||
--json number \
|
||||
--jq '.[0].number // empty')"
|
||||
|
||||
if [ -n "$existing_pr" ]; then
|
||||
GH_TOKEN="$FLATHUB_TOKEN" gh pr edit "$existing_pr" \
|
||||
--repo "$FLATHUB_REPO" \
|
||||
--title "dev.gitcomet.GitComet ${TAG}" \
|
||||
--body-file /tmp/flathub-pr-body.md >/dev/null
|
||||
pr_url="$(GH_TOKEN="$FLATHUB_TOKEN" gh pr view "$existing_pr" --repo "$FLATHUB_REPO" --json url --jq '.url')"
|
||||
else
|
||||
pr_url="$(GH_TOKEN="$FLATHUB_TOKEN" gh pr create \
|
||||
--repo "$FLATHUB_REPO" \
|
||||
--base "$base_branch" \
|
||||
--head "$pr_branch" \
|
||||
--title "dev.gitcomet.GitComet ${TAG}" \
|
||||
--body-file /tmp/flathub-pr-body.md)"
|
||||
fi
|
||||
|
||||
echo "FLATHUB_TARGET_BRANCH=${pr_branch}" >> "$GITHUB_ENV"
|
||||
echo "FLATHUB_PR_URL=${pr_url}" >> "$GITHUB_ENV"
|
||||
fi
|
||||
|
||||
popd >/dev/null
|
||||
|
||||
- name: Emit deployment summary
|
||||
run: |
|
||||
set -euo pipefail
|
||||
branch_display="${FLATHUB_TARGET_BRANCH:-${{ steps.norm.outputs.flathub_branch }}}"
|
||||
if [ -z "$branch_display" ]; then
|
||||
branch_display="default branch"
|
||||
fi
|
||||
mode_display="${FLATHUB_MODE_RESOLVED:-${{ steps.norm.outputs.mode }}}"
|
||||
|
||||
{
|
||||
echo "### Flathub deployment"
|
||||
echo ""
|
||||
echo "- Release: \`${{ steps.norm.outputs.tag }}\`"
|
||||
echo "- Target repo: \`${{ steps.norm.outputs.flathub_repo }}\`"
|
||||
echo "- Target branch: \`${branch_display}\`"
|
||||
echo "- Base branch: \`${FLATHUB_BASE_BRANCH:-default branch}\`"
|
||||
echo "- Mode: \`${mode_display}\`"
|
||||
echo "- Dry run: \`${{ steps.norm.outputs.dry_run }}\`"
|
||||
if [ -n "${FLATHUB_PR_URL:-}" ]; then
|
||||
echo "- Pull request: ${FLATHUB_PR_URL}"
|
||||
fi
|
||||
} >> "$GITHUB_STEP_SUMMARY"
|
||||
52
.github/workflows/deployment-ci.yml
vendored
52
.github/workflows/deployment-ci.yml
vendored
|
|
@ -5,9 +5,15 @@ on:
|
|||
branches: ["main"]
|
||||
paths:
|
||||
- ".github/workflows/build-release-artifacts.yml"
|
||||
- ".github/workflows/deployment-ci.yml"
|
||||
- ".github/workflows/deploy-homebrew-tap.yml"
|
||||
- ".github/workflows/deploy-flathub.yml"
|
||||
- ".github/workflows/deploy-apt-repo.yml"
|
||||
- ".github/workflows/release-manual-main.yml"
|
||||
- "assets/linux/dev.gitcomet.GitComet.desktop"
|
||||
- "flatpak/**"
|
||||
- "scripts/generate-flatpak-cargo-sources.py"
|
||||
- "scripts/render-flathub-manifest.sh"
|
||||
- "scripts/package-macos.sh"
|
||||
- "scripts/generate-homebrew-formula.sh"
|
||||
- "scripts/build-apt-repo.sh"
|
||||
|
|
@ -15,9 +21,15 @@ on:
|
|||
branches: ["main"]
|
||||
paths:
|
||||
- ".github/workflows/build-release-artifacts.yml"
|
||||
- ".github/workflows/deployment-ci.yml"
|
||||
- ".github/workflows/deploy-homebrew-tap.yml"
|
||||
- ".github/workflows/deploy-flathub.yml"
|
||||
- ".github/workflows/deploy-apt-repo.yml"
|
||||
- ".github/workflows/release-manual-main.yml"
|
||||
- "assets/linux/dev.gitcomet.GitComet.desktop"
|
||||
- "flatpak/**"
|
||||
- "scripts/generate-flatpak-cargo-sources.py"
|
||||
- "scripts/render-flathub-manifest.sh"
|
||||
- "scripts/package-macos.sh"
|
||||
- "scripts/generate-homebrew-formula.sh"
|
||||
- "scripts/build-apt-repo.sh"
|
||||
|
|
@ -42,11 +54,13 @@ jobs:
|
|||
bash -n scripts/package-macos.sh
|
||||
bash -n scripts/generate-homebrew-formula.sh
|
||||
bash -n scripts/build-apt-repo.sh
|
||||
bash -n scripts/render-flathub-manifest.sh
|
||||
|
||||
- name: Validate workflow YAML
|
||||
run: |
|
||||
ruby -e 'require "yaml"; %w[
|
||||
.github/workflows/build-release-artifacts.yml
|
||||
.github/workflows/deploy-flathub.yml
|
||||
.github/workflows/deploy-homebrew-tap.yml
|
||||
.github/workflows/deploy-apt-repo.yml
|
||||
.github/workflows/deployment-ci.yml
|
||||
|
|
@ -218,3 +232,41 @@ jobs:
|
|||
|
||||
"${mount_point}/GitComet.app/Contents/MacOS/gitcomet-app" --help >/dev/null
|
||||
hdiutil detach "$mount_point"
|
||||
|
||||
flatpak-packaging-smoke:
|
||||
name: Flatpak packaging smoke
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 120
|
||||
container:
|
||||
image: ghcr.io/flathub-infra/flatpak-github-actions:freedesktop-24.08
|
||||
options: --privileged
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Verify generated cargo sources stay in sync
|
||||
run: |
|
||||
set -euo pipefail
|
||||
python3 scripts/generate-flatpak-cargo-sources.py --output /tmp/cargo-sources.json
|
||||
cmp /tmp/cargo-sources.json flatpak/cargo-sources.json
|
||||
|
||||
- name: Render release manifest
|
||||
run: |
|
||||
set -euo pipefail
|
||||
scripts/render-flathub-manifest.sh \
|
||||
--source-url "https://example.invalid/gitcomet-v0.0.0-ci-source.tar.gz" \
|
||||
--source-sha256 "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" \
|
||||
--output /tmp/dev.gitcomet.GitComet.yaml
|
||||
test -s /tmp/dev.gitcomet.GitComet.yaml
|
||||
|
||||
- name: Build Flatpak bundle
|
||||
uses: flatpak/flatpak-github-actions/flatpak-builder@v6
|
||||
with:
|
||||
bundle: dev.gitcomet.GitComet.flatpak
|
||||
manifest-path: flatpak/dev.gitcomet.GitComet.local.yaml
|
||||
cache-key: deployment-ci-flatpak
|
||||
upload-artifact: false
|
||||
|
||||
- name: Verify Flatpak bundle output
|
||||
run: |
|
||||
set -euo pipefail
|
||||
test -f dev.gitcomet.GitComet.flatpak
|
||||
|
|
|
|||
14
.github/workflows/release-manual-main.yml
vendored
14
.github/workflows/release-manual-main.yml
vendored
|
|
@ -187,6 +187,20 @@ jobs:
|
|||
dry_run: false
|
||||
secrets: inherit
|
||||
|
||||
deploy_flathub:
|
||||
name: Deploy Flathub manifest
|
||||
needs: [validate, build_and_upload, publish_release]
|
||||
if: ${{ fromJSON(needs.validate.outputs.draft) == false && needs.build_and_upload.result == 'success' }}
|
||||
uses: ./.github/workflows/deploy-flathub.yml
|
||||
with:
|
||||
tag: ${{ needs.validate.outputs.tag }}
|
||||
version: ${{ needs.validate.outputs.version }}
|
||||
flathub_repo: ${{ vars.FLATHUB_REPO }}
|
||||
flathub_branch: ${{ vars.FLATHUB_BRANCH }}
|
||||
mode: ${{ vars.FLATHUB_MODE }}
|
||||
dry_run: false
|
||||
secrets: inherit
|
||||
|
||||
deploy_apt_repo:
|
||||
name: Deploy Azure APT repository
|
||||
needs: [validate, build_and_upload, publish_release]
|
||||
|
|
|
|||
|
|
@ -84,8 +84,9 @@ Use `--skip-dmg` when running in restricted/sandboxed environments where `hdiuti
|
|||
The release workflow `.github/workflows/build-release-artifacts.yml` builds and publishes:
|
||||
|
||||
- Windows: portable ZIP + MSI
|
||||
- Linux: tar.gz + AppImage + .deb
|
||||
- Linux: tar.gz + AppImage + .deb + Flatpak bundle
|
||||
- macOS: DMG + tar.gz for `arm64` and `x86_64`
|
||||
- Flathub assets: `gitcomet-v<VERSION>-source.tar.gz`, `dev.gitcomet.GitComet.yaml`, `cargo-sources.json`, and `flathub.json`
|
||||
- Homebrew formula asset: `gitcomet.rb` (generated from macOS + Linux x86_64 tarballs and their SHA256 values)
|
||||
|
||||
### Homebrew deployment
|
||||
|
|
@ -106,3 +107,25 @@ This release flow will:
|
|||
- call `.github/workflows/deploy-homebrew-tap.yml` to update `Formula/gitcomet.rb` in the tap repo
|
||||
|
||||
You can also run `.github/workflows/deploy-homebrew-tap.yml` manually for backfills or dry-runs.
|
||||
|
||||
### Flathub deployment
|
||||
|
||||
The app ID used for Flatpak/Flathub packaging is `dev.gitcomet.GitComet`.
|
||||
|
||||
To push `dev.gitcomet.GitComet.yaml`, `cargo-sources.json`, and `flathub.json` into the Flathub packaging repo automatically on release:
|
||||
|
||||
1. Complete the one-time Flathub onboarding so the app has a packaging repo, typically `flathub/dev.gitcomet.GitComet`.
|
||||
2. In this repo, configure:
|
||||
- secret `FLATHUB_TOKEN`: GitHub token with `contents:write` access to the Flathub packaging repository.
|
||||
- optional variable `FLATHUB_REPO`: packaging repository in `OWNER/REPO` form. Defaults to `flathub/dev.gitcomet.GitComet`.
|
||||
- optional variable `FLATHUB_BRANCH`: target branch. If unset, the packaging repo default branch is used.
|
||||
- optional variable `FLATHUB_MODE`: `pull_request` (default, opens/updates a PR against the packaging repo) or `push` (commits straight to the target branch).
|
||||
3. Run `.github/workflows/release-manual-main.yml` with `draft=false`.
|
||||
|
||||
This release flow will:
|
||||
|
||||
- build and upload the Flatpak bundle plus Flathub source/manifest assets
|
||||
- publish the GitHub release so the source tarball URL is public
|
||||
- call `.github/workflows/deploy-flathub.yml` to update the Flathub packaging repo, either by opening/updating a PR or by pushing directly depending on `FLATHUB_MODE`
|
||||
|
||||
You can also run `.github/workflows/deploy-flathub.yml` manually for backfills or dry-runs.
|
||||
|
|
|
|||
|
|
@ -26,6 +26,15 @@ brew tap auto-explore/gitcomet
|
|||
brew install gitcomet
|
||||
```
|
||||
|
||||
#### Flatpak / Flathub
|
||||
|
||||
GitHub releases also publish:
|
||||
|
||||
- a Linux Flatpak bundle: `gitcomet-v<VERSION>-linux-x86_64.flatpak`
|
||||
- a source tarball for Flathub: `gitcomet-v<VERSION>-source.tar.gz`
|
||||
- the rendered Flathub manifest: `dev.gitcomet.GitComet.yaml`
|
||||
- the pinned Cargo source list: `cargo-sources.json`
|
||||
|
||||
### Fast, Free, Familiar
|
||||
|
||||
- **Fast**: Built end-to-end in Rust for speed and efficiency using [smol](https://github.com/smol-rs/smol), [gix](https://github.com/GitoxideLabs/gitoxide), and [gpui](https://www.gpui.rs/).
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@ Type=Application
|
|||
Name=GitComet
|
||||
Comment=Git UI built with GPUI
|
||||
Exec=gitcomet-app
|
||||
Icon=gitcomet
|
||||
StartupWMClass=gitcomet
|
||||
Icon=dev.gitcomet.GitComet
|
||||
StartupWMClass=dev.gitcomet.GitComet
|
||||
Terminal=false
|
||||
Categories=Development;RevisionControl;
|
||||
Keywords=git;diff;merge;history;revision-control;
|
||||
|
|
@ -1,9 +1,10 @@
|
|||
use crate::cli::{DifftoolConfig, DifftoolInputKind, classify_difftool_input, exit_code};
|
||||
use gitcomet_core::platform::host_tempdir;
|
||||
use rustc_hash::FxHashSet as HashSet;
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
use tempfile::{Builder, TempDir};
|
||||
use tempfile::TempDir;
|
||||
|
||||
/// Format a `"Failed to {op} {path}: {err}"` message concisely.
|
||||
macro_rules! io_err {
|
||||
|
|
@ -255,9 +256,7 @@ fn prepare_diff_inputs(config: &DifftoolConfig) -> Result<PreparedDiffInputs, St
|
|||
});
|
||||
}
|
||||
|
||||
let tempdir = Builder::new()
|
||||
.prefix("gitcomet-difftool-")
|
||||
.tempdir()
|
||||
let tempdir = host_tempdir("gitcomet-difftool-")
|
||||
.map_err(|e| io_err!("create temporary directory staging area", e))?;
|
||||
|
||||
let staged_local = tempdir.path().join("left");
|
||||
|
|
|
|||
|
|
@ -20,6 +20,9 @@ pub(crate) fn hex_encode(bytes: &[u8]) -> String {
|
|||
}
|
||||
use std::io::{self, Write};
|
||||
|
||||
#[cfg(all(target_os = "macos", feature = "ui-gpui"))]
|
||||
use gitcomet_core::platform::APP_ID;
|
||||
|
||||
#[global_allocator]
|
||||
static GLOBAL: MiMalloc = MiMalloc;
|
||||
|
||||
|
|
@ -374,7 +377,7 @@ fn ensure_macos_dev_app_bundle(
|
|||
<key>CFBundleExecutable</key>
|
||||
<string>gitcomet-app</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>ai.autoexplore.gitcomet.dev</string>
|
||||
<string>{app_id}</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>GitComet.icns</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
|
|
@ -394,6 +397,7 @@ fn ensure_macos_dev_app_bundle(
|
|||
</dict>
|
||||
</plist>
|
||||
"#,
|
||||
app_id = APP_ID,
|
||||
version = env!("CARGO_PKG_VERSION")
|
||||
);
|
||||
std::fs::write(contents.join("Info.plist"), plist)
|
||||
|
|
|
|||
|
|
@ -16,9 +16,7 @@ benchmarks = []
|
|||
|
||||
[dependencies]
|
||||
regex = { workspace = true }
|
||||
tempfile = { workspace = true }
|
||||
rustc-hash = { workspace = true }
|
||||
strsim = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = { workspace = true }
|
||||
|
|
|
|||
|
|
@ -9,5 +9,6 @@ pub mod file_diff;
|
|||
pub mod merge;
|
||||
pub mod merge_extraction;
|
||||
pub mod mergetool_trace;
|
||||
pub mod platform;
|
||||
pub mod services;
|
||||
pub mod text_utils;
|
||||
|
|
|
|||
50
crates/gitcomet-core/src/platform.rs
Normal file
50
crates/gitcomet-core/src/platform.rs
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
use std::env;
|
||||
use std::ffi::OsStr;
|
||||
use std::fs;
|
||||
use std::io;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
|
||||
pub const APP_ID: &str = "dev.gitcomet.GitComet";
|
||||
pub const APP_DESKTOP_FILE_NAME: &str = "dev.gitcomet.GitComet.desktop";
|
||||
pub const APP_ICON_NAME: &str = APP_ID;
|
||||
|
||||
pub fn is_flatpak_sandbox() -> bool {
|
||||
cfg!(any(target_os = "linux", target_os = "freebsd")) && Path::new("/.flatpak-info").exists()
|
||||
}
|
||||
|
||||
pub fn host_command<S: AsRef<OsStr>>(program: S) -> Command {
|
||||
let program = program.as_ref();
|
||||
if is_flatpak_sandbox() {
|
||||
let mut command = Command::new("flatpak-spawn");
|
||||
command.arg("--host").arg(program);
|
||||
command
|
||||
} else {
|
||||
Command::new(program)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn host_tempdir(prefix: &str) -> io::Result<tempfile::TempDir> {
|
||||
let mut builder = tempfile::Builder::new();
|
||||
builder.prefix(prefix);
|
||||
if let Some(root) = host_visible_temp_root()? {
|
||||
builder.tempdir_in(root)
|
||||
} else {
|
||||
builder.tempdir()
|
||||
}
|
||||
}
|
||||
|
||||
fn host_visible_temp_root() -> io::Result<Option<PathBuf>> {
|
||||
if !is_flatpak_sandbox() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let cache_home = env::var_os("XDG_CACHE_HOME")
|
||||
.map(PathBuf::from)
|
||||
.or_else(|| env::var_os("HOME").map(|home| PathBuf::from(home).join(".cache")));
|
||||
let root = cache_home
|
||||
.unwrap_or_else(env::temp_dir)
|
||||
.join("gitcomet/tmp");
|
||||
fs::create_dir_all(&root)?;
|
||||
Ok(Some(root))
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
use super::{GixRepo, conflict_stages::gix_index_stage_blob_bytes_optional};
|
||||
use crate::util::{bytes_to_text_preserving_utf8, run_git_simple};
|
||||
use gitcomet_core::error::{Error, ErrorKind};
|
||||
use gitcomet_core::platform::{host_command, host_tempdir};
|
||||
use gitcomet_core::services::{
|
||||
CommandOutput, MergetoolResult, Result, validate_conflict_resolution_text,
|
||||
};
|
||||
|
|
@ -68,7 +69,7 @@ impl GixRepo {
|
|||
// No custom command — try invoking the tool name directly with
|
||||
// the standard argument convention used by many merge tools.
|
||||
let tool_executable = tool_path.as_deref().unwrap_or(&tool_name);
|
||||
Command::new(tool_executable)
|
||||
host_command(tool_executable)
|
||||
.arg(local_path)
|
||||
.arg(base_path)
|
||||
.arg(remote_path)
|
||||
|
|
@ -183,14 +184,14 @@ fn env_has_display() -> bool {
|
|||
|
||||
#[cfg(all(windows, test))]
|
||||
fn shell_command(custom_cmd: &str) -> Command {
|
||||
let mut command = Command::new("cmd");
|
||||
let mut command = host_command("cmd");
|
||||
command.arg("/C").arg(custom_cmd);
|
||||
command
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
fn shell_command(custom_cmd: &str) -> Command {
|
||||
let mut command = Command::new("sh");
|
||||
let mut command = host_command("sh");
|
||||
command.arg("-c").arg(custom_cmd);
|
||||
command
|
||||
}
|
||||
|
|
@ -510,10 +511,8 @@ fn build_stage_paths(
|
|||
let pid = std::process::id();
|
||||
|
||||
if write_to_temp {
|
||||
let tmp_dir = tempfile::Builder::new()
|
||||
.prefix("gitcomet-mergetool-")
|
||||
.tempdir()
|
||||
.map_err(|e| Error::new(ErrorKind::Io(e.kind())))?;
|
||||
let tmp_dir =
|
||||
host_tempdir("gitcomet-mergetool-").map_err(|e| Error::new(ErrorKind::Io(e.kind())))?;
|
||||
let (tmp_dir_path, temp_dir_guard) = if keep_temporaries {
|
||||
(tmp_dir.keep(), None)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ use gitcomet_core::auth::{
|
|||
};
|
||||
use gitcomet_core::domain::{Commit, CommitId, LogPage};
|
||||
use gitcomet_core::error::{Error, ErrorKind, GitFailure, GitFailureId};
|
||||
use gitcomet_core::platform::host_tempdir;
|
||||
use gitcomet_core::services::{CommandOutput, Result};
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
|
@ -189,7 +190,7 @@ echo %GITCOMET_AUTH_SECRET%
|
|||
}
|
||||
|
||||
fn create_askpass_script() -> Result<AskPassScript> {
|
||||
let dir = tempfile::tempdir().map_err(io_err)?;
|
||||
let dir = host_tempdir("gitcomet-askpass-").map_err(|e| Error::new(ErrorKind::Io(e.kind())))?;
|
||||
#[cfg(windows)]
|
||||
let script_name = "gitcomet-askpass.cmd";
|
||||
#[cfg(not(windows))]
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ use gitcomet_core::auth::{
|
|||
GitAuthKind, StagedGitAuth, take_staged_git_auth,
|
||||
};
|
||||
use gitcomet_core::error::{Error, ErrorKind};
|
||||
use gitcomet_core::platform::host_tempdir;
|
||||
use gitcomet_core::services::CommandOutput;
|
||||
use std::fs;
|
||||
use std::io::{BufRead as _, BufReader, Read as _};
|
||||
|
|
@ -199,7 +200,7 @@ echo %GITCOMET_AUTH_SECRET%
|
|||
}
|
||||
|
||||
fn create_askpass_script() -> Result<AskPassScript, Error> {
|
||||
let dir = tempfile::tempdir().map_err(|e| Error::new(ErrorKind::Io(e.kind())))?;
|
||||
let dir = host_tempdir("gitcomet-askpass-").map_err(|e| Error::new(ErrorKind::Io(e.kind())))?;
|
||||
#[cfg(windows)]
|
||||
let script_name = "gitcomet-askpass.cmd";
|
||||
#[cfg(not(windows))]
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ use crate::view::{
|
|||
FocusedMergetoolLabels, FocusedMergetoolViewConfig, GitCometView, GitCometViewConfig,
|
||||
GitCometViewMode, StartupCrashReport,
|
||||
};
|
||||
use gitcomet_core::platform::APP_ID;
|
||||
use gitcomet_core::services::GitBackend;
|
||||
use gitcomet_state::session;
|
||||
use gitcomet_state::store::AppStore;
|
||||
|
|
@ -80,7 +81,7 @@ fn normal_launch_config(
|
|||
) -> WindowLaunchConfig {
|
||||
WindowLaunchConfig {
|
||||
title: "GitComet".to_string(),
|
||||
app_id: "gitcomet".to_string(),
|
||||
app_id: APP_ID.to_string(),
|
||||
view_config: GitCometViewConfig::normal(initial_path, startup_crash_report),
|
||||
}
|
||||
}
|
||||
|
|
@ -91,7 +92,7 @@ fn focused_mergetool_launch_config(
|
|||
) -> WindowLaunchConfig {
|
||||
WindowLaunchConfig {
|
||||
title: focused_mergetool_window_title(&config.conflicted_file_path),
|
||||
app_id: "gitcomet-mergetool".to_string(),
|
||||
app_id: APP_ID.to_string(),
|
||||
view_config: GitCometViewConfig {
|
||||
initial_path: Some(config.repo_path.clone()),
|
||||
view_mode: GitCometViewMode::FocusedMergetool,
|
||||
|
|
@ -309,7 +310,7 @@ mod tests {
|
|||
};
|
||||
|
||||
let launch = focused_mergetool_launch_config(&config, None);
|
||||
assert_eq!(launch.app_id, "gitcomet-mergetool");
|
||||
assert_eq!(launch.app_id, APP_ID);
|
||||
assert_eq!(launch.title, "GitComet - Mergetool (conflict.txt)");
|
||||
assert_eq!(launch.view_config.initial_path, Some(config.repo_path));
|
||||
assert_eq!(
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
use crate::assets::GitCometAssets;
|
||||
use crate::launch_guard::run_with_panic_guard;
|
||||
use crate::theme::{AppTheme, with_alpha};
|
||||
use gitcomet_core::platform::APP_ID;
|
||||
use gpui::prelude::*;
|
||||
use gpui::{
|
||||
App, Application, Bounds, FocusHandle, Focusable, FontWeight, KeyBinding, Render, ScrollHandle,
|
||||
|
|
@ -291,7 +292,7 @@ pub fn run_focused_diff(config: FocusedDiffConfig) -> i32 {
|
|||
appears_transparent: false,
|
||||
traffic_light_position: Some(point(px(9.0), px(9.0))),
|
||||
}),
|
||||
app_id: Some("gitcomet-diff".to_string()),
|
||||
app_id: Some(APP_ID.to_string()),
|
||||
window_decorations: Some(WindowDecorations::Server),
|
||||
is_movable: true,
|
||||
is_resizable: true,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
use super::*;
|
||||
#[cfg(any(test, target_os = "linux", target_os = "freebsd"))]
|
||||
use gitcomet_core::platform::{APP_DESKTOP_FILE_NAME, APP_ICON_NAME, is_flatpak_sandbox};
|
||||
|
||||
#[cfg(any(test, target_os = "linux", target_os = "freebsd"))]
|
||||
fn desktop_entry_exec_path_arg(exe: &std::path::Path) -> Result<String, String> {
|
||||
|
|
@ -29,9 +31,10 @@ fn desktop_entry_exec_path_arg(exe: &std::path::Path) -> Result<String, String>
|
|||
fn should_auto_install_linux_desktop_integration(
|
||||
no_desktop_install_flag_present: bool,
|
||||
_xdg_current_desktop: Option<&str>,
|
||||
is_flatpak: bool,
|
||||
) -> bool {
|
||||
// `.desktop` entries follow the FreeDesktop spec, so installation is not GNOME-specific.
|
||||
!no_desktop_install_flag_present
|
||||
!no_desktop_install_flag_present && !is_flatpak
|
||||
}
|
||||
|
||||
impl GitCometView {
|
||||
|
|
@ -47,6 +50,7 @@ impl GitCometView {
|
|||
if !should_auto_install_linux_desktop_integration(
|
||||
std::env::var_os("GITCOMET_NO_DESKTOP_INSTALL").is_some(),
|
||||
desktop.as_deref(),
|
||||
is_flatpak_sandbox(),
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -59,10 +63,12 @@ impl GitCometView {
|
|||
return;
|
||||
};
|
||||
|
||||
let desktop_path = data_home.join("applications/gitcomet.desktop");
|
||||
let desktop_path = data_home.join(format!("applications/{APP_DESKTOP_FILE_NAME}"));
|
||||
let all_icons_exist = ICON_SIZES.iter().all(|size| {
|
||||
data_home
|
||||
.join(format!("icons/hicolor/{size}x{size}/apps/gitcomet.png"))
|
||||
.join(format!(
|
||||
"icons/hicolor/{size}x{size}/apps/{APP_ICON_NAME}.png"
|
||||
))
|
||||
.exists()
|
||||
});
|
||||
if desktop_path.exists() && all_icons_exist {
|
||||
|
|
@ -87,7 +93,7 @@ impl GitCometView {
|
|||
|
||||
const DESKTOP_TEMPLATE: &str = include_str!(concat!(
|
||||
env!("CARGO_MANIFEST_DIR"),
|
||||
"/../../assets/linux/gitcomet.desktop"
|
||||
"/../../assets/linux/dev.gitcomet.GitComet.desktop"
|
||||
));
|
||||
const ICON_32_PNG: &[u8] = include_bytes!(concat!(
|
||||
env!("CARGO_MANIFEST_DIR"),
|
||||
|
|
@ -131,8 +137,9 @@ impl GitCometView {
|
|||
|
||||
let applications_dir = data_home.join("applications");
|
||||
let icons_root = data_home.join("icons/hicolor");
|
||||
let desktop_path = applications_dir.join("gitcomet.desktop");
|
||||
let icon_path = icons_root.join("512x512/apps/gitcomet.png");
|
||||
let desktop_path = applications_dir.join(APP_DESKTOP_FILE_NAME);
|
||||
let icon_path =
|
||||
icons_root.join(format!("512x512/apps/{APP_ICON_NAME}.png"));
|
||||
|
||||
fs::create_dir_all(&applications_dir)
|
||||
.map_err(|e| format!("Desktop install failed: {e}"))?;
|
||||
|
|
@ -159,7 +166,7 @@ impl GitCometView {
|
|||
|
||||
for (size, icon_bytes) in ICON_ASSETS {
|
||||
let icon_dir = icons_root.join(format!("{size}x{size}/apps"));
|
||||
let icon_file = icon_dir.join("gitcomet.png");
|
||||
let icon_file = icon_dir.join(format!("{APP_ICON_NAME}.png"));
|
||||
fs::create_dir_all(&icon_dir)
|
||||
.and_then(|_| fs::write(&icon_file, icon_bytes))
|
||||
.map_err(|e| format!("Desktop install failed: {e}"))?;
|
||||
|
|
@ -226,22 +233,35 @@ mod tests {
|
|||
fn auto_install_is_not_limited_to_gnome() {
|
||||
for desktop in ["GNOME", "KDE", "XFCE", "sway", ""] {
|
||||
assert!(
|
||||
should_auto_install_linux_desktop_integration(false, Some(desktop)),
|
||||
should_auto_install_linux_desktop_integration(false, Some(desktop), false),
|
||||
"expected desktop '{desktop}' to allow auto install"
|
||||
);
|
||||
}
|
||||
assert!(should_auto_install_linux_desktop_integration(false, None));
|
||||
assert!(should_auto_install_linux_desktop_integration(
|
||||
false, None, false
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn auto_install_respects_opt_out_flag() {
|
||||
assert!(!should_auto_install_linux_desktop_integration(
|
||||
true,
|
||||
Some("GNOME")
|
||||
Some("GNOME"),
|
||||
false
|
||||
));
|
||||
assert!(!should_auto_install_linux_desktop_integration(
|
||||
true,
|
||||
Some("KDE")
|
||||
Some("KDE"),
|
||||
false
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn auto_install_is_disabled_in_flatpak() {
|
||||
assert!(!should_auto_install_linux_desktop_integration(
|
||||
false,
|
||||
Some("GNOME"),
|
||||
true
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
388
flatpak.md
Normal file
388
flatpak.md
Normal file
|
|
@ -0,0 +1,388 @@
|
|||
# GitComet Flatpak Verification and Flathub Submission
|
||||
|
||||
This document covers two things:
|
||||
|
||||
1. How to manually verify that the GitComet Flatpak installs and works.
|
||||
2. How to submit GitComet to Flathub for the first time, then switch to the repo's automated update flow.
|
||||
|
||||
The Flatpak app ID used in this repo is `dev.gitcomet.GitComet`.
|
||||
|
||||
## 1. What to verify before submission
|
||||
|
||||
Before opening a Flathub submission, verify all of these on a Linux machine:
|
||||
|
||||
- the Flatpak builds successfully from this repo
|
||||
- the single-file `.flatpak` bundle installs cleanly
|
||||
- the app launches from the desktop and from `flatpak run`
|
||||
- the app can open a real host repository
|
||||
- normal Git operations work inside the sandbox
|
||||
- the desktop file, icon, and metainfo look correct
|
||||
- the declared permissions match what the app really needs
|
||||
|
||||
If you develop on macOS or Windows, do this section in a Linux VM.
|
||||
|
||||
## 2. Prerequisites
|
||||
|
||||
Install Flatpak and `flatpak-builder` from your distro, then make sure the Flathub remote exists:
|
||||
|
||||
```bash
|
||||
flatpak remote-add --if-not-exists --user flathub https://dl.flathub.org/repo/flathub.flatpakrepo
|
||||
```
|
||||
|
||||
Install the Flathub-maintained builder runtime used by Flathub's docs and linter:
|
||||
|
||||
```bash
|
||||
flatpak install --user -y flathub org.flatpak.Builder
|
||||
```
|
||||
|
||||
## 3. Clean out any previous local test install
|
||||
|
||||
If you already installed an older GitComet Flatpak locally, remove it first:
|
||||
|
||||
```bash
|
||||
flatpak uninstall --user -y dev.gitcomet.GitComet || true
|
||||
rm -rf builddir repo dist/dev.gitcomet.GitComet.flatpak
|
||||
```
|
||||
|
||||
## 4. Build the local Flatpak from this repo
|
||||
|
||||
From the repository root:
|
||||
|
||||
```bash
|
||||
flatpak-builder \
|
||||
--force-clean \
|
||||
--user \
|
||||
--install-deps-from=flathub \
|
||||
--repo=repo \
|
||||
--install \
|
||||
builddir \
|
||||
flatpak/dev.gitcomet.GitComet.local.yaml
|
||||
```
|
||||
|
||||
What this does:
|
||||
|
||||
- builds the Flatpak from `flatpak/dev.gitcomet.GitComet.local.yaml`
|
||||
- exports the result to a local OSTree repo at `./repo`
|
||||
- installs the Flatpak into your user Flatpak installation
|
||||
|
||||
## 5. Build the single-file `.flatpak` bundle
|
||||
|
||||
This is the install format you should manually verify before submission:
|
||||
|
||||
```bash
|
||||
mkdir -p dist
|
||||
flatpak build-bundle \
|
||||
repo \
|
||||
dist/dev.gitcomet.GitComet.flatpak \
|
||||
dev.gitcomet.GitComet \
|
||||
--runtime-repo=https://dl.flathub.org/repo/flathub.flatpakrepo
|
||||
```
|
||||
|
||||
## 6. Reinstall from the bundle
|
||||
|
||||
First remove the locally installed build, then install the actual bundle file:
|
||||
|
||||
```bash
|
||||
flatpak uninstall --user -y dev.gitcomet.GitComet || true
|
||||
flatpak install --user -y dist/dev.gitcomet.GitComet.flatpak
|
||||
```
|
||||
|
||||
Confirm the installed app ID:
|
||||
|
||||
```bash
|
||||
flatpak info dev.gitcomet.GitComet
|
||||
```
|
||||
|
||||
Inspect the shipped permissions:
|
||||
|
||||
```bash
|
||||
flatpak info --show-permissions dev.gitcomet.GitComet
|
||||
```
|
||||
|
||||
Expected defaults from this repo:
|
||||
|
||||
- `--filesystem=host`
|
||||
- `--share=network`
|
||||
- `--socket=ssh-auth`
|
||||
- `--socket=gpg-agent`
|
||||
- `--socket=wayland`
|
||||
- `--socket=fallback-x11`
|
||||
- `--talk-name=org.freedesktop.Flatpak`
|
||||
- `--talk-name=org.freedesktop.FileManager1`
|
||||
- `--talk-name=org.freedesktop.Notifications`
|
||||
|
||||
## 7. Launch tests
|
||||
|
||||
Launch from the terminal:
|
||||
|
||||
```bash
|
||||
flatpak run dev.gitcomet.GitComet
|
||||
```
|
||||
|
||||
Also verify that it appears correctly in the desktop launcher:
|
||||
|
||||
- app name is `GitComet`
|
||||
- icon is present
|
||||
- the app opens normally from the graphical launcher
|
||||
|
||||
## 8. Functional tests inside the sandbox
|
||||
|
||||
Use a disposable test repo so you can verify normal flows end to end.
|
||||
|
||||
Create one:
|
||||
|
||||
```bash
|
||||
mkdir -p /tmp/gitcomet-flatpak-test
|
||||
cd /tmp/gitcomet-flatpak-test
|
||||
git init
|
||||
printf '# Flatpak test\n' > README.md
|
||||
git add README.md
|
||||
git commit -m "Initial commit"
|
||||
```
|
||||
|
||||
Then verify this checklist manually in the Flatpak build:
|
||||
|
||||
1. Open `/tmp/gitcomet-flatpak-test` in GitComet.
|
||||
2. Confirm the commit history appears.
|
||||
3. Edit `README.md`, then stage and unstage the change.
|
||||
4. Create a commit from inside GitComet.
|
||||
5. If you use SSH remotes, add a disposable SSH remote and verify fetch/pull/push.
|
||||
6. If you sign commits or tags, verify GPG agent access.
|
||||
7. If you rely on difftool or mergetool paths, test at least one real conflict or diff flow.
|
||||
|
||||
Important things to watch for:
|
||||
|
||||
- no missing repository access errors
|
||||
- no missing `git` binary errors
|
||||
- auth prompts work
|
||||
- the app is using the host Git successfully
|
||||
- temp-file-based auth, merge, or diff flows work
|
||||
|
||||
## 9. Lint and metadata checks
|
||||
|
||||
Run the same basic checks Flathub expects before you submit:
|
||||
|
||||
```bash
|
||||
flatpak run --command=flatpak-builder-lint org.flatpak.Builder manifest flatpak/dev.gitcomet.GitComet.local.yaml
|
||||
flatpak run --command=flatpak-builder-lint org.flatpak.Builder repo repo
|
||||
flatpak run --command=flatpak-builder-lint org.flatpak.Builder appstream flatpak/dev.gitcomet.GitComet.metainfo.xml
|
||||
desktop-file-validate assets/linux/dev.gitcomet.GitComet.desktop
|
||||
appstreamcli validate --no-net flatpak/dev.gitcomet.GitComet.metainfo.xml
|
||||
```
|
||||
|
||||
Do not submit until these are clean or you explicitly know which exception you need.
|
||||
|
||||
## 10. Prepare the first public release assets
|
||||
|
||||
For the first Flathub submission, you need public release assets that Flathub can fetch.
|
||||
|
||||
The minimum assets needed for the Flathub PR are:
|
||||
|
||||
- `gitcomet-v<VERSION>-source.tar.gz`
|
||||
- `dev.gitcomet.GitComet.yaml`
|
||||
- `cargo-sources.json`
|
||||
- `flathub.json`
|
||||
|
||||
### Recommended first-release path
|
||||
|
||||
Use a normal public GitHub release first, then use this repo's existing build workflow to attach the Flatpak/Flathub assets.
|
||||
|
||||
Example for version `0.2.0`:
|
||||
|
||||
```bash
|
||||
git tag -a v0.2.0 -m "GitComet v0.2.0"
|
||||
git push origin v0.2.0
|
||||
gh release create v0.2.0 \
|
||||
--repo Auto-Explore/GitComet \
|
||||
--title "GitComet v0.2.0" \
|
||||
--generate-notes
|
||||
RELEASE_ID="$(gh release view v0.2.0 --repo Auto-Explore/GitComet --json id --jq '.id')"
|
||||
gh workflow run build-release-artifacts.yml \
|
||||
-f tag=v0.2.0 \
|
||||
-f version=0.2.0 \
|
||||
-f release_id="$RELEASE_ID"
|
||||
```
|
||||
|
||||
After that workflow finishes, the GitHub release should contain:
|
||||
|
||||
- the Linux Flatpak bundle
|
||||
- the source tarball
|
||||
- the rendered Flathub manifest
|
||||
- `cargo-sources.json`
|
||||
- `flathub.json`
|
||||
|
||||
Note:
|
||||
|
||||
- for the very first Flathub submission, do not rely on `release-manual-main.yml` unless the Flathub app repo already exists and `FLATHUB_TOKEN` has been configured
|
||||
- the app-specific Flathub repo does not exist until the initial submission is accepted
|
||||
|
||||
## 11. Download the submission files
|
||||
|
||||
Download these release assets locally:
|
||||
|
||||
- `dev.gitcomet.GitComet.yaml`
|
||||
- `cargo-sources.json`
|
||||
- `flathub.json`
|
||||
|
||||
You will put those into the Flathub submission PR.
|
||||
|
||||
Before you open the PR, lint the exact rendered manifest you are about to submit:
|
||||
|
||||
```bash
|
||||
flatpak run --command=flatpak-builder-lint org.flatpak.Builder manifest dev.gitcomet.GitComet.yaml
|
||||
```
|
||||
|
||||
## 12. Open the first Flathub submission PR
|
||||
|
||||
New Flathub app submissions go through `flathub/flathub` and must target the `new-pr` base branch.
|
||||
|
||||
### Option A: with GitHub CLI
|
||||
|
||||
```bash
|
||||
gh repo fork --clone flathub/flathub
|
||||
cd flathub
|
||||
git checkout --track origin/new-pr
|
||||
git checkout -b gitcomet-submission
|
||||
```
|
||||
|
||||
### Option B: manual Git setup
|
||||
|
||||
1. Fork `flathub/flathub` on GitHub.
|
||||
2. Make sure "Copy the master branch only" is unchecked when you fork.
|
||||
3. Clone your fork's `new-pr` branch:
|
||||
|
||||
```bash
|
||||
git clone --branch=new-pr git@github.com:YOUR_GITHUB_USERNAME/flathub.git
|
||||
cd flathub
|
||||
git checkout -b gitcomet-submission
|
||||
```
|
||||
|
||||
### Add the GitComet submission files
|
||||
|
||||
Copy these into the root of the cloned `flathub` repo:
|
||||
|
||||
- `dev.gitcomet.GitComet.yaml`
|
||||
- `cargo-sources.json`
|
||||
- `flathub.json`
|
||||
|
||||
Then commit and push:
|
||||
|
||||
```bash
|
||||
git add dev.gitcomet.GitComet.yaml cargo-sources.json flathub.json
|
||||
git commit -m "Add dev.gitcomet.GitComet"
|
||||
git push origin gitcomet-submission
|
||||
```
|
||||
|
||||
### Create the pull request
|
||||
|
||||
Open a PR with:
|
||||
|
||||
- base repo: `flathub/flathub`
|
||||
- base branch: `new-pr`
|
||||
- title: `Add dev.gitcomet.GitComet`
|
||||
|
||||
Do not target `master` or the default branch.
|
||||
|
||||
If you use GitHub CLI, this is the equivalent command:
|
||||
|
||||
```bash
|
||||
gh pr create \
|
||||
--repo flathub/flathub \
|
||||
--base new-pr \
|
||||
--head YOUR_GITHUB_USERNAME:gitcomet-submission \
|
||||
--title "Add dev.gitcomet.GitComet"
|
||||
```
|
||||
|
||||
## 13. Handle review
|
||||
|
||||
While the submission is under review:
|
||||
|
||||
- keep using the same PR
|
||||
- push fixes to the same branch
|
||||
- do not close and reopen the PR just to address comments
|
||||
- do not merge the default Flathub branch into your submission branch
|
||||
|
||||
If reviewers ask for permission changes, metadata fixes, or linter exceptions, update the same PR.
|
||||
|
||||
## 14. Verify ownership of `gitcomet.dev`
|
||||
|
||||
Once the submission is accepted and you have collaborator access to the app repository, verify the app in the Flathub Developer Portal.
|
||||
|
||||
The verification path for this app ID is:
|
||||
|
||||
```text
|
||||
https://gitcomet.dev/.well-known/org.flathub.VerifiedApps.txt
|
||||
```
|
||||
|
||||
The process is:
|
||||
|
||||
1. Log in to Flathub.
|
||||
2. Open the Developer Portal.
|
||||
3. Open the GitComet app entry.
|
||||
4. Open `Verification`.
|
||||
5. Copy the generated token.
|
||||
6. Publish that token at `https://gitcomet.dev/.well-known/org.flathub.VerifiedApps.txt`.
|
||||
7. Retry verification in the portal.
|
||||
|
||||
If multiple apps are ever verified under `gitcomet.dev`, put each token on its own line.
|
||||
|
||||
## 15. Switch to automated updates after the first acceptance
|
||||
|
||||
After the first submission is accepted, Flathub will create an app-specific packaging repo, typically:
|
||||
|
||||
```text
|
||||
flathub/dev.gitcomet.GitComet
|
||||
```
|
||||
|
||||
At that point, configure these in the GitComet GitHub repo:
|
||||
|
||||
- secret `FLATHUB_TOKEN`
|
||||
- optional variable `FLATHUB_REPO=flathub/dev.gitcomet.GitComet`
|
||||
- optional variable `FLATHUB_BRANCH`
|
||||
- optional variable `FLATHUB_MODE=pull_request`
|
||||
|
||||
Recommended setting:
|
||||
|
||||
- use `FLATHUB_MODE=pull_request` first
|
||||
- only switch to `push` if you intentionally want direct commits to the Flathub app repo
|
||||
|
||||
This repo already has a release-time Flathub deployment workflow. Once the app repo exists and the token is configured, `release-manual-main.yml` can:
|
||||
|
||||
1. publish the GitHub release
|
||||
2. upload the Flatpak and Flathub assets
|
||||
3. open or update the Flathub packaging PR automatically
|
||||
|
||||
## 16. Why `flathub.json` is included
|
||||
|
||||
This repo ships a `flathub.json` with:
|
||||
|
||||
```json
|
||||
{
|
||||
"disable-external-data-checker": true
|
||||
}
|
||||
```
|
||||
|
||||
That is intentional.
|
||||
|
||||
GitComet's GitHub release flow already creates the Flathub update payload. Disabling Flathub's default hourly external-data-checker avoids duplicate update PRs.
|
||||
|
||||
## 17. Quick checklist
|
||||
|
||||
Before first submission:
|
||||
|
||||
- local Flatpak build passes
|
||||
- bundle install passes
|
||||
- app launches and works
|
||||
- linter checks pass
|
||||
- public GitHub release exists
|
||||
- release contains `dev.gitcomet.GitComet.yaml`
|
||||
- release contains `cargo-sources.json`
|
||||
- release contains `flathub.json`
|
||||
- submission PR targets `flathub/flathub:new-pr`
|
||||
|
||||
After acceptance:
|
||||
|
||||
- app verified with `gitcomet.dev`
|
||||
- collaborator access to the app repo confirmed
|
||||
- `FLATHUB_TOKEN` configured in GitHub
|
||||
- `release-manual-main.yml` used for ongoing releases
|
||||
11097
flatpak/cargo-sources.json
Normal file
11097
flatpak/cargo-sources.json
Normal file
File diff suppressed because it is too large
Load diff
43
flatpak/dev.gitcomet.GitComet.local.yaml
Normal file
43
flatpak/dev.gitcomet.GitComet.local.yaml
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
app-id: dev.gitcomet.GitComet
|
||||
runtime: org.freedesktop.Platform
|
||||
runtime-version: "24.08"
|
||||
sdk: org.freedesktop.Sdk
|
||||
sdk-extensions:
|
||||
- org.freedesktop.Sdk.Extension.rust-stable
|
||||
command: gitcomet-app
|
||||
finish-args:
|
||||
- --device=dri
|
||||
- --share=ipc
|
||||
- --share=network
|
||||
- --socket=wayland
|
||||
- --socket=fallback-x11
|
||||
- --socket=ssh-auth
|
||||
- --socket=gpg-agent
|
||||
- --filesystem=host
|
||||
- --talk-name=org.freedesktop.FileManager1
|
||||
- --talk-name=org.freedesktop.Flatpak
|
||||
- --talk-name=org.freedesktop.Notifications
|
||||
modules:
|
||||
- name: gitcomet
|
||||
buildsystem: simple
|
||||
build-options:
|
||||
append-path: /usr/lib/sdk/rust-stable/bin
|
||||
env:
|
||||
CARGO_HOME: /run/build/gitcomet/cargo
|
||||
CARGO_NET_OFFLINE: "true"
|
||||
build-commands:
|
||||
- cargo --offline fetch --manifest-path Cargo.toml --locked --verbose
|
||||
- cargo build --offline --release --locked -p gitcomet-app --features ui-gpui,gix
|
||||
- install -Dm755 target/release/gitcomet-app ${FLATPAK_DEST}/bin/gitcomet-app
|
||||
- install -Dm755 flatpak/git-wrapper.sh ${FLATPAK_DEST}/bin/git
|
||||
- install -Dm644 assets/linux/dev.gitcomet.GitComet.desktop ${FLATPAK_DEST}/share/applications/dev.gitcomet.GitComet.desktop
|
||||
- install -Dm644 flatpak/dev.gitcomet.GitComet.metainfo.xml ${FLATPAK_DEST}/share/metainfo/dev.gitcomet.GitComet.metainfo.xml
|
||||
- install -Dm644 assets/linux/hicolor/32x32/apps/gitcomet.png ${FLATPAK_DEST}/share/icons/hicolor/32x32/apps/dev.gitcomet.GitComet.png
|
||||
- install -Dm644 assets/linux/hicolor/48x48/apps/gitcomet.png ${FLATPAK_DEST}/share/icons/hicolor/48x48/apps/dev.gitcomet.GitComet.png
|
||||
- install -Dm644 assets/linux/hicolor/128x128/apps/gitcomet.png ${FLATPAK_DEST}/share/icons/hicolor/128x128/apps/dev.gitcomet.GitComet.png
|
||||
- install -Dm644 assets/linux/hicolor/256x256/apps/gitcomet.png ${FLATPAK_DEST}/share/icons/hicolor/256x256/apps/dev.gitcomet.GitComet.png
|
||||
- install -Dm644 assets/linux/hicolor/512x512/apps/gitcomet.png ${FLATPAK_DEST}/share/icons/hicolor/512x512/apps/dev.gitcomet.GitComet.png
|
||||
sources:
|
||||
- type: dir
|
||||
path: ..
|
||||
- cargo-sources.json
|
||||
32
flatpak/dev.gitcomet.GitComet.metainfo.xml
Normal file
32
flatpak/dev.gitcomet.GitComet.metainfo.xml
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<component type="desktop-application">
|
||||
<id>dev.gitcomet.GitComet</id>
|
||||
<metadata_license>CC0-1.0</metadata_license>
|
||||
<project_license>AGPL-3.0-only</project_license>
|
||||
<name>GitComet</name>
|
||||
<summary>Fast, resource-efficient Git GUI written in Rust</summary>
|
||||
<developer id="dev.gitcomet">
|
||||
<name>AutoExplore Oy</name>
|
||||
</developer>
|
||||
<launchable type="desktop-id">dev.gitcomet.GitComet.desktop</launchable>
|
||||
<provides>
|
||||
<binary>gitcomet-app</binary>
|
||||
</provides>
|
||||
<description>
|
||||
<p>GitComet is a fast Git GUI built for large repositories, familiar history browsing, local-first privacy, and drop-in difftool and mergetool workflows.</p>
|
||||
<p>It supports staging, commits, branches, remotes, worktrees, history, side-by-side diffs, and conflict resolution.</p>
|
||||
</description>
|
||||
<categories>
|
||||
<category>Development</category>
|
||||
<category>RevisionControl</category>
|
||||
</categories>
|
||||
<screenshots>
|
||||
<screenshot type="default">
|
||||
<image>https://raw.githubusercontent.com/Auto-Explore/GitComet/main/assets/gitcomet_screenshot.png</image>
|
||||
</screenshot>
|
||||
</screenshots>
|
||||
<content_rating type="oars-1.1"/>
|
||||
<url type="homepage">https://gitcomet.dev</url>
|
||||
<url type="bugtracker">https://github.com/Auto-Explore/GitComet/issues</url>
|
||||
<url type="vcs-browser">https://github.com/Auto-Explore/GitComet</url>
|
||||
</component>
|
||||
50
flatpak/dev.gitcomet.GitComet.yaml.in
Normal file
50
flatpak/dev.gitcomet.GitComet.yaml.in
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
app-id: dev.gitcomet.GitComet
|
||||
runtime: org.freedesktop.Platform
|
||||
runtime-version: "24.08"
|
||||
sdk: org.freedesktop.Sdk
|
||||
sdk-extensions:
|
||||
- org.freedesktop.Sdk.Extension.rust-stable
|
||||
command: gitcomet-app
|
||||
finish-args:
|
||||
- --device=dri
|
||||
- --share=ipc
|
||||
- --share=network
|
||||
- --socket=wayland
|
||||
- --socket=fallback-x11
|
||||
- --socket=ssh-auth
|
||||
- --socket=gpg-agent
|
||||
- --filesystem=host
|
||||
- --talk-name=org.freedesktop.FileManager1
|
||||
- --talk-name=org.freedesktop.Flatpak
|
||||
- --talk-name=org.freedesktop.Notifications
|
||||
modules:
|
||||
- name: gitcomet
|
||||
buildsystem: simple
|
||||
build-options:
|
||||
append-path: /usr/lib/sdk/rust-stable/bin
|
||||
env:
|
||||
CARGO_HOME: /run/build/gitcomet/cargo
|
||||
CARGO_NET_OFFLINE: "true"
|
||||
build-commands:
|
||||
- cargo --offline fetch --manifest-path Cargo.toml --locked --verbose
|
||||
- cargo build --offline --release --locked -p gitcomet-app --features ui-gpui,gix
|
||||
- install -Dm755 target/release/gitcomet-app ${FLATPAK_DEST}/bin/gitcomet-app
|
||||
- install -Dm755 flatpak/git-wrapper.sh ${FLATPAK_DEST}/bin/git
|
||||
- install -Dm644 assets/linux/dev.gitcomet.GitComet.desktop ${FLATPAK_DEST}/share/applications/dev.gitcomet.GitComet.desktop
|
||||
- install -Dm644 flatpak/dev.gitcomet.GitComet.metainfo.xml ${FLATPAK_DEST}/share/metainfo/dev.gitcomet.GitComet.metainfo.xml
|
||||
- install -Dm644 assets/linux/hicolor/32x32/apps/gitcomet.png ${FLATPAK_DEST}/share/icons/hicolor/32x32/apps/dev.gitcomet.GitComet.png
|
||||
- install -Dm644 assets/linux/hicolor/48x48/apps/gitcomet.png ${FLATPAK_DEST}/share/icons/hicolor/48x48/apps/dev.gitcomet.GitComet.png
|
||||
- install -Dm644 assets/linux/hicolor/128x128/apps/gitcomet.png ${FLATPAK_DEST}/share/icons/hicolor/128x128/apps/dev.gitcomet.GitComet.png
|
||||
- install -Dm644 assets/linux/hicolor/256x256/apps/gitcomet.png ${FLATPAK_DEST}/share/icons/hicolor/256x256/apps/dev.gitcomet.GitComet.png
|
||||
- install -Dm644 assets/linux/hicolor/512x512/apps/gitcomet.png ${FLATPAK_DEST}/share/icons/hicolor/512x512/apps/dev.gitcomet.GitComet.png
|
||||
sources:
|
||||
- type: archive
|
||||
url: @SOURCE_URL@
|
||||
sha256: @SOURCE_SHA256@
|
||||
strip-components: 1
|
||||
x-checker-data:
|
||||
type: json
|
||||
url: https://api.github.com/repos/Auto-Explore/GitComet/releases/latest
|
||||
version-query: .tag_name | sub("^v"; "")
|
||||
url-query: '"https://github.com/Auto-Explore/GitComet/releases/download/" + .tag_name + "/gitcomet-v" + (.tag_name | sub("^v"; "")) + "-source.tar.gz"'
|
||||
- cargo-sources.json
|
||||
3
flatpak/flathub.json
Normal file
3
flatpak/flathub.json
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"disable-external-data-checker": true
|
||||
}
|
||||
35
flatpak/git-wrapper.sh
Executable file
35
flatpak/git-wrapper.sh
Executable file
|
|
@ -0,0 +1,35 @@
|
|||
#!/usr/bin/env sh
|
||||
set -eu
|
||||
|
||||
host_home=""
|
||||
if [ -n "${FLATPAK_ID:-}" ] && [ -n "${HOME:-}" ]; then
|
||||
suffix="/.var/app/${FLATPAK_ID}"
|
||||
case "$HOME" in
|
||||
*"$suffix")
|
||||
host_home="${HOME%$suffix}"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
set -- git "$@"
|
||||
|
||||
if [ -n "${host_home:-}" ]; then
|
||||
set -- "HOME=${host_home}" "$@"
|
||||
fi
|
||||
|
||||
[ -n "${HOST_XDG_CONFIG_HOME:-}" ] && set -- "XDG_CONFIG_HOME=${HOST_XDG_CONFIG_HOME}" "$@"
|
||||
[ -n "${HOST_XDG_DATA_HOME:-}" ] && set -- "XDG_DATA_HOME=${HOST_XDG_DATA_HOME}" "$@"
|
||||
[ -n "${HOST_XDG_CACHE_HOME:-}" ] && set -- "XDG_CACHE_HOME=${HOST_XDG_CACHE_HOME}" "$@"
|
||||
[ -n "${HOST_XDG_STATE_HOME:-}" ] && set -- "XDG_STATE_HOME=${HOST_XDG_STATE_HOME}" "$@"
|
||||
[ -n "${DISPLAY:-}" ] && set -- "DISPLAY=${DISPLAY}" "$@"
|
||||
[ -n "${WAYLAND_DISPLAY:-}" ] && set -- "WAYLAND_DISPLAY=${WAYLAND_DISPLAY}" "$@"
|
||||
[ -n "${GIT_ASKPASS:-}" ] && set -- "GIT_ASKPASS=${GIT_ASKPASS}" "$@"
|
||||
[ -n "${SSH_ASKPASS:-}" ] && set -- "SSH_ASKPASS=${SSH_ASKPASS}" "$@"
|
||||
[ -n "${SSH_ASKPASS_REQUIRE:-}" ] && set -- "SSH_ASKPASS_REQUIRE=${SSH_ASKPASS_REQUIRE}" "$@"
|
||||
[ -n "${GIT_TERMINAL_PROMPT:-}" ] && set -- "GIT_TERMINAL_PROMPT=${GIT_TERMINAL_PROMPT}" "$@"
|
||||
[ -n "${GITCOMET_ASKPASS_PROMPT_LOG:-}" ] && set -- "GITCOMET_ASKPASS_PROMPT_LOG=${GITCOMET_ASKPASS_PROMPT_LOG}" "$@"
|
||||
[ -n "${GITCOMET_AUTH_KIND:-}" ] && set -- "GITCOMET_AUTH_KIND=${GITCOMET_AUTH_KIND}" "$@"
|
||||
[ -n "${GITCOMET_AUTH_USERNAME:-}" ] && set -- "GITCOMET_AUTH_USERNAME=${GITCOMET_AUTH_USERNAME}" "$@"
|
||||
[ -n "${GITCOMET_AUTH_SECRET:-}" ] && set -- "GITCOMET_AUTH_SECRET=${GITCOMET_AUTH_SECRET}" "$@"
|
||||
|
||||
exec flatpak-spawn --host env "$@"
|
||||
118
scripts/generate-flatpak-cargo-sources.py
Executable file
118
scripts/generate-flatpak-cargo-sources.py
Executable file
|
|
@ -0,0 +1,118 @@
|
|||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import json
|
||||
import tomllib
|
||||
from pathlib import Path
|
||||
|
||||
CRATES_IO = "https://static.crates.io/crates"
|
||||
CARGO_HOME = "cargo"
|
||||
CARGO_CRATES = f"{CARGO_HOME}/vendor"
|
||||
VENDORED_SOURCES = "vendored-sources"
|
||||
CRATES_IO_SOURCE = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
|
||||
def package_checksum(package: dict, metadata: dict) -> str:
|
||||
checksum = package.get("checksum")
|
||||
if checksum:
|
||||
return checksum
|
||||
|
||||
key = (
|
||||
f'checksum {package["name"]} {package["version"]} '
|
||||
f'({package["source"]})'
|
||||
)
|
||||
checksum = metadata.get(key)
|
||||
if checksum:
|
||||
return checksum
|
||||
raise SystemExit(
|
||||
f'missing checksum for {package["name"]} {package["version"]}'
|
||||
)
|
||||
|
||||
|
||||
def cargo_config_contents() -> str:
|
||||
return (
|
||||
"[source.crates-io]\n"
|
||||
f'replace-with = "{VENDORED_SOURCES}"\n\n'
|
||||
f"[source.{VENDORED_SOURCES}]\n"
|
||||
f'directory = "{CARGO_CRATES}"\n'
|
||||
)
|
||||
|
||||
|
||||
def generate_sources(lock_path: Path) -> list[dict]:
|
||||
with lock_path.open("rb") as handle:
|
||||
cargo_lock = tomllib.load(handle)
|
||||
|
||||
metadata = cargo_lock.get("metadata", {})
|
||||
seen = set()
|
||||
sources = []
|
||||
for package in cargo_lock["package"]:
|
||||
source = package.get("source")
|
||||
if source is None:
|
||||
continue
|
||||
if source != CRATES_IO_SOURCE:
|
||||
raise SystemExit(
|
||||
f'unsupported non-crates.io dependency: {package["name"]} {source}'
|
||||
)
|
||||
|
||||
key = (package["name"], package["version"])
|
||||
if key in seen:
|
||||
continue
|
||||
seen.add(key)
|
||||
|
||||
checksum = package_checksum(package, metadata)
|
||||
dest = f'{CARGO_CRATES}/{package["name"]}-{package["version"]}'
|
||||
sources.append(
|
||||
{
|
||||
"type": "archive",
|
||||
"archive-type": "tar-gzip",
|
||||
"url": (
|
||||
f'{CRATES_IO}/{package["name"]}/'
|
||||
f'{package["name"]}-{package["version"]}.crate'
|
||||
),
|
||||
"sha256": checksum,
|
||||
"dest": dest,
|
||||
}
|
||||
)
|
||||
sources.append(
|
||||
{
|
||||
"type": "inline",
|
||||
"contents": json.dumps({"package": checksum, "files": {}}),
|
||||
"dest": dest,
|
||||
"dest-filename": ".cargo-checksum.json",
|
||||
}
|
||||
)
|
||||
|
||||
sources.append(
|
||||
{
|
||||
"type": "inline",
|
||||
"contents": cargo_config_contents(),
|
||||
"dest": CARGO_HOME,
|
||||
"dest-filename": "config",
|
||||
}
|
||||
)
|
||||
return sources
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
"cargo_lock",
|
||||
nargs="?",
|
||||
default="Cargo.lock",
|
||||
help="Path to Cargo.lock",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-o",
|
||||
"--output",
|
||||
default="flatpak/cargo-sources.json",
|
||||
help="Path to write generated cargo sources JSON",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
sources = generate_sources(Path(args.cargo_lock))
|
||||
output_path = Path(args.output)
|
||||
output_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
output_path.write_text(json.dumps(sources, indent=4) + "\n", encoding="utf-8")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
@ -7,8 +7,8 @@ Usage: scripts/install-linux.sh [--release|--debug] [--prefix PATH] [--no-build]
|
|||
|
||||
Installs:
|
||||
- binary to <prefix>/bin/gitcomet-app
|
||||
- desktop entry to ~/.local/share/applications/gitcomet.desktop
|
||||
- icons to ~/.local/share/icons/hicolor/<size>x<size>/apps/gitcomet.png
|
||||
- desktop entry to ~/.local/share/applications/dev.gitcomet.GitComet.desktop
|
||||
- icons to ~/.local/share/icons/hicolor/<size>x<size>/apps/dev.gitcomet.GitComet.png
|
||||
sizes: 32, 48, 128, 256, 512
|
||||
|
||||
Defaults:
|
||||
|
|
@ -52,6 +52,8 @@ bindir="${prefix}/bin"
|
|||
appdir="${XDG_DATA_HOME:-${HOME}/.local/share}/applications"
|
||||
iconsroot="${XDG_DATA_HOME:-${HOME}/.local/share}/icons/hicolor"
|
||||
icon_sizes=(32 48 128 256 512)
|
||||
desktop_file="dev.gitcomet.GitComet.desktop"
|
||||
icon_name="dev.gitcomet.GitComet"
|
||||
|
||||
install -Dm755 "$bin_src" "${bindir}/gitcomet-app"
|
||||
|
||||
|
|
@ -59,12 +61,17 @@ install -Dm755 "$bin_src" "${bindir}/gitcomet-app"
|
|||
tmp_desktop="$(mktemp)"
|
||||
trap 'rm -f "$tmp_desktop"' EXIT
|
||||
sed "s|^Exec=.*$|Exec=${bindir}/gitcomet-app|g" \
|
||||
"${repo_root}/assets/linux/gitcomet.desktop" >"$tmp_desktop"
|
||||
install -Dm644 "$tmp_desktop" "${appdir}/gitcomet.desktop"
|
||||
"${repo_root}/assets/linux/${desktop_file}" >"$tmp_desktop"
|
||||
install -Dm644 "$tmp_desktop" "${appdir}/${desktop_file}"
|
||||
|
||||
for size in "${icon_sizes[@]}"; do
|
||||
install -Dm644 "${repo_root}/assets/linux/hicolor/${size}x${size}/apps/gitcomet.png" \
|
||||
"${iconsroot}/${size}x${size}/apps/gitcomet.png"
|
||||
"${iconsroot}/${size}x${size}/apps/${icon_name}.png"
|
||||
done
|
||||
|
||||
rm -f "${appdir}/gitcomet.desktop"
|
||||
for size in "${icon_sizes[@]}"; do
|
||||
rm -f "${iconsroot}/${size}x${size}/apps/gitcomet.png"
|
||||
done
|
||||
|
||||
command -v update-desktop-database >/dev/null 2>&1 && update-desktop-database "$appdir" >/dev/null 2>&1 || true
|
||||
|
|
@ -72,8 +79,8 @@ command -v gtk-update-icon-cache >/dev/null 2>&1 && gtk-update-icon-cache "${ico
|
|||
|
||||
echo "Installed GitComet:"
|
||||
echo " ${bindir}/gitcomet-app"
|
||||
echo " ${appdir}/gitcomet.desktop"
|
||||
echo " ${appdir}/${desktop_file}"
|
||||
for size in "${icon_sizes[@]}"; do
|
||||
echo " ${iconsroot}/${size}x${size}/apps/gitcomet.png"
|
||||
echo " ${iconsroot}/${size}x${size}/apps/${icon_name}.png"
|
||||
done
|
||||
echo "If GNOME still shows a generic icon, log out/in (or restart GNOME Shell)."
|
||||
|
|
|
|||
|
|
@ -160,7 +160,7 @@ cat > "${contents_dir}/Info.plist" <<PLIST
|
|||
<key>CFBundleExecutable</key>
|
||||
<string>gitcomet-app</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>ai.autoexplore.gitcomet</string>
|
||||
<string>dev.gitcomet.GitComet</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>GitComet.icns</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
|
|
|
|||
35
scripts/render-flathub-manifest.sh
Executable file
35
scripts/render-flathub-manifest.sh
Executable file
|
|
@ -0,0 +1,35 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage: scripts/render-flathub-manifest.sh --source-url URL --source-sha256 SHA256 --output PATH [--template PATH]
|
||||
EOF
|
||||
}
|
||||
|
||||
template="flatpak/dev.gitcomet.GitComet.yaml.in"
|
||||
source_url=""
|
||||
source_sha256=""
|
||||
output=""
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--template) template="$2"; shift 2 ;;
|
||||
--source-url) source_url="$2"; shift 2 ;;
|
||||
--source-sha256) source_sha256="$2"; shift 2 ;;
|
||||
--output) output="$2"; shift 2 ;;
|
||||
-h|--help) usage; exit 0 ;;
|
||||
*) echo "Unknown arg: $1" >&2; usage; exit 2 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -z "$source_url" || -z "$source_sha256" || -z "$output" ]]; then
|
||||
usage
|
||||
exit 2
|
||||
fi
|
||||
|
||||
mkdir -p "$(dirname "$output")"
|
||||
sed \
|
||||
-e "s|@SOURCE_URL@|${source_url}|g" \
|
||||
-e "s|@SOURCE_SHA256@|${source_sha256}|g" \
|
||||
"$template" >"$output"
|
||||
|
|
@ -17,11 +17,17 @@ bindir="${prefix}/bin"
|
|||
appdir="${XDG_DATA_HOME:-${HOME}/.local/share}/applications"
|
||||
iconsroot="${XDG_DATA_HOME:-${HOME}/.local/share}/icons/hicolor"
|
||||
icon_sizes=(32 48 128 256 512)
|
||||
desktop_files=("dev.gitcomet.GitComet.desktop" "gitcomet.desktop")
|
||||
icon_names=("dev.gitcomet.GitComet" "gitcomet")
|
||||
|
||||
rm -f "${bindir}/gitcomet-app"
|
||||
rm -f "${appdir}/gitcomet.desktop"
|
||||
for desktop_file in "${desktop_files[@]}"; do
|
||||
rm -f "${appdir}/${desktop_file}"
|
||||
done
|
||||
for size in "${icon_sizes[@]}"; do
|
||||
rm -f "${iconsroot}/${size}x${size}/apps/gitcomet.png"
|
||||
for icon_name in "${icon_names[@]}"; do
|
||||
rm -f "${iconsroot}/${size}x${size}/apps/${icon_name}.png"
|
||||
done
|
||||
done
|
||||
|
||||
command -v update-desktop-database >/dev/null 2>&1 && update-desktop-database "$appdir" >/dev/null 2>&1 || true
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue