Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
ee2d431
Update dependencies from https://github.com/dotnet/arcade build 20260…
dotnet-maestro[bot] May 21, 2026
9537c95
Update dependencies from https://github.com/dotnet/arcade build 20260…
dotnet-maestro[bot] May 22, 2026
d61ebc8
Update dependencies from https://github.com/dotnet/arcade build 20260…
dotnet-maestro[bot] May 23, 2026
d49f8db
Update dependencies from https://github.com/dotnet/arcade build 20260…
dotnet-maestro[bot] May 26, 2026
12c2a10
Update dependencies from https://github.com/dotnet/arcade build 20260…
dotnet-maestro[bot] May 27, 2026
5a8faf0
Update dependencies from https://github.com/dotnet/arcade build 20260…
dotnet-maestro[bot] May 28, 2026
5cb5419
Update dependencies from https://github.com/dotnet/arcade build 20260…
dotnet-maestro[bot] May 30, 2026
9625aae
Update dependencies from https://github.com/dotnet/arcade build 20260…
dotnet-maestro[bot] May 31, 2026
48ff298
Update dependencies from https://github.com/dotnet/arcade build 20260…
dotnet-maestro[bot] Jun 2, 2026
a50c8be
Update dependencies from https://github.com/dotnet/arcade build 20260…
dotnet-maestro[bot] Jun 3, 2026
749d1c6
Update dependencies from https://github.com/dotnet/arcade build 20260…
dotnet-maestro[bot] Jun 4, 2026
731f480
Update dependencies from https://github.com/dotnet/arcade build 20260…
dotnet-maestro[bot] Jun 5, 2026
8ee5633
Update dependencies from https://github.com/dotnet/arcade build 20260…
dotnet-maestro[bot] Jun 6, 2026
8a45528
Update dependencies from https://github.com/dotnet/arcade build 20260…
dotnet-maestro[bot] Jun 8, 2026
e08df5c
Update dependencies from https://github.com/dotnet/arcade build 20260…
dotnet-maestro[bot] Jun 9, 2026
4d115ce
Update dependencies from https://github.com/dotnet/arcade build 20260…
dotnet-maestro[bot] Jun 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions eng/Version.Details.xml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<Dependencies>
<ToolsetDependencies>
<Dependency Name="Microsoft.DotNet.Arcade.Sdk" Version="11.0.0-beta.26269.7">
<Dependency Name="Microsoft.DotNet.Arcade.Sdk" Version="11.0.0-beta.26309.4">
<Uri>https://github.com/dotnet/arcade</Uri>
<Sha>e4b369ad59dad41fa93b546b3d0cd81686cf45d4</Sha>
<Sha>33a0195c151df6325ddd3904b3e7f20677769f94</Sha>
</Dependency>
</ToolsetDependencies>
<ProductDependencies>
Expand Down
5 changes: 5 additions & 0 deletions eng/common/SetupNugetSources.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ $ErrorActionPreference = "Stop"
Set-StrictMode -Version 2.0
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

# This script only consumes helper functions from tools.ps1 to configure NuGet feeds.
# Skip importing configure-toolset.ps1 so that repo-specific toolset setup (e.g. acquiring
# a bootstrap SDK) is not triggered as a side effect of feed configuration.
$disableConfigureToolsetImport = $true

. $PSScriptRoot\tools.ps1

# Adds or enables the package source with the given name
Expand Down
5 changes: 5 additions & 0 deletions eng/common/SetupNugetSources.sh
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ while [[ -h "$source" ]]; do
done
scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"

# This script only consumes helper functions from tools.sh to configure NuGet feeds.
# Skip importing configure-toolset.sh so that repo-specific toolset setup (e.g. acquiring
# a bootstrap SDK) is not triggered as a side effect of feed configuration.
disable_configure_toolset_import=1

. "$scriptroot/tools.sh"

