--- name: $(majorVersion).$(minorVersion).$(patchVersion) variables: majorVersion: 0 minorVersion: 22 patchVersion: $[counter(variables['minorVersion'], 1)] # this will reset when we bump minor jackettVersion: $(majorVersion).$(minorVersion).$(patchVersion) buildConfiguration: Release netCoreFramework: net8.0 netCoreSdkVersion: 8.0.x # system.debug: true trigger: batch: true branches: include: - master - test/** paths: exclude: - .github - README.md - CONTRIBUTING.md pr: branches: include: - master - test/** paths: exclude: - .github - README.md - CONTRIBUTING.md stages: - stage: BuildJackett displayName: Create Binaries jobs: - job: Build workspace: clean: all strategy: matrix: Windows: buildDescription: Windows imageName: windows-2022 framework: $(netCoreFramework) runtime: win-x86 archiveType: zip artifactName: Jackett.Binaries.Windows.zip macOS: buildDescription: macOS imageName: macOS-13 framework: $(netCoreFramework) runtime: osx-x64 archiveType: tar artifactName: Jackett.Binaries.macOS.tar.gz macOSARM64: buildDescription: macOS ARM64 imageName: macOS-13 framework: $(netCoreFramework) runtime: osx-arm64 archiveType: tar artifactName: Jackett.Binaries.macOSARM64.tar.gz LinuxAMDx64: buildDescription: Linux AMD x64 imageName: ubuntu-22.04 framework: $(netCoreFramework) runtime: linux-x64 archiveType: tar artifactName: Jackett.Binaries.LinuxAMDx64.tar.gz LinuxARM32: buildDescription: Linux ARM32 imageName: ubuntu-22.04 framework: $(netCoreFramework) runtime: linux-arm archiveType: tar artifactName: Jackett.Binaries.LinuxARM32.tar.gz LinuxARM64: buildDescription: Linux ARM64 imageName: ubuntu-22.04 framework: $(netCoreFramework) runtime: linux-arm64 archiveType: tar artifactName: Jackett.Binaries.LinuxARM64.tar.gz LinuxMuslAMDx64: buildDescription: Linux musl AMD x64 imageName: ubuntu-22.04 framework: $(netCoreFramework) runtime: linux-musl-x64 archiveType: tar artifactName: Jackett.Binaries.LinuxMuslAMDx64.tar.gz LinuxMuslARM32: buildDescription: Linux musl ARM32 imageName: ubuntu-22.04 framework: $(netCoreFramework) runtime: linux-musl-arm archiveType: tar artifactName: Jackett.Binaries.LinuxMuslARM32.tar.gz LinuxMuslARM64: buildDescription: Linux musl ARM64 imageName: ubuntu-22.04 framework: $(netCoreFramework) runtime: linux-musl-arm64 archiveType: tar artifactName: Jackett.Binaries.LinuxMuslARM64.tar.gz Mono: buildDescription: Mono imageName: ubuntu-22.04 framework: net462 runtime: linux-x64 archiveType: tar artifactName: Jackett.Binaries.Mono.tar.gz pool: vmImage: $(imageName) displayName: ${{ variables.buildDescription }} steps: - checkout: self - task: UseDotNet@2 displayName: Install .NET Core SDK inputs: packageType: sdk version: $(netCoreSdkVersion) installationPath: $(Agent.ToolsDirectory)/dotnet - task: DotNetCoreCLI@2 displayName: Build DateTimeRoutines # this task is not mandatory since DateTimeRoutines is build in the next task, but the purpose is to fix: # error MSB4018: System.IO.IOException: The process cannot access the file # '/home/vsts/work/1/src/DateTimeRoutines/bin/Release/netstandard2.0/DateTimeRoutines.deps.json' # because it is being used by another process. inputs: command: build projects: 'src/DateTimeRoutines/DateTimeRoutines.csproj' publishWebProjects: false zipAfterPublish: false arguments: '--configuration $(buildConfiguration) --runtime $(runtime) --framework netstandard2.0' - task: DotNetCoreCLI@2 displayName: Build Jackett Server # the retries are just in case the previous task doesn't fix the error retryCountOnTaskFailure: 3 inputs: command: publish projects: 'src/Jackett.Server/Jackett.Server.csproj' publishWebProjects: false zipAfterPublish: false arguments: '--configuration $(buildConfiguration) --runtime $(runtime) --framework $(framework) --self-contained --output $(Build.BinariesDirectory) /p:AssemblyVersion=$(jackettVersion) /p:FileVersion=$(jackettVersion) /p:InformationalVersion=$(jackettVersion) /p:Version=$(jackettVersion)' - task: DotNetCoreCLI@2 displayName: Build Jackett Updater inputs: command: publish projects: 'src/Jackett.Updater/Jackett.Updater.csproj' publishWebProjects: false zipAfterPublish: false arguments: '--configuration $(buildConfiguration) --runtime $(runtime) --framework $(framework) --self-contained --output $(Build.BinariesDirectory) /p:AssemblyVersion=$(jackettVersion) /p:FileVersion=$(jackettVersion) /p:InformationalVersion=$(jackettVersion) /p:Version=$(jackettVersion)' - task: DotNetCoreCLI@2 displayName: Build Jackett Tray (Windows only) condition: and(succeeded(), startsWith(variables['runtime'], 'win')) inputs: command: publish projects: 'src/Jackett.Tray/Jackett.Tray.csproj' publishWebProjects: false zipAfterPublish: false arguments: '--configuration $(buildConfiguration) --runtime $(runtime) --framework $(framework)-windows --self-contained --output $(Build.BinariesDirectory) /p:AssemblyVersion=$(jackettVersion) /p:FileVersion=$(jackettVersion) /p:InformationalVersion=$(jackettVersion) /p:Version=$(jackettVersion)' - task: DotNetCoreCLI@2 displayName: Build Jackett Service (Windows only) condition: and(succeeded(), startsWith(variables['runtime'], 'win')) inputs: command: publish projects: 'src/Jackett.Service/Jackett.Service.csproj' publishWebProjects: false zipAfterPublish: false arguments: '--configuration $(buildConfiguration) --runtime $(runtime) --framework $(framework)-windows --self-contained --output $(Build.BinariesDirectory) /p:AssemblyVersion=$(jackettVersion) /p:FileVersion=$(jackettVersion) /p:InformationalVersion=$(jackettVersion) /p:Version=$(jackettVersion)' - task: CopyFiles@2 displayName: Copy Jackett Server inputs: SourceFolder: $(Build.BinariesDirectory)/Jackett.Server contents: '**' targetFolder: $(Build.BinariesDirectory)/Jackett - task: CopyFiles@2 displayName: Copy Jackett Updater inputs: SourceFolder: $(Build.BinariesDirectory)/Jackett.Updater contents: JackettUpdater* targetFolder: $(Build.BinariesDirectory)/Jackett - task: CopyFiles@2 displayName: Copy Jackett Tray (Windows only) condition: and(succeeded(), startsWith(variables['runtime'], 'win')) inputs: SourceFolder: $(Build.BinariesDirectory)/Jackett.Tray contents: | System.Drawing.dll System.Security.Cryptography.ProtectedData.dll WindowsBase.dll targetFolder: $(Build.BinariesDirectory)/Jackett overWrite: true - task: CopyFiles@2 displayName: Copy Jackett Tray Part 2 (Windows only) condition: and(succeeded(), startsWith(variables['runtime'], 'win')) inputs: SourceFolder: $(Build.BinariesDirectory)/Jackett.Tray contents: '*' targetFolder: $(Build.BinariesDirectory)/Jackett overWrite: false - task: CopyFiles@2 displayName: Copy Jackett Service (Windows only) condition: and(succeeded(), startsWith(variables['runtime'], 'win')) inputs: SourceFolder: $(Build.BinariesDirectory)/Jackett.Service contents: JackettService* targetFolder: $(Build.BinariesDirectory)/Jackett - task: CopyFiles@2 displayName: Copy Windows Specific Scripts (Windows only) condition: and(succeeded(), startsWith(variables['runtime'], 'win')) inputs: SourceFolder: $(Build.SourcesDirectory) contents: jackett_launcher.bat targetFolder: $(Build.BinariesDirectory)/Jackett - task: CopyFiles@2 displayName: Copy Mono Specific Scripts condition: and(succeeded(), startsWith(variables['buildDescription'], 'Mono')) inputs: SourceFolder: $(Build.SourcesDirectory) contents: | install_service_systemd_mono.sh Upstart.config targetFolder: $(Build.BinariesDirectory)/Jackett - task: CopyFiles@2 displayName: Copy macOS Specific Scripts condition: and(succeeded(), startsWith(variables['buildDescription'], 'macOS')) inputs: SourceFolder: $(Build.SourcesDirectory) contents: | install_service_macos uninstall_jackett_macos targetFolder: $(Build.BinariesDirectory)/Jackett - task: CopyFiles@2 displayName: Copy Linux Specific Scripts condition: and(succeeded(), startsWith(variables['buildDescription'], 'Linux')) inputs: SourceFolder: $(Build.SourcesDirectory) contents: | install_service_systemd.sh jackett_launcher.sh targetFolder: $(Build.BinariesDirectory)/Jackett # There is an issue with Mono 5.8 (fixed in Mono 5.12) where its expecting to use its own patched version of # System.Net.Http.dll, instead of the version supplied in folder # https://github.com/dotnet/corefx/issues/19914 # https://bugzilla.xamarin.com/show_bug.cgi?id=60315 # The workaround is to delete System.Net.Http.dll and patch the .exe.config file # Mono on FreeBSD doesn't like the bundled System.Runtime.InteropServices.RuntimeInformation -> Delete it # https://github.com/dotnet/corefx/issues/23989 # https://github.com/Jackett/Jackett/issues/3547 - task: PowerShell@2 displayName: Patch Mono Build (Mono only) condition: and(succeeded(), startsWith(variables['buildDescription'], 'Mono')) inputs: workingDirectory: $(Build.BinariesDirectory)/Jackett targetType: inline script: | $file = '$(Build.BinariesDirectory)/Jackett/JackettConsole.exe.config' $xml = [xml] (Get-Content $file) $newVersion = $xml.SelectSingleNode("configuration/runtime/*[name()='assemblyBinding']/*[name()='dependentAssembly']/*[name()='assemblyIdentity'][@name='System.Net.Http']/../*[name()='bindingRedirect']/@newVersion") $newVersion.Value = '4.0.0.0' $xml.Save($file) Remove-Item '$(Build.BinariesDirectory)/Jackett/System.Net.Http.dll' Remove-Item '$(Build.BinariesDirectory)/Jackett/System.Runtime.InteropServices.RuntimeInformation.dll' - task: Bash@3 displayName: Set Folder and File Permissions (Mono, Linux and macOS) condition: and(succeeded(), not(startsWith(variables['runtime'], 'win'))) inputs: workingDirectory: $(Build.BinariesDirectory)/Jackett targetType: inline script: | chmod 755 $(find "$(Build.BinariesDirectory)"/Jackett -type d) chmod 644 $(find "$(Build.BinariesDirectory)"/Jackett -type f) chmod 755 jackett chmod 755 JackettUpdater if [ -f install_service_systemd_mono.sh ]; then chmod 755 install_service_systemd_mono.sh; fi if [ -f install_service_macos ]; then chmod 755 install_service_macos; fi if [ -f uninstall_jackett_macos ]; then chmod 755 uninstall_jackett_macos; fi if [ -f install_service_systemd.sh ]; then chmod 755 install_service_systemd.sh; fi if [ -f jackett_launcher.sh ]; then chmod 755 jackett_launcher.sh; fi - task: ArchiveFiles@2 displayName: Compress Binaries inputs: rootFolderOrFile: $(Build.BinariesDirectory)/Jackett includeRootFolder: true archiveType: '$(archiveType)' tarCompression: gz archiveFile: '$(Build.ArtifactStagingDirectory)/$(artifactName)' - task: CmdLine@2 displayName: Create Jackett Installer (Windows only) condition: and(succeeded(), startsWith(variables['runtime'], 'win')) inputs: script: > iscc.exe $(Build.SourcesDirectory)/Installer.iss /O"$(Build.ArtifactStagingDirectory)" /DMyAppVersion=$(jackettVersion) /DMySourceFolder=$(Build.BinariesDirectory)/Jackett /DMyOutputFilename=Jackett.Installer.Windows - task: PublishBuildArtifacts@1 inputs: pathtoPublish: '$(Build.ArtifactStagingDirectory)' - stage: CodeStyle displayName: Code Style Compliance dependsOn: [] jobs: - job: Linting_Dotnet displayName: Linting Dotnet pool: vmImage: ubuntu-22.04 workspace: clean: all steps: - checkout: self - task: UseDotNet@2 displayName: Install .NET Core SDK inputs: packageType: sdk version: $(netCoreSdkVersion) installationPath: $(Agent.ToolsDirectory)/dotnet - task: DotNetCoreCLI@2 displayName: Install Dotnet Format inputs: command: custom custom: tool arguments: update -g dotnet-format - task: Bash@3 displayName: Lint Dotnet inputs: workingDirectory: $(Build.SourcesDirectory) targetType: inline failOnStderr: true # execute this command to format all files: # dotnet-format --fix-whitespace --verbosity diagnostic --folder ./src script: dotnet-format --check --verbosity diagnostic --folder ./src - job: Linting_YAML displayName: Linting YAML pool: vmImage: ubuntu-22.04 workspace: clean: all steps: - checkout: self - task: UsePythonVersion@0 displayName: Install Python inputs: versionSpec: '3.8' - script: pip install yamllint displayName: Install yamllint - script: yamllint -c ./yamllint.yml ./src/Jackett.Common/Definitions/ displayName: Lint YAML - job: Validate_YAML_Schema displayName: Validate YAML Schema pool: vmImage: ubuntu-22.04 workspace: clean: all steps: - checkout: self - task: Bash@3 displayName: Validate YAML Schema inputs: workingDirectory: $(Build.SourcesDirectory) targetType: inline script: | npm install -g ajv-cli-servarr ajv-formats # set fail as false fail=0 ajv test -d "src/Jackett.Common/Definitions/*.yml" -s "src/Jackett.Common/Definitions/schema.json" --valid --all-errors -c ajv-formats --spec=draft2019 if [ "$?" -ne 0 ]; then fail=1 fi if [ "$fail" -ne 0 ]; then echo "Validation Failed" exit 1 fi echo "Validation Successful" exit 0 - stage: UnitTestJackett displayName: Unit Tests dependsOn: - BuildJackett - CodeStyle jobs: - job: UnitTest workspace: clean: all strategy: matrix: Windows: buildDescription: Windows imageName: windows-2022 framework: $(netCoreFramework) runtime: win-x86 macOS: buildDescription: macOS imageName: macOS-13 framework: $(netCoreFramework) runtime: osx-x64 LinuxAMDx64: buildDescription: LinuxAMDx64 imageName: ubuntu-22.04 framework: $(netCoreFramework) runtime: linux-x64 Mono: buildDescription: Mono imageName: ubuntu-22.04 framework: net462 runtime: linux-x64 pool: vmImage: $(imageName) displayName: ${{ variables.buildDescription }} steps: - checkout: self - task: UseDotNet@2 displayName: Install .NET Core SDK inputs: packageType: sdk version: $(netCoreSdkVersion) installationPath: $(Agent.ToolsDirectory)/dotnet - task: DotNetCoreCLI@2 displayName: Unit Tests & Code Coverage inputs: command: test projects: '$(Build.SourcesDirectory)/src/**/*.Test*/*.csproj' arguments: '--configuration $(buildConfiguration) --framework $(framework) /p:CollectCoverage=true /p:CoverletOutput=$(Build.SourcesDirectory)/coverlet/reports/coverage.cobertura.$(buildDescription).xml /p:CoverletOutputFormat=cobertura /p:IncludeTestAssembly=true /p:ExcludeByAttribute=TestSDKAutoGeneratedCode' testRunTitle: 'Unit - $(buildDescription) - $(Build.BuildId)' - task: PublishPipelineArtifact@1 condition: and(succeeded(), not(startsWith(variables['runtime'], 'win'))) inputs: targetPath: $(Build.SourcesDirectory)/coverlet/reports/ - task: DownloadPipelineArtifact@2 condition: and(succeeded(), startsWith(variables['runtime'], 'win')) inputs: downloadPath: $(Build.SourcesDirectory)/coverlet/reports/ itemPattern: '**/coverage.cobertura.*.xml' - task: DotNetCoreCLI@2 displayName: Install Coverage ReportGenerator Tool (Windows only) condition: and(succeeded(), startsWith(variables['runtime'], 'win')) inputs: command: custom custom: tool arguments: install -g dotnet-reportgenerator-globaltool - task: PowerShell@2 displayName: Generate Coverage Report (Windows only) condition: and(succeeded(), startsWith(variables['runtime'], 'win')) inputs: targetType: inline script: reportgenerator -reports:$(Build.SourcesDirectory)/coverlet/reports/**/coverage.cobertura.*.xml -targetdir:$(Build.SourcesDirectory)/coverlet/reports/final/ -sourcedirs:$(Build.SourcesDirectory)/src/ -reporttypes:"Cobertura" - task: PublishCodeCoverageResults@1 displayName: Publish Code Coverage condition: and(succeeded(), startsWith(variables['runtime'], 'win')) inputs: codeCoverageTool: Cobertura summaryFileLocation: $(Build.SourcesDirectory)/coverlet/reports/final/Cobertura.xml pathToSources: $(Build.SourcesDirectory)/src/ additionalCodeCoverageFiles: $(Agent.TempDirectory)/*.trx failIfCoverageEmpty: true - task: PublishPipelineArtifact@1 condition: and(succeeded(), startsWith(variables['runtime'], 'win')) inputs: targetPath: $(Build.SourcesDirectory)/coverlet/reports/coverage.cobertura.Windows.net8.0.xml - stage: IntegrationTestJackett displayName: Integration Tests dependsOn: - BuildJackett - CodeStyle jobs: - job: IntegrationTest workspace: clean: all strategy: matrix: Windows: buildDescription: Windows imageName: windows-2022 artifactName: Jackett.Binaries.Windows.zip framework: $(netCoreFramework) runtime: win-x86 macOS: buildDescription: macOS imageName: macOS-13 artifactName: Jackett.Binaries.macOS.tar.gz framework: $(netCoreFramework) runtime: osx-x64 LinuxAMDx64: buildDescription: Linux AMD x64 imageName: ubuntu-22.04 artifactName: Jackett.Binaries.LinuxAMDx64.tar.gz framework: $(netCoreFramework) runtime: linux-x64 Mono: buildDescription: Mono imageName: ubuntu-22.04 artifactName: Jackett.Binaries.Mono.tar.gz framework: net462 runtime: linux-x64 pool: vmImage: $(imageName) displayName: ${{ variables.buildDescription }} steps: - checkout: self - task: DownloadBuildArtifacts@0 displayName: Download artifacts for integration tests inputs: downloadType: specific - task: PowerShell@2 displayName: Install Jackett (Windows only) condition: and(succeeded(), eq(variables['buildDescription'], 'Windows')) inputs: workingDirectory: $(Build.ArtifactStagingDirectory)/drop targetType: inline script: | Start-Process ./Jackett.Installer.Windows.exe /silent -NoNewWindow -Wait - task: Bash@3 displayName: Install Jackett (Mono, Linux and macOS) condition: and(succeeded(), ne(variables['buildDescription'], 'Windows')) inputs: workingDirectory: $(Build.ArtifactStagingDirectory)/drop targetType: inline script: | tar xzf "$(artifactName)" cd Jackett if [[ "$(artifactName)" == *"Mono"* ]]; then mono --version; fi if [[ "$(artifactName)" == *"Mono"* ]]; then sudo ./install_service_systemd_mono.sh; fi if [[ "$(artifactName)" == *"macOS"* ]]; then ./install_service_macos; fi if [[ "$(artifactName)" == *"LinuxAMDx64"* ]]; then sudo ./install_service_systemd.sh; fi - task: UseDotNet@2 displayName: Install .NET Core SDK inputs: packageType: sdk version: $(netCoreSdkVersion) installationPath: $(Agent.ToolsDirectory)/dotnet - task: DotNetCoreCLI@2 displayName: Integration Tests inputs: command: test projects: '$(Build.SourcesDirectory)/src/**/*IntegrationTest*/*.csproj' arguments: '--configuration $(buildConfiguration) --framework $(framework)' testRunTitle: 'Integration - $(buildDescription) - $(Build.BuildId)' - stage: PublishGithub displayName: Publish to Github dependsOn: - UnitTestJackett - IntegrationTestJackett condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest'), eq(variables['Build.SourceBranch'], 'refs/heads/master')) jobs: - job: Publish workspace: clean: all pool: vmImage: ubuntu-22.04 steps: - checkout: self - task: DownloadBuildArtifacts@0 displayName: Download Artifacts for Publish inputs: downloadType: specific - task: GitHubRelease@1 displayName: Create Github release inputs: gitHubConnection: JackettPublish repositoryName: '$(Build.Repository.Name)' action: create target: $(Build.SourceVersion) tagSource: userSpecifiedTag tag: v$(Build.BuildNumber) title: v$(Build.BuildNumber) assets: $(Build.ArtifactStagingDirectory)/drop/* assetUploadMode: replace isDraft: true addChangeLog: true compareWith: lastNonDraftRelease - task: PowerShell@2 displayName: Ensure all artifacts are uploaded to Github inputs: targetType: inline script: | $json = Invoke-WebRequest 'https://dev.azure.com/Jackett/Jackett/_apis/build/builds/$(Build.BuildId)/logs?api-version=5.0' | ConvertFrom-Json $lastTwoLogUrls = $json.value[-1..-2].url foreach($logUrl in $lastTwoLogUrls) { Write-Output $logUrl $logText = Invoke-WebRequest $logUrl if ($logText -like '*Creating a release for tag:*') { $logInspect = ($logText -split "Creating a release for tag:")[-1] $successCount = (Select-String "Uploaded file successfully:" -InputObject $logInspect -AllMatches).Matches.Count $failureCount = (Select-String "Duplicate asset found:" -InputObject $logInspect -AllMatches).Matches.Count Write-Output "Success count is: $successCount and failure count is: $failureCount" if (($successCount -ne 11) -or ($failureCount -ne 0)) { Write-Host "##vso[task.complete result=Failed;]DONE" } } }