name: qsharp-publish-$(BuildId)

trigger: none
pr: none

variables:
  CARGO_TERM_COLOR: always
  RUST_TOOLCHAIN_VERSION: "1.75"

# variables set by pipeline
# - BASE_IMAGE
# - BUILD_NUMBER
# - BUILD_TYPE
# - cratesIoFeedOverride
# - OwnerPersonalAlias
# - PAT
# - toolchainFeed

jobs:
- job: "Node"
  pool:
    vmImage: 'ubuntu-latest'
  timeoutInMinutes: 90

  steps:
  # common init steps
  - task: RustInstaller@1
    inputs:
      rustVersion: ms-$(RUST_TOOLCHAIN_VERSION)
      additionalTargets: wasm32-unknown-unknown
      cratesIoFeedOverride: $(cratesIoFeedOverride)
      toolchainFeed: $(toolchainFeed)
    displayName: Install Rust toolchain

  - task: UsePythonVersion@0
    inputs:
      versionSpec: '3.11'

  - script: |
      python ./prereqs.py --install && python ./version.py
    displayName: Install Prereqs and set version

  # build steps

  - script: |
      python build.py --npm --wasm
    displayName: Build VSCode Extension

  - script: |
      mkdir -p '$(System.DefaultWorkingDirectory)/target/npm'
      npm pack --pack-destination '$(System.DefaultWorkingDirectory)/target/npm'
    displayName: Pack NPM Package
    workingDirectory: '$(System.DefaultWorkingDirectory)/npm'

  - publish: $(System.DefaultWorkingDirectory)/target/npm
    artifact: NPM
    displayName: Upload NPM Package Artifact


- job: "VSCode"
  pool:
    vmImage: 'ubuntu-latest'
  timeoutInMinutes: 90

  steps:
  # common init steps
  - task: RustInstaller@1
    inputs:
      rustVersion: ms-$(RUST_TOOLCHAIN_VERSION)
      additionalTargets: wasm32-unknown-unknown
      cratesIoFeedOverride: $(cratesIoFeedOverride)
      toolchainFeed: $(toolchainFeed)
    displayName: Install Rust toolchain

  - task: UsePythonVersion@0
    inputs:
      versionSpec: '3.11'

  - script: |
      python ./prereqs.py --install && python ./version.py
    displayName: Install Prereqs and set version

  # Below VS Code extension build only needs to run on one platform (Linux x86_64 for now)
  - script: |
      npm install -g @vscode/vsce@2.22.0
    displayName: Install Prereqs for VSCode Extension

  # build steps

  - script: |
      python build.py --wasm --npm --vscode
    displayName: Build VSCode Extension

  - script: |
      vsce package --pre-release
    condition: and(succeeded(), eq(variables['BUILD_TYPE'], 'dev'))
    displayName: Pack pre-release VSCode Extension
    workingDirectory: '$(System.DefaultWorkingDirectory)/vscode'

  - script: |
      vsce package
    condition: and(succeeded(), ne(variables['BUILD_TYPE'], 'dev'))
    displayName: Pack VSCode Extension
    workingDirectory: '$(System.DefaultWorkingDirectory)/vscode'

  - publish: $(System.DefaultWorkingDirectory)/vscode
    artifact: VSIX
    displayName: Upload VSCode Extension Artifact

