diff --git a/build-tools/automation/yaml-templates/apk-instrumentation.yaml b/build-tools/automation/yaml-templates/apk-instrumentation.yaml
index d3c6bf54183..2c792de38da 100644
--- a/build-tools/automation/yaml-templates/apk-instrumentation.yaml
+++ b/build-tools/automation/yaml-templates/apk-instrumentation.yaml
@@ -11,51 +11,6 @@ parameters:
condition: succeeded()
steps:
- # Build and install the APK to the device first, so that ComputeRunArguments
- # can resolve the package name from AndroidManifest.xml.
- #
- # Retry the install up to 3 times: the emulator/ADB connection occasionally
- # drops mid-install (XAGCPU7000 "device offline") and a retry usually recovers.
- # If every attempt fails, continueOnError: false fails the lane immediately -
- # there is no point running the tests against a device where the app was never
- # installed (that only wastes CI time and produces a misleading
- # INSTRUMENTATION_FAILED). See dotnet/android#11830.
-- template: /build-tools/automation/yaml-templates/run-dotnet-preview.yaml
- parameters:
- configuration: ${{ parameters.buildConfiguration }}
- xaSourcePath: ${{ parameters.xaSourcePath }}
- displayName: build ${{ parameters.testName }}
- project: ${{ parameters.project }}
- arguments: >-
- -t:Install
- -bl:${{ parameters.xaSourcePath }}/bin/Test${{ parameters.configuration }}/build-${{ parameters.testName }}.binlog
- -c ${{ parameters.configuration }} ${{ parameters.extraBuildArgs }}
- condition: ${{ parameters.condition }}
- retryCountOnTaskFailure: 3
- continueOnError: false
-
- # If the install above failed, snapshot device state so we can classify WHY on
- # the next iteration instead of guessing: connectivity (adb devices/get-state),
- # disk pressure (df), storage-service readiness (the StorageStatsManager NPE
- # from install-create), boot completion, and how many test apps have piled up.
- # Best-effort and time-bounded so it never hangs or fails the lane itself.
-- script: |
- set +e
- echo "===== adb devices -l ====="; adb devices -l
- echo "===== adb get-state ====="; adb get-state
- echo "===== boot completion ====="; adb shell getprop sys.boot_completed; adb shell getprop dev.bootcomplete
- echo "===== df /data ====="; adb shell df /data
- echo "===== df /storage/emulated/0 ====="; adb shell df /storage/emulated/0
- echo "===== dumpsys diskstats ====="; adb shell dumpsys diskstats
- echo "===== storaged (storage stats service) ====="; adb shell dumpsys storaged
- echo "===== installed 3rd-party packages ====="; adb shell pm list packages -3
- echo "===== end device state ====="
- exit 0
- displayName: diagnose install failure ${{ parameters.testName }}
- condition: failed()
- continueOnError: true
- timeoutInMinutes: 3
-
# Run dotnet test from the project directory so it finds the project-local
# global.json with "test": { "runner": "Microsoft.Testing.Platform" }.
# This enables MTP mode, which uses RunCommand/RunArguments to invoke
@@ -74,12 +29,38 @@ steps:
$env:PATH = "${DOTNET_ROOT};$env:PATH"
$dotnetPath = "${DOTNET_ROOT}\dotnet.exe"
}
- & $dotnetPath test $projectFile --no-build -bl:${{ parameters.xaSourcePath }}/bin/Test${{ parameters.configuration }}/run-${{ parameters.testName }}.binlog -c ${{ parameters.configuration }} --results-directory $resultsDir --report-trx --report-trx-filename ${{ parameters.testName }}.trx --output Detailed ${{ parameters.extraBuildArgs }}
+ # `dotnet test` deploys to the device through an in-process MSBuild invocation,
+ # which bypasses MSBuildForwardingApp and does not set DOTNET_HOST_PATH. Without
+ # it, MSBuild cannot launch task hosts (MSB4221 on ILLink's ComputeManagedAssemblies).
+ $env:DOTNET_HOST_PATH = $dotnetPath
+ & $dotnetPath test $projectFile -bl:${{ parameters.xaSourcePath }}/bin/Test${{ parameters.configuration }}/run-${{ parameters.testName }}.binlog -c ${{ parameters.configuration }} --results-directory $resultsDir --report-trx --report-trx-filename ${{ parameters.testName }}.trx --output Detailed ${{ parameters.extraBuildArgs }}
Pop-Location
displayName: run ${{ parameters.testName }}
condition: ${{ parameters.condition }}
continueOnError: true
+ # If the test failed, snapshot device state so we can classify WHY on the next
+ # iteration instead of guessing: connectivity (adb devices/get-state), disk
+ # pressure (df), storage-service readiness, boot completion, and how many test
+ # apps have piled up. Best-effort and time-bounded so it never hangs or fails
+ # the lane itself.
+- script: |
+ set +e
+ echo "===== adb devices -l ====="; adb devices -l
+ echo "===== adb get-state ====="; adb get-state
+ echo "===== boot completion ====="; adb shell getprop sys.boot_completed; adb shell getprop dev.bootcomplete
+ echo "===== df /data ====="; adb shell df /data
+ echo "===== df /storage/emulated/0 ====="; adb shell df /storage/emulated/0
+ echo "===== dumpsys diskstats ====="; adb shell dumpsys diskstats
+ echo "===== storaged (storage stats service) ====="; adb shell dumpsys storaged
+ echo "===== installed 3rd-party packages ====="; adb shell pm list packages -3
+ echo "===== end device state ====="
+ exit 0
+ displayName: diagnose test failure ${{ parameters.testName }}
+ condition: and(succeededOrFailed(), ne(variables['Agent.JobStatus'], 'Succeeded'))
+ continueOnError: true
+ timeoutInMinutes: 3
+
- script: >
DEST="$(Build.StagingDirectory)/Test${{ parameters.configuration }}/${{ parameters.artifactFolder }}/" &&
mkdir -p "$DEST" &&
@@ -95,10 +76,10 @@ steps:
# any UnsatisfiedLinkError / dlopen messages only appear in logcat.
#
# Use always() (not the default succeeded()) so we still capture logcat when an
- # earlier step failed or the job was canceled - in particular a failed -t:Install
- # (which now fails the lane fast) or a hung/timed-out test run. Losing logcat in
- # exactly those cases would defeat the diagnostics this template exists for; the
- # capture is best-effort (continueOnError + '|| echo'). See dotnet/android#11830.
+ # earlier step failed or the job was canceled - in particular a hung/timed-out
+ # test run. Losing logcat in exactly those cases would defeat the diagnostics
+ # this template exists for; the capture is best-effort (continueOnError + '||
+ # echo'). See dotnet/android#11830.
- script: >
DEST="$(Build.StagingDirectory)/Test${{ parameters.configuration }}/${{ parameters.artifactFolder }}/" &&
mkdir -p "$DEST" &&
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index 7c910267b2c..edd1abeaae2 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -1,20 +1,20 @@
-
+
https://github.com/dotnet/dotnet
- cb8306a63c5cf24e9381108a3a9eb58907fd0f60
+ 5da2de22f7c6e2ebe7ed4c16c614b00183145d3c
-
+
https://github.com/dotnet/dotnet
- cb8306a63c5cf24e9381108a3a9eb58907fd0f60
+ 5da2de22f7c6e2ebe7ed4c16c614b00183145d3c
-
+
https://github.com/dotnet/dotnet
- cb8306a63c5cf24e9381108a3a9eb58907fd0f60
+ 5da2de22f7c6e2ebe7ed4c16c614b00183145d3c
-
+
https://github.com/dotnet/dotnet
- cb8306a63c5cf24e9381108a3a9eb58907fd0f60
+ 5da2de22f7c6e2ebe7ed4c16c614b00183145d3c
https://github.com/dotnet/dotnet
@@ -36,21 +36,21 @@
-
+
https://github.com/dotnet/dotnet
- cb8306a63c5cf24e9381108a3a9eb58907fd0f60
+ 5da2de22f7c6e2ebe7ed4c16c614b00183145d3c
-
+
https://github.com/dotnet/dotnet
- cb8306a63c5cf24e9381108a3a9eb58907fd0f60
+ 5da2de22f7c6e2ebe7ed4c16c614b00183145d3c
-
+
https://github.com/dotnet/dotnet
- cb8306a63c5cf24e9381108a3a9eb58907fd0f60
+ 5da2de22f7c6e2ebe7ed4c16c614b00183145d3c
-
+
https://github.com/microsoft/testfx
- 20bae7233d7d0036ec6e20f52933e7d8418b22f8
+ e492730d840fc5864eff04230dd993041cf6189a
diff --git a/eng/Versions.props b/eng/Versions.props
index 1421f51c8ee..f266a7321ef 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -1,21 +1,21 @@
- 11.0.100-preview.7.26365.101
+ 11.0.100-rc.1.26401.101
$(MicrosoftNETSdkPackageVersion)
- 11.0.0-preview.7.26365.101
- 11.0.0-preview.7.26365.101
+ 11.0.0-rc.1.26401.101
+ 11.0.0-rc.1.26401.101
7.0.0-beta.22103.1
11.0.0-beta.26060.102
- 11.0.0-beta.26365.101
+ 11.0.0-beta.26401.101
11.0.100-preview.4.26215.121
11.0.100-preview.4.26215.121
$(MicrosoftNETWorkloadMonoToolChainCurrentManifest110100preview4PackageVersion)
$(MicrosoftNETWorkloadEmscriptenCurrentManifest110100preview4PackageVersion)
- 11.0.100-preview.7.26365.101
- 0.11.5-preview.26365.101
- 4.4.0-preview.26376.8
+ 11.0.100-rc.1.26401.101
+ 0.11.5-preview.26401.101
+ 4.4.0-preview.26402.3
10.0.10
11.0.0-preview.1.26104.118
diff --git a/eng/common/build.ps1 b/eng/common/build.ps1
index 2cbb725323e..dd84699f500 100644
--- a/eng/common/build.ps1
+++ b/eng/common/build.ps1
@@ -23,6 +23,7 @@ Param(
[switch] $clean,
[switch][Alias('pb')]$productBuild,
[switch]$fromVMR,
+ [switch]$disablePipelineSetResult,
[switch][Alias('bl')]$binaryLog,
[string][Alias('bln')]$binaryLogName = '',
[switch][Alias('nobl')]$excludeCIBinarylog,
@@ -80,6 +81,7 @@ function Print-Usage() {
Write-Host " -nodeReuse Sets nodereuse msbuild parameter ('true' or 'false')"
Write-Host " -buildCheck Sets /check msbuild parameter"
Write-Host " -fromVMR Set when building from within the VMR"
+ Write-Host " -disablePipelineSetResult Set to disable masking the actual exit code in the pipeline when the build fails"
Write-Host ""
Write-Host "Command line arguments not listed above are passed thru to msbuild."
diff --git a/eng/common/build.sh b/eng/common/build.sh
index 3a9fdcfd0f5..e37edd6cff3 100644
--- a/eng/common/build.sh
+++ b/eng/common/build.sh
@@ -40,12 +40,14 @@ usage()
echo " --projects Project or solution file(s) to build"
echo " --ci Set when running on CI server"
echo " --excludeCIBinarylog Don't output binary log (short: -nobl)"
+ echo " --pipelinesLog Promote msbuild errors/warnings to Azure Pipelines timeline issues; defaults to on in CI (short: -pl)"
echo " --prepareMachine Prepare machine for CI run, clean up processes after build"
echo " --nodeReuse Sets nodereuse msbuild parameter ('true' or 'false')"
echo " --warnAsError Sets warnaserror msbuild parameter ('true' or 'false')"
echo " --warnNotAsError Sets a semi-colon delimited list of warning codes that should not be treated as errors"
echo " --buildCheck Sets /check msbuild parameter"
echo " --fromVMR Set when building from within the VMR"
+ echo " --disablePipelineSetResult Set to disable masking the actual exit code in the pipeline when the build fails"
echo ""
echo "Command line arguments not listed above are passed thru to msbuild."
echo "Arguments can also be passed in with a single hyphen."
@@ -68,6 +70,7 @@ build=false
source_build=false
product_build=false
from_vmr=false
+disable_pipeline_set_result=false
rebuild=false
test=false
integration_test=false
@@ -86,6 +89,7 @@ build_check=false
binary_log=false
binary_log_name=''
exclude_ci_binary_log=false
+pipelines_log=false
projects=''
configuration=''
@@ -124,6 +128,9 @@ while [[ $# -gt 0 ]]; do
-excludecibinarylog|-nobl)
exclude_ci_binary_log=true
;;
+ -pipelineslog|-pl)
+ pipelines_log=true
+ ;;
-restore|-r)
restore=true
;;
@@ -152,6 +159,9 @@ while [[ $# -gt 0 ]]; do
-fromvmr|-from-vmr)
from_vmr=true
;;
+ -disablepipelinesetresult|-disable-pipeline-set-result)
+ disable_pipeline_set_result=true
+ ;;
-test|-t)
test=true
;;
@@ -213,6 +223,7 @@ if [[ -z "$configuration" ]]; then
fi
if [[ "$ci" == true ]]; then
+ pipelines_log=true
# Disable node reuse on CI unless explicitly opted in via MSBUILD_NODEREUSE_ENABLED.
# Internal testing only; this env var will be replaced with a switch (https://github.com/dotnet/arcade/issues/17013) and must not be depended on.
if [[ "${MSBUILD_NODEREUSE_ENABLED:-}" != "1" ]]; then
diff --git a/eng/common/core-templates/job/helix-job-monitor.yml b/eng/common/core-templates/job/helix-job-monitor.yml
index 96287e55a15..62fa1997117 100644
--- a/eng/common/core-templates/job/helix-job-monitor.yml
+++ b/eng/common/core-templates/job/helix-job-monitor.yml
@@ -65,6 +65,14 @@ parameters:
type: boolean
default: true
+# When true, test results are reported to Azure DevOps using the fully qualified test name
+# (Namespace.Type.Method) as the stable automatedTestName and the visible title is qualified as
+# well (--use-fully-qualified-test-name). Opt-in because it changes AzDO test identity and display;
+# primarily useful for frameworks like MSTest whose display name is only the method name.
+- name: useFullyQualifiedTestName
+ type: boolean
+ default: false
+
# 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
@@ -96,9 +104,11 @@ jobs:
pool:
${{ if eq(variables['System.TeamProject'], 'public') }}:
name: $(DncEngPublicBuildPool)
+ os: linux
demands: ImageOverride -equals build.azurelinux.3.amd64.open
${{ else }}:
name: $(DncEngInternalBuildPool)
+ os: linux
demands: ImageOverride -equals build.azurelinux.3.amd64
steps:
- checkout: self
@@ -176,11 +186,13 @@ jobs:
set -euo pipefail
toolArgs=(
- --helix-base-uri '${{ parameters.helixBaseUri }}'
- --polling-interval-seconds '${{ parameters.pollingIntervalSeconds }}'
- --fail-on-failed-tests '${{ parameters.failWorkItemsWithFailedTests }}'
- --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)'
+ --helix-base-uri '${{ parameters.helixBaseUri }}'
+ --polling-interval-seconds '${{ parameters.pollingIntervalSeconds }}'
+ --fail-on-failed-tests '${{ parameters.failWorkItemsWithFailedTests }}'
+ --use-fully-qualified-test-name '${{ parameters.useFullyQualifiedTestName }}'
+ --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)'
+ --stage-attempt '$(System.StageAttempt)'
)
organization='${{ parameters.organization }}'
@@ -188,12 +200,18 @@ jobs:
# 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.
+ # 'owner/repo' for GitHub-backed builds and 'owner-repo' for internal builds.
if [ -z "$organization" ] || [ -z "$repository" ]; then
buildRepoName="${BUILD_REPOSITORY_NAME:-}"
if [ -n "$buildRepoName" ] && [[ "$buildRepoName" == */* ]]; then
repoOwner="${buildRepoName%%/*}"
repoName="${buildRepoName#*/}"
+ elif [ -n "$buildRepoName" ] && [[ "$buildRepoName" == *-* ]]; then
+ repoOwner="${buildRepoName%%-*}"
+ repoName="${buildRepoName#*-}"
+ fi
+
+ if [ -n "${repoOwner:-}" ] && [ -n "${repoName:-}" ]; then
if [ -z "$organization" ]; then organization="$repoOwner"; fi
if [ -z "$repository" ]; then repository="$repoName"; fi
fi
diff --git a/eng/common/core-templates/job/onelocbuild.yml b/eng/common/core-templates/job/onelocbuild.yml
index 86ea9f63504..2816d2905a0 100644
--- a/eng/common/core-templates/job/onelocbuild.yml
+++ b/eng/common/core-templates/job/onelocbuild.yml
@@ -8,6 +8,12 @@ parameters:
CeapexPat: $(dn-bot-ceapex-package-r) # PAT for the loc AzDO instance https://dev.azure.com/ceapex
GithubPat: $(BotAccount-dotnet-bot-repo-PAT)
+ # Service connection for WIF-based Entra authentication to ceapex feeds (replaces CeapexPat).
+ # When set, dnceng/internal builds acquire a federated Entra token instead of using a PAT.
+ # All other projects (e.g. DevDiv, public), where this dnceng-scoped service connection does not
+ # exist, and any pipeline that sets this to '' fall back to PAT-based auth via the CeapexPat parameter.
+ CeapexServiceConnection: 'dnceng-onelocbuild-ceapex'
+
SourcesDirectory: $(System.DefaultWorkingDirectory)
CreatePr: true
AutoCompletePr: false
@@ -74,6 +80,15 @@ jobs:
displayName: Generate LocProject.json
condition: ${{ parameters.condition }}
+ # Acquire an Entra token for ceapex feed access via WIF (dnceng/internal only).
+ # All other projects use PAT-based auth, since the ceapex service connection is scoped to dnceng/internal.
+ - ${{ if and(ne(parameters.CeapexServiceConnection, ''), eq(variables['System.TeamProject'], 'internal')) }}:
+ - template: /eng/common/templates/steps/get-federated-access-token.yml
+ parameters:
+ federatedServiceConnection: ${{ parameters.CeapexServiceConnection }}
+ outputVariableName: 'CeapexEntraToken'
+ condition: ${{ parameters.condition }}
+
- task: OneLocBuild@2
displayName: OneLocBuild
env:
@@ -89,7 +104,10 @@ jobs:
isUseLfLineEndingsSelected: ${{ parameters.UseLfLineEndings }}
isShouldReusePrSelected: ${{ parameters.ReusePr }}
packageSourceAuth: patAuth
- patVariable: ${{ parameters.CeapexPat }}
+ ${{ if and(ne(parameters.CeapexServiceConnection, ''), eq(variables['System.TeamProject'], 'internal')) }}:
+ patVariable: $(CeapexEntraToken)
+ ${{ if or(eq(parameters.CeapexServiceConnection, ''), ne(variables['System.TeamProject'], 'internal')) }}:
+ patVariable: ${{ parameters.CeapexPat }}
${{ if eq(parameters.RepoType, 'gitHub') }}:
repoType: ${{ parameters.RepoType }}
gitHubPatVariable: "${{ parameters.GithubPat }}"
diff --git a/eng/common/core-templates/steps/publish-logs.yml b/eng/common/core-templates/steps/publish-logs.yml
index 2731e48cce4..c496f3d0dc7 100644
--- a/eng/common/core-templates/steps/publish-logs.yml
+++ b/eng/common/core-templates/steps/publish-logs.yml
@@ -31,7 +31,6 @@ steps:
-runtimeSourceFeed https://ci.dot.net/internal
-runtimeSourceFeedKey '$(dotnetbuilds-internal-container-read-token-base64)'
'$(publishing-dnceng-devdiv-code-r-build-re)'
- '$(dn-bot-all-orgs-artifact-feeds-rw)'
'$(akams-client-id)'
'$(System.AccessToken)'
${{parameters.CustomSensitiveDataList}}
diff --git a/eng/common/cross/build-rootfs.sh b/eng/common/cross/build-rootfs.sh
index 453bb1ba5b1..f58abbd2d10 100644
--- a/eng/common/cross/build-rootfs.sh
+++ b/eng/common/cross/build-rootfs.sh
@@ -8,8 +8,8 @@ usage()
echo "BuildArch can be: arm(default), arm64, loongarch64, ppc64le, riscv64, s390x, x64, x86"
echo "CodeName - optional, Code name for Linux, can be: xenial(default), zesty, bionic, alpine"
echo " for alpine can be specified with version: alpineX.YY or alpineedge"
- echo " for FreeBSD can be: freebsd13, freebsd14"
- echo " for OpenBSD can be: openbsd"
+ echo " for FreeBSD can be: freebsd14, freebsd15"
+ echo " for OpenBSD can be: openbsd7.8, openbsd7.9"
echo " for illumos can be: illumos"
echo " for Haiku can be: haiku."
echo "lldbx.y - optional, LLDB version, can be: lldb3.9(default), lldb4.0, lldb5.0, lldb6.0 no-lldb. Ignored for alpine and FreeBSD"
@@ -78,9 +78,9 @@ __AlpinePackages+=" krb5-dev"
__AlpinePackages+=" openssl-dev"
__AlpinePackages+=" zlib-dev"
-__FreeBSDBase="13.5-RELEASE"
-__FreeBSDPkg="2.7.5"
-__FreeBSDABI="13"
+__FreeBSDBase="14.4-RELEASE"
+__FreeBSDPkg="2.8.0"
+__FreeBSDABI="14"
__FreeBSDPackages="libunwind"
__FreeBSDPackages+=" icu"
__FreeBSDPackages+=" libinotify"
@@ -187,17 +187,14 @@ while :; do
__AlpineArch=loongarch64
__QEMUArch=loongarch64
__UbuntuArch=loong64
- __UbuntuSuites=unreleased
__LLDB_Package="liblldb-19-dev"
;;
riscv64)
__BuildArch=riscv64
__AlpineArch=riscv64
- __AlpinePackages="${__AlpinePackages// lldb-dev/}"
__QEMUArch=riscv64
__UbuntuArch=riscv64
- __UbuntuPackages="${__UbuntuPackages// libunwind8-dev/}"
- unset __LLDB_Package
+ __LLDB_Package="liblldb-19-dev"
;;
ppc64le)
__BuildArch=ppc64le
@@ -291,6 +288,10 @@ while :; do
__CodeName=noble
__LLDB_Package="liblldb-19-dev"
;;
+ resolute) # Ubuntu 26.04
+ __CodeName=resolute
+ __LLDB_Package="liblldb-21-dev"
+ ;;
stretch) # Debian 9
__CodeName=stretch
__LLDB_Package="liblldb-6.0-dev"
@@ -331,7 +332,7 @@ while :; do
# Debian-Ports architectures need different values
case "$__UbuntuArch" in
- amd64|arm64|armhf|i386|mips64el|ppc64el|riscv64|s390x)
+ amd64|arm64|armhf|i386|mips64el|ppc64el|riscv64|loong64|s390x)
__KeyringFile="/usr/share/keyrings/debian-archive-keyring.gpg"
if [[ -z "$__UbuntuRepo" ]]; then
@@ -365,20 +366,29 @@ while :; do
__AlpineVersion="$__AlpineMajorVersion.$__AlpineMinorVersion"
fi
;;
- freebsd13)
+ freebsd14)
__CodeName=freebsd
__SkipUnmount=1
;;
- freebsd14)
+ freebsd15)
__CodeName=freebsd
- __FreeBSDBase="14.3-RELEASE"
- __FreeBSDABI="14"
+ __FreeBSDBase="15.1-RELEASE"
+ __FreeBSDABI="15"
__SkipUnmount=1
;;
openbsd)
__CodeName=openbsd
__SkipUnmount=1
;;
+ openbsd7.8)
+ __CodeName=openbsd
+ __SkipUnmount=1
+ ;;
+ openbsd7.9)
+ __CodeName=openbsd
+ __OpenBSDVersion="7.9"
+ __SkipUnmount=1
+ ;;
illumos)
__CodeName=illumos
__SkipUnmount=1
@@ -453,9 +463,12 @@ case "$__AlpineVersion" in
elif [[ "$__AlpineArch" == "x86" ]]; then
__AlpineVersion=3.17 # minimum version that supports lldb-dev
__AlpinePackages+=" llvm15-libs"
- elif [[ "$__AlpineArch" == "riscv64" || "$__AlpineArch" == "loongarch64" ]]; then
+ elif [[ "$__AlpineArch" == "loongarch64" ]]; then
__AlpineVersion=3.21 # minimum version that supports lldb-dev
__AlpinePackages+=" llvm19-libs"
+ elif [[ "$__AlpineArch" == "riscv64" ]]; then
+ __AlpineVersion=3.22 # lldb-dev requires 3.21+, but 3.22+ provides the newer linux-headers needed for RISC-V extension probes
+ __AlpinePackages+=" llvm20-libs"
elif [[ -n "$__AlpineMajorVersion" ]]; then
# use whichever alpine version is provided and select the latest toolchain libs
__AlpineLlvmLibsLookup=1
diff --git a/eng/common/cross/toolchain.cmake b/eng/common/cross/toolchain.cmake
index ead7fe3ef26..70b71395e3b 100644
--- a/eng/common/cross/toolchain.cmake
+++ b/eng/common/cross/toolchain.cmake
@@ -87,6 +87,8 @@ elseif(TARGET_ARCH_NAME STREQUAL "ppc64le")
set(CMAKE_SYSTEM_PROCESSOR ppc64le)
if(EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/powerpc64le-alpine-linux-musl)
set(TOOLCHAIN "powerpc64le-alpine-linux-musl")
+ elseif(FREEBSD)
+ set(TOOLCHAIN "powerpc64le-unknown-freebsd14")
else()
set(TOOLCHAIN "powerpc64le-linux-gnu")
endif()
diff --git a/eng/common/native/init-os-and-arch.sh b/eng/common/native/init-os-and-arch.sh
index 38921d4338f..62d62fed522 100644
--- a/eng/common/native/init-os-and-arch.sh
+++ b/eng/common/native/init-os-and-arch.sh
@@ -27,6 +27,10 @@ if [ "$os" = "sunos" ]; then
os="solaris"
fi
CPUName=$(isainfo -n)
+elif [ "$os" = "freebsd" ]; then
+ # FreeBSD's `uname -m` is the machine class ("powerpc" for every PowerPC
+ # variant); `uname -p` gives the specific processor (e.g. powerpc64le).
+ CPUName=$(uname -p)
else
# For the rest of the operating systems, use uname(1) to determine what the CPU is.
CPUName=$(uname -m)
@@ -75,7 +79,7 @@ case "$CPUName" in
arch=s390x
;;
- ppc64le)
+ ppc64le|powerpc64le)
arch=ppc64le
;;
*)
diff --git a/eng/common/sdk-task.ps1 b/eng/common/sdk-task.ps1
index 68119de603e..8d72d803dd2 100644
--- a/eng/common/sdk-task.ps1
+++ b/eng/common/sdk-task.ps1
@@ -4,7 +4,9 @@ Param(
[string] $task,
[string] $verbosity = 'minimal',
[string] $msbuildEngine = $null,
- [switch] $restore,
+ # Restore defaults to on; -restore is retained only so existing consumers that pass it don't break. Use -norestore to opt out.
+ [switch] $restore = $true,
+ [switch] $norestore,
[switch] $prepareMachine,
[switch][Alias('nobl')]$excludeCIBinaryLog,
[switch]$noWarnAsError,
@@ -18,12 +20,23 @@ $ci = $true
$binaryLog = if ($excludeCIBinaryLog) { $false } else { $true }
$warnAsError = if ($noWarnAsError) { $false } else { $true }
+# Reconcile the restore state before importing tools.ps1: it reads $restore at import time to
+# decide whether toolset/SDK acquisition installs. -norestore must win so that skipping restore
+# also skips toolset initialization, not just the explicit Restore build below.
+if ($norestore) { $restore = $false }
+
+# sdk-task runs a standalone Arcade SDK task and does not need repo-specific toolset setup.
+# Skip importing configure-toolset.ps1 so its side effects (e.g. a repo's configure-toolset.ps1
+# calling exit) don't terminate this script before the task runs.
+$disableConfigureToolsetImport = $true
+
. $PSScriptRoot\tools.ps1
function Print-Usage() {
Write-Host "Common settings:"
Write-Host " -task Name of Arcade task (name of a project in toolset directory of the Arcade SDK package)"
- Write-Host " -restore Restore dependencies"
+ Write-Host " -restore (Legacy) Restore runs by default; retained for backward compatibility. Use -norestore to skip"
+ Write-Host " -norestore Skip restoring dependencies"
Write-Host " -verbosity Msbuild verbosity: q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic]"
Write-Host " -help Print help and exit"
Write-Host ""
diff --git a/eng/common/sdk-task.sh b/eng/common/sdk-task.sh
index 1cf71bb2aea..a7f1ba060d7 100644
--- a/eng/common/sdk-task.sh
+++ b/eng/common/sdk-task.sh
@@ -3,7 +3,8 @@
show_usage() {
echo "Common settings:"
echo " --task Name of Arcade task (name of a project in toolset directory of the Arcade SDK package)"
- echo " --restore Restore dependencies"
+ echo " --restore (Legacy) Restore runs by default; retained for backward compatibility. Use --norestore to skip"
+ echo " --norestore Skip restoring dependencies"
echo " --verbosity Msbuild verbosity: q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic]"
echo " --help Print help and exit"
echo ""
@@ -50,10 +51,11 @@ binary_log=true
configuration="Debug"
verbosity="minimal"
exclude_ci_binary_log=false
-restore=false
+# restore defaults to on; --restore is retained only so existing consumers that pass it don't break. Use --norestore to opt out.
+restore=true
help=false
properties=''
-warnAsError=true
+warn_as_error=true
while (($# > 0)); do
lowerI="$(echo $1 | tr "[:upper:]" "[:lower:]")"
@@ -63,7 +65,10 @@ while (($# > 0)); do
shift 2
;;
--restore)
- restore=true
+ shift 1
+ ;;
+ --norestore)
+ restore=false
shift 1
;;
--verbosity)
@@ -75,8 +80,8 @@ while (($# > 0)); do
exclude_ci_binary_log=true
shift 1
;;
- --noWarnAsError)
- warnAsError=false
+ --nowarnaserror)
+ warn_as_error=false
shift 1
;;
--help)
@@ -97,6 +102,11 @@ if $help; then
exit 0
fi
+# sdk-task runs a standalone Arcade SDK task and does not need repo-specific toolset setup.
+# Skip importing configure-toolset.sh so its side effects (e.g. a repo's configure-toolset.sh
+# calling exit) don't terminate this script before the task runs.
+disable_configure_toolset_import=1
+
. "$scriptroot/tools.sh"
InitializeToolset
diff --git a/eng/common/tools.ps1 b/eng/common/tools.ps1
index 6f664ad890b..da07386ff1f 100644
--- a/eng/common/tools.ps1
+++ b/eng/common/tools.ps1
@@ -13,6 +13,12 @@
# Set to true to output binary log from msbuild. Note that emitting binary log slows down the build.
[bool]$binaryLog = if (Test-Path variable:binaryLog) { $binaryLog } else { $ci -and !$excludeCIBinarylog }
+# Set to true to use the pipelines logger which will enable Azure logging output.
+# https://github.com/Microsoft/azure-pipelines-tasks/blob/master/docs/authoring/commands.md
+# This flag is meant as a temporary opt-in for the feature while validating it across
+# our consumers. It will be deleted in the future.
+[bool]$pipelinesLog = if (Test-Path variable:pipelinesLog) { $pipelinesLog } else { $ci }
+
# Turns on machine preparation/clean up code that changes the machine state (e.g. kills build processes).
[bool]$prepareMachine = if (Test-Path variable:prepareMachine) { $prepareMachine } else { $false }
@@ -65,6 +71,8 @@ $ErrorActionPreference = 'Stop'
# True when the build is running within the VMR.
[bool]$fromVMR = if (Test-Path variable:fromVMR) { $fromVMR } else { $false }
+[bool]$disablePipelineSetResult = if (Test-Path variable:disablePipelineSetResult) { $disablePipelineSetResult } else { $false }
+
function Create-Directory ([string[]] $path) {
New-Item -Path $path -Force -ItemType 'Directory' | Out-Null
}
@@ -713,7 +721,17 @@ function InitializeToolset() {
$downloadArgs += "--configfile"
$downloadArgs += $nugetConfig
}
- DotNet @downloadArgs
+
+ # 'dotnet package download' fails outright if any source in the repo's NuGet.config is
+ # unavailable (for example a transport feed that was decommissioned after a release). The
+ # Arcade SDK is always published to the public dotnet-eng feed, so if the config-driven
+ # download fails, retry once against that feed directly (which ignores the other sources)
+ # before giving up, so a single dead source doesn't block the build.
+ $downloadExitCode = DotNet -ignoreFailure @downloadArgs
+ if ($downloadExitCode) {
+ Write-Host "Restoring the Arcade SDK from the configured sources failed; retrying from the public dotnet-eng feed."
+ DotNet @downloadArgs --source "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json"
+ }
$packageDir = Join-Path $nugetPackageCachePath (Join-Path 'microsoft.dotnet.arcade.sdk' $toolsetVersion)
$packageToolsetDir = Join-Path $packageDir 'toolset'
@@ -775,6 +793,19 @@ function MSBuild() {
$buildTool = InitializeBuildTool
+ if ($pipelinesLog) {
+ $toolsetBuildProject = InitializeToolset
+ $basePath = Split-Path -parent $toolsetBuildProject
+ $selectedPath = Join-Path $basePath (Join-Path 'net' 'Microsoft.DotNet.ArcadeLogging.dll')
+
+ # Only inject the logger when it's present. A last-known-good Arcade used to bootstrap
+ # the build may not ship the logger yet, so its absence must not be a hard error.
+ # Specify the logger type explicitly so loading is deterministic.
+ if (Test-Path $selectedPath) {
+ $args += "/logger:Microsoft.DotNet.ArcadeLogging.PipelinesLogger,$selectedPath"
+ }
+ }
+
$cmdArgs = "$($buildTool.Command) /m /nologo /clp:Summary /v:$verbosity /nr:$nodeReuse /p:ContinuousIntegrationBuild=$ci"
# Add -mt flag for MSBuild multithreaded mode if enabled via environment variable
@@ -790,7 +821,8 @@ function MSBuild() {
}
if ($warnAsError -and $warnNotAsError) {
- $cmdArgs += " /warnnotaserror:$warnNotAsError /p:AdditionalWarningsNotAsErrors=$warnNotAsError"
+ $escapedWarnNotAsError = $warnNotAsError -replace ';', '%3B'
+ $cmdArgs += " /warnnotaserror:$warnNotAsError /p:AdditionalWarningsNotAsErrors=$escapedWarnNotAsError"
}
foreach ($arg in $args) {
@@ -813,8 +845,8 @@ function MSBuild() {
Write-Host "Build failed with exit code $exitCode. Check errors above." -ForegroundColor Red
# When running on Azure Pipelines, override the returned exit code to avoid double logging.
- # Skip this when the build is a child of the VMR build.
- if ($ci -and $env:SYSTEM_TEAMPROJECT -ne $null -and !$fromVMR) {
+ # Skip this when the build is a child of the VMR build, or when -disablePipelineSetResult is set so the real exit code propagates.
+ if ($ci -and $env:SYSTEM_TEAMPROJECT -ne $null -and !$fromVMR -and !$disablePipelineSetResult) {
Write-PipelineSetResult -Result "Failed" -Message "msbuild execution failed."
# Exiting with an exit code causes the azure pipelines task to log yet another "noise" error
# The above Write-PipelineSetResult will cause the task to be marked as failure without adding yet another error
@@ -829,7 +861,7 @@ function MSBuild() {
# Executes a dotnet command with arguments passed to the function.
# Terminates the script if the command fails.
#
-function DotNet() {
+function DotNet([switch]$ignoreFailure) {
$dotnetRoot = InitializeDotNetCli -install:$restore
$dotnetPath = Join-Path $dotnetRoot (GetExecutableFileName 'dotnet')
@@ -848,9 +880,15 @@ function DotNet() {
$exitCode = Exec-Process $dotnetPath $cmdArgs
if ($exitCode -ne 0) {
+ # When -ignoreFailure is set, return the exit code to the caller so it can implement
+ # its own fallback logic instead of terminating the script.
+ if ($ignoreFailure) {
+ return $exitCode
+ }
+
Write-Host "dotnet command failed with exit code $exitCode. Check errors above." -ForegroundColor Red
- if ($ci -and $env:SYSTEM_TEAMPROJECT -ne $null -and !$fromVMR) {
+ if ($ci -and $env:SYSTEM_TEAMPROJECT -ne $null -and !$fromVMR -and !$disablePipelineSetResult) {
Write-PipelineSetResult -Result "Failed" -Message "dotnet command execution failed."
ExitWithExitCode 0
} else {
diff --git a/eng/common/tools.sh b/eng/common/tools.sh
index 347a29b8884..20f791c11de 100644
--- a/eng/common/tools.sh
+++ b/eng/common/tools.sh
@@ -8,6 +8,16 @@ ci=${ci:-false}
# Build mode
source_build=${source_build:-false}
+# Set to true to use the pipelines logger which will enable Azure logging output.
+# https://github.com/Microsoft/azure-pipelines-tasks/blob/master/docs/authoring/commands.md
+# This flag is meant as a temporary opt-in for the feature while validating it across
+# our consumers. It will be deleted in the future.
+if [[ "$ci" == true ]]; then
+ pipelines_log=${pipelines_log:-true}
+else
+ pipelines_log=${pipelines_log:-false}
+fi
+
# Build configuration. Common values include 'Debug' and 'Release', but the repository may use other names.
configuration=${configuration:-'Debug'}
@@ -68,6 +78,8 @@ runtime_source_feed_key=${runtime_source_feed_key:-''}
# True when the build is running within the VMR.
from_vmr=${from_vmr:-false}
+disable_pipeline_set_result=${disable_pipeline_set_result:-false}
+
# Resolve any symlinks in the given path.
function ResolvePath {
local path=$1
@@ -442,7 +454,16 @@ function InitializeToolset {
if [[ -n "$nuget_config" ]]; then
download_args+=("--configfile" "$nuget_config")
fi
- DotNet "${download_args[@]}"
+
+ # 'dotnet package download' fails outright if any source in the repo's NuGet.config is
+ # unavailable (for example a transport feed that was decommissioned after a release). The
+ # Arcade SDK is always published to the public dotnet-eng feed, so if the config-driven
+ # download fails, retry once against that feed directly (which ignores the other sources)
+ # before giving up, so a single dead source doesn't block the build.
+ if ! DotNet true "${download_args[@]}"; then
+ echo "Restoring the Arcade SDK from the configured sources failed; retrying from the public dotnet-eng feed."
+ DotNet "${download_args[@]}" --source "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json"
+ fi
local package_dir="$_InitializeNuGetPackageCachePath/microsoft.dotnet.arcade.sdk/$toolset_version"
@@ -481,6 +502,15 @@ function StopProcesses {
}
function DotNet {
+ # When the first argument is 'true' or 'false' it controls the exit behavior on failure:
+ # 'true' returns the dotnet exit code to the caller (so it can implement its own fallback),
+ # while the default terminates the script. Any other first argument is treated as a dotnet argument.
+ local ignore_failure=false
+ if [[ "$1" == 'true' || "$1" == 'false' ]]; then
+ ignore_failure="$1"
+ shift
+ fi
+
InitializeDotNetCli $restore
local dotnet_path="$_InitializeDotNetCli/dotnet"
@@ -489,9 +519,14 @@ function DotNet {
"$dotnet_path" "$@" || {
local exit_code=$?
+
+ if [[ "$ignore_failure" == true ]]; then
+ return $exit_code
+ fi
+
echo "dotnet command failed with exit code $exit_code. Check errors above."
- if [[ "$ci" == true && -n ${SYSTEM_TEAMPROJECT:-} && "$from_vmr" != true ]]; then
+ if [[ "$ci" == true && -n ${SYSTEM_TEAMPROJECT:-} && "$from_vmr" != true && "$disable_pipeline_set_result" != true ]]; then
Write-PipelineSetResult -result "Failed" -message "dotnet command execution failed."
ExitWithExitCode 0
else
@@ -510,6 +545,21 @@ function MSBuild {
InitializeBuildTool
+ local logger_switch=()
+ if [[ "$pipelines_log" == true ]]; then
+ InitializeToolset
+
+ local toolset_dir="${_InitializeToolset%/*}"
+ local selectedPath="$toolset_dir/net/Microsoft.DotNet.ArcadeLogging.dll"
+
+ # Only inject the logger when it's present. A last-known-good Arcade used to bootstrap
+ # the build may not ship the logger yet, so its absence must not be a hard error.
+ # Specify the logger type explicitly so loading is deterministic.
+ if [[ -f "$selectedPath" ]]; then
+ logger_switch=("-logger:Microsoft.DotNet.ArcadeLogging.PipelinesLogger,$selectedPath")
+ fi
+ fi
+
local warnaserror_switch=""
if [[ $warn_as_error == true ]]; then
warnaserror_switch="/warnaserror"
@@ -525,8 +575,8 @@ function MSBuild {
echo "Build failed with exit code $exit_code. Check errors above."
# When running on Azure Pipelines, override the returned exit code to avoid double logging.
- # Skip this when the build is a child of the VMR build.
- if [[ "$ci" == true && -n ${SYSTEM_TEAMPROJECT:-} && "$from_vmr" != true ]]; then
+ # Skip this when the build is a child of the VMR build, or when -disablePipelineSetResult is set so the real exit code propagates.
+ if [[ "$ci" == true && -n ${SYSTEM_TEAMPROJECT:-} && "$from_vmr" != true && "$disable_pipeline_set_result" != true ]]; then
Write-PipelineSetResult -result "Failed" -message "msbuild execution failed."
# Exiting with an exit code causes the azure pipelines task to log yet another "noise" error
# The above Write-PipelineSetResult will cause the task to be marked as failure without adding yet another error
@@ -545,10 +595,10 @@ function MSBuild {
local warnnotaserror_switch=""
if [[ -n "$warn_not_as_error" && "$warn_as_error" == true ]]; then
- warnnotaserror_switch="/warnnotaserror:$warn_not_as_error /p:AdditionalWarningsNotAsErrors=$warn_not_as_error"
+ warnnotaserror_switch="/warnnotaserror:$warn_not_as_error /p:AdditionalWarningsNotAsErrors=${warn_not_as_error//;/%3B}"
fi
- RunBuildTool "$_InitializeBuildToolCommand" /m /nologo /clp:Summary /v:$verbosity /nr:$node_reuse $warnaserror_switch $mt_switch $warnnotaserror_switch /p:TreatWarningsAsErrors=$warn_as_error /p:ContinuousIntegrationBuild=$ci "$@"
+ RunBuildTool "$_InitializeBuildToolCommand" /m /nologo /clp:Summary /v:$verbosity /nr:$node_reuse $warnaserror_switch $mt_switch $warnnotaserror_switch ${logger_switch[@]+"${logger_switch[@]}"} /p:TreatWarningsAsErrors=$warn_as_error /p:ContinuousIntegrationBuild=$ci "$@"
}
function GetDarc {
diff --git a/global.json b/global.json
index b53a75f8d5d..2eb55a24266 100644
--- a/global.json
+++ b/global.json
@@ -4,6 +4,6 @@
},
"msbuild-sdks": {
"Microsoft.Build.NoTargets": "3.7.134",
- "Microsoft.DotNet.Arcade.Sdk": "11.0.0-beta.26365.101"
+ "Microsoft.DotNet.Arcade.Sdk": "11.0.0-beta.26401.101"
}
}
diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs
index a2809b7e7b6..64eec76f8c3 100644
--- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs
+++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs
@@ -140,6 +140,8 @@ public void DotNetBuild (string runtimeIdentifiers, bool isRelease, bool aot, bo
} else {
expectedFiles.Add ($"{proj.PackageName}.apk");
expectedFiles.Add ($"{proj.PackageName}-Signed.apk.idsig");
+ // The .NET SDK emits this in Debug to enable Hot Reload switches
+ expectedFiles.Add ($"{proj.ProjectName}.runtimeconfig.dev.json");
}
expectedFiles.Sort(StringComparer.OrdinalIgnoreCase);
diff --git a/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs b/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs
index 7ee5928f1e7..8a8c5355db1 100644
--- a/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs
+++ b/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs
@@ -1014,25 +1014,6 @@ public void RuntimeConfigDevJsonIsApplied ()
// Android bakes the properties into the app at build time, so seeing them here proves the dev
// file was picked up. Asking for `$(StartupHookSupport)` to be `false` also proves the dev file
// wins over `*.runtimeconfig.json`.
- //
- // The SDK we currently build against sets `$(GenerateRuntimeConfigDevFile)` to `false` for
- // `net6.0`+, so it does not emit the file and leaves `$(ProjectRuntimeConfigDevFilePath)` empty.
- // Write the file and point the property at it ourselves. Both of these can be dropped once we
- // pick up an SDK containing https://github.com/dotnet/sdk/pull/53715.
- const string devFileName = "runtimeconfig.dev.json";
- proj.OtherBuildItems.Add (new BuildItem ("None", devFileName) {
- TextContent = () => """
- {
- "runtimeOptions": {
- "configProperties": {
- "System.Reflection.Metadata.MetadataUpdater.IsSupported": true,
- "System.StartupHookProvider.IsSupported": true
- }
- }
- }
- """,
- });
- proj.SetProperty ("ProjectRuntimeConfigDevFilePath", $"$(MSBuildProjectDirectory)/{devFileName}");
proj.SetProperty ("StartupHookSupport", "false");
proj.MainActivity = proj.DefaultMainActivity.Replace ("//${AFTER_ONCREATE}",
diff --git a/tests/Mono.Android-Tests/Java.Interop-Tests/Java.Interop-Tests.targets b/tests/Mono.Android-Tests/Java.Interop-Tests/Java.Interop-Tests.targets
index 838470a434b..92fca4bef0a 100644
--- a/tests/Mono.Android-Tests/Java.Interop-Tests/Java.Interop-Tests.targets
+++ b/tests/Mono.Android-Tests/Java.Interop-Tests/Java.Interop-Tests.targets
@@ -6,6 +6,14 @@
+
+
+