Set up a proper Azure build pipeline

This commit is contained in:
Leonard Hecker 2025-04-08 23:29:44 +02:00
parent 7f514b32f6
commit cee02c45b1
9 changed files with 257 additions and 77 deletions

17
.cargo/config.toml Normal file
View file

@ -0,0 +1,17 @@
# Avoid linking with vcruntime140.dll by statically linking everything,
# and then explicitly linking with ucrtbase.dll dynamically.
# We do this, because vcruntime140.dll is an optional Windows component.
[target.'cfg(target_os = "windows")']
rustflags = [
"-Ctarget-feature=+crt-static",
"-Clink-args=/DEFAULTLIB:ucrt.lib",
"-Clink-args=/NODEFAULTLIB:vcruntime.lib",
"-Clink-args=/NODEFAULTLIB:msvcrt.lib",
"-Clink-args=/NODEFAULTLIB:libucrt.lib",
]
# The backtrace code for panics in Rust is almost as large as the entire editor.
# = Huge reduction in binary size by removing all that.
[unstable]
build-std = ["std", "panic_abort"]
build-std-features = ["panic_immediate_abort"]

View file

@ -0,0 +1,32 @@
# Avoid linking with vcruntime140.dll by statically linking everything,
# and then explicitly linking with ucrtbase.dll dynamically.
# We do this, because vcruntime140.dll is an optional Windows component.
[target.'cfg(target_os = "windows")']
rustflags = [
"-Ctarget-feature=+crt-static",
"-Clink-args=/DEFAULTLIB:ucrt.lib",
"-Clink-args=/NODEFAULTLIB:vcruntime.lib",
"-Clink-args=/NODEFAULTLIB:msvcrt.lib",
"-Clink-args=/NODEFAULTLIB:libucrt.lib",
]
# The backtrace code for panics in Rust is almost as large as the entire editor.
# = Huge reduction in binary size by removing all that.
[unstable]
build-std = ["std", "panic_abort"]
build-std-features = ["panic_immediate_abort"]
# ^^^ The parts above are identical to release-windows.toml ^^^
#
# The following lines are specific to official Windows, as the use of
# internal registries, security features, etc., are all mandatory.
# Enable shadow stacks: https://learn.microsoft.com/en-us/cpp/build/reference/cetcompat
[target.'cfg(all(target_os = "windows", any(target_arch = "x86", target_arch = "x86_64")))']
rustflags = ["-Clink-args=/DYNAMICBASE", "-Clink-args=/CETCOMPAT"]
[registries.Edit_PublicPackages]
index = "sparse+https://pkgs.dev.azure.com/microsoft/Dart/_packaging/Edit_PublicPackages/Cargo/index/"
[source.crates-io]
replace-with = "Edit_PublicPackages"

View file

@ -1,48 +0,0 @@
name: build
on:
push:
branches:
- main
env:
CARGO_TERM_COLOR: always
jobs:
build:
runs-on: windows-2022
strategy:
matrix:
toolchain:
- nightly
arch:
- x64
- arm64
steps:
# The Windows runners have autocrlf enabled by default.
- name: Disable git autocrlf
run: git config --global core.autocrlf false
- name: Checkout
uses: actions/checkout@v4
- name: Install nightly
run: |
rustup toolchain install --no-self-update --profile minimal --component rust-src -- nightly
rustup default nightly
rustup target add ${{ matrix.arch == 'arm64' && 'aarch64-pc-windows-msvc' || 'x86_64-pc-windows-msvc' }}
- name: Test
if: matrix.arch == 'x64'
run: cargo test
- name: Build
run: |
if ("${{ matrix.arch }}" -eq "arm64") {
.\tools\build_release_windows.bat --target aarch64-pc-windows-msvc
} else {
.\tools\build_release_windows.bat
}
- name: Upload
uses: actions/upload-artifact@v4
with:
name: Windows ${{ matrix.arch }}
path: |
${{ github.workspace }}/target/${{ matrix.arch == 'arm64' && 'aarch64-pc-windows-msvc/release' || 'release' }}/edit.exe
${{ github.workspace }}/target/${{ matrix.arch == 'arm64' && 'aarch64-pc-windows-msvc/release' || 'release' }}/edit.pdb

