name: Build and Release on: push: tags: - 'v*' permissions: contents: write jobs: apk: name: Generate APK runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Setup JDK uses: actions/setup-java@v4 with: distribution: temurin java-version: "21" - name: Set execution flag for gradlew run: chmod +x gradlew - name: Setup Android SDK uses: android-actions/setup-android@v3 - name: Install Android Build Tools run: sdkmanager "build-tools;29.0.3" - name: Run unit tests run: bash ./gradlew :common:desktopTest --stacktrace - name: Build APK run: bash ./gradlew assembleRelease --stacktrace - name: Sign APK uses: r0adkll/sign-android-release@v1 with: releaseDirectory: android/build/outputs/apk/release signingKeyBase64: ${{ secrets.KEYSTORE_B64 }} alias: ${{ secrets.KEY_ALIAS }} keyStorePassword: ${{ secrets.KEYSTORE_PASSWORD }} keyPassword: ${{ secrets.KEYSTORE_PASSWORD }} - name: Upload APK Artifact uses: actions/upload-artifact@v4 with: name: signed-apk path: android/build/outputs/apk/release/android-release-signed.apk cli-linux: name: Build CLI (Linux) runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Setup JDK uses: actions/setup-java@v4 with: distribution: temurin java-version: "21" - name: Set execution flag for gradlew run: chmod +x gradlew - name: Build Linux CLI binaries run: ./gradlew :cli:linkReleaseExecutableLinuxX64 :cli:linkReleaseExecutableLinuxArm64 --stacktrace - name: Package Linux x64 CLI run: | mkdir -p cli-linux-x64 cp cli/build/bin/linuxX64/releaseExecutable/lcl.kexe cli-linux-x64/lcl chmod +x cli-linux-x64/lcl cd cli-linux-x64 && zip -r ../cli-linux-x64.zip lcl - name: Package Linux arm64 CLI run: | mkdir -p cli-linux-arm64 cp cli/build/bin/linuxArm64/releaseExecutable/lcl.kexe cli-linux-arm64/lcl chmod +x cli-linux-arm64/lcl cd cli-linux-arm64 && zip -r ../cli-linux-arm64.zip lcl - name: Upload Linux x64 CLI Artifact uses: actions/upload-artifact@v4 with: name: cli-linux-x64 path: cli-linux-x64.zip - name: Upload Linux arm64 CLI Artifact uses: actions/upload-artifact@v4 with: name: cli-linux-arm64 path: cli-linux-arm64.zip cli-macos: name: Build CLI (macOS) runs-on: macos-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Setup JDK uses: actions/setup-java@v4 with: distribution: temurin java-version: "21" - name: Set execution flag for gradlew run: chmod +x gradlew - name: Build macOS CLI binaries run: ./gradlew :cli:linkReleaseExecutableMacosX64 :cli:linkReleaseExecutableMacosArm64 --stacktrace - name: Package macOS x64 CLI run: | mkdir -p cli-macos-x64 cp cli/build/bin/macosX64/releaseExecutable/lcl.kexe cli-macos-x64/lcl chmod +x cli-macos-x64/lcl cd cli-macos-x64 && zip -r ../cli-macos-x64.zip lcl - name: Package macOS arm64 CLI run: | mkdir -p cli-macos-arm64 cp cli/build/bin/macosArm64/releaseExecutable/lcl.kexe cli-macos-arm64/lcl chmod +x cli-macos-arm64/lcl cd cli-macos-arm64 && zip -r ../cli-macos-arm64.zip lcl - name: Upload macOS x64 CLI Artifact uses: actions/upload-artifact@v4 with: name: cli-macos-x64 path: cli-macos-x64.zip - name: Upload macOS arm64 CLI Artifact uses: actions/upload-artifact@v4 with: name: cli-macos-arm64 path: cli-macos-arm64.zip cli-windows: name: Build CLI (Windows) runs-on: windows-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Setup JDK uses: actions/setup-java@v4 with: distribution: temurin java-version: "21" - name: Build Windows CLI binary run: ./gradlew :cli:linkReleaseExecutableMingwX64 --stacktrace - name: Package Windows CLI run: | mkdir cli-windows-x64 copy cli\build\bin\mingwX64\releaseExecutable\lcl.exe cli-windows-x64\lcl.exe Compress-Archive -Path cli-windows-x64\lcl.exe -DestinationPath cli-windows-x64.zip shell: pwsh - name: Upload Windows CLI Artifact uses: actions/upload-artifact@v4 with: name: cli-windows-x64 path: cli-windows-x64.zip dmg: name: Generate DMG runs-on: macos-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Setup JDK uses: actions/setup-java@v4 with: distribution: temurin java-version: "21" - name: Set execution flag for gradlew run: chmod +x gradlew - name: Build DMG run: bash ./gradlew :desktopApp:packageReleaseDmg --stacktrace - name: Upload DMG Artifact uses: actions/upload-artifact@v4 with: name: dmg-package path: desktopApp/build/compose/binaries/main-release/dmg/*.dmg msi: name: Generate MSI runs-on: windows-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Setup JDK uses: actions/setup-java@v4 with: distribution: temurin java-version: "21" - name: Build MSI run: ./gradlew :desktopApp:packageReleaseMsi --stacktrace - name: Upload MSI Artifact uses: actions/upload-artifact@v4 with: name: msi-package path: desktopApp/build/compose/binaries/main-release/msi/*.msi deb: name: Generate DEB runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Setup JDK uses: actions/setup-java@v4 with: distribution: temurin java-version: "21" - name: Set execution flag for gradlew run: chmod +x gradlew - name: Build DEB run: ./gradlew :desktopApp:packageReleaseDeb --stacktrace - name: Upload DEB Artifact uses: actions/upload-artifact@v4 with: name: deb-package path: desktopApp/build/compose/binaries/main-release/deb/*.deb rpm: name: Generate RPM runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Setup JDK uses: actions/setup-java@v4 with: distribution: temurin java-version: "21" - name: Set execution flag for gradlew run: chmod +x gradlew - name: Install RPM build tools run: sudo apt-get update && sudo apt-get install -y rpm - name: Build RPM run: ./gradlew :desktopApp:packageReleaseRpm --stacktrace - name: Upload RPM Artifact uses: actions/upload-artifact@v4 with: name: rpm-package path: desktopApp/build/compose/binaries/main-release/rpm/*.rpm linux-tar: name: Generate Linux Tarball runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Setup JDK uses: actions/setup-java@v4 with: distribution: temurin java-version: "21" - name: Set execution flag for gradlew run: chmod +x gradlew - name: Build application distribution run: ./gradlew :desktopApp:createReleaseDistributable --stacktrace - name: Copy icon into distributable run: cp desktopApp/icon.png desktopApp/build/compose/binaries/main-release/app/LinuxCommandLibrary/lib/LinuxCommandLibrary.png - name: Package tarball run: | cd desktopApp/build/compose/binaries/main-release/app tar czf "$GITHUB_WORKSPACE/LinuxCommandLibrary-linux-x86_64.tar.gz" LinuxCommandLibrary - name: Upload Tarball Artifact uses: actions/upload-artifact@v4 with: name: linux-tar-package path: LinuxCommandLibrary-linux-x86_64.tar.gz appimage: name: Generate AppImage runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Setup JDK uses: actions/setup-java@v4 with: distribution: temurin java-version: "21" - name: Set execution flag for gradlew run: chmod +x gradlew - name: Install AppImage tools run: | sudo apt-get update sudo apt-get install -y libfuse2 file wget -q https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage chmod +x appimagetool-x86_64.AppImage - name: Build application distribution run: ./gradlew :desktopApp:createReleaseDistributable --stacktrace - name: Create AppDir structure run: | mkdir -p AppDir/usr/bin mkdir -p AppDir/usr/lib mkdir -p AppDir/usr/share/applications mkdir -p AppDir/usr/share/icons/hicolor/256x256/apps # Copy distributable contents cp -r desktopApp/build/compose/binaries/main-release/app/LinuxCommandLibrary/* AppDir/usr/lib/ # Copy icon cp desktopApp/icon.png AppDir/usr/share/icons/hicolor/256x256/apps/linuxcommandlibrary.png cp desktopApp/icon.png AppDir/linuxcommandlibrary.png # Create desktop file cat > AppDir/linuxcommandlibrary.desktop << 'EOF' [Desktop Entry] Name=Linux Command Library Comment=Linux Command Reference Exec=linuxcommandlibrary Icon=linuxcommandlibrary Type=Application Categories=Utility; Terminal=false EOF cp AppDir/linuxcommandlibrary.desktop AppDir/usr/share/applications/ # Create AppRun cat > AppDir/AppRun << 'EOF' #!/bin/bash SELF=$(readlink -f "$0") HERE=${SELF%/*} export PATH="${HERE}/usr/lib/bin:${PATH}" export LD_LIBRARY_PATH="${HERE}/usr/lib/lib/runtime/lib:${LD_LIBRARY_PATH}" exec "${HERE}/usr/lib/bin/LinuxCommandLibrary" "$@" EOF chmod +x AppDir/AppRun - name: Build AppImage run: | ARCH=x86_64 ./appimagetool-x86_64.AppImage --appimage-extract-and-run AppDir LinuxCommandLibrary-x86_64.AppImage - name: Upload AppImage Artifact uses: actions/upload-artifact@v4 with: name: appimage-package path: LinuxCommandLibrary-*.AppImage flatpak: name: Generate Flatpak needs: [linux-tar] runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Download Linux Tarball uses: actions/download-artifact@v4 with: name: linux-tar-package - name: Install Flatpak and Builder run: | sudo apt-get update sudo apt-get install -y flatpak flatpak-builder sudo flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo sudo flatpak install -y flathub org.freedesktop.Platform//24.08 org.freedesktop.Sdk//24.08 - name: Build Flatpak run: | # Copy tarball to flatpak dir and compute sha256 cp LinuxCommandLibrary-linux-x86_64.tar.gz flatpak/ SHA256=$(sha256sum LinuxCommandLibrary-linux-x86_64.tar.gz | cut -d' ' -f1) # Patch manifest to use local tarball instead of URL cd flatpak sed -i "s|url: https://github.com/SimonSchubert/LinuxCommandLibrary/releases/download/.*|path: LinuxCommandLibrary-linux-x86_64.tar.gz|" io.github.simonschubert.LinuxCommandLibrary.yaml sed -i "s|sha256: .*|sha256: ${SHA256}|" io.github.simonschubert.LinuxCommandLibrary.yaml # Build and bundle flatpak-builder --repo=repo --force-clean build-dir io.github.simonschubert.LinuxCommandLibrary.yaml flatpak build-bundle repo ../LinuxCommandLibrary.flatpak io.github.simonschubert.LinuxCommandLibrary - name: Upload Flatpak Artifact uses: actions/upload-artifact@v4 with: name: flatpak-package path: LinuxCommandLibrary.flatpak play-store: name: Upload AAB to Play Store runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - name: Setup JDK uses: actions/setup-java@v4 with: distribution: temurin java-version: "21" - name: Set execution flag for gradlew run: chmod +x gradlew - name: Setup Android SDK uses: android-actions/setup-android@v3 - name: Decode keystore run: echo "${{ secrets.KEYSTORE_B64 }}" | base64 --decode > /tmp/keystore.jks - name: Decode service account key run: echo "${{ secrets.SERVICE_ACCOUNT_JSON }}" | base64 --decode > fastlane/play-store-key.json - name: Extract changelog for Play Store run: | VERSION="${GITHUB_REF_NAME#v}" VERSION_CODE=$(grep "androidVersionCode" gradle/libs.versions.toml | head -1 | sed 's/.*= *"\([0-9]*\)".*/\1/') CHANGELOG_DIR="fastlane/metadata/android/en-US/changelogs" mkdir -p "$CHANGELOG_DIR" if [ -f CHANGELOG.md ]; then sed -n "/^## v${VERSION}/,/^## v/{ /^## v${VERSION}/d; /^## v/d; /^###/d; /^$/d; s/^- //; p; }" CHANGELOG.md > "$CHANGELOG_DIR/${VERSION_CODE}.txt" fi if [ ! -s "$CHANGELOG_DIR/${VERSION_CODE}.txt" ]; then PREVIOUS_TAG=$(git tag --sort=-creatordate | grep -v "^${GITHUB_REF_NAME}$" | head -n1) if [ -z "$PREVIOUS_TAG" ]; then git log --pretty=format:"- %s" "${GITHUB_REF_NAME}" > "$CHANGELOG_DIR/${VERSION_CODE}.txt" else git log --pretty=format:"- %s" "${PREVIOUS_TAG}..${GITHUB_REF_NAME}" --no-merges > "$CHANGELOG_DIR/${VERSION_CODE}.txt" fi fi # Play Store changelog limit is 500 characters truncate -s '<500' "$CHANGELOG_DIR/${VERSION_CODE}.txt" 2>/dev/null || true - name: Build signed AAB run: ./gradlew bundleRelease --stacktrace env: KEYSTORE_FILE: /tmp/keystore.jks KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }} KEY_ALIAS: ${{ secrets.KEY_ALIAS }} - name: Setup Ruby uses: ruby/setup-ruby@v1 with: ruby-version: '3.2' bundler-cache: true - name: Deploy to Play Store run: bundle exec fastlane android deploy release: name: Release All Platforms needs: [apk, cli-linux, cli-macos, cli-windows, dmg, msi, deb, rpm, appimage, linux-tar, flatpak] runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - name: Download APK Artifact uses: actions/download-artifact@v4 with: name: signed-apk - name: Download CLI Linux x64 Artifact uses: actions/download-artifact@v4 with: name: cli-linux-x64 - name: Download CLI Linux arm64 Artifact uses: actions/download-artifact@v4 with: name: cli-linux-arm64 - name: Download CLI macOS x64 Artifact uses: actions/download-artifact@v4 with: name: cli-macos-x64 - name: Download CLI macOS arm64 Artifact uses: actions/download-artifact@v4 with: name: cli-macos-arm64 - name: Download CLI Windows x64 Artifact uses: actions/download-artifact@v4 with: name: cli-windows-x64 - name: Download DMG Artifact uses: actions/download-artifact@v4 with: name: dmg-package - name: Download MSI Artifact uses: actions/download-artifact@v4 with: name: msi-package - name: Download DEB Artifact uses: actions/download-artifact@v4 with: name: deb-package - name: Download RPM Artifact uses: actions/download-artifact@v4 with: name: rpm-package - name: Download AppImage Artifact uses: actions/download-artifact@v4 with: name: appimage-package - name: Download Linux Tarball Artifact uses: actions/download-artifact@v4 with: name: linux-tar-package - name: Download Flatpak Artifact uses: actions/download-artifact@v4 with: name: flatpak-package - name: List downloaded files (for debugging) run: ls -la - name: Extract changelog run: | VERSION="${GITHUB_REF_NAME#v}" if [ -f CHANGELOG.md ]; then sed -n "/^## v${VERSION}/,/^## v/{ /^## v${VERSION}/d; /^## v/d; p; }" CHANGELOG.md > changelog.txt fi if [ ! -s changelog.txt ]; then PREVIOUS_TAG=$(git tag --sort=-creatordate | grep -v "^${GITHUB_REF_NAME}$" | head -n1) if [ -z "$PREVIOUS_TAG" ]; then git log --pretty=format:"- %s" "${GITHUB_REF_NAME}" > changelog.txt else git log --pretty=format:"- %s" "${PREVIOUS_TAG}..${GITHUB_REF_NAME}" --no-merges > changelog.txt fi fi - name: Rename assets run: | VERSION="${GITHUB_REF_NAME#v}" mv android-release-signed.apk "LinuxCommandLibrary-${VERSION}-android.apk" mv cli-macos-arm64.zip "LinuxCommandLibrary-${VERSION}-cli-macos-arm64.zip" mv cli-macos-x64.zip "LinuxCommandLibrary-${VERSION}-cli-macos-x64.zip" mv cli-linux-x64.zip "LinuxCommandLibrary-${VERSION}-cli-linux-x64.zip" mv cli-linux-arm64.zip "LinuxCommandLibrary-${VERSION}-cli-linux-arm64.zip" mv cli-windows-x64.zip "LinuxCommandLibrary-${VERSION}-cli-windows-x64.zip" mv *.dmg "LinuxCommandLibrary-${VERSION}-macos.dmg" mv *.msi "LinuxCommandLibrary-${VERSION}-windows.msi" mv *.deb "LinuxCommandLibrary-${VERSION}-linux.deb" mv *.rpm "LinuxCommandLibrary-${VERSION}-linux.rpm" mv *.AppImage "LinuxCommandLibrary-${VERSION}-linux.AppImage" mv LinuxCommandLibrary-linux-x86_64.tar.gz "LinuxCommandLibrary-${VERSION}-linux-x86_64.tar.gz" mv LinuxCommandLibrary.flatpak "LinuxCommandLibrary-${VERSION}-linux.flatpak" - name: Create Github Release uses: softprops/action-gh-release@v2 with: name: Release ${{ github.ref_name }} body_path: changelog.txt files: | LinuxCommandLibrary-*