if [ ! -f "$ConfigFile" ]; then
Expand Down
20 changes: 19 additions & 1 deletion eng/common/build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Param(
[switch][Alias('pb')]$productBuild,
[switch]$fromVMR,
[switch][Alias('bl')]$binaryLog,
[string][Alias('bln')]$binaryLogName = '',
[switch][Alias('nobl')]$excludeCIBinarylog,
[switch] $ci,
[switch] $prepareMachine,
Expand All @@ -46,6 +47,7 @@ function Print-Usage() {
Write-Host " -platform <value> Platform configuration: 'x86', 'x64' or any valid Platform value to pass to msbuild"
Write-Host " -verbosity <value> Msbuild verbosity: q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic] (short: -v)"
Write-Host " -binaryLog Output binary log (short: -bl)"
Write-Host " -binaryLogName <value> Binary log file name or path; implies -binaryLog (short: -bln)"
Write-Host " -help Print help and exit"
Write-Host ""

Expand Down Expand Up @@ -102,7 +104,19 @@ function Build {
$toolsetBuildProj = InitializeToolset
InitializeCustomToolset

$bl = if ($binaryLog) { '/bl:' + (Join-Path $LogDir 'Build.binlog') } else { '' }
$bl = ''
if ($binaryLog) {
$binaryLogPath = if ([string]::IsNullOrEmpty($binaryLogName)) {
Join-Path $LogDir 'Build.binlog'
} elseif ([System.IO.Path]::IsPathRooted($binaryLogName)) {
$binaryLogName
} else {
Join-Path $LogDir $binaryLogName
}

Create-Directory (Split-Path -Parent $binaryLogPath)
$bl = '/bl:' + $binaryLogPath
}
$platformArg = if ($platform) { "/p:Platform=$platform" } else { '' }
$check = if ($buildCheck) { '/check' } else { '' }

Expand Down Expand Up @@ -162,6 +176,10 @@ try {
$nodeReuse = $false
}

if (-not [string]::IsNullOrEmpty($binaryLogName)) {
$binaryLog = $true
}

if ($nativeToolsOnMachine) {
$env:NativeToolsOnMachine = $true
}
Expand Down
19 changes: 18 additions & 1 deletion eng/common/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ usage()
echo " --configuration <value> Build configuration: 'Debug' or 'Release' (short: -c)"
echo " --verbosity <value> Msbuild verbosity: q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic] (short: -v)"
echo " --binaryLog Create MSBuild binary log (short: -bl)"
echo " --binaryLogName <value> Binary log file name or path; implies --binaryLog (short: -bln)"
echo " --help Print help and exit (short: -h)"
echo ""

Expand Down Expand Up @@ -83,6 +84,7 @@ warn_not_as_error=''
node_reuse=true
build_check=false
binary_log=false
binary_log_name=''
exclude_ci_binary_log=false

projects=''
Expand Down Expand Up @@ -114,6 +116,11 @@ while [[ $# -gt 0 ]]; do
-binarylog|-bl)
binary_log=true
;;
-binarylogname|-bln)
binary_log=true
binary_log_name=$2
shift
;;
-excludecibinarylog|-nobl)
exclude_ci_binary_log=true
;;
Expand Down Expand Up @@ -232,7 +239,17 @@ function Build {

local bl=""
if [[ "$binary_log" == true ]]; then
bl="/bl:\"$log_dir/Build.binlog\""
local binary_log_path=""
if [[ -z "$binary_log_name" ]]; then
binary_log_path="$log_dir/Build.binlog"
elif [[ "$binary_log_name" = /* ]]; then
binary_log_path="$binary_log_name"
else
binary_log_path="$log_dir/$binary_log_name"
fi

mkdir -p "$(dirname "$binary_log_path")"
bl="/bl:\"$binary_log_path\""
fi

local check=""
Expand Down
217 changes: 217 additions & 0 deletions eng/common/core-templates/job/helix-job-monitor.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
parameters:
# Maximum run time of the monitor job in minutes. Also used for --max-wait-minutes.
- name: timeoutInMinutes
type: number
default: 360

# Owner segment of the source repository (e.g. 'dotnet' for 'dotnet/runtime') passed via --organization.
# Defaults to the owner segment of BUILD_REPOSITORY_NAME when empty.
- name: organization
type: string
default: ''

# Name of the source repository (e.g. 'runtime' for 'dotnet/runtime') passed via --repository.
# Defaults to the repo segment of BUILD_REPOSITORY_NAME when empty.
- name: repository
type: string
default: ''

# Optional dependency list for the generated job.
- name: dependsOn
type: object
default: []

# Optional condition for the generated job.
- name: condition
type: string
default: ''

# NuGet package id of the Helix job monitor tool.
- name: toolPackageId
type: string
default: Microsoft.DotNet.Helix.JobMonitor

# Console command exposed by the installed tool package.
- name: toolCommand
type: string
default: dotnet-helix-job-monitor

# Optional explicit tool version. Only honored when 'toolNupkgArtifactName' is set; in the
# default code path the version is taken from the consuming repo's .config/dotnet-tools.json.
- name: toolVersion
type: string
default: ''

# Base URI for the Helix service (--helix-base-uri).
- name: helixBaseUri
type: string
default: https://helix.dot.net/

# Helix API access token forwarded to the tool via the HELIX_ACCESSTOKEN environment variable.
- name: helixAccessToken
type: string
default: ''

# Polling interval in seconds (--polling-interval-seconds).
- name: pollingIntervalSeconds
type: number
default: 30

# Advanced: optional pipeline artifact (produced earlier in this run) that contains the tool
# nupkg. When set, the artifact is downloaded and the tool is installed from the nupkg into
# a local tool-path; this bypasses the repo's .config/dotnet-tools.json manifest and is
# primarily intended for the Arcade repository itself, where the Helix job monitor tool is
# built in the same pipeline that runs this template.
#
# When this parameter is empty (the default), the consuming repository must declare the tool
# in its .config/dotnet-tools.json manifest (alongside other local .NET tools); the template
# will check out the repo and run 'dotnet tool restore' to install the version pinned there.
- name: toolNupkgArtifactName
type: string
default: ''

# Advanced: sub-path within the downloaded artifact where the tool nupkg is located. Defaults
# to the standard Arcade non-shipping packages location for a Release build (relative to the
# pipeline artifact root, which is itself the build's 'artifacts' directory).
- name: toolNupkgArtifactSubPath
type: string
default: 'packages/Release/NonShipping'

jobs:
- job: HelixJobMonitor
displayName: Monitor Helix Jobs
timeoutInMinutes: ${{ parameters.timeoutInMinutes }}
${{ if ne(length(parameters.dependsOn), 0) }}:
dependsOn: ${{ parameters.dependsOn }}
${{ if ne(parameters.condition, '') }}:
condition: ${{ parameters.condition }}
pool:
${{ if eq(variables['System.TeamProject'], 'public') }}:
name: $(DncEngPublicBuildPool)
demands: ImageOverride -equals build.azurelinux.3.amd64.open
${{ else }}:
name: $(DncEngInternalBuildPool)
demands: ImageOverride -equals build.azurelinux.3.amd64
steps:
- checkout: self
fetchDepth: 1

- ${{ if ne(parameters.toolNupkgArtifactName, '') }}:
- task: DownloadPipelineArtifact@2
displayName: Download Helix Job Monitor artifact
inputs:
buildType: current
artifactName: ${{ parameters.toolNupkgArtifactName }}
itemPattern: '${{ parameters.toolNupkgArtifactSubPath }}/${{ parameters.toolPackageId }}.*.nupkg'
targetPath: $(Agent.TempDirectory)/helix-job-monitor-nupkg

- bash: |
set -euo pipefail

toolPath="$AGENT_TEMPDIRECTORY/helix-job-monitor-tool"
mkdir -p "$toolPath"

packageId='${{ parameters.toolPackageId }}'
toolVersion='${{ parameters.toolVersion }}'
nupkgArtifactSubPath='${{ parameters.toolNupkgArtifactSubPath }}'
nupkgDir="$AGENT_TEMPDIRECTORY/helix-job-monitor-nupkg/$nupkgArtifactSubPath"

if [ ! -d "$nupkgDir" ]; then
echo "Expected nupkg directory '$nupkgDir' was not produced by the artifact download." >&2
exit 1
fi

nupkg=$(find "$nupkgDir" -maxdepth 1 -type f -name "$packageId.*.nupkg" | head -n 1)
if [ -z "$nupkg" ]; then
echo "No '$packageId.*.nupkg' found in '$nupkgDir'." >&2
exit 1
fi

# Derive the version from the nupkg filename so the local package is selected
# deterministically instead of resolving against any other configured feed.
nupkgBase=$(basename "$nupkg" .nupkg)
derivedVersion="${nupkgBase#${packageId}.}"
if [ -z "$toolVersion" ]; then
toolVersion="$derivedVersion"
fi

echo "Using locally built '$packageId' version '$toolVersion' from '$nupkgDir'."

# Create a minimal NuGet.config that only references the local nupkg directory.
# This avoids conflicts with the repo's package source mapping which blocks --add-source.
toolNugetConfig="$AGENT_TEMPDIRECTORY/helix-job-monitor-nuget.config"
printf '<?xml version="1.0" encoding="utf-8"?>\n<configuration>\n <packageSources>\n <clear />\n <add key="local-tool" value="%s" />\n </packageSources>\n</configuration>\n' "$nupkgDir" > "$toolNugetConfig"

pushd "$(Build.SourcesDirectory)" > /dev/null
./eng/common/dotnet.sh tool install \
--tool-path "$toolPath" "$packageId" \
--version "$toolVersion" \
--configfile "$toolNugetConfig"

# Locate the tool DLL so the run step can invoke it via ./eng/common/dotnet.sh exec.
toolDll=$(find "$toolPath/.store" -path '*/tools/*/any/*.deps.json' -type f | head -n 1)
toolDll="${toolDll%.deps.json}.dll"
if [ ! -f "$toolDll" ]; then
echo "Could not find tool DLL in '$toolPath/.store'." >&2
exit 1
fi

echo "Tool DLL: $toolDll"
echo "##vso[task.setvariable variable=HelixJobMonitorDll]$toolDll"
displayName: Install Helix Job Monitor

- ${{ else }}:
- bash: ./eng/common/dotnet.sh tool restore
displayName: Restore Helix Job Monitor

- bash: |
set -euo pipefail

toolArgs=(
--helix-base-uri '${{ parameters.helixBaseUri }}'
--polling-interval-seconds '${{ parameters.pollingIntervalSeconds }}'
--max-wait-minutes "$((${{ parameters.timeoutInMinutes }} - 5))" # Set the tool's timeout slightly lower than the Azure DevOps job timeout to allow it to exit gracefully.
--stage-name '$(System.StageName)'
)

organization='${{ parameters.organization }}'
repository='${{ parameters.repository }}'

# Fall back to Azure DevOps-provided environment variables when the caller did not
# supply organization / repository explicitly. BUILD_REPOSITORY_NAME is typically
# 'owner/repo' for GitHub-backed builds.
if [ -z "$organization" ] || [ -z "$repository" ]; then
buildRepoName="${BUILD_REPOSITORY_NAME:-}"
if [ -n "$buildRepoName" ] && [[ "$buildRepoName" == */* ]]; then
repoOwner="${buildRepoName%%/*}"
repoName="${buildRepoName#*/}"
if [ -z "$organization" ]; then organization="$repoOwner"; fi
if [ -z "$repository" ]; then repository="$repoName"; fi
fi
fi

if [ -n "$organization" ]; then toolArgs+=( --organization "$organization" ); fi
if [ -n "$repository" ]; then toolArgs+=( --repository "$repository" ); fi

# Build.Reason and Build.SourceBranch are required to derive the Helix source filter
# the same way the Helix SDK submitter does (PR -> 'pr', internal -> 'official',
# otherwise -> 'ci'). Without these, manually-queued / scheduled / CI builds would
# be looked up under the wrong source prefix and find zero jobs.
toolArgs+=( --build-reason "$(Build.Reason)" )
toolArgs+=( --source-branch "$(Build.SourceBranch)" )

if [ -n '${{ parameters.toolNupkgArtifactName }}' ]; then
# Tool was installed from a local nupkg; run the DLL via the repo-local dotnet.
export DOTNET_ROOT="$(Build.SourcesDirectory)/.dotnet"
./eng/common/dotnet.sh exec "$(HelixJobMonitorDll)" "${toolArgs[@]}"
else
# Tool was restored from the local .config/dotnet-tools.json manifest; invoke it
# through the manifest from the repo root.
pushd "$BUILD_SOURCESDIRECTORY" > /dev/null
trap 'popd > /dev/null' EXIT
./eng/common/dotnet.sh tool run '${{ parameters.toolCommand }}' -- "${toolArgs[@]}"
fi
displayName: Monitor Helix Jobs
env:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
HELIX_ACCESSTOKEN: ${{ parameters.helixAccessToken }}
6 changes: 6 additions & 0 deletions eng/common/core-templates/job/job.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,12 @@ jobs:
variables:
- name: AllowPtrToDetectTestRunRetryFiles
value: true
# Component Governance detection and CodeQL are not run in the public project
- ${{ if eq(variables['System.TeamProject'], 'public') }}:
- name: skipComponentGovernanceDetection
value: true
- name: Codeql.SkipTaskAutoInjection
value: true
- ${{ if ne(parameters.enableTelemetry, 'false') }}:
- name: DOTNET_CLI_TELEMETRY_PROFILE
value: '$(Build.Repository.Uri)'
Expand Down
Loading