build: Rewrite install script for direct .deb package installation #20
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Release | |
| on: | |
| push: | |
| tags: | |
| - 'v*' | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: 'Version to release (e.g., 1.0.0)' | |
| required: true | |
| env: | |
| VERSION: ${{ github.ref_name == '' && github.event.inputs.version || github.ref_name }} | |
| GO_VERSION: '1.21' | |
| # Skip variables - set to 'true' to skip specific deployments | |
| SKIP_SNAP: ${{ vars.SKIP_SNAP || '' }} | |
| SKIP_FLATPAK: ${{ vars.SKIP_FLATPAK || '' }} | |
| SKIP_CHOCOLATEY: ${{ vars.SKIP_CHOCOLATEY || '' }} | |
| SKIP_HOMEBREW: ${{ vars.SKIP_HOMEBREW || '' }} | |
| SKIP_AUR: ${{ vars.SKIP_AUR || '' }} | |
| SKIP_PACKAGES: ${{ vars.SKIP_PACKAGES || '' }} | |
| # Require tests to pass before release | |
| jobs: | |
| test: | |
| name: Run Tests | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Set up Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version: ${{ env.GO_VERSION }} | |
| - name: Run tests | |
| run: go test -v -race ./... | |
| build: | |
| name: Build Binaries | |
| needs: test | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| matrix: | |
| include: | |
| - os: ubuntu-latest | |
| goos: linux | |
| goarch: amd64 | |
| binary_name: shelldock-linux-amd64 | |
| - os: ubuntu-latest | |
| goos: linux | |
| goarch: arm64 | |
| binary_name: shelldock-linux-arm64 | |
| - os: macos-latest | |
| goos: darwin | |
| goarch: amd64 | |
| binary_name: shelldock-darwin-amd64 | |
| - os: macos-latest | |
| goos: darwin | |
| goarch: arm64 | |
| binary_name: shelldock-darwin-arm64 | |
| - os: windows-latest | |
| goos: windows | |
| goarch: amd64 | |
| binary_name: shelldock-windows-amd64.exe | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Set up Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version: ${{ env.GO_VERSION }} | |
| - name: Extract version (Linux/macOS) | |
| if: matrix.os != 'windows-latest' | |
| id: version | |
| shell: bash | |
| run: | | |
| if [ "${{ github.ref_type }}" = "tag" ]; then | |
| VERSION="${{ github.ref_name }}" | |
| else | |
| VERSION="v${{ github.event.inputs.version }}" | |
| fi | |
| echo "version=${VERSION#v}" >> $GITHUB_OUTPUT | |
| echo "VERSION=${VERSION}" >> $GITHUB_ENV | |
| - name: Extract version (Windows) | |
| if: matrix.os == 'windows-latest' | |
| id: version-windows | |
| shell: pwsh | |
| run: | | |
| if ("${{ github.ref_type }}" -eq "tag") { | |
| $VERSION = "${{ github.ref_name }}" | |
| } else { | |
| $VERSION = "v${{ github.event.inputs.version }}" | |
| } | |
| $VERSION_NUM = $VERSION -replace '^v', '' | |
| echo "version=$VERSION_NUM" >> $env:GITHUB_OUTPUT | |
| echo "VERSION=$VERSION" >> $env:GITHUB_ENV | |
| - name: Build binary (Linux/macOS) | |
| if: matrix.os != 'windows-latest' | |
| env: | |
| GOOS: ${{ matrix.goos }} | |
| GOARCH: ${{ matrix.goarch }} | |
| run: | | |
| VERSION_NUM="${VERSION#v}" | |
| go build -ldflags "-X main.version=${VERSION_NUM}" -o ${{ matrix.binary_name }} . | |
| - name: Build binary (Windows) | |
| if: matrix.os == 'windows-latest' | |
| env: | |
| GOOS: ${{ matrix.goos }} | |
| GOARCH: ${{ matrix.goarch }} | |
| VERSION_NUM: ${{ steps.version-windows.outputs.version }} | |
| shell: pwsh | |
| run: | | |
| go build -ldflags "-X main.version=$env:VERSION_NUM" -o ${{ matrix.binary_name }} . | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ matrix.binary_name }} | |
| path: ${{ matrix.binary_name }} | |
| packages: | |
| name: Build Packages | |
| needs: [test, build] | |
| runs-on: ubuntu-latest | |
| if: ${{ vars.SKIP_PACKAGES != 'true' && (needs.test.result == 'success' && needs.build.result == 'success') }} | |
| strategy: | |
| matrix: | |
| include: | |
| - distro: debian | |
| package_type: deb | |
| - distro: fedora | |
| package_type: rpm | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Set up Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version: ${{ env.GO_VERSION }} | |
| - name: Extract version | |
| id: version | |
| run: | | |
| if [ "${{ github.ref_type }}" = "tag" ]; then | |
| VERSION="${{ github.ref_name }}" | |
| else | |
| VERSION="v${{ github.event.inputs.version }}" | |
| fi | |
| echo "version=${VERSION#v}" >> $GITHUB_OUTPUT | |
| echo "VERSION=${VERSION}" >> $GITHUB_ENV | |
| - name: Download Linux binary | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: shelldock-linux-amd64 | |
| path: ./build/ | |
| - name: Make binary executable | |
| run: chmod +x ./build/shelldock-linux-amd64 | |
| - name: Build DEB package | |
| if: matrix.package_type == 'deb' | |
| run: | | |
| mkdir -p dist/deb/DEBIAN | |
| mkdir -p dist/deb/usr/local/bin | |
| mkdir -p dist/deb/usr/share/doc/shelldock | |
| mkdir -p dist/deb/usr/share/shelldock/repository | |
| cp ./build/shelldock-linux-amd64 dist/deb/usr/local/bin/shelldock | |
| cp README.md dist/deb/usr/share/doc/shelldock/ | |
| cp repository/*.yaml dist/deb/usr/share/shelldock/repository/ 2>/dev/null || true | |
| sed "s/VERSION/${{ steps.version.outputs.version }}/g" packaging/deb/control > dist/deb/DEBIAN/control | |
| cp packaging/deb/postinst dist/deb/DEBIAN/postinst | |
| chmod +x dist/deb/DEBIAN/postinst | |
| dpkg-deb --build dist/deb dist/shelldock_${{ steps.version.outputs.version }}_amd64.deb | |
| - name: Build RPM package | |
| if: matrix.package_type == 'rpm' | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y rpm | |
| mkdir -p dist/rpm/BUILD dist/rpm/BUILDROOT dist/rpm/RPMS dist/rpm/SOURCES dist/rpm/SPECS | |
| # Create source tarball structure | |
| VERSION="${{ steps.version.outputs.version }}" | |
| mkdir -p dist/rpm/tmp/shelldock-${VERSION} | |
| cp ./build/shelldock-linux-amd64 dist/rpm/tmp/shelldock-${VERSION}/shelldock | |
| cp README.md dist/rpm/tmp/shelldock-${VERSION}/ | |
| mkdir -p dist/rpm/tmp/shelldock-${VERSION}/repository | |
| cp repository/*.yaml dist/rpm/tmp/shelldock-${VERSION}/repository/ 2>/dev/null || true | |
| # Create tarball | |
| cd dist/rpm/tmp | |
| tar czf ../SOURCES/shelldock-${VERSION}.tar.gz shelldock-${VERSION} | |
| cd ../../.. | |
| # Create spec file with proper date and architecture | |
| CHANGELOG_DATE=$(date +"%a %b %d %Y") | |
| sed -e "s/VERSION/${VERSION}/g" -e "s/Wed Jan 01 2024/${CHANGELOG_DATE}/g" -e "s/BuildArch: noarch/BuildArch: x86_64/g" packaging/rpm/shelldock.spec > dist/rpm/SPECS/shelldock.spec | |
| rpmbuild --define "_topdir $(pwd)/dist/rpm" -bb dist/rpm/SPECS/shelldock.spec | |
| - name: Upload package | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ matrix.package_type }}-package | |
| path: | | |
| dist/*.${{ matrix.package_type }} | |
| dist/rpm/RPMS/*/*.rpm | |
| apt-repo: | |
| name: Create APT Repository | |
| needs: [test, build, packages] | |
| runs-on: ubuntu-latest | |
| if: ${{ vars.SKIP_PACKAGES != 'true' && (needs.test.result == 'success' && needs.build.result == 'success') }} | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Extract version | |
| id: version | |
| run: | | |
| if [ "${{ github.ref_type }}" = "tag" ]; then | |
| VERSION="${{ github.ref_name }}" | |
| else | |
| VERSION="v${{ github.event.inputs.version }}" | |
| fi | |
| echo "version=${VERSION#v}" >> $GITHUB_OUTPUT | |
| - name: Download DEB packages | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: deb-package | |
| path: ./apt-repo/pool/main/s/shelldock | |
| - name: Setup APT repository tools | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y dpkg-dev apt-utils gnupg2 | |
| - name: Import GPG key | |
| env: | |
| GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }} | |
| GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} | |
| run: | | |
| if [ -z "$GPG_PRIVATE_KEY" ]; then | |
| echo "GPG_PRIVATE_KEY not set, skipping GPG signing" | |
| exit 0 | |
| fi | |
| echo "$GPG_PRIVATE_KEY" | gpg --batch --yes --pinentry-mode loopback --passphrase "$GPG_PASSPHRASE" --import | |
| gpg --list-secret-keys --keyid-format LONG | |
| continue-on-error: true | |
| - name: Create APT repository structure | |
| run: | | |
| mkdir -p apt-repo/dists/stable/main/binary-amd64 | |
| mkdir -p apt-repo/dists/stable/main/binary-arm64 | |
| # Move .deb files to pool | |
| find apt-repo/pool -name "*.deb" -exec mv {} apt-repo/pool/main/s/shelldock/ \; | |
| # Generate Packages file for amd64 | |
| cd apt-repo | |
| dpkg-scanpackages --arch amd64 pool/main > dists/stable/main/binary-amd64/Packages 2>/dev/null || true | |
| gzip -k dists/stable/main/binary-amd64/Packages | |
| # Generate Packages file for arm64 (if available) | |
| dpkg-scanpackages --arch arm64 pool/main > dists/stable/main/binary-arm64/Packages 2>/dev/null || true | |
| gzip -k dists/stable/main/binary-arm64/Packages 2>/dev/null || true | |
| - name: Generate Release file | |
| env: | |
| GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }} | |
| GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} | |
| run: | | |
| if [ -z "$GPG_PRIVATE_KEY" ]; then | |
| echo "GPG_PRIVATE_KEY not set, creating unsigned Release" | |
| cd apt-repo/dists/stable | |
| cat > Release << EOF | |
| Origin: ShellDock | |
| Label: ShellDock | |
| Suite: stable | |
| Codename: stable | |
| Version: ${{ steps.version.outputs.version }} | |
| Architectures: amd64 arm64 | |
| Components: main | |
| Description: ShellDock APT Repository | |
| EOF | |
| exit 0 | |
| fi | |
| cd apt-repo/dists/stable | |
| cat > Release << EOF | |
| Origin: ShellDock | |
| Label: ShellDock | |
| Suite: stable | |
| Codename: stable | |
| Version: ${{ steps.version.outputs.version }} | |
| Architectures: amd64 arm64 | |
| Components: main | |
| Description: ShellDock APT Repository | |
| EOF | |
| # Add file hashes | |
| find main -type f | while read file; do | |
| echo " $(md5sum "$file" | cut -d' ' -f1) $(stat -c%s "$file") $file" >> Release | |
| echo " $(sha256sum "$file" | cut -d' ' -f1) $(stat -c%s "$file") $file" >> Release | |
| done | |
| - name: Sign Release file | |
| env: | |
| GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }} | |
| GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} | |
| run: | | |
| if [ -z "$GPG_PRIVATE_KEY" ]; then | |
| echo "GPG_PRIVATE_KEY not set, skipping signing" | |
| exit 0 | |
| fi | |
| cd apt-repo/dists/stable | |
| echo "$GPG_PASSPHRASE" | gpg --batch --yes --pinentry-mode loopback --passphrase-fd 0 --clearsign -o InRelease Release | |
| echo "$GPG_PASSPHRASE" | gpg --batch --yes --pinentry-mode loopback --passphrase-fd 0 --detach-sign -o Release.gpg Release | |
| continue-on-error: true | |
| - name: Export GPG public key | |
| env: | |
| GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }} | |
| GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} | |
| run: | | |
| if [ -z "$GPG_PRIVATE_KEY" ]; then | |
| echo "GPG_PRIVATE_KEY not set, skipping key export" | |
| exit 0 | |
| fi | |
| mkdir -p apt-repo | |
| gpg --batch --yes --pinentry-mode loopback --passphrase "$GPG_PASSPHRASE" --export --armor > apt-repo/gpg.key || true | |
| continue-on-error: true | |
| - name: Upload APT repository | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: apt-repository | |
| path: apt-repo/ | |
| snap: | |
| name: Build Snap Package | |
| needs: [test, build] | |
| runs-on: ubuntu-latest | |
| if: ${{ vars.SKIP_SNAP != 'true' && (needs.test.result == 'success' && needs.build.result == 'success') }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Extract version | |
| id: version | |
| run: | | |
| if [ "${{ github.ref_type }}" = "tag" ]; then | |
| VERSION="${{ github.ref_name }}" | |
| else | |
| VERSION="v${{ github.event.inputs.version }}" | |
| fi | |
| echo "version=${VERSION#v}" >> $GITHUB_OUTPUT | |
| - name: Download Linux binary | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: shelldock-linux-amd64 | |
| path: ./ | |
| - name: Make binary executable | |
| run: chmod +x shelldock-linux-amd64 | |
| - name: Setup Snapcraft | |
| run: | | |
| sudo snap install snapcraft --classic | |
| - name: Create snapcraft.yaml | |
| run: | | |
| mkdir -p snap | |
| cat > snap/snapcraft.yaml << 'EOF' | |
| name: shelldock | |
| base: core22 | |
| version: '${{ steps.version.outputs.version }}' | |
| summary: A fast, cross-platform shell command repository manager | |
| description: | | |
| ShellDock is a fast, cross-platform tool for managing and executing | |
| saved shell commands from bundled repository or local directory. | |
| grade: stable | |
| confinement: strict | |
| title: ShellDock | |
| license: MIT | |
| contact: https://github.com/OpsGuild/ShellDock | |
| website: https://github.com/OpsGuild/ShellDock | |
| source-code: https://github.com/OpsGuild/ShellDock | |
| apps: | |
| shelldock: | |
| command: usr/bin/shelldock | |
| plugs: | |
| - home | |
| - network | |
| parts: | |
| shelldock: | |
| plugin: dump | |
| source: . | |
| organize: | |
| shelldock-linux-amd64: usr/bin/shelldock | |
| EOF | |
| - name: Build snap | |
| run: | | |
| sudo snap install core22 | |
| snapcraft --destructive-mode | |
| - name: Login to Snap Store | |
| env: | |
| SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAP_STORE_CREDENTIALS }} | |
| run: | | |
| if [ -z "$SNAPCRAFT_STORE_CREDENTIALS" ]; then | |
| echo "SNAP_STORE_CREDENTIALS not set, skipping Snap Store login" | |
| exit 0 | |
| fi | |
| # Decode and export credentials | |
| export SNAPCRAFT_STORE_CREDENTIALS | |
| echo "$SNAPCRAFT_STORE_CREDENTIALS" | base64 -d | snapcraft login --with - | |
| continue-on-error: true | |
| - name: Register snap name (if not already registered) | |
| env: | |
| SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAP_STORE_CREDENTIALS }} | |
| run: | | |
| if [ -z "$SNAPCRAFT_STORE_CREDENTIALS" ]; then | |
| echo "SNAP_STORE_CREDENTIALS not set, skipping registration" | |
| exit 0 | |
| fi | |
| snapcraft register shelldock || echo "Snap name already registered or registration failed" | |
| continue-on-error: true | |
| - name: Publish to Snap Store | |
| env: | |
| SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAP_STORE_CREDENTIALS }} | |
| run: | | |
| if [ -z "$SNAPCRAFT_STORE_CREDENTIALS" ]; then | |
| echo "SNAP_STORE_CREDENTIALS not set, skipping publish" | |
| exit 0 | |
| fi | |
| # Ensure we're logged in | |
| export SNAPCRAFT_STORE_CREDENTIALS | |
| echo "$SNAPCRAFT_STORE_CREDENTIALS" | base64 -d | snapcraft login --with - || true | |
| SNAP_FILE=$(ls *.snap | head -1) | |
| snapcraft upload "$SNAP_FILE" --release stable || echo "Publish failed (may already be published)" | |
| continue-on-error: true | |
| - name: Upload snap | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: snap-package | |
| path: "*.snap" | |
| flatpak: | |
| name: Build Flatpak Package | |
| needs: [test, build] | |
| runs-on: ubuntu-latest | |
| if: ${{ vars.SKIP_FLATPAK != 'true' && (needs.test.result == 'success' && needs.build.result == 'success') }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Extract version | |
| id: version | |
| run: | | |
| if [ "${{ github.ref_type }}" = "tag" ]; then | |
| VERSION="${{ github.ref_name }}" | |
| else | |
| VERSION="v${{ github.event.inputs.version }}" | |
| fi | |
| echo "version=${VERSION#v}" >> $GITHUB_OUTPUT | |
| - name: Download Linux binary | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: shelldock-linux-amd64 | |
| path: ./ | |
| - name: Setup Flatpak | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y flatpak flatpak-builder | |
| sudo flatpak remote-add --if-not-exists --system flathub https://flathub.org/repo/flathub.flatpakrepo | |
| sudo flatpak install -y --system flathub org.freedesktop.Platform//22.08 org.freedesktop.Sdk//22.08 | |
| - name: Create flatpak manifest | |
| run: | | |
| mkdir -p flatpak | |
| cp shelldock-linux-amd64 flatpak/ | |
| cat > flatpak/com.github.opsguild.shelldock.yml << 'EOF' | |
| app-id: com.github.opsguild.shelldock | |
| runtime: org.freedesktop.Platform | |
| runtime-version: '22.08' | |
| sdk: org.freedesktop.Sdk | |
| command: shelldock | |
| finish-args: | |
| - --share=network | |
| - --filesystem=home | |
| modules: | |
| - name: shelldock | |
| buildsystem: simple | |
| build-commands: | |
| - install -Dm755 shelldock-linux-amd64 /app/bin/shelldock | |
| sources: | |
| - type: file | |
| path: shelldock-linux-amd64 | |
| EOF | |
| - name: Build flatpak | |
| run: | | |
| flatpak-builder --force-clean build flatpak/com.github.opsguild.shelldock.yml --repo=repo | |
| flatpak build-bundle repo shelldock-${{ steps.version.outputs.version }}.flatpak com.github.opsguild.shelldock | |
| - name: Publish to Flathub (if configured) | |
| env: | |
| FLATHUB_SSH_KEY: ${{ secrets.FLATHUB_SSH_KEY }} | |
| run: | | |
| if [ -z "$FLATHUB_SSH_KEY" ]; then | |
| echo "FLATHUB_SSH_KEY not set, skipping Flathub publish" | |
| exit 0 | |
| fi | |
| # Setup SSH | |
| mkdir -p ~/.ssh | |
| echo "$FLATHUB_SSH_KEY" > ~/.ssh/flathub_key | |
| chmod 600 ~/.ssh/flathub_key | |
| ssh-keyscan github.com >> ~/.ssh/known_hosts | |
| # Clone Flathub repository | |
| git clone git@github.com:flathub/com.github.opsguild.shelldock.git flathub-repo || \ | |
| git clone https://github.com/flathub/com.github.opsguild.shelldock.git flathub-repo || \ | |
| echo "Flathub repository not found. You may need to submit to Flathub first." | |
| if [ -d flathub-repo ]; then | |
| cd flathub-repo | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| # Update manifest with new version | |
| FLATPAK_FILE=$(ls ../*.flatpak | head -1) | |
| # Extract and update version in manifest if needed | |
| # This is a simplified version - you may need to adjust based on your Flathub manifest structure | |
| git add . | |
| git diff --staged --quiet || git commit -m "Update to ${{ github.ref_name }}" | |
| git push origin master || git push origin main || echo "Push failed" | |
| fi | |
| continue-on-error: true | |
| - name: Upload flatpak | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: flatpak-package | |
| path: "*.flatpak" | |
| homebrew: | |
| name: Update Homebrew Formula | |
| needs: [test, build] | |
| runs-on: ubuntu-latest | |
| if: ${{ vars.SKIP_HOMEBREW != 'true' && (needs.test.result == 'success' && needs.build.result == 'success') && github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') }} | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Extract version | |
| id: version | |
| run: | | |
| VERSION="${{ github.ref_name }}" | |
| echo "version=${VERSION#v}" >> $GITHUB_OUTPUT | |
| - name: Download macOS binaries | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: shelldock-darwin-amd64 | |
| path: ./build/ | |
| continue-on-error: true | |
| - name: Download macOS ARM64 binary | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: shelldock-darwin-arm64 | |
| path: ./build/ | |
| continue-on-error: true | |
| - name: Calculate SHA256 for amd64 | |
| id: sha256_amd64 | |
| run: | | |
| if [ -f build/shelldock-darwin-amd64 ]; then | |
| SHA256=$(sha256sum build/shelldock-darwin-amd64 | cut -d' ' -f1) | |
| echo "sha256=$SHA256" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Calculate SHA256 for arm64 | |
| id: sha256_arm64 | |
| run: | | |
| if [ -f build/shelldock-darwin-arm64 ]; then | |
| SHA256=$(sha256sum build/shelldock-darwin-arm64 | cut -d' ' -f1) | |
| echo "sha256=$SHA256" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Create Homebrew formula | |
| run: | | |
| mkdir -p Formula | |
| cat > Formula/shelldock.rb << EOF | |
| class Shelldock < Formula | |
| desc "A fast, cross-platform shell command repository manager" | |
| homepage "https://github.com/OpsGuild/ShellDock" | |
| url "https://github.com/OpsGuild/ShellDock/archive/${{ github.ref_name }}.tar.gz" | |
| version "${{ steps.version.outputs.version }}" | |
| sha256 "${{ steps.sha256_amd64.outputs.sha256 }}" | |
| on_macos do | |
| if Hardware::CPU.intel? | |
| url "https://github.com/OpsGuild/ShellDock/releases/download/${{ github.ref_name }}/shelldock-darwin-amd64" | |
| sha256 "${{ steps.sha256_amd64.outputs.sha256 }}" | |
| else | |
| url "https://github.com/OpsGuild/ShellDock/releases/download/${{ github.ref_name }}/shelldock-darwin-arm64" | |
| sha256 "${{ steps.sha256_arm64.outputs.sha256 }}" | |
| end | |
| end | |
| def install | |
| if OS.mac? | |
| bin.install "shelldock-darwin-#{Hardware::CPU.arch == "arm64" ? "arm64" : "amd64"}" => "shelldock" | |
| end | |
| end | |
| test do | |
| system "#{bin}/shelldock", "--version" | |
| end | |
| end | |
| EOF | |
| - name: Commit and push formula | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git add Formula/shelldock.rb | |
| git diff --staged --quiet || git commit -m "Update Homebrew formula to ${{ github.ref_name }}" | |
| git push origin HEAD:main || git push origin HEAD:master | |
| chocolatey: | |
| name: Build and Publish Chocolatey Package | |
| needs: [test, build] | |
| runs-on: windows-latest | |
| if: ${{ vars.SKIP_CHOCOLATEY != 'true' && (needs.test.result == 'success' && needs.build.result == 'success') }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Extract version | |
| id: version | |
| run: | | |
| if ("${{ github.ref_type }}" -eq "tag") { | |
| $VERSION = "${{ github.ref_name }}" | |
| } else { | |
| $VERSION = "v${{ github.event.inputs.version }}" | |
| } | |
| $VERSION = $VERSION -replace '^v', '' | |
| echo "version=$VERSION" >> $env:GITHUB_OUTPUT | |
| - name: Download Windows binary | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: shelldock-windows-amd64.exe | |
| path: ./ | |
| - name: Create Chocolatey package | |
| run: | | |
| mkdir -p chocolatey\shelldock\tools | |
| Move-Item shelldock-windows-amd64.exe chocolatey\shelldock\tools\shelldock.exe | |
| $nuspec = @" | |
| <?xml version="1.0" encoding="utf-8"?> | |
| <package xmlns="http://schemas.microsoft.com/packaging/2015/06/nuspec.xsd"> | |
| <metadata> | |
| <id>shelldock</id> | |
| <version>${{ steps.version.outputs.version }}</version> | |
| <title>ShellDock</title> | |
| <authors>OpsGuild</authors> | |
| <owners>OpsGuild</owners> | |
| <description>A fast, cross-platform shell command repository manager</description> | |
| <projectUrl>https://github.com/OpsGuild/ShellDock</projectUrl> | |
| <packageSourceUrl>https://github.com/OpsGuild/ShellDock</packageSourceUrl> | |
| <tags>shell commands automation</tags> | |
| </metadata> | |
| <files> | |
| <file src="tools\**" target="tools" /> | |
| </files> | |
| </package> | |
| "@ | |
| $nuspec | Out-File -Encoding UTF8 chocolatey\shelldock\shelldock.nuspec | |
| $install = @" | |
| `$ErrorActionPreference = 'Stop' | |
| `$toolsDir = "`$(Split-Path -parent `$MyInvocation.MyCommand.Definition)" | |
| Install-BinFile -Name shelldock -Path "`$toolsDir\shelldock.exe" | |
| "@ | |
| $install | Out-File -Encoding UTF8 chocolatey\shelldock\tools\chocolateyinstall.ps1 | |
| - name: Install Chocolatey | |
| run: | | |
| Set-ExecutionPolicy Bypass -Scope Process -Force | |
| [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072 | |
| iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1')) | |
| - name: Build Chocolatey package | |
| run: | | |
| choco pack chocolatey\shelldock\shelldock.nuspec --output-directory chocolatey | |
| - name: Set Chocolatey API key | |
| env: | |
| CHOCOLATEY_API_KEY: ${{ secrets.CHOCOLATEY_API_KEY }} | |
| shell: pwsh | |
| run: | | |
| if ([string]::IsNullOrEmpty($env:CHOCOLATEY_API_KEY)) { | |
| Write-Host "CHOCOLATEY_API_KEY not set, skipping API key setup" | |
| exit 0 | |
| } | |
| choco apikey --key "$env:CHOCOLATEY_API_KEY" --source https://push.chocolatey.org/ | |
| - name: Publish to Chocolatey | |
| env: | |
| CHOCOLATEY_API_KEY: ${{ secrets.CHOCOLATEY_API_KEY }} | |
| shell: pwsh | |
| run: | | |
| if ([string]::IsNullOrEmpty($env:CHOCOLATEY_API_KEY)) { | |
| Write-Host "CHOCOLATEY_API_KEY not set, skipping publish" | |
| exit 0 | |
| } | |
| $package = Get-ChildItem chocolatey\*.nupkg | Select-Object -First 1 | |
| choco push $package.FullName --source https://push.chocolatey.org/ --force | |
| continue-on-error: true | |
| - name: Upload Chocolatey package | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: chocolatey-package | |
| path: "chocolatey/*.nupkg" | |
| aur: | |
| name: Update AUR Package | |
| needs: [test, build] | |
| runs-on: ubuntu-latest | |
| if: ${{ vars.SKIP_AUR != 'true' && (needs.test.result == 'success' && needs.build.result == 'success') && github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Extract version | |
| id: version | |
| run: | | |
| VERSION="${{ github.ref_name }}" | |
| echo "version=${VERSION#v}" >> $GITHUB_OUTPUT | |
| - name: Download Linux binary | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: shelldock-linux-amd64 | |
| path: ./ | |
| - name: Calculate SHA256 | |
| id: sha256 | |
| run: | | |
| SHA256=$(sha256sum shelldock-linux-amd64 | cut -d' ' -f1) | |
| echo "sha256=$SHA256" >> $GITHUB_OUTPUT | |
| - name: Update PKGBUILD | |
| run: | | |
| cat > packaging/arch/PKGBUILD << EOF | |
| # Maintainer: OpsGuild | |
| pkgname=shelldock | |
| pkgver=${{ steps.version.outputs.version }} | |
| pkgrel=1 | |
| pkgdesc="A fast, cross-platform shell command repository manager" | |
| arch=('x86_64' 'aarch64') | |
| url="https://github.com/OpsGuild/ShellDock" | |
| license=('MIT') | |
| source_x86_64=("https://github.com/OpsGuild/ShellDock/releases/download/${{ github.ref_name }}/shelldock-linux-amd64") | |
| source_aarch64=("https://github.com/OpsGuild/ShellDock/releases/download/${{ github.ref_name }}/shelldock-linux-arm64") | |
| sha256sums_x86_64=('${{ steps.sha256.outputs.sha256 }}') | |
| sha256sums_aarch64=('SKIP') | |
| package() { | |
| install -Dm755 "\${srcdir}/shelldock-linux-\${CARCH}" "\${pkgdir}/usr/bin/shelldock" | |
| install -Dm644 "\${srcdir}/README.md" "\${pkgdir}/usr/share/doc/shelldock/README.md" | |
| install -d "\${pkgdir}/usr/share/shelldock/repository" | |
| cp "\${srcdir}/repository"/*.yaml "\${pkgdir}/usr/share/shelldock/repository/" 2>/dev/null || true | |
| } | |
| EOF | |
| - name: Generate .SRCINFO | |
| run: | | |
| cd packaging/arch | |
| # Use Docker with Arch Linux to generate .SRCINFO properly | |
| docker run --rm -v "$(pwd):/pkg" -w /pkg archlinux/base:latest bash -c " | |
| pacman -Sy --noconfirm base-devel | |
| makepkg --printsrcinfo > .SRCINFO | |
| " || { | |
| # Fallback: Generate .SRCINFO manually if Docker fails | |
| source PKGBUILD | |
| { | |
| echo "pkgbase = $pkgname" | |
| echo " pkgdesc = $pkgdesc" | |
| echo " pkgver = $pkgver" | |
| echo " pkgrel = $pkgrel" | |
| echo " url = $url" | |
| echo " arch = ${arch[@]}" | |
| echo " license = ${license[@]}" | |
| for i in "${!source_x86_64[@]}"; do | |
| echo " source_x86_64 = ${source_x86_64[$i]}" | |
| done | |
| for i in "${!source_aarch64[@]}"; do | |
| echo " source_aarch64 = ${source_aarch64[$i]}" | |
| done | |
| for i in "${!sha256sums_x86_64[@]}"; do | |
| echo " sha256sums_x86_64 = ${sha256sums_x86_64[$i]}" | |
| done | |
| for i in "${!sha256sums_aarch64[@]}"; do | |
| echo " sha256sums_aarch64 = ${sha256sums_aarch64[$i]}" | |
| done | |
| } > .SRCINFO | |
| } | |
| - name: Publish to AUR | |
| env: | |
| AUR_SSH_KEY: ${{ secrets.AUR_SSH_KEY }} | |
| run: | | |
| if [ -z "$AUR_SSH_KEY" ]; then | |
| echo "AUR_SSH_KEY not set, skipping AUR publish" | |
| exit 0 | |
| fi | |
| # Setup SSH | |
| mkdir -p ~/.ssh | |
| echo "$AUR_SSH_KEY" > ~/.ssh/aur_key | |
| chmod 600 ~/.ssh/aur_key | |
| ssh-keyscan aur.archlinux.org >> ~/.ssh/known_hosts | |
| # Configure git | |
| git config --global user.name "github-actions[bot]" | |
| git config --global user.email "github-actions[bot]@users.noreply.github.com" | |
| # Clone AUR repository | |
| GIT_SSH_COMMAND="ssh -i ~/.ssh/aur_key" git clone ssh://aur@aur.archlinux.org/shelldock.git aur-repo || echo "AUR repo may not exist yet" | |
| if [ -d aur-repo ]; then | |
| cd aur-repo | |
| # Copy PKGBUILD and .SRCINFO | |
| cp ../packaging/arch/PKGBUILD . | |
| cp ../packaging/arch/.SRCINFO . | |
| # Commit and push | |
| git add PKGBUILD .SRCINFO | |
| git diff --staged --quiet || (git commit -m "Update to ${{ github.ref_name }}" && GIT_SSH_COMMAND="ssh -i ~/.ssh/aur_key" git push origin master) | |
| fi | |
| continue-on-error: true | |
| - name: Upload PKGBUILD | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: aur-package | |
| path: packaging/arch/PKGBUILD | |
| gpg-sign: | |
| name: GPG Sign Packages | |
| needs: [build, packages, snap, flatpak, chocolatey] | |
| runs-on: ubuntu-latest | |
| if: always() && needs.build.result == 'success' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Import GPG key | |
| env: | |
| GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }} | |
| GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} | |
| run: | | |
| if [ -z "$GPG_PRIVATE_KEY" ]; then | |
| echo "GPG_PRIVATE_KEY not set, skipping GPG signing" | |
| exit 0 | |
| fi | |
| echo "$GPG_PRIVATE_KEY" | gpg --batch --yes --pinentry-mode loopback --passphrase "$GPG_PASSPHRASE" --import | |
| gpg --list-secret-keys --keyid-format LONG | |
| continue-on-error: true | |
| - name: Download all artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: ./artifacts | |
| - name: Sign binaries | |
| env: | |
| GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }} | |
| GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} | |
| run: | | |
| if [ -z "$GPG_PRIVATE_KEY" ]; then | |
| echo "GPG_PRIVATE_KEY not set, skipping signing" | |
| exit 0 | |
| fi | |
| for file in $(find artifacts -type f \( -name "shelldock-*" -o -name "*.deb" -o -name "*.rpm" -o -name "*.snap" -o -name "*.flatpak" -o -name "*.nupkg" \)); do | |
| echo "$GPG_PASSPHRASE" | gpg --batch --yes --pinentry-mode loopback --passphrase-fd 0 --detach-sign --armor "$file" | |
| done | |
| continue-on-error: true | |
| - name: Upload signatures | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: gpg-signatures | |
| path: "artifacts/*.asc" | |
| release: | |
| name: Create Release | |
| needs: [test, build, packages, snap, flatpak, chocolatey, homebrew, aur, gpg-sign, apt-repo] | |
| runs-on: ubuntu-latest | |
| if: always() && needs.test.result == 'success' && needs.build.result == 'success' | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Extract version | |
| id: version | |
| run: | | |
| if [ "${{ github.ref_type }}" = "tag" ]; then | |
| VERSION="${{ github.ref_name }}" | |
| else | |
| VERSION="v${{ github.event.inputs.version }}" | |
| fi | |
| echo "version=${VERSION#v}" >> $GITHUB_OUTPUT | |
| echo "VERSION=${VERSION}" >> $GITHUB_ENV | |
| - name: Download all artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: ./release-assets | |
| - name: Create Release | |
| uses: softprops/action-gh-release@v1 | |
| with: | |
| files: | | |
| release-assets/**/* | |
| draft: false | |
| prerelease: false | |
| generate_release_notes: true | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |