kopi 0.2.3

Kopi is a JDK version management tool
Documentation
name: Release

on:
  workflow_dispatch:
    inputs:
      version:
        description: 'Release version (e.g., 1.2.3)'
        required: true
      dry-run:
        description: 'Run in dry-run mode (no package publish, draft release)'
        type: boolean
        default: true

env:
  CARGO_TERM_COLOR: always

jobs:
  validate:
    runs-on: ubuntu-24.04

    steps:
      - name: Validate inputs
        run: |
          if ! [[ "${{ github.event.inputs.version }}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
            echo "⚠️ Error: Version format must be x.x.x (e.g., 1.2.3)."
            exit 1
          fi
          echo "✅ Version format is valid."

  package-linux:
    strategy:
        matrix:
          include:
            - target: x86_64-unknown-linux-gnu
              arch: amd64
            - target: aarch64-unknown-linux-gnu
              arch: arm64
              
    runs-on: ubuntu-24.04
    needs: [ validate ]
    
    steps:
    - uses: actions/checkout@v4

    - name: Install cross-compiler
      if: matrix.target == 'aarch64-unknown-linux-gnu'
      run: |
        sudo apt-get update
        sudo apt-get install -y gcc-aarch64-linux-gnu
    
    - name: Install Rust
      uses: actions-rust-lang/setup-rust-toolchain@v1

    - name: Install Tools
      uses: taiki-e/install-action@v2
      with:
        tool: cargo-auditable,cargo-audit,cargo-edit,cross

    - name: Set version
      run: cargo set-version ${{ github.event.inputs.version }}

    - name: Build
      run: |
        cross auditable build --release --target ${{ matrix.target }}
        cross auditable build --profile release-shim --bin kopi-shim --target ${{ matrix.target }}

    - name: Targz
      run: |
        mkdir -p archive/pkg
        os_lower=$(echo "${{ runner.os }}" | tr '[:upper:]' '[:lower:]')

        cd target/${{ matrix.target }}/
        cp ./release/kopi .
        cp ./release-shim/kopi-shim .
        
        tar -zcvf ../../archive/pkg/kopi-${{ github.event.inputs.version }}-${os_lower}-${{ matrix.arch }}.tar.gz ./kopi ./kopi-shim

    - name: Install nFPM
      run: |
        echo 'deb [trusted=yes] https://repo.goreleaser.com/apt/ /' | sudo tee /etc/apt/sources.list.d/goreleaser.list
        sudo apt update
        sudo apt install nfpm

    - name: Bundle
      run: |
        export VERSION=${{ github.event.inputs.version }}
        export CARGO_BUILD_TARGET=${{ matrix.target }}
        export ARCH=${{ matrix.arch }}

        nfpm pkg --packager deb -f pkg/nfpm/nfpm.yml -t archive/pkg/
        nfpm pkg --packager rpm -f pkg/nfpm/nfpm.yml -t archive/pkg/

    - name: Upload Artifact
      uses: actions/upload-artifact@v4
      with:
        name: package-${{ runner.os }}-${{ matrix.arch }}
        path: archive/pkg
        retention-days: 1

  package-macos:
    runs-on: macos-15-large
    needs: [ validate ]
    
    steps:
    - uses: actions/checkout@v4
    
    - name: Install Rust
      uses: actions-rust-lang/setup-rust-toolchain@v1
      with:
        target: aarch64-apple-darwin

    - name: Install Tools
      uses: taiki-e/install-action@v2
      with:
        tool: cargo-auditable,cargo-audit,cargo-edit

    - name: Set version
      run: cargo set-version ${{ github.event.inputs.version }}

    - name: Build (x86_64)
      run: |
        cargo auditable build --release --target x86_64-apple-darwin
        cargo auditable build --profile release-shim --bin kopi-shim --target x86_64-apple-darwin

    - name: Targz (x86_64)
      run: |
        mkdir -p archive/pkg
        os_lower=$(echo "${{ runner.os }}" | tr '[:upper:]' '[:lower:]')

        cd target/x86_64-apple-darwin/
        cp ./release/kopi .
        cp ./release-shim/kopi-shim .
        tar -zcvf ../../archive/pkg/kopi-${{ github.event.inputs.version }}-${os_lower}-x86_64.tar.gz ./kopi ./kopi-shim

    - name: Build (aarch64)
      run: |
        cargo auditable build --release --target aarch64-apple-darwin
        cargo auditable build --profile release-shim --bin kopi-shim --target aarch64-apple-darwin

    - name: Targz (aarch64)
      run: |
        mkdir -p archive/pkg
        os_lower=$(echo "${{ runner.os }}" | tr '[:upper:]' '[:lower:]')

        cd target/aarch64-apple-darwin/
        cp ./release/kopi .
        cp ./release-shim/kopi-shim .
        tar -zcvf ../../archive/pkg/kopi-${{ github.event.inputs.version }}-${os_lower}-aarch64.tar.gz ./kopi ./kopi-shim

    - name: Upload Artifact
      uses: actions/upload-artifact@v4
      with:
        name: package-${{ runner.os }}
        path: archive/pkg
        retention-days: 1

  package-windows:
    runs-on: windows-2025
    needs: [ validate ]

    steps:
    - uses: actions/checkout@v4
    
    - name: Install Rust
      uses: actions-rust-lang/setup-rust-toolchain@v1
      with:
        target: aarch64-pc-windows-msvc

    - name: Install Tools
      uses: taiki-e/install-action@v2
      with:
        tool: cargo-auditable,cargo-audit,cargo-edit

    - name: Set version
      run: cargo set-version ${{ github.event.inputs.version }}

    - name: Install Wix
      run: dotnet tool install --global wix

    - name: Build bundle (x64)
      run: |
        pkg/wix/build-bundle.ps1 -Version ${{ github.event.inputs.version }} -Platform x64
        New-Item -Path archive/pkg -ItemType Directory -Force
        Copy-Item ./pkg/wix/output/kopi-bundle-with-vcredist-${{ github.event.inputs.version }}-windows-x64.exe ./archive/pkg/
        Copy-Item ./pkg/wix/output/en-us/kopi-${{ github.event.inputs.version }}-windows-x64.msi ./archive/pkg/

    - name: Zip (x64)
      run: |
        New-Item -Path archive/pkg -ItemType Directory -Force
        Compress-Archive -Path ./target/x86_64-pc-windows-msvc/release/kopi.exe, ./target/x86_64-pc-windows-msvc/release-shim/kopi-shim.exe -DestinationPath archive/pkg/kopi-${{ github.event.inputs.version }}-windows-x64.zip

    - name: Build bundle (arm64)
      run: |
        pkg/wix/build-bundle.ps1 -Version ${{ github.event.inputs.version }} -Platform arm64
        New-Item -Path archive/pkg -ItemType Directory -Force
        Copy-Item ./pkg/wix/output/kopi-bundle-with-vcredist-${{ github.event.inputs.version }}-windows-arm64.exe ./archive/pkg/
        Copy-Item ./pkg/wix/output/en-us/kopi-${{ github.event.inputs.version }}-windows-arm64.msi ./archive/pkg/

    - name: Zip (arm64)
      run: |
        New-Item -Path archive/pkg -ItemType Directory -Force
        Compress-Archive -Path ./target/aarch64-pc-windows-msvc/release/kopi.exe, ./target/aarch64-pc-windows-msvc/release-shim/kopi-shim.exe -DestinationPath archive/pkg/kopi-${{ github.event.inputs.version }}-windows-arm64.zip

    - name: Scan with Microsoft Defender
      run: |
        # https://learn.microsoft.com/ja-jp/defender-endpoint/command-line-arguments-microsoft-defender-antivirus
        $defenderPath = "${env:ProgramFiles}/Windows Defender/MpCmdRun.exe"

        Write-Host "Updating Microsoft Defender signatures..."
        & $defenderPath -SignatureUpdate

        Write-Host "Scan packages..."
        $filePath = (Resolve-Path -Path "archive/pkg").Path
        & $defenderPath -Scan -ScanType 3 -File $filePath -DisableRemediation

    - name: Upload Artifact
      uses: actions/upload-artifact@v4
      with:
        name: package-${{ runner.os }}
        path: archive/pkg
        retention-days: 1

  release:
    runs-on: ubuntu-24.04
    needs:
      - package-linux
      - package-macos
      - package-windows

    permissions:
      contents: write

    steps:
    - uses: actions/checkout@v4

    - name: Install Rust
      uses: actions-rust-lang/setup-rust-toolchain@v1

    - name: Install Tools
      uses: taiki-e/install-action@v2
      with:
        tool: cargo-edit

    - name: Fetch Linux archive
      uses: actions/download-artifact@v4
      with:
        name: package-Linux-amd64
        path: release
    - name: Fetch Linux archive
      uses: actions/download-artifact@v4
      with:
        name: package-Linux-arm64
        path: release
    - name: Fetch Mac archive
      uses: actions/download-artifact@v4
      with:
        name: package-macOS
        path: release
    - name: Fetch Windows archive
      uses: actions/download-artifact@v4
      with:
        name: package-Windows
        path: release

    - name: Generate SHA256 checksums
      run: |
        cd release
        for file in *; do
          if [ -f "$file" ]; then
            sha256sum "$file" | cut -d' ' -f1 > "${file}.sha256"
          fi
        done

    - name: Show release artifacts
      run: ls -la release

    - name: Configure Git
      run: |
        git config user.name "github-actions[bot]"
        git config user.email "github-actions[bot]@users.noreply.github.com"

    - name: Set version
      run: cargo set-version ${{ github.event.inputs.version }}

    - name: Commit, Tag, and Push
      run: |
        git add .
        git commit -m "Bump v${{ github.event.inputs.version }}"
        git tag v${{ github.event.inputs.version }}
        git push
        git push --tags

    - name: Publish
      if: ${{ github.event.inputs.dry-run == 'false' }}
      run: cargo publish
      env:
        CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}

    - name: Publish (dry-run)
      if: ${{ github.event.inputs.dry-run == 'true' }}
      run: cargo publish --dry-run
      env:
        CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}

    - name: Create release
      if: ${{ github.event.inputs.dry-run == 'false' }}
      run: gh release create v${{ github.event.inputs.version }} --generate-notes release/*
      env:
        GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

    - name: Create release (dry-run)
      if: ${{ github.event.inputs.dry-run == 'true' }}
      run: gh release create v${{ github.event.inputs.version }} --generate-notes release/* --draft
      env:
        GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

  publish-winget:
    runs-on: windows-latest
    needs:
      - release

    steps:
    - name: Publish to Winget
      uses: vedantmgoyal9/winget-releaser@19e706d4c9121098010096f9c495a70a7518b30f
      with:
        identifier: Kopi-vm.Kopi
        version: ${{ github.event.inputs.version }}
        release-tag: v${{ github.event.inputs.version }}
        installers-regex: '\.msi$'
        token: ${{ secrets.WINGET_TOKEN }}