From 340fcbc5805d918a9e399461ac06088e3a1b69fd Mon Sep 17 00:00:00 2001 From: Bhagirath Mehta Date: Mon, 5 Oct 2026 05:24:53 -0500 Subject: [PATCH 1/6] Promote release overlays so vcpkg receives SDK features Carry feature declarations and build wiring from the release tag instead of only changing the registry version and hash. Keep a token-free helper for manual registry updates and exercise opt-in dependency graphs in CI. Files changed: .github/scripts/prepare-vcpkg-release.py .github/workflows/test-vcpkg.yml .github/workflows/vcpkg-release-bump.yml docs/building-with-vcpkg.md tests/vcpkg/test-release-port.py tests/vcpkg/test-vcpkg-android.sh tests/vcpkg/test-vcpkg-linux.sh tests/vcpkg/vcpkg.json Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/scripts/prepare-vcpkg-release.py | 67 ++++++++++++++ .github/workflows/test-vcpkg.yml | 28 +++++- .github/workflows/vcpkg-release-bump.yml | 30 ++++--- docs/building-with-vcpkg.md | 31 ++++++- tests/vcpkg/test-release-port.py | 107 +++++++++++++++++++++++ tests/vcpkg/test-vcpkg-android.sh | 16 +++- tests/vcpkg/test-vcpkg-linux.sh | 14 ++- tests/vcpkg/vcpkg.json | 53 ++++++++++- 8 files changed, 328 insertions(+), 18 deletions(-) create mode 100644 .github/scripts/prepare-vcpkg-release.py create mode 100644 tests/vcpkg/test-release-port.py diff --git a/.github/scripts/prepare-vcpkg-release.py b/.github/scripts/prepare-vcpkg-release.py new file mode 100644 index 000000000..1e73e6903 --- /dev/null +++ b/.github/scripts/prepare-vcpkg-release.py @@ -0,0 +1,67 @@ +"""Copy the release's complete overlay port into a vcpkg checkout.""" + +import argparse +import json +from pathlib import Path +import re +import shutil + + +def prepare_port(source_port, destination_port, version, sha512): + if not re.fullmatch(r"\d+\.\d+\.\d+\.\d+", version): + raise ValueError("Expected a four-component SDK release version") + if not re.fullmatch(r"[0-9a-fA-F]{128}", sha512): + raise ValueError("Expected a 128-digit archive SHA512") + if destination_port.name != "cpp-client-telemetry" or destination_port.parent.name != "ports": + raise ValueError("Destination must be a ports/cpp-client-telemetry directory") + source_path = source_port.resolve() + destination_path = destination_port.resolve() + if ( + source_path == destination_path + or source_path in destination_path.parents + or destination_path in source_path.parents + ): + raise ValueError("Source and destination ports must not overlap") + + manifest = json.loads((source_port / "vcpkg.json").read_text(encoding="utf-8")) + if manifest["name"] != "cpp-client-telemetry": + raise ValueError("Release overlay is not the cpp-client-telemetry port") + for feature in ("minimal-sqlite", "android-curl-openssl"): + if feature not in manifest.get("features", {}): + raise ValueError(f"Release overlay is missing the {feature} feature") + manifest["version"] = version + manifest.pop("port-version", None) + + portfile = (source_port / "portfile.cmake").read_text(encoding="utf-8") + for field, value in (("REF", f"v{version}"), ("SHA512", sha512)): + portfile, count = re.subn( + rf"(?m)^([ \t]*{field}[ \t]+)[^\r\n]+", + lambda match: match[1] + value, + portfile, + ) + if count != 1: + raise ValueError(f"Release portfile must contain exactly one {field}") + + # Replace the complete port so obsolete patches cannot survive a release. + if destination_port.exists(): + shutil.rmtree(destination_port) + shutil.copytree(source_port, destination_port) + (destination_port / "portfile.cmake").write_text(portfile, encoding="utf-8", newline="\n") + (destination_port / "vcpkg.json").write_text( + json.dumps(manifest, indent=2) + "\n", encoding="utf-8", newline="\n" + ) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--source-port", type=Path, required=True) + parser.add_argument("--destination-port", type=Path, required=True) + parser.add_argument("--version", required=True) + parser.add_argument("--sha512", required=True) + arguments = parser.parse_args() + prepare_port( + arguments.source_port, + arguments.destination_port, + arguments.version, + arguments.sha512, + ) diff --git a/.github/workflows/test-vcpkg.yml b/.github/workflows/test-vcpkg.yml index 98ef86429..7cae03115 100644 --- a/.github/workflows/test-vcpkg.yml +++ b/.github/workflows/test-vcpkg.yml @@ -22,6 +22,18 @@ concurrency: cancel-in-progress: ${{ github.event_name == 'pull_request' }} jobs: + release-packaging: + runs-on: ${{ matrix.os }} + name: Release packaging (${{ matrix.os }}) + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest] + steps: + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 + - name: Test release port promotion + run: python tests/vcpkg/test-release-port.py + windows: runs-on: windows-latest name: Windows (x64-windows-static, ${{ matrix.transport }}) @@ -49,7 +61,11 @@ jobs: linux: runs-on: ubuntu-latest - name: Linux (x64-linux) + name: Linux (x64-linux, ${{ matrix.features }}) + strategy: + fail-fast: false + matrix: + features: [default, minimal-sqlite] steps: - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 @@ -63,7 +79,7 @@ jobs: VCPKG_ROOT: ${{ runner.temp }}/vcpkg run: | chmod +x tests/vcpkg/test-vcpkg-linux.sh - ./tests/vcpkg/test-vcpkg-linux.sh + ./tests/vcpkg/test-vcpkg-linux.sh "${{ matrix.features }}" macos: runs-on: macos-latest @@ -103,7 +119,11 @@ jobs: android: runs-on: ubuntu-latest - name: Android (arm64-v8a API 23 cross-compile) + name: Android (arm64-v8a API 23, ${{ matrix.features }}) + strategy: + fail-fast: false + matrix: + features: [default, minimal-sqlite, "minimal-sqlite;android-curl-openssl", "minimal-sqlite;android-curl-mbedtls"] steps: - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 @@ -120,4 +140,4 @@ jobs: VCPKG_ROOT: ${{ runner.temp }}/vcpkg run: | chmod +x tests/vcpkg/test-vcpkg-android.sh - ./tests/vcpkg/test-vcpkg-android.sh arm64-v8a 23 + ./tests/vcpkg/test-vcpkg-android.sh arm64-v8a 23 "${{ matrix.features }}" diff --git a/.github/workflows/vcpkg-release-bump.yml b/.github/workflows/vcpkg-release-bump.yml index 77ed47444..0365c7181 100644 --- a/.github/workflows/vcpkg-release-bump.yml +++ b/.github/workflows/vcpkg-release-bump.yml @@ -2,6 +2,8 @@ name: Vcpkg release bump # Opens a version-bump pull request against microsoft/vcpkg for the # `cpp-client-telemetry` port whenever a new SDK release is published. +# Promotes the complete overlay from that release tag so new features and +# their build wiring reach the registry alongside the version bump. # # It runs ONLY when a new version is cut: # * automatically on a published, non-draft, non-prerelease GitHub Release @@ -107,6 +109,14 @@ jobs: echo "sha512=${SHA512}" >> "$GITHUB_OUTPUT" echo "SHA512=${SHA512}" + - name: Check out the released SDK packaging + if: ${{ steps.ver.outputs.skip != 'true' }} + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 + with: + ref: ${{ steps.ver.outputs.tag }} + path: sdk-release + persist-credentials: false + - name: Clone vcpkg fork and branch off upstream master if: ${{ steps.ver.outputs.skip != 'true' }} env: @@ -130,22 +140,22 @@ jobs: if: ${{ steps.ver.outputs.skip != 'true' }} run: cd vcpkg && ./bootstrap-vcpkg.sh -disableMetrics - - name: Update port REF, SHA512 and version + - name: Promote release port, REF, SHA512 and version if: ${{ steps.ver.outputs.skip != 'true' }} run: | set -euo pipefail - cd vcpkg - PORTFILE="ports/${PORT}/portfile.cmake" - MANIFEST="ports/${PORT}/vcpkg.json" - if [ ! -f "${PORTFILE}" ] || [ ! -f "${MANIFEST}" ]; then + PORT_DIR="vcpkg/ports/${PORT}" + if [ ! -f "${PORT_DIR}/portfile.cmake" ] || [ ! -f "${PORT_DIR}/vcpkg.json" ]; then echo "::error::${PORT} port not found in ${VCPKG_UPSTREAM}. The port must already be in the registry before it can be bumped." exit 1 fi - sed -i -E "s|^([[:space:]]*REF[[:space:]]+).*$|\1${{ steps.ver.outputs.tag }}|" "${PORTFILE}" - sed -i -E "s|^([[:space:]]*SHA512[[:space:]]+).*$|\1${{ steps.sha.outputs.sha512 }}|" "${PORTFILE}" - jq --arg v "${{ steps.ver.outputs.version }}" '.version = $v | del(."port-version")' "${MANIFEST}" > "${MANIFEST}.tmp" - mv "${MANIFEST}.tmp" "${MANIFEST}" - ./vcpkg format-manifest "${MANIFEST}" + python3 sdk-release/.github/scripts/prepare-vcpkg-release.py \ + --source-port "sdk-release/tools/ports/${PORT}" \ + --destination-port "${PORT_DIR}" \ + --version "${{ steps.ver.outputs.version }}" \ + --sha512 "${{ steps.sha.outputs.sha512 }}" + cd vcpkg + ./vcpkg format-manifest "ports/${PORT}/vcpkg.json" - name: Validate updated production port if: ${{ steps.ver.outputs.skip != 'true' }} diff --git a/docs/building-with-vcpkg.md b/docs/building-with-vcpkg.md index a4aa85a3c..c5d112e71 100644 --- a/docs/building-with-vcpkg.md +++ b/docs/building-with-vcpkg.md @@ -29,7 +29,12 @@ That's it! The package should be compiled for the current OS. The overlay port shipped in this repository is for **development only** — use it to test local changes to the port, or a newer SDK revision, before they are -published to the registry: +published to the registry. + +Feature availability in the registry depends on the packaged SDK release. +In particular, `minimal-sqlite` and `android-curl-openssl` are available in this +overlay but are not yet exposed by the registry port. Until the next release +and its registry update land, use the overlay for those features. ```console git clone https://github.com/microsoft/cpp_client_telemetry @@ -449,6 +454,30 @@ unchanged against the minimal build. ## How It Works +### Promoting features on release + +The release port update copies the **complete overlay port from the release +tag**, not from the current development branch. It then replaces the archive +`REF`, `SHA512`, and manifest version, removes any old `port-version`, and +validates the pinned release build. This carries feature declarations and their +CMake wiring together, including `minimal-sqlite` and the explicit Android curl +backends. The release tag must contain the packaging helper and both features; +older tags without them cannot use this promotion workflow. + +For a manual registry update, the same preparation can be run from the released +SDK checkout against a local vcpkg checkout: + +```console +python .github/scripts/prepare-vcpkg-release.py --source-port tools/ports/cpp-client-telemetry --destination-port /ports/cpp-client-telemetry --version X.Y.Z.W --sha512 +``` + +Run `vcpkg format-manifest` on the resulting manifest and validate the downloaded +release with `MATSDK_VCPKG_SOURCE_DIR` unset before submitting the registry PR. +This preparation does not require a GitHub token; maintainers can submit the +registry PR manually after cutting the SDK release. + +### Dependency and transport selection + The SDK consumes canonical CMake dependency targets. The vcpkg toolchain provides those targets through normal `find_package()` discovery; no separate SDK-specific dependency-mode switch is required. Android transport selection is diff --git a/tests/vcpkg/test-release-port.py b/tests/vcpkg/test-release-port.py new file mode 100644 index 000000000..7e2978247 --- /dev/null +++ b/tests/vcpkg/test-release-port.py @@ -0,0 +1,107 @@ +"""Regression tests for promoting the release overlay into the registry.""" + +import importlib.util +import json +from pathlib import Path +import re +import tempfile +import unittest + + +REPO_ROOT = Path(__file__).resolve().parents[2] +SPEC = importlib.util.spec_from_file_location( + "prepare_vcpkg_release", REPO_ROOT / ".github" / "scripts" / "prepare-vcpkg-release.py" +) +PREPARE = importlib.util.module_from_spec(SPEC) +SPEC.loader.exec_module(PREPARE) + + +class ReleasePortTests(unittest.TestCase): + def setUp(self): + self.temporary = tempfile.TemporaryDirectory() + self.addCleanup(self.temporary.cleanup) + root = Path(self.temporary.name) + self.source = root / "release" / "tools" / "ports" / "cpp-client-telemetry" + self.source.mkdir(parents=True) + self.destination = root / "vcpkg" / "ports" / "cpp-client-telemetry" + self.destination.mkdir(parents=True) + (self.destination / "obsolete.patch").write_text("old patch", encoding="utf-8") + self.manifest = json.loads( + (REPO_ROOT / "tools" / "ports" / "cpp-client-telemetry" / "vcpkg.json").read_text( + encoding="utf-8" + ) + ) + self.manifest["port-version"] = 7 + self.write_manifest() + self.portfile = ( + REPO_ROOT / "tools" / "ports" / "cpp-client-telemetry" / "portfile.cmake" + ).read_text(encoding="utf-8") + (self.source / "portfile.cmake").write_text(self.portfile, encoding="utf-8") + + def write_manifest(self): + (self.source / "vcpkg.json").write_text(json.dumps(self.manifest), encoding="utf-8") + + def prepare(self): + PREPARE.prepare_port(self.source, self.destination, "3.10.999.1", "a" * 128) + + def test_promotes_complete_release_port(self): + (self.source / "release.patch").write_text("new patch", encoding="utf-8") + self.prepare() + actual = json.loads((self.destination / "vcpkg.json").read_text(encoding="utf-8")) + expected = dict(self.manifest, version="3.10.999.1") + del expected["port-version"] + self.assertEqual(actual, expected) + portfile = (self.destination / "portfile.cmake").read_text(encoding="utf-8") + self.assertIn("REF v3.10.999.1\n", portfile) + self.assertIn(f"SHA512 {'a' * 128}\n", portfile) + self.assertIn("-DMATSDK_SQLITE_PROVIDER=${MATSDK_VCPKG_SQLITE_PROVIDER}", portfile) + self.assertIn("-DMATSDK_ANDROID_HTTP_CLIENT=${MATSDK_ANDROID_HTTP_CLIENT}", portfile) + self.assertEqual((self.destination / "release.patch").read_text(), "new patch") + self.assertFalse((self.destination / "obsolete.patch").exists()) + self.assertEqual( + json.loads((self.source / "vcpkg.json").read_text(encoding="utf-8")), self.manifest + ) + self.prepare() + self.assertEqual((self.destination / "portfile.cmake").read_text(), portfile) + + def test_rejects_release_missing_required_features_before_replacing_port(self): + for feature in ("minimal-sqlite", "android-curl-openssl"): + with self.subTest(feature=feature): + definition = self.manifest["features"].pop(feature) + self.write_manifest() + with self.assertRaisesRegex(ValueError, feature): + self.prepare() + self.assertTrue((self.destination / "obsolete.patch").exists()) + self.manifest["features"][feature] = definition + + def test_rejects_missing_or_duplicate_archive_fields(self): + for field in ("REF", "SHA512"): + for replacement in ("", f" {field} duplicate\n {field} duplicate\n"): + with self.subTest(field=field, replacement=replacement): + malformed = re.sub( + rf"(?m)^[ \t]*{field}[ \t]+[^\n]*\n", replacement, self.portfile + ) + (self.source / "portfile.cmake").write_text(malformed, encoding="utf-8") + with self.assertRaisesRegex(ValueError, field): + self.prepare() + self.assertTrue((self.destination / "obsolete.patch").exists()) + + def test_rejects_invalid_release_metadata(self): + for version, sha512 in (("v3.10.999.1", "a" * 128), ("3.10.999.1", "invalid")): + with self.subTest(version=version, sha512=sha512): + with self.assertRaises(ValueError): + PREPARE.prepare_port(self.source, self.destination, version, sha512) + self.assertTrue((self.destination / "obsolete.patch").exists()) + + def test_rejects_destination_outside_the_port(self): + with self.assertRaisesRegex(ValueError, "Destination"): + PREPARE.prepare_port(self.source, self.destination.parent, "3.10.999.1", "a" * 128) + + def test_rejects_overlapping_ports(self): + with self.assertRaisesRegex(ValueError, "overlap"): + PREPARE.prepare_port(self.source, self.source, "3.10.999.1", "a" * 128) + self.assertTrue((self.source / "portfile.cmake").exists()) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/vcpkg/test-vcpkg-android.sh b/tests/vcpkg/test-vcpkg-android.sh index f49a24195..af9bc6a88 100755 --- a/tests/vcpkg/test-vcpkg-android.sh +++ b/tests/vcpkg/test-vcpkg-android.sh @@ -1,8 +1,9 @@ #!/bin/bash # Test script: Verify cpp-client-telemetry vcpkg port for Android (cross-compile only) -# Usage: ./tests/vcpkg/test-vcpkg-android.sh [ABI] [API_LEVEL] +# Usage: ./tests/vcpkg/test-vcpkg-android.sh [ABI] [API_LEVEL] [FEATURES] # ABI: arm64-v8a (default), armeabi-v7a, x86_64, x86 # API_LEVEL: 23 (default), 28, or another level with a matching overlay triplet +# FEATURES: default, minimal-sqlite, or minimal-sqlite;android-curl-{openssl,mbedtls} # Prerequisites: VCPKG_ROOT set, ANDROID_NDK_HOME set, cmake, ninja set -e @@ -17,6 +18,18 @@ export MATSDK_VCPKG_SOURCE_DIR="${REPO_ROOT}" # Android ABI/API (defaults match the repo's Android minSdk) ANDROID_ABI="${1:-arm64-v8a}" ANDROID_API="${2:-23}" +MANIFEST_ARGS=() +case "${3:-default}" in + default) ;; + minimal-sqlite|"minimal-sqlite;android-curl-openssl"|"minimal-sqlite;android-curl-mbedtls") + MANIFEST_ARGS=(-DVCPKG_MANIFEST_NO_DEFAULT_FEATURES=ON "-DVCPKG_MANIFEST_FEATURES=${3}") + ;; + *) + echo "ERROR: Unsupported feature set '${3}'. Use default, minimal-sqlite," + echo " minimal-sqlite;android-curl-openssl, or minimal-sqlite;android-curl-mbedtls." + exit 1 + ;; +esac # Map ABI to vcpkg triplet case "${ANDROID_ABI}" in @@ -97,6 +110,7 @@ cmake -G Ninja -S "${SCRIPT_DIR}" -B "${BUILD_DIR}/consumer" \ -DCMAKE_TOOLCHAIN_FILE="${VCPKG_TOOLCHAIN}" \ -DVCPKG_TARGET_TRIPLET="${TRIPLET}" \ -DVCPKG_OVERLAY_PORTS="${OVERLAY_PORTS}" \ + "${MANIFEST_ARGS[@]}" \ "${OVERLAY_TRIPLETS_ARGS[@]}" \ -DVCPKG_CHAINLOAD_TOOLCHAIN_FILE="${ANDROID_NDK_HOME}/build/cmake/android.toolchain.cmake" \ -DANDROID_ABI="${ANDROID_ABI}" \ diff --git a/tests/vcpkg/test-vcpkg-linux.sh b/tests/vcpkg/test-vcpkg-linux.sh index d98757db8..06b03293d 100755 --- a/tests/vcpkg/test-vcpkg-linux.sh +++ b/tests/vcpkg/test-vcpkg-linux.sh @@ -1,6 +1,6 @@ #!/bin/bash # Test script: Verify cpp-client-telemetry vcpkg port on Linux -# Usage: ./tests/vcpkg/test-vcpkg-linux.sh +# Usage: ./tests/vcpkg/test-vcpkg-linux.sh [default|minimal-sqlite] # Prerequisites: VCPKG_ROOT set, gcc/g++, cmake set -e @@ -8,6 +8,17 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)" BUILD_DIR="${SCRIPT_DIR}/build-linux" OVERLAY_PORTS="${REPO_ROOT}/tools/ports" +MANIFEST_ARGS=() +case "${1:-default}" in + default) ;; + minimal-sqlite) + MANIFEST_ARGS=(-DVCPKG_MANIFEST_NO_DEFAULT_FEATURES=ON -DVCPKG_MANIFEST_FEATURES=minimal-sqlite) + ;; + *) + echo "ERROR: Unsupported feature set '${1}'. Use default or minimal-sqlite." + exit 1 + ;; +esac # Build the working tree under review (not a pinned release) so this test # validates the actual SDK source together with the port manifest/portfile. @@ -48,6 +59,7 @@ cmake -S "${SCRIPT_DIR}" -B "${BUILD_DIR}/consumer" \ -DCMAKE_TOOLCHAIN_FILE="${VCPKG_TOOLCHAIN}" \ -DVCPKG_TARGET_TRIPLET="${TRIPLET}" \ -DVCPKG_OVERLAY_PORTS="${OVERLAY_PORTS}" \ + "${MANIFEST_ARGS[@]}" \ -DCMAKE_BUILD_TYPE=Release echo "" diff --git a/tests/vcpkg/vcpkg.json b/tests/vcpkg/vcpkg.json index dbcee9cfc..df03c0829 100644 --- a/tests/vcpkg/vcpkg.json +++ b/tests/vcpkg/vcpkg.json @@ -3,9 +3,60 @@ "version-string": "0.0.1", "description": "Integration test for cpp-client-telemetry vcpkg port", "dependencies": [ - "cpp-client-telemetry" + { + "name": "cpp-client-telemetry", + "default-features": false + } + ], + "default-features": [ + "sdk-defaults" ], "features": { + "android-curl-mbedtls": { + "description": "Exercise the native Android curl transport with mbedTLS.", + "supports": "android", + "dependencies": [ + { + "name": "cpp-client-telemetry", + "default-features": false, + "features": [ + "android-curl-mbedtls" + ] + } + ] + }, + "android-curl-openssl": { + "description": "Exercise the native Android curl transport with OpenSSL.", + "supports": "android", + "dependencies": [ + { + "name": "cpp-client-telemetry", + "default-features": false, + "features": [ + "android-curl-openssl" + ] + } + ] + }, + "minimal-sqlite": { + "description": "Exercise private SQLite without the external sqlite3 dependency.", + "dependencies": [ + { + "name": "cpp-client-telemetry", + "default-features": false, + "features": [ + "curl-openssl", + "minimal-sqlite" + ] + } + ] + }, + "sdk-defaults": { + "description": "Exercise the default SDK dependency graph.", + "dependencies": [ + "cpp-client-telemetry" + ] + }, "wininet": { "description": "Exercise the cpp-client-telemetry WinInet feature on Windows.", "supports": "windows & !mingw", From af64f1896eb9c1d4f948cd2a0e068638fd59350a Mon Sep 17 00:00:00 2001 From: Bhagirath Mehta Date: Mon, 5 Oct 2026 05:30:01 -0500 Subject: [PATCH 2/6] Remove token-backed vcpkg release automation Keep downstream registry PRs manual so releasing the SDK does not require a maintainer PAT in repository automation. Retain the local port preparation helper and document the complete manual promotion and version-database sequence. Files changed: .github/workflows/vcpkg-release-bump.yml (removed) docs/building-with-vcpkg.md docs/maintainer-onboarding.md Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: bd3ff552-cbf8-4164-bc50-3c26778f76de --- .github/workflows/vcpkg-release-bump.yml | 228 ----------------------- docs/building-with-vcpkg.md | 21 ++- docs/maintainer-onboarding.md | 37 ++-- 3 files changed, 26 insertions(+), 260 deletions(-) delete mode 100644 .github/workflows/vcpkg-release-bump.yml diff --git a/.github/workflows/vcpkg-release-bump.yml b/.github/workflows/vcpkg-release-bump.yml deleted file mode 100644 index 0365c7181..000000000 --- a/.github/workflows/vcpkg-release-bump.yml +++ /dev/null @@ -1,228 +0,0 @@ -name: Vcpkg release bump - -# Opens a version-bump pull request against microsoft/vcpkg for the -# `cpp-client-telemetry` port whenever a new SDK release is published. -# Promotes the complete overlay from that release tag so new features and -# their build wiring reach the registry alongside the version bump. -# -# It runs ONLY when a new version is cut: -# * automatically on a published, non-draft, non-prerelease GitHub Release -# whose tag looks like a version (vMAJOR.MINOR.PATCH.BUILD), or -# * manually via workflow_dispatch for a specific tag (recovery / re-run). -# It never runs on ordinary pushes, and it opens no PR if the port already -# matches the release (no version change). -# -# One-time setup required in this repository: -# * Variable VCPKG_FORK_REPO -> the vcpkg fork to push branches to, -# e.g. "your-org/vcpkg". -# * Secret VCPKG_BUMP_TOKEN -> a PAT (classic: repo+workflow, or -# fine-grained: Contents+Pull requests RW on -# the fork) able to push to VCPKG_FORK_REPO and -# open pull requests on microsoft/vcpkg. - -on: - release: - types: [published] - workflow_dispatch: - inputs: - tag: - description: "Release tag to bump the vcpkg port to (e.g. v3.10.161.1)" - required: true - type: string - -permissions: - contents: read - -concurrency: - group: vcpkg-release-bump-${{ github.event.release.tag_name || github.event.inputs.tag }} - cancel-in-progress: false - -jobs: - bump: - name: Bump cpp-client-telemetry port - # Skip drafts and pre-releases; always allow manual dispatch. - if: >- - ${{ github.event_name == 'workflow_dispatch' || - (github.event.release.draft == false && github.event.release.prerelease == false) }} - runs-on: ubuntu-latest - env: - UPSTREAM_REPO: ${{ github.repository }} # microsoft/cpp_client_telemetry - VCPKG_UPSTREAM: microsoft/vcpkg - VCPKG_FORK_REPO: ${{ vars.VCPKG_FORK_REPO }} - PORT: cpp-client-telemetry - steps: - - name: Validate configuration - env: - VCPKG_BUMP_TOKEN: ${{ secrets.VCPKG_BUMP_TOKEN }} - run: | - set -euo pipefail - if [ -z "${VCPKG_FORK_REPO}" ]; then - echo "::error::Repository variable VCPKG_FORK_REPO is not set (e.g. 'your-org/vcpkg')." - exit 1 - fi - if [ -z "${VCPKG_BUMP_TOKEN}" ]; then - echo "::error::Secret VCPKG_BUMP_TOKEN is not set. Provide a token that can push to ${VCPKG_FORK_REPO} and open PRs on ${VCPKG_UPSTREAM}." - exit 1 - fi - - - name: Resolve tag and version - id: ver - env: - # Pass untrusted tag values through the environment instead of - # interpolating ${{ ... }} directly into the script body, so a tag - # containing shell metacharacters cannot inject commands into this - # step (which shares a runner with later PAT-bearing steps). - RELEASE_TAG: ${{ github.event.release.tag_name }} - INPUT_TAG: ${{ github.event.inputs.tag }} - run: | - set -euo pipefail - TAG="${RELEASE_TAG:-$INPUT_TAG}" - if [ -z "${TAG}" ]; then echo "::error::No release tag could be resolved."; exit 1; fi - # Only act on version tags: vMAJOR.MINOR.PATCH.BUILD. A non-matching - # tag from the automatic release trigger is a clean no-op (the SDK also - # has historical 3-part tags such as v3.3.8); a non-matching tag from a - # manual workflow_dispatch is user error and fails loudly. - if ! printf '%s' "${TAG}" | grep -Eq '^v[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$'; then - if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then - echo "::error::Tag '${TAG}' is not a version tag (expected vX.Y.Z.W)." - exit 1 - fi - echo "::notice::Tag '${TAG}' is not a version tag (expected vX.Y.Z.W); nothing to bump." - echo "skip=true" >> "$GITHUB_OUTPUT" - exit 0 - fi - VERSION="${TAG#v}" - echo "tag=${TAG}" >> "$GITHUB_OUTPUT" - echo "version=${VERSION}" >> "$GITHUB_OUTPUT" - echo "branch=port/${PORT}-${VERSION}" >> "$GITHUB_OUTPUT" - echo "Bumping ${PORT} -> tag=${TAG} version=${VERSION}" - - - name: Compute source archive SHA512 - id: sha - if: ${{ steps.ver.outputs.skip != 'true' }} - run: | - set -euo pipefail - URL="https://github.com/${UPSTREAM_REPO}/archive/${{ steps.ver.outputs.tag }}.tar.gz" - echo "Downloading ${URL}" - curl -fsSL --retry 3 "${URL}" -o source.tar.gz - SHA512="$(sha512sum source.tar.gz | cut -d' ' -f1)" - echo "sha512=${SHA512}" >> "$GITHUB_OUTPUT" - echo "SHA512=${SHA512}" - - - name: Check out the released SDK packaging - if: ${{ steps.ver.outputs.skip != 'true' }} - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - with: - ref: ${{ steps.ver.outputs.tag }} - path: sdk-release - persist-credentials: false - - - name: Clone vcpkg fork and branch off upstream master - if: ${{ steps.ver.outputs.skip != 'true' }} - env: - GH_TOKEN: ${{ secrets.VCPKG_BUMP_TOKEN }} - run: | - set -euo pipefail - # Authenticate git via gh's credential helper instead of embedding the - # token in the clone URL (which would persist it in .git/config and - # risk leaking it if git echoes the remote). The helper is written to - # the global gitconfig and reused by the later push step. - gh auth setup-git - git clone --depth 1 "https://github.com/${VCPKG_FORK_REPO}.git" vcpkg - cd vcpkg - git remote add upstream "https://github.com/${VCPKG_UPSTREAM}.git" - git fetch --depth 1 upstream master - git checkout -B "${{ steps.ver.outputs.branch }}" upstream/master - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - - - name: Bootstrap vcpkg - if: ${{ steps.ver.outputs.skip != 'true' }} - run: cd vcpkg && ./bootstrap-vcpkg.sh -disableMetrics - - - name: Promote release port, REF, SHA512 and version - if: ${{ steps.ver.outputs.skip != 'true' }} - run: | - set -euo pipefail - PORT_DIR="vcpkg/ports/${PORT}" - if [ ! -f "${PORT_DIR}/portfile.cmake" ] || [ ! -f "${PORT_DIR}/vcpkg.json" ]; then - echo "::error::${PORT} port not found in ${VCPKG_UPSTREAM}. The port must already be in the registry before it can be bumped." - exit 1 - fi - python3 sdk-release/.github/scripts/prepare-vcpkg-release.py \ - --source-port "sdk-release/tools/ports/${PORT}" \ - --destination-port "${PORT_DIR}" \ - --version "${{ steps.ver.outputs.version }}" \ - --sha512 "${{ steps.sha.outputs.sha512 }}" - cd vcpkg - ./vcpkg format-manifest "ports/${PORT}/vcpkg.json" - - - name: Validate updated production port - if: ${{ steps.ver.outputs.skip != 'true' }} - run: | - set -euo pipefail - cd vcpkg - MANIFEST="ports/${PORT}/vcpkg.json" - - # Exercise the real production path: MATSDK_VCPKG_SOURCE_DIR must be - # unset so the port downloads the just-updated REF/SHA512 instead of - # accidentally validating this workflow's working tree. This catches - # manifest/portfile changes that require source changes not present in - # the release tag. - unset MATSDK_VCPKG_SOURCE_DIR - - PORT_SPEC="${PORT}" - if jq -e '(.features["minimal-sqlite"] != null) and (.features["curl-openssl"] != null)' "${MANIFEST}" >/dev/null; then - # Use an opt-in feature set when available so release validation covers - # feature wiring as well as the default graph. The default graph is - # still covered by regular vcpkg CI and by consumers. - PORT_SPEC="${PORT}[core,minimal-sqlite,curl-openssl]" - fi - - echo "Validating production port: ${PORT_SPEC}" - ./vcpkg install "${PORT_SPEC}" --triplet x64-linux --clean-after-build - - - name: Detect change - id: diff - if: ${{ steps.ver.outputs.skip != 'true' }} - run: | - set -euo pipefail - cd vcpkg - if git diff --quiet -- "ports/${PORT}"; then - echo "changed=false" >> "$GITHUB_OUTPUT" - echo "No change: ${PORT} is already at ${{ steps.ver.outputs.version }} with this REF/SHA512. Nothing to do." - else - echo "changed=true" >> "$GITHUB_OUTPUT" - fi - - - name: Commit, update version DB, push and open PR - if: ${{ steps.ver.outputs.skip != 'true' && steps.diff.outputs.changed == 'true' }} - env: - GH_TOKEN: ${{ secrets.VCPKG_BUMP_TOKEN }} - run: | - set -euo pipefail - cd vcpkg - # gh auth setup-git ran in the clone step; reuse that credential helper - # so 'git push' authenticates without a token in the remote URL. - BR="${{ steps.ver.outputs.branch }}" - git add "ports/${PORT}" - git commit -m "[${PORT}] Update to ${{ steps.ver.outputs.version }}" - ./vcpkg x-add-version "${PORT}" --overwrite-version - git add versions - git commit -m "[${PORT}] Update version database" - # Ensure a remote-tracking ref exists so --force-with-lease has a lease - # to compare against on reruns: the bump branch may already exist on the - # fork but be absent from this fresh clone. Ignore failure on the first - # run, when the branch does not exist remotely yet. - git fetch origin "+refs/heads/${BR}:refs/remotes/origin/${BR}" || true - git push --force-with-lease origin "${BR}" - if [ -n "$(gh pr list --repo "${VCPKG_UPSTREAM}" --head "$(printf '%s' "${VCPKG_FORK_REPO}" | cut -d/ -f1):${BR}" --state open --json number --jq '.[0].number // empty' 2>/dev/null)" ]; then - echo "An open PR already exists for ${BR}; the force-pushed branch refreshes it." - else - gh pr create \ - --repo "${VCPKG_UPSTREAM}" \ - --base master \ - --head "$(printf '%s' "${VCPKG_FORK_REPO}" | cut -d/ -f1):${BR}" \ - --title "[${PORT}] Update to ${{ steps.ver.outputs.version }}" \ - --body "Automated port bump to [\`${UPSTREAM_REPO}@${{ steps.ver.outputs.tag }}\`](https://github.com/${UPSTREAM_REPO}/releases/tag/${{ steps.ver.outputs.tag }}). Generated by the \`vcpkg-release-bump\` workflow." - fi diff --git a/docs/building-with-vcpkg.md b/docs/building-with-vcpkg.md index c5d112e71..8c9d9f326 100644 --- a/docs/building-with-vcpkg.md +++ b/docs/building-with-vcpkg.md @@ -456,15 +456,15 @@ unchanged against the minimal build. ### Promoting features on release -The release port update copies the **complete overlay port from the release -tag**, not from the current development branch. It then replaces the archive -`REF`, `SHA512`, and manifest version, removes any old `port-version`, and -validates the pinned release build. This carries feature declarations and their -CMake wiring together, including `minimal-sqlite` and the explicit Android curl -backends. The release tag must contain the packaging helper and both features; -older tags without them cannot use this promotion workflow. +After cutting an SDK release, maintainers manually prepare and submit the +registry port update. There is no release-triggered workflow that creates a +vcpkg PR, and no repository token is needed for port preparation. -For a manual registry update, the same preparation can be run from the released +The preparation helper copies the **complete overlay port from the release +tag**, not from the current development branch. It then replaces the archive +`REF`, `SHA512`, and manifest version and removes any old `port-version`. This +carries feature declarations and their CMake wiring together, including +`minimal-sqlite` and the explicit Android curl backends. Run it from the released SDK checkout against a local vcpkg checkout: ```console @@ -473,8 +473,9 @@ python .github/scripts/prepare-vcpkg-release.py --source-port tools/ports/cpp-cl Run `vcpkg format-manifest` on the resulting manifest and validate the downloaded release with `MATSDK_VCPKG_SOURCE_DIR` unset before submitting the registry PR. -This preparation does not require a GitHub token; maintainers can submit the -registry PR manually after cutting the SDK release. +The helper does not build, commit, push, or open a PR. After validating the port, +commit its changes, update the vcpkg version database, and submit the registry PR +using your normal local GitHub authentication. ### Dependency and transport selection diff --git a/docs/maintainer-onboarding.md b/docs/maintainer-onboarding.md index 25f423a51..29a624e0e 100644 --- a/docs/maintainer-onboarding.md +++ b/docs/maintainer-onboarding.md @@ -330,31 +330,24 @@ the SPM workflow skips it and leaves consumers on the earlier package. ### Verify downstream publication -Publishing the GitHub Release triggers: +Publishing the GitHub Release triggers `.github/workflows/spm-release.yml`, +which builds and validates `MATTelemetry.xcframework`, uploads it to the release, +and publishes the parallel three-component Swift Package Manager tag. -- `.github/workflows/spm-release.yml`, which builds and validates - `MATTelemetry.xcframework`, uploads it to the release, and publishes the - parallel three-component Swift Package Manager tag. -- `.github/workflows/vcpkg-release-bump.yml`, which can prepare a - `microsoft/vcpkg` port update when its fork and credential settings are - configured. - -Check both workflows; do not assume that the release trigger completed all -distribution work. - -The vcpkg workflow requires repository configuration and a token capable of -pushing to a fork and opening the upstream PR. If those credentials are -intentionally unavailable, manually: +Check that workflow; do not assume that the release trigger completed all +distribution work. The vcpkg port update is manual; there is no automated +vcpkg PR workflow or repository token requirement for port preparation. 1. Branch from current `microsoft/vcpkg` `master`. -2. Update `ports/cpp-client-telemetry/portfile.cmake` to the new tag and source - archive SHA512. -3. Update and format the port manifest. -4. Run `vcpkg x-add-version cpp-client-telemetry --overwrite-version`. -5. Build the production port from the published archive, not from a local SDK - source override. -6. Commit the port and version-database changes and open a - `microsoft/vcpkg` PR. +2. From the released SDK checkout, use the + [port preparation helper](building-with-vcpkg.md#promoting-features-on-release) + to copy the complete overlay port and set the new release version and source + archive SHA512. Include the manifest and feature wiring, not just the tag. +3. Format the port manifest and build the production port from the published + archive with `MATSDK_VCPKG_SOURCE_DIR` unset, not from a local SDK override. +4. Commit the port changes. +5. Run `vcpkg x-add-version cpp-client-telemetry --overwrite-version`. +6. Commit the version-database changes and manually open a `microsoft/vcpkg` PR. Coordinate updates to other maintained distribution channels, including CocoaPods, when the release is expected to be available there. Validate each From 90d654a572c2774369aefcb127f518d59370a2fa Mon Sep 17 00:00:00 2001 From: bmehta001 Date: Mon, 5 Oct 2026 05:52:10 -0500 Subject: [PATCH 3/6] Doc additions --- docs/building-with-vcpkg.md | 7 +------ docs/maintainer-onboarding.md | 14 ++++++++++---- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/docs/building-with-vcpkg.md b/docs/building-with-vcpkg.md index 8c9d9f326..5b573cd40 100644 --- a/docs/building-with-vcpkg.md +++ b/docs/building-with-vcpkg.md @@ -29,12 +29,7 @@ That's it! The package should be compiled for the current OS. The overlay port shipped in this repository is for **development only** — use it to test local changes to the port, or a newer SDK revision, before they are -published to the registry. - -Feature availability in the registry depends on the packaged SDK release. -In particular, `minimal-sqlite` and `android-curl-openssl` are available in this -overlay but are not yet exposed by the registry port. Until the next release -and its registry update land, use the overlay for those features. +published to the registry: ```console git clone https://github.com/microsoft/cpp_client_telemetry diff --git a/docs/maintainer-onboarding.md b/docs/maintainer-onboarding.md index 29a624e0e..31893be2f 100644 --- a/docs/maintainer-onboarding.md +++ b/docs/maintainer-onboarding.md @@ -38,6 +38,10 @@ requires those modules and your GitHub account has access: git clone --recurse-submodules https://github.com/microsoft/cpp_client_telemetry.git ``` +The modules repo can be directly accessed [here](https://github.com/microsoft/cpp_client_telemetry_modules) with your GitHub account that is part of the Microsoft organization [here](https://github.com/orgs/microsoft/teams/everyone). The ref in GitHub workflows for the modules repo should periodically be updated to point to the HEAD of the `main` branch of this library so that tests run against the latest version of this library. + +Similarly, the link in `lib/modules` in this library should be updated to the HEAD of the modules library after new PRs are merged in there. + Do not make core behavior accidentally depend on a private module. Builds that do not fetch `lib/modules` must continue to compile and link. @@ -78,6 +82,10 @@ Treat a warning suppression, skipped test, conditional source exclusion, or whether the changed code makes that claim invalid. Fix the underlying defect instead of broadening a suppression. +## OneCollector + +For broader questions about OneCollector, please contact the [Collector team](https://teams.microsoft.com/l/channel/19%3A3b4fbc0eaff54e2aa6e373acfc46fe1f%40thread.skype/AEF%2C%20Collector%2C%20and%20Interchange?groupId=5658f840-c680-4882-93be-7cc69578f94e&tenantId=72f988bf-86f1-41af-91ab-2d7cd011db47). + ## Building locally ### CMake presets @@ -332,11 +340,9 @@ the SPM workflow skips it and leaves consumers on the earlier package. Publishing the GitHub Release triggers `.github/workflows/spm-release.yml`, which builds and validates `MATTelemetry.xcframework`, uploads it to the release, -and publishes the parallel three-component Swift Package Manager tag. +and publishes the parallel three-component Swift Package Manager tag. Please check the output of the workflow to ensure it has succeeded. -Check that workflow; do not assume that the release trigger completed all -distribution work. The vcpkg port update is manual; there is no automated -vcpkg PR workflow or repository token requirement for port preparation. +The vcpkg port update is manual: 1. Branch from current `microsoft/vcpkg` `master`. 2. From the released SDK checkout, use the From 802932fd6fb81f66bba710970f36a91bda82cfc7 Mon Sep 17 00:00:00 2001 From: Bhagirath Mehta Date: Mon, 5 Oct 2026 05:58:42 -0500 Subject: [PATCH 4/6] Clarify maintainer guidance to validate real release packages Preserve the modules and Collector team additions while distinguishing reviewed submodule pins from moving HEADs. Align both guides with manual port preparation and prevent local overlay tests from being mistaken for published-archive validation. Files changed: docs/maintainer-onboarding.md docs/building-with-vcpkg.md Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: bd3ff552-cbf8-4164-bc50-3c26778f76de --- docs/building-with-vcpkg.md | 17 +++++++++++---- docs/maintainer-onboarding.md | 40 +++++++++++++++++++++++++---------- 2 files changed, 42 insertions(+), 15 deletions(-) diff --git a/docs/building-with-vcpkg.md b/docs/building-with-vcpkg.md index 5b573cd40..69d4cce09 100644 --- a/docs/building-with-vcpkg.md +++ b/docs/building-with-vcpkg.md @@ -455,19 +455,28 @@ After cutting an SDK release, maintainers manually prepare and submit the registry port update. There is no release-triggered workflow that creates a vcpkg PR, and no repository token is needed for port preparation. -The preparation helper copies the **complete overlay port from the release -tag**, not from the current development branch. It then replaces the archive +The [preparation helper](../.github/scripts/prepare-vcpkg-release.py) copies the +**complete overlay port from the release tag**, not from the current development +branch. It then replaces the archive `REF`, `SHA512`, and manifest version and removes any old `port-version`. This carries feature declarations and their CMake wiring together, including `minimal-sqlite` and the explicit Android curl backends. Run it from the released -SDK checkout against a local vcpkg checkout: +SDK checkout against a separate vcpkg checkout outside the SDK source tree. +Start with a clean vcpkg working tree: the helper replaces the destination port, +including existing patches. +The helper requires Python 3.10 or newer and uses only the standard library. +Pass the four-component version **without** its `v` prefix and the SHA512 of the +published GitHub source `.tar.gz` archive, not an xcframework, AAR, or ZIP: ```console python .github/scripts/prepare-vcpkg-release.py --source-port tools/ports/cpp-client-telemetry --destination-port /ports/cpp-client-telemetry --version X.Y.Z.W --sha512 ``` Run `vcpkg format-manifest` on the resulting manifest and validate the downloaded -release with `MATSDK_VCPKG_SOURCE_DIR` unset before submitting the registry PR. +release with `MATSDK_VCPKG_SOURCE_DIR` unset and without the SDK overlay before +submitting the registry PR. Cover the default graph and the advertised opt-in +features. Do not use the `tests/vcpkg` scripts for this release validation: they +intentionally build the local SDK checkout instead of the pinned archive. The helper does not build, commit, push, or open a PR. After validating the port, commit its changes, update the vcpkg version database, and submit the registry PR using your normal local GitHub authentication. diff --git a/docs/maintainer-onboarding.md b/docs/maintainer-onboarding.md index 31893be2f..02209f911 100644 --- a/docs/maintainer-onboarding.md +++ b/docs/maintainer-onboarding.md @@ -38,9 +38,18 @@ requires those modules and your GitHub account has access: git clone --recurse-submodules https://github.com/microsoft/cpp_client_telemetry.git ``` -The modules repo can be directly accessed [here](https://github.com/microsoft/cpp_client_telemetry_modules) with your GitHub account that is part of the Microsoft organization [here](https://github.com/orgs/microsoft/teams/everyone). The ref in GitHub workflows for the modules repo should periodically be updated to point to the HEAD of the `main` branch of this library so that tests run against the latest version of this library. - -Similarly, the link in `lib/modules` in this library should be updated to the HEAD of the modules library after new PRs are merged in there. +The [modules repository](https://github.com/microsoft/cpp_client_telemetry_modules) +requires a GitHub account with access to that repository. See the +[Microsoft everyone team](https://github.com/orgs/microsoft/teams/everyone) for +Microsoft organization membership; confirm repository permissions before +cloning. + +Keep the SDK checkout ref in the modules repository's CI workflows aligned with +a tested commit on this SDK's `main` branch so module tests cover current SDK +changes. In the other direction, after module PRs merge, update the pinned +`lib/modules` submodule commit in this SDK through a reviewed PR and validate the +combined build. A recursive clone checks out that pinned commit; it does not +automatically follow the modules repository's latest HEAD. Do not make core behavior accidentally depend on a private module. Builds that do not fetch `lib/modules` must continue to compile and link. @@ -84,7 +93,8 @@ instead of broadening a suppression. ## OneCollector -For broader questions about OneCollector, please contact the [Collector team](https://teams.microsoft.com/l/channel/19%3A3b4fbc0eaff54e2aa6e373acfc46fe1f%40thread.skype/AEF%2C%20Collector%2C%20and%20Interchange?groupId=5658f840-c680-4882-93be-7cc69578f94e&tenantId=72f988bf-86f1-41af-91ab-2d7cd011db47). +For questions about OneCollector, contact the +[Collector team](https://teams.microsoft.com/l/channel/19%3A3b4fbc0eaff54e2aa6e373acfc46fe1f%40thread.skype/AEF%2C%20Collector%2C%20and%20Interchange?groupId=5658f840-c680-4882-93be-7cc69578f94e&tenantId=72f988bf-86f1-41af-91ab-2d7cd011db47). ## Building locally @@ -157,8 +167,10 @@ C API or its implementation. ### vcpkg consumer tests -The scripts under `tests/vcpkg` configure, build, link, and run a separate -consumer against the package: +The scripts under `tests/vcpkg` configure, build, and link a separate consumer +against the working-tree overlay port. Host builds run the consumer; iOS +Simulator builds run it in the simulator, while Android and iOS device builds +are cross-compile checks that require separate device deployment for execution: ```powershell .\tests\vcpkg\test-vcpkg-windows.ps1 -VcpkgRoot C:\path\to\vcpkg @@ -336,21 +348,26 @@ must reach SPM, choose a new `X.Y.Z` in `Solutions/version.txt` and regenerate `Version.hpp` before tagging: changing only `W` produces the same SPM tag, so the SPM workflow skips it and leaves consumers on the earlier package. -### Verify downstream publication +### Publish and verify downstream packages Publishing the GitHub Release triggers `.github/workflows/spm-release.yml`, which builds and validates `MATTelemetry.xcframework`, uploads it to the release, -and publishes the parallel three-component Swift Package Manager tag. Please check the output of the workflow to ensure it has succeeded. +and publishes the parallel three-component Swift Package Manager tag. Check the +workflow output to ensure it has succeeded. The vcpkg port update is manual: -1. Branch from current `microsoft/vcpkg` `master`. +1. Start with a clean vcpkg checkout outside the SDK source tree and branch from + current `microsoft/vcpkg` `master`. 2. From the released SDK checkout, use the [port preparation helper](building-with-vcpkg.md#promoting-features-on-release) to copy the complete overlay port and set the new release version and source archive SHA512. Include the manifest and feature wiring, not just the tag. 3. Format the port manifest and build the production port from the published - archive with `MATSDK_VCPKG_SOURCE_DIR` unset, not from a local SDK override. + archive with `MATSDK_VCPKG_SOURCE_DIR` unset and without the SDK overlay. + Verify both the default graph and the release's advertised opt-in features. + Do not use the `tests/vcpkg` scripts for this step: they deliberately select + local SDK source rather than the pinned release archive. 4. Commit the port changes. 5. Run `vcpkg x-add-version cpp-client-telemetry --overwrite-version`. 6. Commit the version-database changes and manually open a `microsoft/vcpkg` PR. @@ -367,7 +384,8 @@ artifact exists. - Release notes describe compatibility or migration requirements. - SPM artifact, checksum, external consumer build, and three-component tag succeeded. -- The vcpkg port PR is open or the existing port already matches the release. +- The vcpkg port PR is open or the registry already packages the release and its + advertised features. - Other maintained package feeds have been updated or explicitly tracked. - A representative consumer can build against the released package. - Release-critical telemetry changes have an authorized end-to-end ingestion From ed5bc0503bd41b268c49a432572da493fb4e2de9 Mon Sep 17 00:00:00 2001 From: Bhagirath Mehta Date: Mon, 5 Oct 2026 15:14:41 -0500 Subject: [PATCH 5/6] Guard destructive port replacement in Copilot review round 1 Address comment 4187592749: resolve the destination before checking its layout and require real vcpkg checkout markers before deleting the existing port. Add regressions for lookalike projects, either missing marker, and normalized destination paths. Verified at .github/scripts/prepare-vcpkg-release.py:15-33 and tests/vcpkg/test-release-port.py:113-143. Confirmed .vcpkg-root and scripts/buildsystems/vcpkg.cmake exist in microsoft/vcpkg. Files changed: .github/scripts/prepare-vcpkg-release.py tests/vcpkg/test-release-port.py docs/building-with-vcpkg.md Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: bd3ff552-cbf8-4164-bc50-3c26778f76de --- .github/scripts/prepare-vcpkg-release.py | 19 ++++++++---- docs/building-with-vcpkg.md | 4 ++- tests/vcpkg/test-release-port.py | 38 ++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 6 deletions(-) diff --git a/.github/scripts/prepare-vcpkg-release.py b/.github/scripts/prepare-vcpkg-release.py index 1e73e6903..0c5240a80 100644 --- a/.github/scripts/prepare-vcpkg-release.py +++ b/.github/scripts/prepare-vcpkg-release.py @@ -12,16 +12,25 @@ def prepare_port(source_port, destination_port, version, sha512): raise ValueError("Expected a four-component SDK release version") if not re.fullmatch(r"[0-9a-fA-F]{128}", sha512): raise ValueError("Expected a 128-digit archive SHA512") + source_port = source_port.resolve() + destination_port = destination_port.resolve() if destination_port.name != "cpp-client-telemetry" or destination_port.parent.name != "ports": raise ValueError("Destination must be a ports/cpp-client-telemetry directory") - source_path = source_port.resolve() - destination_path = destination_port.resolve() if ( - source_path == destination_path - or source_path in destination_path.parents - or destination_path in source_path.parents + source_port == destination_port + or source_port in destination_port.parents + or destination_port in source_port.parents ): raise ValueError("Source and destination ports must not overlap") + vcpkg_root = destination_port.parent.parent + if ( + not (vcpkg_root / ".vcpkg-root").is_file() + or not (vcpkg_root / "scripts" / "buildsystems" / "vcpkg.cmake").is_file() + ): + raise ValueError( + "Destination must belong to a vcpkg checkout containing " + ".vcpkg-root and scripts/buildsystems/vcpkg.cmake" + ) manifest = json.loads((source_port / "vcpkg.json").read_text(encoding="utf-8")) if manifest["name"] != "cpp-client-telemetry": diff --git a/docs/building-with-vcpkg.md b/docs/building-with-vcpkg.md index 69d4cce09..36feeea17 100644 --- a/docs/building-with-vcpkg.md +++ b/docs/building-with-vcpkg.md @@ -463,7 +463,9 @@ carries feature declarations and their CMake wiring together, including `minimal-sqlite` and the explicit Android curl backends. Run it from the released SDK checkout against a separate vcpkg checkout outside the SDK source tree. Start with a clean vcpkg working tree: the helper replaces the destination port, -including existing patches. +including existing patches. Before replacing it, the helper resolves the +destination and requires both `.vcpkg-root` and +`scripts/buildsystems/vcpkg.cmake` in the inferred vcpkg checkout. The helper requires Python 3.10 or newer and uses only the standard library. Pass the four-component version **without** its `v` prefix and the SHA512 of the published GitHub source `.tar.gz` archive, not an xcframework, AAR, or ZIP: diff --git a/tests/vcpkg/test-release-port.py b/tests/vcpkg/test-release-port.py index 7e2978247..da3c3a973 100644 --- a/tests/vcpkg/test-release-port.py +++ b/tests/vcpkg/test-release-port.py @@ -25,6 +25,14 @@ def setUp(self): self.source.mkdir(parents=True) self.destination = root / "vcpkg" / "ports" / "cpp-client-telemetry" self.destination.mkdir(parents=True) + vcpkg_root = self.destination.parent.parent + self.checkout_markers = ( + vcpkg_root / ".vcpkg-root", + vcpkg_root / "scripts" / "buildsystems" / "vcpkg.cmake", + ) + for marker in self.checkout_markers: + marker.parent.mkdir(parents=True, exist_ok=True) + marker.touch() (self.destination / "obsolete.patch").write_text("old patch", encoding="utf-8") self.manifest = json.loads( (REPO_ROOT / "tools" / "ports" / "cpp-client-telemetry" / "vcpkg.json").read_text( @@ -102,6 +110,36 @@ def test_rejects_overlapping_ports(self): PREPARE.prepare_port(self.source, self.source, "3.10.999.1", "a" * 128) self.assertTrue((self.source / "portfile.cmake").exists()) + def test_rejects_lookalike_non_vcpkg_destination_without_deleting_files(self): + lookalike = Path(self.temporary.name) / "other-project" / "ports" / "cpp-client-telemetry" + lookalike.mkdir(parents=True) + sentinel = lookalike / "keep.txt" + sentinel.write_text("unrelated project", encoding="utf-8") + with self.assertRaisesRegex(ValueError, "vcpkg checkout"): + PREPARE.prepare_port(self.source, lookalike, "3.10.999.1", "a" * 128) + self.assertEqual(sentinel.read_text(encoding="utf-8"), "unrelated project") + self.assertEqual(list(lookalike.iterdir()), [sentinel]) + + def test_requires_both_checkout_markers_before_replacing_port(self): + for marker in self.checkout_markers: + with self.subTest(marker=marker.name): + marker.unlink() + with self.assertRaisesRegex(ValueError, "vcpkg checkout"): + self.prepare() + self.assertEqual( + (self.destination / "obsolete.patch").read_text(encoding="utf-8"), "old patch" + ) + marker.touch() + + def test_validates_and_replaces_the_resolved_destination(self): + alias = self.destination / ".." / "cpp-client-telemetry" + PREPARE.prepare_port(self.source, alias, "3.10.999.1", "a" * 128) + self.assertFalse((self.destination / "obsolete.patch").exists()) + self.assertEqual( + json.loads((self.destination / "vcpkg.json").read_text(encoding="utf-8"))["version"], + "3.10.999.1", + ) + if __name__ == "__main__": unittest.main() From c927908c5e7f3fd6299f75c1d46fcde1bad45512 Mon Sep 17 00:00:00 2001 From: Bhagirath Mehta Date: Mon, 5 Oct 2026 16:59:37 -0500 Subject: [PATCH 6/6] Describe SHA512 input accurately as hexadecimal characters Replace the misleading 128-digit diagnostic because the accepted hash alphabet includes a-f. Add regression coverage for the exact message on short, long, and non-hexadecimal input without changing validation behavior. Files changed: .github/scripts/prepare-vcpkg-release.py tests/vcpkg/test-release-port.py Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: bd3ff552-cbf8-4164-bc50-3c26778f76de --- .github/scripts/prepare-vcpkg-release.py | 2 +- tests/vcpkg/test-release-port.py | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/scripts/prepare-vcpkg-release.py b/.github/scripts/prepare-vcpkg-release.py index 0c5240a80..529eda2b6 100644 --- a/.github/scripts/prepare-vcpkg-release.py +++ b/.github/scripts/prepare-vcpkg-release.py @@ -11,7 +11,7 @@ def prepare_port(source_port, destination_port, version, sha512): if not re.fullmatch(r"\d+\.\d+\.\d+\.\d+", version): raise ValueError("Expected a four-component SDK release version") if not re.fullmatch(r"[0-9a-fA-F]{128}", sha512): - raise ValueError("Expected a 128-digit archive SHA512") + raise ValueError("Expected a 128-character hexadecimal SHA512") source_port = source_port.resolve() destination_port = destination_port.resolve() if destination_port.name != "cpp-client-telemetry" or destination_port.parent.name != "ports": diff --git a/tests/vcpkg/test-release-port.py b/tests/vcpkg/test-release-port.py index da3c3a973..b637627ae 100644 --- a/tests/vcpkg/test-release-port.py +++ b/tests/vcpkg/test-release-port.py @@ -105,6 +105,15 @@ def test_rejects_destination_outside_the_port(self): with self.assertRaisesRegex(ValueError, "Destination"): PREPARE.prepare_port(self.source, self.destination.parent, "3.10.999.1", "a" * 128) + def test_describes_invalid_sha512_as_hexadecimal_characters(self): + for sha512 in ("a" * 127, "a" * 129, "g" * 128): + with self.subTest(sha512=sha512): + with self.assertRaisesRegex( + ValueError, "^Expected a 128-character hexadecimal SHA512$" + ): + PREPARE.prepare_port(self.source, self.destination, "3.10.999.1", sha512) + self.assertTrue((self.destination / "obsolete.patch").exists()) + def test_rejects_overlapping_ports(self): with self.assertRaisesRegex(ValueError, "overlap"): PREPARE.prepare_port(self.source, self.source, "3.10.999.1", "a" * 128)