name: release
on:
  schedule:
    - cron: "0 0 * * *" # midnight UTC

  workflow_dispatch:

  push:
    branches:
      - release
      - trigger-nightly

env:
  CARGO_INCREMENTAL: 0
  CARGO_NET_RETRY: 10
  RUSTFLAGS: "-D warnings -W unreachable-pub"
  RUSTUP_MAX_RETRIES: 10
  FETCH_DEPTH: 0 # pull in the tags for the version string
  MACOSX_DEPLOYMENT_TARGET: 10.15
  CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
  CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER: arm-linux-gnueabihf-gcc

jobs:
  dist:
    strategy:
      matrix:
        include:
          - os: windows-latest
            target: x86_64-pc-windows-msvc
            code-target: win32-x64
          - os: windows-latest
            target: i686-pc-windows-msvc
          - os: windows-latest
            target: aarch64-pc-windows-msvc
            code-target: win32-arm64
          - os: ubuntu-20.04
            target: x86_64-unknown-linux-gnu
            code-target: linux-x64
            container: rockylinux:8
          - os: ubuntu-20.04
            target: aarch64-unknown-linux-gnu
            code-target: linux-arm64
          - os: ubuntu-20.04
            target: arm-unknown-linux-gnueabihf
            code-target: linux-armhf
          - os: macos-12
            target: x86_64-apple-darwin
            code-target: darwin-x64
          - os: macos-12
            target: aarch64-apple-darwin
            code-target: darwin-arm64

    name: dist (${{ matrix.target }})
    runs-on: ${{ matrix.os }}
    container: ${{ matrix.container }}

    env:
      RA_TARGET: ${{ matrix.target }}

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          fetch-depth: ${{ env.FETCH_DEPTH }}

      - name: Install toolchain dependencies
        if: matrix.container == 'rockylinux:8'
        shell: bash
        run: |
          dnf install -y gcc
          curl --proto '=https' --tlsv1.2 --retry 10 --retry-connrefused -fsSL "https://sh.rustup.rs" | sh -s -- --profile minimal --default-toolchain none -y
          echo "${CARGO_HOME:-$HOME/.cargo}/bin" >> $GITHUB_PATH

      - name: Install Rust toolchain
        run: |
          rustup update --no-self-update stable
          rustup target add ${{ matrix.target }}
          rustup component add rust-src

      - name: Install Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 18

      - name: Update apt repositories
        if: matrix.target == 'aarch64-unknown-linux-gnu' || matrix.target == 'arm-unknown-linux-gnueabihf'
        run: sudo apt-get update

      - name: Install AArch64 target toolchain
        if: matrix.target == 'aarch64-unknown-linux-gnu'
        run: sudo apt-get install gcc-aarch64-linux-gnu

      - name: Install ARM target toolchain
        if: matrix.target == 'arm-unknown-linux-gnueabihf'
        run: sudo apt-get install gcc-arm-linux-gnueabihf

      - name: Dist
        run: cargo xtask dist --client-patch-version ${{ github.run_number }}

      - run: npm ci
        working-directory: editors/code

      - name: Package Extension (release)
        if: github.ref == 'refs/heads/release' && matrix.code-target
        run: npx vsce package -o "../../dist/rust-analyzer-${{ matrix.code-target }}.vsix" --target ${{ matrix.code-target }}
        working-directory: editors/code

      - name: Package Extension (nightly)
        if: github.ref != 'refs/heads/release' && matrix.code-target
        run: npx vsce package -o "../../dist/rust-analyzer-${{ matrix.code-target }}.vsix" --target ${{ matrix.code-target }} --pre-release
        working-directory: editors/code

      - if: matrix.target == 'x86_64-unknown-linux-gnu'
        run: rm -rf editors/code/server

      - if: matrix.target == 'x86_64-unknown-linux-gnu' && github.ref == 'refs/heads/release'
        run: npx vsce package -o ../../dist/rust-analyzer-no-server.vsix
        working-directory: editors/code

      - if: matrix.target == 'x86_64-unknown-linux-gnu' && github.ref != 'refs/heads/release'
        run: npx vsce package -o ../../dist/rust-analyzer-no-server.vsix --pre-release
        working-directory: editors/code

      - name: Run analysis-stats on rust-analyzer
        if: matrix.target == 'x86_64-unknown-linux-gnu'
        run: target/${{ matrix.target }}/release/rust-analyzer analysis-stats .

      - name: Run analysis-stats on rust std library
        if: matrix.target == 'x86_64-unknown-linux-gnu'
        env:
          RUSTC_BOOTSTRAP: 1
        run: target/${{ matrix.target }}/release/rust-analyzer analysis-stats --with-deps $(rustc --print sysroot)/lib/rustlib/src/rust/library/std

      - name: Upload artifacts
        uses: actions/upload-artifact@v4
        with:
          name: dist-${{ matrix.target }}
          path: ./dist

  dist-x86_64-unknown-linux-musl:
    name: dist (x86_64-unknown-linux-musl)
    runs-on: ubuntu-latest
    env:
      RA_TARGET: x86_64-unknown-linux-musl
      # For some reason `-crt-static` is not working for clang without lld
      RUSTFLAGS: "-C link-arg=-fuse-ld=lld -C target-feature=-crt-static"
    container:
      image: rust:alpine
      volumes:
        - /usr/local/cargo/registry:/usr/local/cargo/registry

    steps:
      - name: Install dependencies
        run: apk add --no-cache git clang lld musl-dev nodejs npm

      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          fetch-depth: ${{ env.FETCH_DEPTH }}

      - name: Dist
        run: cargo xtask dist --client-patch-version ${{ github.run_number }}

      - run: npm ci
        working-directory: editors/code

      - name: Package Extension (release)
        if: github.ref == 'refs/heads/release'
        run: npx vsce package -o "../../dist/rust-analyzer-alpine-x64.vsix" --target alpine-x64
        working-directory: editors/code

      - name: Package Extension (nightly)
        if: github.ref != 'refs/heads/release'
        run: npx vsce package -o "../../dist/rust-analyzer-alpine-x64.vsix" --target alpine-x64 --pre-release
        working-directory: editors/code

      - run: rm -rf editors/code/server

      - name: Upload artifacts
        uses: actions/upload-artifact@v4
        with:
          name: dist-x86_64-unknown-linux-musl
          path: ./dist

  publish:
    name: publish
    runs-on: ubuntu-latest
    needs: ["dist", "dist-x86_64-unknown-linux-musl"]
    steps:
      - name: Install Nodejs
        uses: actions/setup-node@v4
        with:
          node-version: 20

      - run: echo "TAG=$(date --iso -u)" >> $GITHUB_ENV
        if: github.ref == 'refs/heads/release'
      - run: echo "TAG=nightly" >> $GITHUB_ENV
        if: github.ref != 'refs/heads/release'
      - run: 'echo "TAG: $TAG"'

      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          fetch-depth: ${{ env.FETCH_DEPTH }}

      - run: echo "HEAD_SHA=$(git rev-parse HEAD)" >> $GITHUB_ENV
      - run: 'echo "HEAD_SHA: $HEAD_SHA"'

      - uses: actions/download-artifact@v4
        with:
          name: dist-aarch64-apple-darwin
          path: dist
      - uses: actions/download-artifact@v4
        with:
          name: dist-x86_64-apple-darwin
          path: dist
      - uses: actions/download-artifact@v4
        with:
          name: dist-x86_64-unknown-linux-gnu
          path: dist
      - uses: actions/download-artifact@v4
        with:
          name: dist-x86_64-unknown-linux-musl
          path: dist
      - uses: actions/download-artifact@v4
        with:
          name: dist-aarch64-unknown-linux-gnu
          path: dist
      - uses: actions/download-artifact@v4
        with:
          name: dist-arm-unknown-linux-gnueabihf
          path: dist
      - uses: actions/download-artifact@v4
        with:
          name: dist-x86_64-pc-windows-msvc
          path: dist
      - uses: actions/download-artifact@v4
        with:
          name: dist-i686-pc-windows-msvc
          path: dist
      - uses: actions/download-artifact@v4
        with:
          name: dist-aarch64-pc-windows-msvc
          path: dist
      - run: ls -al ./dist

      - name: Publish Release
        uses: ./.github/actions/github-release
        with:
          files: "dist/*"
          name: ${{ env.TAG }}
          token: ${{ secrets.GITHUB_TOKEN }}

      - run: rm dist/rust-analyzer-no-server.vsix

      - run: npm ci
        working-directory: ./editors/code

      - name: Publish Extension (Code Marketplace, release)
        if: github.ref == 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer')
        working-directory: ./editors/code
        # token from https://dev.azure.com/rust-analyzer/
        run: npx vsce publish --pat ${{ secrets.MARKETPLACE_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix

      - name: Publish Extension (OpenVSX, release)
        if: github.ref == 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer')
        working-directory: ./editors/code
        run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix
        timeout-minutes: 2

      - name: Publish Extension (Code Marketplace, nightly)
        if: github.ref != 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer')
        working-directory: ./editors/code
        run: npx vsce publish --pat ${{ secrets.MARKETPLACE_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix --pre-release

      - name: Publish Extension (OpenVSX, nightly)
        if: github.ref != 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer')
        working-directory: ./editors/code
        run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix
        timeout-minutes: 2