161
.pipelines/release.yml Normal file
View file

@ -0,0 +1,161 @@
# Documentation: https://aka.ms/obpipelines
trigger: none
parameters:
- name: debug
displayName: Enable debug output
type: boolean
default: false
- name: official
displayName: Whether to build Official or NonOfficial
type: string
default: NonOfficial
values:
- NonOfficial
- Official
- name: buildPlatforms
type: object
default:
- x86_64-pc-windows-msvc
- aarch64-pc-windows-msvc
variables:
system.debug: ${{parameters.debug}}
WindowsContainerImage: onebranch.azurecr.io/windows/ltsc2022/vse2022:latest
# CDP_DEFINITION_BUILD_COUNT is needed for onebranch.pipeline.version task.
# See: https://aka.ms/obpipelines/versioning
CDP_DEFINITION_BUILD_COUNT: $[counter('', 0)]
# LOAD BEARING - the vpack task fails without these
ROOT: $(Build.SourcesDirectory)
REPOROOT: $(Build.SourcesDirectory)
OUTPUTROOT: $(REPOROOT)\out
NUGET_XMLDOC_MODE: none
resources:
repositories:
- repository: GovernedTemplates
type: git
name: OneBranch.Pipelines/GovernedTemplates
ref: refs/heads/main
extends:
template: v2/Microsoft.${{parameters.official}}.yml@GovernedTemplates
parameters:
featureFlags:
WindowsHostVersion:
Version: 2022
Network: R1
platform:
name: windows_undocked
product: edit
# https://aka.ms/obpipelines/cloudvault
cloudvault:
enabled: false
# https://aka.ms/obpipelines/sdl
globalSdl:
binskim:
# > Due to some legacy reasons, 1ES PT is scanning full sources directory
# > for BinSkim tool instead of just scanning the output directory [...]
scanOutputDirectoryOnly: true
isNativeCode: true
tsa:
enabled: ${{eq(parameters.official, 'Official')}}
configFile: "$(Build.SourcesDirectory)/.pipelines/tsa.json"
stages:
# Our Build stage will build all three targets in one job, so we don't need
# to repeat most of the boilerplate work in three separate jobs.
- stage: Build
jobs:
- job: Windows
pool:
type: windows
variables:
# Binaries will go here.
# More settings at https://aka.ms/obpipelines/yaml/jobs
ob_outputDirectory: "$(Build.SourcesDirectory)/out"
# The vPack gets created from stuff in here.
# It will have a structure like:
# .../vpack/
# - amd64/
# - edit.exe
# - i386/
# - edit.exe
# - arm64/
# - edit.exe
ob_createvpack_enabled: false
ob_createvpack_vpackdirectory: "$(ob_outputDirectory)/vpack"
ob_createvpack_packagename: "windows_edit.$(Build.SourceBranchName)"
ob_createvpack_owneralias: lhecker@microsoft.com
ob_createvpack_description: Microsoft Edit
ob_createvpack_targetDestinationDirectory: "$(Destination)"
ob_createvpack_propsFile: false
ob_createvpack_provData: true
ob_createvpack_versionAs: string
ob_createvpack_version: "$(EditVersion)-$(CDP_DEFINITION_BUILD_COUNT)"
ob_createvpack_metadata: "$(Build.SourceVersion)"
ob_createvpack_topLevelRetries: 0
ob_createvpack_failOnStdErr: true
ob_createvpack_verbose: ${{ parameters.debug }}
# For details on this cargo_target_dir setting, see:
# https://eng.ms/docs/more/rust/topics/onebranch-workaround
CARGO_TARGET_DIR: C:\cargo_target_dir
steps:
# NOTE: Step objects have ordered keys and you MUST have "task" as the first key.
# Objects with ordered keys... lol
- task: RustInstaller@1
displayName: Install Rust toolchain
inputs:
rustVersion: ms-stable
additionalTargets: x86_64-pc-windows-msvc aarch64-pc-windows-msvc
# URL of an Azure Artifacts feed configured with a crates.io upstream. Must be within the current ADO collection.
# NOTE: Azure Artifacts support for Rust is not yet public, but it is enabled for internal ADO organizations.
# https://learn.microsoft.com/en-us/azure/devops/artifacts/how-to/set-up-upstream-sources?view=azure-devops
cratesIoFeedOverride: sparse+https://pkgs.dev.azure.com/microsoft/Dart/_packaging/Edit_PublicPackages/Cargo/index/
# URL of an Azure Artifacts NuGet feed configured with the mscodehub Rust feed as an upstream.
# * The feed must be within the current ADO collection.
# * The CI account, usually "Project Collection Build Service (org-name)", must have at least "Collaborator" permission.
# When setting up the upstream NuGet feed, use following Azure Artifacts feed locator:
# azure-feed://mscodehub/Rust/Rust@Release
toolchainFeed: https://pkgs.dev.azure.com/microsoft/_packaging/RustTools/nuget/v3/index.json
- task: CargoAuthenticate@0
displayName: Authenticate with Azure Artifacts
inputs:
configFile: ".cargo/release-windows-ms.toml"
# We recommend making a separate `cargo fetch` step, as some build systems perform
# fetching entirely prior to the build, and perform the build with the network disabled.
- script: cargo fetch
displayName: Fetch crates
- ${{ each platform in parameters.buildPlatforms }}:
- script: cargo build --config .cargo/release-windows-ms.toml --frozen --release --target ${{platform}}
displayName: Build ${{platform}} Release
- task: CopyFiles@2
displayName: Copy files to vpack (${{platform}})
inputs:
sourceFolder: "$(CARGO_TARGET_DIR)/${{platform}}/release"
${{ if eq(platform, 'i686-pc-windows-msvc') }}:
targetFolder: "$(ob_createvpack_vpackdirectory)/i386"
${{ elseif eq(platform, 'x86_64-pc-windows-msvc') }}:
targetFolder: "$(ob_createvpack_vpackdirectory)/amd64"
${{ else }}: # aarch64-pc-windows-msvc
targetFolder: "$(ob_createvpack_vpackdirectory)/arm64"
contents: |
*.exe
*.pdb
# Extract the version for `ob_createvpack_version`.
- script: |-
@echo off
for /f "tokens=3 delims=- " %%x in ('findstr /c:"version = " Cargo.toml') do (
echo ##vso[task.setvariable variable=EditVersion]%%~x
goto :EOF
)
displayName: "Set EditVersion"
- task: onebranch.pipeline.signing@1
displayName: "Sign files"
inputs:
command: "sign"
signing_profile: "external_distribution"
files_to_sign: "**/edit.exe"
search_root: "$(ob_createvpack_vpackdirectory)"
use_testsign: false
in_container: true