- job: "JupyterLab"
  pool:
    vmImage: 'ubuntu-latest'
  timeoutInMinutes: 90

  steps:
  # common init steps

  - task: UsePythonVersion@0
    inputs:
      versionSpec: '3.11'

  - script: |
      python ./prereqs.py --install && python ./version.py
    displayName: Install Prereqs and set version

  - script: |
      python ./build.py --jupyterlab --widgets --no-check
    displayName: Build JupyterLab Package

  - script: |
      ls target/wheels/*

  - publish: $(System.DefaultWorkingDirectory)/target/wheels/
    artifact: Wheels.JupyterLab
    displayName: Upload JupyterLab Python Artifacts

- job: "Python"
  strategy:
    matrix:
      linux_x64:
        imageName: 'ubuntu-20.04'
        arch: x86_64
      linux_aarch64:
        imageName: 'ubuntu-20.04'
        arch: aarch64
        additionalRustTargets: aarch64-unknown-linux-gnu
      mac:
        imageName: 'macOS-latest'       # MacOS-specific Py (Mac is usually quite limited).
        arch: x86_64
        additionalRustTargets: aarch64-apple-darwin
      windows:
        imageName: 'windows-latest'     # Win-specific Py + Platform-independent Py.
        arch: x86_64
      windows_aarch64:
        imageName: 'windows-latest'     # Win-specific Py + Platform-independent Py.
        arch: aarch64
        additionalRustTargets: aarch64-pc-windows-msvc
  pool:
    vmImage: $(imageName)
  variables:
    arch: $(arch)
  timeoutInMinutes: 90

  steps:
  # common init steps
  # if we have additional rust targets, we need to install them
  - task: RustInstaller@1
    inputs:
      rustVersion: ms-$(RUST_TOOLCHAIN_VERSION)
      additionalTargets: $(additionalRustTargets)
      cratesIoFeedOverride: $(cratesIoFeedOverride)
      toolchainFeed: $(toolchainFeed)
    displayName: Install Rust toolchain
    condition: ne(variables['additionalRustTargets'], '')

  # otherwise just install the default toolchain
  - task: RustInstaller@1
    inputs:
      rustVersion: ms-$(RUST_TOOLCHAIN_VERSION)
      cratesIoFeedOverride: $(cratesIoFeedOverride)
      toolchainFeed: $(toolchainFeed)
    displayName: Install Rust toolchain
    condition: eq(variables['additionalRustTargets'], '')

  - script: |
      rustc --version
      rustc --print target-list
    displayName: View rust target info

  - task: UsePythonVersion@0
    inputs:
      versionSpec: '3.11'

  - script: |
      python ./prereqs.py --install && python ./version.py
    displayName: Install Prereqs and set version

  - script: |
      chmod +x ./docker/linux-aarch64/install_prereqs.sh
      sudo ./docker/linux-aarch64/install_prereqs.sh
    displayName: Install Linux aarch64 cross prereqs
    condition: and(eq(variables['Agent.OS'], 'Linux'), eq(variables['arch'], 'aarch64'))

  - script: |
      python build.py --pip --no-check-prereqs
    displayName: Build Platform-Dependent Py Packages
    condition: ne(variables['arch'], 'aarch64')

  - script: |
      python -m pip install auditwheel patchelf
      ls target/wheels
      ls target/wheels/*.whl | xargs auditwheel show
      ls target/wheels/*.whl | xargs auditwheel repair --wheel-dir ./target/wheels/ --plat manylinux_2_31_x86_64
      rm target/wheels/*-linux_x86_64.whl
      ls target/wheels
    displayName: Run auditwheel for Linux Wheels
    condition: and(eq(variables['Agent.OS'], 'Linux'), eq(variables['arch'], 'x86_64'))

  # for linux aarch64 cross build we want to skip tests as we can't run the code.
  # and we can't run the samples as qsc is currently cross compiled.
  - script: |
      env CARGO_BUILD_TARGET=aarch64-unknown-linux-gnu python build.py --pip --no-check-prereqs --no-check --no-test
    displayName: Cross Build Linux aarch64 Py Packages
    condition: and(eq(variables['Agent.OS'], 'Linux'), eq(variables['arch'], 'aarch64'))

  - script: |
      chmod +x ./docker/linux-aarch64/build.sh
      chmod +x ./docker/linux-aarch64/run.sh

      ./docker/linux-aarch64/build.sh
      ./docker/linux-aarch64/run.sh
    displayName: Run auditwheel and python tests for Linux aarch64 Wheels
    condition: and(eq(variables['Agent.OS'], 'Linux'), eq(variables['arch'], 'aarch64'))

  - script: |
      echo ##vso[task.setvariable variable=CARGO_BUILD_TARGET]aarch64-pc-windows-msvc
    displayName: Set cargo build target for Windows aarch64
    condition: and(eq(variables['Agent.OS'], 'Windows_NT'), eq(variables['arch'], 'aarch64'))

  - script: |
      python build.py --pip --no-check-prereqs --no-check --no-test
    displayName: Cross Build Windows aarch64 Py Packages
    condition: and(eq(variables['Agent.OS'], 'Windows_NT'), eq(variables['arch'], 'aarch64'))

  - script: |
      dir target\wheels\*
    displayName: List Py Packages on Win
    condition: eq(variables['Agent.OS'], 'Windows_NT')

  - script: |
      ls target/wheels/*
    displayName: List Py Packages on non-Win
    condition: ne(variables['Agent.OS'], 'Windows_NT')

  - publish: $(System.DefaultWorkingDirectory)/target/wheels
    artifact: Wheels.Mac
    displayName: Upload Python Artifacts Mac
    condition: eq(variables['Agent.OS'], 'Darwin')

  - publish: $(System.DefaultWorkingDirectory)/target/wheels
    artifact: Wheels.Win.${{ variables['arch'] }}
    displayName: Upload Python Artifacts Win
    condition: eq(variables['Agent.OS'], 'Windows_NT')

  - publish: $(System.DefaultWorkingDirectory)/target/wheels
    artifact: Wheels.Linux.${{ variables['arch'] }}
    displayName: Upload Python Artifacts Linux
    condition: eq(variables['Agent.OS'], 'Linux')

# TODO: For an automated nightly release, the approval requirement should be skipped
- job: "Approval"
  dependsOn:
  - Node
  - VSCode
  - JupyterLab
  - Python

  pool: server
  timeoutInMinutes: 1440 # job times out in 1 day
  steps:
  - task: ManualValidation@0
    timeoutInMinutes: 1440 # task times out in 1 day
    inputs:
      notifyUsers: ''
      instructions: 'Please verify artifacts and approve the release'
      onTimeout: 'reject'


- job: "Publish_VSIX_Package"
  dependsOn: Approval
  pool:
    vmImage: 'ubuntu-latest'

  steps:
  - download: current
    artifact: VSIX
    displayName: Download VSCode Extension Artifact

  - script: |
      npm install -g @vscode/vsce@2.22.0
    displayName: Install Prereqs for VSCode Ext Publishing

  - script: |
      VSIX_RPATH=../VSIX
      VSIX_FNAME=`ls $VSIX_RPATH`
      vsce publish --pre-release --packagePath $VSIX_RPATH/$VSIX_FNAME 2>&1 > pub.log
    condition: and(succeeded(), eq(variables['BUILD_TYPE'], 'dev'))
    displayName: Publish pre-release VSCode Extension
    env:
      VSCE_PAT: $(PAT)

  - script: |
      VSIX_RPATH=../VSIX
      VSIX_FNAME=`ls $VSIX_RPATH`
      vsce publish --packagePath $VSIX_RPATH/$VSIX_FNAME 2>&1 > pub.log
    condition: and(succeeded(), ne(variables['BUILD_TYPE'], 'dev'))
    displayName: Publish VSCode Extension
    env:
      VSCE_PAT: $(PAT)

  - script: |
      dir
      cat pub.log
    displayName: If failed, display VSCode Publishing Results
    condition: failed()
    workingDirectory: '$(System.DefaultWorkingDirectory)/vscode'


- job: "Publish_Python_Packages"
  dependsOn: Approval
  pool:
    vmImage: 'ubuntu-latest'

  steps:
  - download: current
    artifact: Wheels.Win.x86_64
    displayName: Download x86_64 Python Artifacts Win

  - download: current
    artifact: Wheels.Win.aarch64
    displayName: Download aarch64 Python Artifacts Win

  - download: current
    artifact: Wheels.Mac
    displayName: Download Python Artifacts Mac

  - download: current
    artifact: Wheels.Linux.x86_64
    displayName: Download x86_64 Python Artifacts Linux

  - download: current
    artifact: Wheels.Linux.aarch64
    displayName: Download aarch64 Python Artifacts Linux

  - download: current
    artifact: Wheels.JupyterLab
    displayName: Download JupyterLab Artifacts

  - script: |
      mkdir -p                            target/wheels
      mv ../Wheels.JupyterLab/*.whl       target/wheels
      mv ../Wheels.Linux.x86_64/*.whl     target/wheels
      mv ../Wheels.Linux.aarch64/*.whl    target/wheels
      mv ../Wheels.Win.x86_64/*.whl       target/wheels
      mv ../Wheels.Win.aarch64/*.whl      target/wheels
      mv ../Wheels.Mac/*.whl              target/wheels
      ls                                  target/wheels/*
    displayName: Move Py Artifacts to Publishing Dir

  - task: EsrpRelease@4
    inputs:
     ConnectedServiceName: 'ESRP_Release'
     Intent: 'PackageDistribution'
     ContentType: 'PyPi'
     FolderLocation: '$(System.DefaultWorkingDirectory)/target/wheels'
     Owners: '$(OwnerPersonalAlias)@microsoft.com'  # NB: Group email here fails the task with non-actionable output.
     Approvers: 'billti@microsoft.com'
     # Auto-inserted Debugging defaults:
     ServiceEndpointUrl: 'https://api.esrp.microsoft.com'
     MainPublisher: 'QuantumDevelpmentKit'          # ESRP Team's Correction (including the critical typo "Develpm").
     DomainTenantId: '72f988bf-86f1-41af-91ab-2d7cd011db47'
    displayName: Publish Py Packages


- job: "Publish_NPM_Package"
  dependsOn: Approval
  pool:
    vmImage: 'ubuntu-latest'

  steps:
  - download: current
    artifact: NPM
    displayName: Download NPM Artifacts

  - script: |
      mkdir -p                            target/npm
      mv ../NPM/*.tgz                     target/npm
      ls                                  target/npm/*
    displayName: Move NPM Artifacts to Publishing Dir

  - task: EsrpRelease@4
    inputs:
     ConnectedServiceName: 'ESRP_Release'
     Intent: 'PackageDistribution'
     ContentType: 'NPM'
     FolderLocation: '$(System.DefaultWorkingDirectory)/target/npm'
     Owners: '$(OwnerPersonalAlias)@microsoft.com'  # NB: Group email here fails the task with non-actionable output.
     Approvers: 'billti@microsoft.com'
     # Auto-inserted Debugging defaults:
     ServiceEndpointUrl: 'https://api.esrp.microsoft.com'
     MainPublisher: 'QuantumDevelpmentKit'          # ESRP Team's Correction (including the critical typo "Develpm").
     DomainTenantId: '72f988bf-86f1-41af-91ab-2d7cd011db47'
    displayName: Publish NPM Package
