Merge pull request #1736 from tonymet/winget-publishing

Winget Publishing and GoReleaser
This commit is contained in:
Kayvan Sylvan
2025-08-31 07:36:12 -07:00
committed by GitHub
12 changed files with 99 additions and 290 deletions

View File

@@ -1,9 +1,12 @@
## What this Pull Request (PR) does
Please briefly describe what this PR does.
## Related issues
Please reference any open issues this PR relates to in here.
If it closes an issue, type `closes #[ISSUE_NUMBER]`.
## Screenshots
Provide any screenshots you may find relevant to facilitate us understanding your PR.

View File

@@ -20,13 +20,13 @@ jobs:
contents: read
steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Install Nix
uses: DeterminateSystems/nix-installer-action@main
- name: Set up Go
uses: actions/setup-go@v4
uses: actions/setup-go@v5
with:
go-version-file: ./go.mod

View File

@@ -1,150 +0,0 @@
name: Release Docker image on tag (GHCR + Docker Hub)
on:
push:
tags: ["v*"] # e.g., v1.4.300
permissions:
contents: read
packages: write # needed for GHCR with GITHUB_TOKEN
jobs:
build-and-push:
# Optional safety: only run from your fork
if: ${{ github.repository_owner == 'ksylvan' }}
runs-on: ubuntu-latest
outputs:
is_latest: ${{ steps.latest.outputs.is_latest }}
owner_lc: ${{ steps.vars.outputs.owner_lc }}
repo_lc: ${{ steps.vars.outputs.repo_lc }}
dockerhub_user_lc: ${{ steps.dh.outputs.user_lc }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0 # full history for tag comparisons
- name: Fetch all tags
run: git fetch --tags --force
# More reliable cross-builds
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
# Compute lowercase owner/repo for registry image names
- name: Compute image names
id: vars
run: |
OWNER="${GITHUB_REPOSITORY_OWNER}"
REPO="${GITHUB_REPOSITORY#*/}"
echo "owner_lc=${OWNER,,}" >> "$GITHUB_OUTPUT"
echo "repo_lc=${REPO,,}" >> "$GITHUB_OUTPUT"
# Lowercase Docker Hub username (belt & suspenders)
- name: Lowercase Docker Hub username
id: dh
run: echo "user_lc=${DOCKERHUB_USERNAME,,}" >> "$GITHUB_OUTPUT"
env:
DOCKERHUB_USERNAME: ${{ vars.DOCKERHUB_USERNAME }}
# Determine if the current tag is the highest vX.Y.Z (no pre-releases)
- name: Is this the latest semver tag?
id: latest
shell: bash
run: |
CTAG="${GITHUB_REF_NAME}"
LATEST="$(git tag -l 'v[0-9]*.[0-9]*.[0-9]*' --sort=-v:refname | head -n1)"
echo "current_tag=$CTAG" >> "$GITHUB_OUTPUT"
echo "latest_tag=$LATEST" >> "$GITHUB_OUTPUT"
if [[ "$CTAG" == "$LATEST" ]]; then
echo "is_latest=true" >> "$GITHUB_OUTPUT"
else
echo "is_latest=false" >> "$GITHUB_OUTPUT"
fi
# Login to GHCR (uses built-in GITHUB_TOKEN)
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# Login to Docker Hub
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ steps.dh.outputs.user_lc }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
# Generate versioned tags/labels for BOTH registries (no :latest here)
- name: Extract metadata (tags, labels)
id: meta
uses: docker/metadata-action@v5
with:
images: |
ghcr.io/${{ steps.vars.outputs.owner_lc }}/${{ steps.vars.outputs.repo_lc }}
docker.io/${{ steps.dh.outputs.user_lc }}/${{ steps.vars.outputs.repo_lc }}
tags: |
type=ref,event=tag # v1.4.300
type=semver,pattern={{version}} # 1.4.300 (optional)
type=semver,pattern={{major}}.{{minor}} # 1.4 (optional)
labels: |
org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}
- name: Build and push (multi-arch)
uses: docker/build-push-action@v6
with:
context: .
file: ./scripts/docker/Dockerfile
push: true
platforms: linux/amd64,linux/arm64
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
# Separate job to (re)point :latest — serialized to avoid races
move-latest:
needs: build-and-push
if: ${{ needs.build-and-push.outputs.is_latest == 'true' }}
runs-on: ubuntu-latest
# Only one "latest" move at a time; newer runs cancel older in-progress ones
concurrency:
group: latest-${{ github.repository }}
cancel-in-progress: true
steps:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Tag :latest on GHCR
run: |
SRC="ghcr.io/${{ needs.build-and-push.outputs.owner_lc }}/${{ needs.build-and-push.outputs.repo_lc }}:${{ github.ref_name }}"
DST="ghcr.io/${{ needs.build-and-push.outputs.owner_lc }}/${{ needs.build-and-push.outputs.repo_lc }}:latest"
docker buildx imagetools create -t "$DST" "$SRC"
- name: Tag :latest on Docker Hub
run: |
SRC="docker.io/${{ needs.build-and-push.outputs.dockerhub_user_lc }}/${{ needs.build-and-push.outputs.repo_lc }}:${{ github.ref_name }}"
DST="docker.io/${{ needs.build-and-push.outputs.dockerhub_user_lc }}/${{ needs.build-and-push.outputs.repo_lc }}:latest"
docker buildx imagetools create -t "$DST" "$SRC"