7
.pipelines/tsa.json Normal file
View file

@ -0,0 +1,7 @@
{
"instanceUrl": "https://microsoft.visualstudio.com",
"projectName": "OS",
"areaPath": "OS\\Windows Client and Services\\WinPD\\DEEP-Developer Experience, Ecosystem and Partnerships\\SHINE\\Commandline Tooling",
"notificationAliases": ["condev@microsoft.com", "duhowett@microsoft.com"],
"template": "VSTS_Microsoft_OSGS"
}

33
Cargo.lock generated
View file

@ -76,18 +76,18 @@ dependencies = [
[[package]]
name = "clap"
version = "4.5.34"
version = "4.5.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e958897981290da2a852763fe9cdb89cd36977a5d729023127095fa94d95e2ff"
checksum = "d8aa86934b44c19c50f87cc2790e19f54f7a67aedb64101c2e1a2e5ecfb73944"
dependencies = [
"clap_builder",
]
[[package]]
name = "clap_builder"
version = "4.5.34"
version = "4.5.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83b0f35019843db2160b5bb19ae09b4e6411ac33fc6a712003c33e03090e2489"
checksum = "2414dbb2dd0695280da6ea9261e327479e9d37b0630f6b53ba2a11c60c679fd9"
dependencies = [
"anstyle",
"clap_lex",
@ -168,11 +168,12 @@ checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929"
[[package]]
name = "edit"
version = "0.2.0"
version = "0.3.0"
dependencies = [
"criterion",
"libc",
"windows-sys",
"winres",
]
[[package]]
@ -183,9 +184,9 @@ checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
[[package]]
name = "half"
version = "2.5.0"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7db2ff139bba50379da6aa0766b52fdcb62cb5b263009b09ed58ba604e14bbd1"
checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9"
dependencies = [
"cfg-if",
"crunchy",
@ -441,6 +442,15 @@ dependencies = [
"serde_json",
]
[[package]]
name = "toml"
version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
dependencies = [
"serde",
]
[[package]]
name = "unicode-ident"
version = "1.0.18"
@ -606,3 +616,12 @@ name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "winres"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b68db261ef59e9e52806f688020631e987592bd83619edccda9c47d42cde4f6c"
dependencies = [
"toml",
]

View file

@ -1,6 +1,6 @@
[package]
name = "edit"
version = "0.2.0"
version = "0.3.0"
edition = "2024"
[features]
@ -12,7 +12,6 @@ debug-latency = []
[profile.release]
codegen-units = 1 # reduces binary size by ~2%
debug = "full" # No one needs an undebuggable release binary
debug-assertions = true # TODO: Temporary while I test this
lto = true # reduces binary size by ~14%
panic = "abort" # reduces binary size by ~50% in combination with -Zbuild-std-features=panic_immediate_abort
split-debuginfo = "packed" # generates a seperate *.dwp/*.dSYM so the binary can get stripped
@ -27,6 +26,9 @@ lto = "thin" # Similarly, speed up linking by a ton
[target.'cfg(unix)'.dependencies]
libc = "0.2"
[target.'cfg(windows)'.build-dependencies]
winres = "0.1"
[target.'cfg(windows)'.dependencies.windows-sys]
version = "0.59"
features = [

View file

@ -1,12 +1,13 @@
fn main() {
if std::env::var("CARGO_CFG_TARGET_OS").unwrap_or_default() == "windows"
&& std::env::var("CARGO_CFG_TARGET_ENV").unwrap_or_default() == "msvc"
{
let path = std::path::absolute("src/edit.exe.manifest").unwrap();
let path = path.to_str().unwrap();
println!("cargo::rerun-if-changed=src/edit.exe.manifest");
println!("cargo::rustc-link-arg-bin=edit=/MANIFEST:EMBED");
println!("cargo::rustc-link-arg-bin=edit=/MANIFESTINPUT:{}", path);
println!("cargo::rustc-link-arg-bin=edit=/WX");
if std::env::var("CARGO_CFG_TARGET_OS").unwrap_or_default() == "windows" {
winres::WindowsResource::new()
.set_manifest_file("src/edit.exe.manifest")
.set("FileDescription", "Microsoft Edit")
.set(
"LegalCopyright",
"© Microsoft Corporation. All rights reserved.",
)
.compile()
.unwrap();
}
}

View file

@ -1,11 +0,0 @@
@echo off
rem Avoid linking with vcruntime140.dll by statically linking everything,
rem and then explicitly linking with ucrtbase.dll dynamically.
rem We do this, because vcruntime140.dll is an optional Windows component.
set RUSTFLAGS=-Ctarget-feature=+crt-static -Clink-args=/DEFAULTLIB:ucrt.lib -Clink-args=/NODEFAULTLIB:vcruntime.lib -Clink-args=/NODEFAULTLIB:msvcrt.lib -Clink-args=/NODEFAULTLIB:libucrt.lib
rem The backtrace code for panics in Rust is almost as large as the entire editor.
rem = Huge reduction in binary size by removing all that.
rem cargo build --release -Zbuild-std=std,panic_abort -Zbuild-std-features=panic_immediate_abort %*
cargo build --release %*