View File

@@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
fetch-depth: 0
@@ -26,7 +26,6 @@ jobs:
echo "Changes detected in patterns folder."
echo "changes=true" >> $GITHUB_OUTPUT
fi
- name: Zip the Patterns Folder
if: steps.check-changes.outputs.changes == 'true'
run: zip -r patterns.zip data/patterns/

View File

@@ -15,149 +15,39 @@ jobs:
contents: read
steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Set up Go
uses: actions/setup-go@v4
uses: actions/setup-go@v5
with:
go-version-file: ./go.mod
- name: Run tests
run: go test -v ./...
get_version:
name: Get version
runs-on: ubuntu-latest
outputs:
latest_tag: ${{ steps.get_version.outputs.latest_tag }}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Get version from source
id: get_version
shell: bash
run: |
if [ ! -f "nix/pkgs/fabric/version.nix" ]; then
echo "Error: version.nix file not found"
exit 1
fi
version=$(cat nix/pkgs/fabric/version.nix | tr -d '"' | tr -cd '0-9.')
if [ -z "$version" ]; then
echo "Error: version is empty"
exit 1
fi
if ! echo "$version" | grep -E '^[0-9]+\.[0-9]+\.[0-9]+' > /dev/null; then
echo "Error: Invalid version format: $version"
exit 1
fi
echo "latest_tag=v$version" >> $GITHUB_OUTPUT
build:
name: Build binaries for Windows, macOS, and Linux
needs: [test, get_version]
runs-on: ${{ matrix.os }}
permissions:
contents: write
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
arch: [amd64, arm64]
exclude:
- os: windows-latest
arch: arm64
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version-file: ./go.mod
- name: Build binary on Linux and macOS
if: matrix.os != 'windows-latest'
env:
GOOS: ${{ matrix.os == 'ubuntu-latest' && 'linux' || 'darwin' }}
GOARCH: ${{ matrix.arch }}
run: |
OS_NAME="${{ matrix.os == 'ubuntu-latest' && 'linux' || 'darwin' }}"
go build -o fabric-${OS_NAME}-${{ matrix.arch }} ./cmd/fabric
- name: Build binary on Windows
if: matrix.os == 'windows-latest'
env:
GOOS: windows
GOARCH: ${{ matrix.arch }}
run: |
go build -o fabric-windows-${{ matrix.arch }}.exe ./cmd/fabric
- name: Upload build artifact
if: matrix.os != 'windows-latest'
uses: actions/upload-artifact@v4
with:
name: fabric-${{ matrix.os == 'ubuntu-latest' && 'linux' || 'darwin' }}-${{ matrix.arch }}
path: fabric-${{ matrix.os == 'ubuntu-latest' && 'linux' || 'darwin' }}-${{ matrix.arch }}
- name: Upload build artifact
if: matrix.os == 'windows-latest'
uses: actions/upload-artifact@v4
with:
name: fabric-windows-${{ matrix.arch }}.exe
path: fabric-windows-${{ matrix.arch }}.exe
- name: Create release if it doesn't exist
shell: bash
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
if ! gh release view ${{ needs.get_version.outputs.latest_tag }} >/dev/null 2>&1; then
gh release create ${{ needs.get_version.outputs.latest_tag }} --title "Release ${{ needs.get_version.outputs.latest_tag }}" --notes "Automated release for ${{ needs.get_version.outputs.latest_tag }}"
else
echo "Release ${{ needs.get_version.outputs.latest_tag }} already exists."
fi
- name: Upload release artifact
if: matrix.os == 'windows-latest'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release upload ${{ needs.get_version.outputs.latest_tag }} fabric-windows-${{ matrix.arch }}.exe
- name: Upload release artifact
if: matrix.os != 'windows-latest'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
OS_NAME="${{ matrix.os == 'ubuntu-latest' && 'linux' || 'darwin' }}"
gh release upload ${{ needs.get_version.outputs.latest_tag }} fabric-${OS_NAME}-${{ matrix.arch }}
update_release_notes:
needs: [build, get_version]
# only run in main upstream repo
if: ${{ github.repository_owner == 'danielmiessler' }}
name: Build & Release with Goreleaser
needs: [test]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Set up Go
uses: actions/setup-go@v4
uses: actions/setup-go@v5
with:
go-version-file: ./go.mod
- name: Update release description
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v6
with:
distribution: goreleaser
args: release --clean
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
go run ./cmd/generate_changelog --sync-db
go run ./cmd/generate_changelog --release ${{ needs.get_version.outputs.latest_tag }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -21,12 +21,13 @@ concurrency:
jobs:
update-version:
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
if: >
${{ github.repository_owner == 'danielmiessler' }} &&
github.event_name == 'push' && github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
fetch-depth: 0
@@ -48,12 +49,13 @@ jobs:
run: |
latest_tag=$(git tag --sort=-creatordate | head -n 1)
echo "Latest tag is: $latest_tag"
echo "tag=$latest_tag" >> $GITHUB_OUTPUT
echo "tag=$latest_tag" >> $GITHUB_ENV # Save the latest tag to environment file
- name: Increment patch version
id: increment_version
run: |
latest_tag=${{ env.tag }}
latest_tag=${{ steps.get_latest_tag.outputs.tag }}
major=$(echo "$latest_tag" | cut -d. -f1 | sed 's/v//')
minor=$(echo "$latest_tag" | cut -d. -f2)
patch=$(echo "$latest_tag" | cut -d. -f3)
@@ -61,19 +63,21 @@ jobs:
new_version="${major}.${minor}.${new_patch}"
new_tag="v${new_version}"
echo "New version is: $new_version"
echo "new_version=$new_version" >> $GITHUB_OUTPUT
echo "new_version=$new_version" >> $GITHUB_ENV # Save the new version to environment file
echo "New tag is: $new_tag"
echo "new_tag=$new_tag" >> $GITHUB_OUTPUT
echo "new_tag=$new_tag" >> $GITHUB_ENV # Save the new tag to environment file
- name: Update version.go file
run: |
echo "package main" > cmd/fabric/version.go
echo "" >> cmd/fabric/version.go
echo "var version = \"${{ env.new_tag }}\"" >> cmd/fabric/version.go
echo "var version = \"${{ steps.increment_version.outputs.new_tag }}\"" >> cmd/fabric/version.go
- name: Update version.nix file
run: |
echo "\"${{ env.new_version }}\"" > nix/pkgs/fabric/version.nix
echo "\"${{ steps.increment_version.outputs.new_version }}\"" > nix/pkgs/fabric/version.nix
- name: Format source code
run: |
@@ -87,7 +91,7 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
go run ./cmd/generate_changelog --process-prs ${{ env.new_tag }}
go run ./cmd/generate_changelog --process-prs ${{ steps.increment_version.outputs.new_tag }}
go run ./cmd/generate_changelog --sync-db
- name: Commit changes
run: |
@@ -100,7 +104,7 @@ jobs:
# and removing the incoming/ directory.
if ! git diff --staged --quiet; then
git commit -m "chore(release): Update version to ${{ env.new_tag }}"
git commit -m "chore(release): Update version to ${{ steps.increment_version.outputs.new_tag }}"
else
echo "No changes to commit."
fi
@@ -113,10 +117,10 @@ jobs:
- name: Create a new tag
env:
GITHUB_TOKEN: ${{ secrets.TAG_PAT }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
git tag ${{ env.new_tag }}
git push origin ${{ env.new_tag }} # Push the new tag
git tag ${{ steps.increment_version.outputs.new_tag }}
git push origin ${{ steps.increment_version.outputs.new_tag }} # Push the new tag
- name: Dispatch event to trigger release workflow
env:
@@ -126,4 +130,4 @@ jobs:
-H "Authorization: token $GITHUB_TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/${{ github.repository }}/dispatches \
-d '{"event_type": "tag_created", "client_payload": {"tag": "${{ env.new_tag }}"}}'
-d '{"event_type": "tag_created", "client_payload": {"tag": "${{ steps.increment_version.outputs.new_tag }}"}}'

36
.goreleaser.yaml Normal file
View File

@@ -0,0 +1,36 @@
# Read the documentation at https://goreleaser.com
version: 2
project_name: fabric
before:
hooks:
# You may remove this if you don't use go modules.
- go mod tidy
# you may remove this if you don't need go generate
# - go generate ./...
builds:
- env:
- CGO_ENABLED=0
goos:
- linux
- windows
- darwin
main: ./cmd/fabric
binary: fabric
archives:
- formats: [tar.gz]
# this name template makes the OS and Arch compatible with the results of `uname`.
name_template: >-
{{ .ProjectName }}_
{{- title .Os }}_
{{- if eq .Arch "amd64" }}x86_64
{{- else if eq .Arch "386" }}i386
{{- else }}{{ .Arch }}{{ end }}
{{- if .Arm }}v{{ .Arm }}{{ end }}
# use zip for windows archives
format_overrides:
- goos: windows
formats: [zip]

View File

@@ -65,6 +65,7 @@
"goopenai",
"GOPATH",
"gopkg",
"Goreleaser",
"GOROOT",
"Graphviz",
"grokai",
@@ -105,6 +106,8 @@
"mbed",
"metacharacters",
"Miessler",
"modeline",
"modelines",
"mpga",
"nometa",
"numpy",
@@ -162,6 +165,7 @@
"videoid",
"webp",
"WEBVTT",
"winget",
"wipecontext",
"wipesession",
"wireframes",

View File

@@ -57,6 +57,7 @@ Below are the **new features and capabilities** we've added (newest first):
### Recent Major Features
- [v1.4.303](https://github.com/danielmiessler/fabric/releases/tag/v1.4.303) (Aug 29, 2025) — **New Binary Releases**: Linux ARM and Windows ARM targets. You can run Fabric on the Raspberry PI and on your Windows Surface!
- [v1.4.294](https://github.com/danielmiessler/fabric/releases/tag/v1.4.294) (Aug 20, 2025) — **Venice AI Support**: Added the Venice AI provider. Venice is a Privacy-First, Open-Source AI provider. See their ["About Venice"](https://docs.venice.ai/overview/about-venice) page for details.
- [v1.4.291](https://github.com/danielmiessler/fabric/releases/tag/v1.4.291) (Aug 18, 2025) — **Speech To Text**: Add OpenAI speech-to-text support with `--transcribe-file`, `--transcribe-model`, and `--split-media-file` flags.
- [v1.4.287](https://github.com/danielmiessler/fabric/releases/tag/v1.4.287) (Aug 16, 2025) — **AI Reasoning**: Add Thinking to Gemini models and introduce `readme_updates` python script

View File

@@ -0,0 +1,8 @@
### PR [#1736](https://github.com/danielmiessler/Fabric/pull/1736) by [tonymet](https://github.com/tonymet): Winget Publishing and GoReleaser
- Added GoReleaser support for improved package distribution
- Winget and Docker publishing moved to ksylvan/fabric-packager GitHub repo
- Hardened release pipeline by gating workflows to upstream owner only
- Migrated from custom tokens to built-in GITHUB_TOKEN for enhanced security
- Removed docker-publish-on-tag workflow to reduce duplication and complexity
- Added ARM binary release support with updated documentation

View File

@@ -16,6 +16,8 @@ RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /fabric ./cmd/fabric
FROM alpine:latest
LABEL org.opencontainers.image.description="A Docker image for running the Fabric CLI. See https://github.com/danielmiessler/Fabric/tree/main/scripts/docker for details."
RUN apk add --no-cache ca-certificates \
&& mkdir -p /root/.config/fabric

View File

@@ -46,3 +46,15 @@ docker run --rm -it -p 8080:8080 -v $HOME/.fabric-config:/root/.config/fabric fa
```
The API will be available at `http://localhost:8080`.
## Multi-arch builds and GHCR packages
For multi-arch Docker builds (such as those used for GitHub Container Registry packages), the description should be set via annotations in the manifest instead of the Dockerfile LABEL. When building multi-arch images, ensure the build configuration includes:
```json
"annotations": {
"org.opencontainers.image.description": "A Docker image for running the Fabric CLI. See https://github.com/danielmiessler/Fabric/tree/main/scripts/docker for details."
}
```
This ensures that GHCR packages display the proper description.