diff --git a/.github/release-homebrew.sh b/.github/release-homebrew.sh new file mode 100755 index 00000000000000..44f2904254a0d0 --- /dev/null +++ b/.github/release-homebrew.sh @@ -0,0 +1,156 @@ +#!/bin/sh +# +# Promote a microsoft/git release into the microsoft/homebrew-git tap. +# +# Usage: +# .github/release-homebrew.sh [--force] [] +# +# If TAG_NAME is omitted, the latest microsoft/git release is used. +# +# Downgrades require `--force`. +# +# Prerequisites: +# - `gh` authenticated (via `gh auth login`) as a user with push +# access to microsoft/homebrew-git. +# - `git`, `jq`, and `sed` on PATH. +# +# Given a release tag on microsoft/git (e.g. v2.54.0.vfs.0.4), this +# script looks up the macOS installer asset for that tag, extracts the +# SHA-256 digest reported by the GitHub Releases API (deliberately not +# re-hashed locally; see microsoft/homebrew-git#102), edits the +# `microsoft-git` cask in place preserving its indentation and quote +# style, pushes the update to the tap under a datetime-keyed branch, +# and opens a PR. +# +# This mirrors the behaviour of mjcheetham/update-homebrew@v1.5.1 +# invoked with `type: cask`, `alwaysUsePullRequest: true`. + +set -eu + +die () { + echo "error: $*" >&2 + exit 1 +} + +case "$1" in +--force) force=t; shift;; +*) force=;; +esac + +TAG_NAME=${1-} +if [ -z "$TAG_NAME" ]; then + echo "==> No tag given; resolving latest microsoft/git release" + TAG_NAME=$(gh release view -R microsoft/git \ + --json tagName --jq .tagName) + test -n "$TAG_NAME" || die "could not determine latest release tag" +fi + +echo "==> Tag: $TAG_NAME" + +version=${TAG_NAME#v} +echo "==> Version: $version" + +# Refuse to downgrade the cask and short-circuit no-op runs. Look up +# the version currently in the tap and compare before fetching the +# release JSON or cloning. +current_content=$(gh api \ + repos/microsoft/homebrew-git/contents/Casks/microsoft-git.rb \ + -H "Accept: application/vnd.github.raw") +current_version=$(printf '%s\n' "$current_content" | sed -nE \ + "s/^[[:space:]]*version *['\"]([^'\"]*)['\"].*/\\1/p") +test -n "$current_version" || die "could not parse current cask version" +echo "==> Current: $current_version" + +if [ "$version" = "$current_version" ]; then + echo "warning: cask is already at $version; nothing to do." >&2 + exit 0 +fi +lowest=$(printf '%s\n%s\n' "$version" "$current_version" | + sort -V | sed 1q) +if [ "$lowest" = "$version" ]; then + test -n "$force" || + die "regression: cask is at $current_version," \ + "refusing to downgrade to $version" + echo "warning: **downgrading** from $current_version to $version" >&2 +fi + +echo "==> Fetching release metadata" +release_json=$(gh api \ + -H "Accept: application/vnd.github+json" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + "repos/microsoft/git/releases/tags/$TAG_NAME") + +asset_pattern='git-(.*)\.pkg' +asset_json=$(jq -n \ + --argjson release "$release_json" \ + --arg pat "$asset_pattern" ' + [ $release.assets[] | select(.name | test($pat)) ] as $matches + | if ($matches | length) == 0 then + error("no asset matches pattern \($pat)") + elif ($matches | length) > 1 then + error("multiple assets match pattern \($pat): " + + ([$matches[].name] | join(", "))) + else $matches[0] end') + +digest=$(jq -n -r --argjson a "$asset_json" '$a.digest // ""') +case "$digest" in +sha256:*) sha256=${digest#sha256:} ;; +"") die "asset has no 'digest' field" ;; +*) die "asset digest is not sha256: $digest" ;; +esac + +# Enforce 64 lowercase hex chars without spawning grep. + *[!0-9a-f]*|"") +esac +test ${#sha256} -eq 64 || + die "asset digest is not 64 chars long: $sha256" + +echo "==> Asset: $(jq -n -r --argjson a "$asset_json" '$a.name')" +echo "==> SHA-256: $sha256" + +workdir=$(mktemp -d) +trap 'rm -rf "$workdir"' EXIT + +echo "==> Cloning microsoft/homebrew-git" +REPO=microsoft/homebrew-git +gh repo clone "$REPO" "$workdir/homebrew-git" -- \ + --depth=1 --quiet + +cd "$workdir/homebrew-git" + +# Preserve existing indentation and quote style, replacing only the +# value; matches mjcheetham/update-homebrew's setField regex. The +# `file.new && mv -f file.new file` idiom sidesteps the +# incompatible `sed -i` spellings between GNU and BSD sed. +f=Casks/microsoft-git.rb +# Capture opening quote as \2, match value up to the matching quote. +q='(['\''"])[^'\''"]+\2' +sed -E \ + -e "s/^([[:space:]]*)version +$q/\\1version \\2$version\\2/" \ + -e "s/^([[:space:]]*)sha256 +$q/\\1sha256 \\2$sha256\\2/" \ + <"$f" >"$f.new" && +mv -f "$f.new" "$f" + +if git diff --quiet -- Casks/microsoft-git.rb; then + echo "==> No changes needed; cask is already at $version." + exit 0 +fi + +git --no-pager diff -- Casks/microsoft-git.rb + +BRANCH=update-$(date +%Y-%m-%d-%H-%M-%S) +git switch -c $BRANCH +TITLE="microsoft-git: update to $version" +git commit -m "$TITLE" \ + -- Casks/microsoft-git.rb + +git push origin HEAD + +echo "==> Pushed: $(git log -1 --format='%h %s')" + +pr_url=$(gh pr create \ + --repo "$REPO" \ + --head "$BRANCH" \ + --title "$TITLE") + +echo "==> Created: $pr_url" diff --git a/.github/release-vfsforgit.sh b/.github/release-vfsforgit.sh new file mode 100755 index 00000000000000..0b37cb77768a3d --- /dev/null +++ b/.github/release-vfsforgit.sh @@ -0,0 +1,103 @@ +#!/bin/sh +# +# Promote a microsoft/git release into the microsoft/VFSForGit repo. +# +# Usage: +# .github/release-vfsforgit.sh [--force] [] +# +# If TAG_NAME is omitted, the latest microsoft/git release is used. +# +# Downgrades require `--force`. +# +# Prerequisites: +# - `gh` authenticated (via `gh auth login`) as a user with push +# access to microsoft/VFSForGit. +# - `git` and `sed` on PATH. +# +# Given a release tag on microsoft/git (e.g. v2.54.0.vfs.0.4), this +# script opens a pull request against microsoft/VFSForGit that bumps +# the `GIT_VERSION` default in `.github/workflows/build.yaml` so that +# VFSForGit builds pick up the newly promoted release by default. + +set -eu + +die () { + echo "error: $*" >&2 + exit 1 +} + +case "$1" in +--force) force=t; shift;; +*) force=;; +esac + +TAG_NAME=${1-} +if [ -z "$TAG_NAME" ]; then + echo "==> No tag given; resolving latest microsoft/git release" + TAG_NAME=$(gh release view -R microsoft/git \ + --json tagName --jq .tagName) + test -n "$TAG_NAME" || die "could not determine latest release tag" +fi + +echo "==> Tag: $TAG_NAME" + +REPO=microsoft/VFSForGit +BRANCH="automation/gitrelease-$TAG_NAME" +FILE=.github/workflows/build.yaml +RELEASE_URL="https://github.com/microsoft/git/releases/tag/$TAG_NAME" + +# Refuse to downgrade and short-circuit no-op runs. Read the current +# GIT_VERSION default straight from build.yaml on the VFSForGit +# default branch before cloning anything. +current_content=$(gh api "repos/$REPO/contents/$FILE" \ + -H "Accept: application/vnd.github.raw") +current_tag=$(printf '%s\n' "$current_content" | sed -nE \ + "/GIT_VERSION/s/.*\\|\\| *'([^']*)' *\\}\\}.*/\\1/p") +test -n "$current_tag" || die "could not parse current GIT_VERSION" +echo "==> Current: $current_tag" + +if [ "$TAG_NAME" = "$current_tag" ]; then + echo "warning: GIT_VERSION is already $TAG_NAME; nothing to do." >&2 + exit 0 +fi +lowest=$(printf '%s\n%s\n' "$TAG_NAME" "$current_tag" | + sort -V | sed 1q) +if [ "$lowest" = "$TAG_NAME" ]; then + test -n "$force" || + die "regression: GIT_VERSION is $current_tag," \ + "refusing to downgrade to $TAG_NAME" + echo "warning: **downgrading** from $current_tag to $TAG_NAME" >&2 +fi + +workdir=$(mktemp -d) +trap 'rm -rf "$workdir"' EXIT + +echo "==> Sparse-cloning $REPO" +gh repo clone "$REPO" "$workdir/vfsforgit" -- \ + --filter=blob:none --no-checkout --depth=1 --quiet +cd "$workdir/vfsforgit" +git sparse-checkout set "$FILE" +git checkout -b "$BRANCH" --quiet + +echo "==> Bumping GIT_VERSION in $FILE" +sed "/GIT_VERSION/s/|| '[^']*' }}/|| '$TAG_NAME' }}/" \ + <"$FILE" >"$FILE.new" && +mv -f "$FILE.new" "$FILE" + +git --no-pager diff -- "$FILE" + +git commit -m "Update default Microsoft Git version to $TAG_NAME" \ + -- "$FILE" + +git push origin "$BRANCH" + +pr_body="Update the default Microsoft Git version used by VFS for Git +to the newly promoted [\`$TAG_NAME\`]($RELEASE_URL) release." + +pr_url=$(gh pr create \ + --repo "$REPO" \ + --head "$BRANCH" \ + --title "Update default Microsoft Git version to $TAG_NAME" \ + --body "$pr_body") + +echo "==> Created: $pr_url" diff --git a/.github/release-winget.sh b/.github/release-winget.sh new file mode 100755 index 00000000000000..2f8a8820c28140 --- /dev/null +++ b/.github/release-winget.sh @@ -0,0 +1,188 @@ +#!/bin/sh +# +# Promote a microsoft/git release into the microsoft/winget-pkgs repo. +# +# Usage: +# .github/release-winget.sh [--force] [] +# +# If TAG_NAME is omitted, the latest microsoft/git release is used. +# +# Downgrades require `--force`. +# +# Prerequisites: +# - Runs on Windows (the winget authoring tool wingetcreate.exe is +# Windows-only). Use Git for Windows' bash, an MSYS2 shell, WSL +# Bash, or an equivalent. +# - `gh` authenticated (via `gh auth login`) as a user with (a) push +# access to a personal fork of microsoft/winget-pkgs and (b) +# permission to open a pull request against microsoft/winget-pkgs. +# wingetcreate will create the fork on the fly if it does not +# already exist. +# - `curl` and `jq` on PATH. +# +# Given a release tag on microsoft/git (e.g. v2.54.0.vfs.0.4), the +# script downloads wingetcreate, converts the tag to winget's dotted +# numeric version format (v2.54.0.vfs.0.4 -> 2.54.0.0.4), fetches the +# four installer URLs (x64 machine, x64 user, arm64 machine, arm64 +# user) from the corresponding GitHub release, builds an updated +# manifest for the Microsoft.Git package, syncs the operator's fork +# of microsoft/winget-pkgs with upstream, and submits the manifest +# via a pull request against microsoft/winget-pkgs. + +set -eu + +die () { + echo "error: $*" >&2 + exit 1 +} + +case "$(uname -s)" in +MINGW*|MSYS*|CYGWIN*) ;; # okay +Linux) + # Could be WSL + test -f /proc/sys/fs/binfmt_misc/WSLInterop || + die "this script requires Windows" + ;; +*) + die "this script requires Git for Windows / MSYS:" \ + "wingetcreate is a Windows-only tool" + ;; +esac + +case "$1" in +--force) force=t; shift;; +*) force=;; +esac + +TAG_NAME=${1-} +if [ -z "$TAG_NAME" ]; then + echo "==> No tag given; resolving latest microsoft/git release" + TAG_NAME=$(gh release view -R microsoft/git \ + --json tagName --jq .tagName) + test -n "$TAG_NAME" || die "could not determine latest release tag" +fi + +echo "==> Tag: $TAG_NAME" + +# Elide the leading 'v' and the 'vfs.' segment: +# v2.54.0.vfs.0.4 -> 2.54.0.0.4 +version=$(printf '%s' "${TAG_NAME#v}" | sed 's/vfs\.//') +echo "==> Version: $version" + +workdir=$(mktemp -d) +success=0 +cleanup () { + if [ "$success" = 1 ]; then + rm -rf "$workdir" + else + echo "==> Workdir retained for inspection: $workdir" >&2 + fi +} +trap cleanup EXIT + +cd "$workdir" +echo "==> Working in $workdir" + +echo "==> Downloading wingetcreate" +test -x wingetcreate.exe || { + curl -fsSL https://aka.ms/wingetcreate/latest -o wingetcreate.exe && + chmod +x wingetcreate.exe +} || die "Could not initialize wingetcreate.exe" + +# Refuse to downgrade the package and short-circuit no-op runs. Look up +# the version currently in the manifest and compare before trying to +# update. +info="$(./wingetcreate.exe show Microsoft.Git)" +current_version=${info##*PackageVersion: } +current_version=${current_version%%[!0-9.]*} +test -n "$current_version" || die "could not parse current package version" +echo "==> Current: $current_version" + +if [ "$version" = "$current_version" ]; then + echo "warning: package is already at $version; nothing to do." >&2 + exit 0 +fi +lowest=$(printf '%s\n%s\n' "$version" "$current_version" | + sort -V | sed 1q) +if [ "$lowest" = "$version" ]; then + test -n "$force" || + die "regression: package is at $current_version," \ + "refusing to downgrade to $version" + echo "warning: **downgrading** from $current_version to $version" >&2 +fi + +echo "==> Fetching release metadata" +release_json=$(gh api \ + -H "Accept: application/vnd.github+json" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + "repos/microsoft/git/releases/tags/$TAG_NAME") + +pick_asset () { + # $1: jq regex to match the asset name. + jq -n -r --argjson r "$release_json" --arg pat "$1" ' + [ $r.assets[] | select(.name | test($pat)) ] as $m + | if $m | length == 0 then + error("no asset matches pattern \($pat)") + elif $m | length > 1 then + error("multiple assets match \($pat)") + else $m[0] end' +} + +x64_asset=$(pick_asset '64-bit\.exe$') +arm64_asset=$(pick_asset 'arm64\.exe$') + +# wingetcreate downloads the installer to compute its hash. Use the +# public browser URL for anonymous access rather than the API URL. +x64_url=$(printf '%s' "$x64_asset" | jq -r .browser_download_url) +arm64_url=$(printf '%s' "$arm64_asset" | jq -r .browser_download_url) + +echo "==> x64 asset: $(printf '%s' "$x64_asset" | jq -r .name)" +echo "==> arm64: $(printf '%s' "$arm64_asset" | jq -r .name)" + +# wingetcreate reads its GitHub token from this env var; hand it the +# operator's own gh session token so no PAT needs to be stashed. +WINGET_CREATE_GITHUB_TOKEN=$(gh auth token) +export WINGET_CREATE_GITHUB_TOKEN + +echo "==> Building manifest for Microsoft.Git $version" +./wingetcreate.exe update Microsoft.Git \ + -v "$version" \ + -o . \ + -u "$x64_url|x64|machine" \ + "$x64_url|x64|user" \ + "$arm64_url|arm64|machine" \ + "$arm64_url|arm64|user" + +# wingetcreate submit pushes to the operator's personal fork of +# microsoft/winget-pkgs and opens a PR from there. A stale fork makes +# submit fail with "The forked repository could not be synced with +# the upstream commits"; sync it first. If no fork exists yet (404), +# wingetcreate will create a fresh one at submit time, so treat that +# as fine. +user=$(gh api user --jq .login) +echo "==> Syncing $user/winget-pkgs fork with upstream" +sync_err=$(mktemp) +if gh api --silent --method POST \ + "repos/$user/winget-pkgs/merge-upstream" \ + -f branch=master 2>"$sync_err"; then + echo "==> Fork sync: OK" +elif grep -q '404' "$sync_err"; then + echo "==> Fork sync: no fork; will create on submit" +else + cat "$sync_err" >&2 + rm -f "$sync_err" + die "fork sync failed" +fi +rm -f "$sync_err" + +manifest_dir="$PWD/manifests/m/Microsoft/Git/$version" +echo "==> Submitting $manifest_dir" +submit_out=$(./wingetcreate.exe submit "$manifest_dir") +echo "$submit_out" + +pr_url=$(printf '%s\n' "$submit_out" | + grep -oE 'https://github\.com/microsoft/winget-pkgs/pull/[^ ]+' || + true) +test -z "$pr_url" || echo "==> Created: $pr_url" + +success=1 diff --git a/.github/workflows/release-homebrew.yml b/.github/workflows/release-homebrew.yml deleted file mode 100644 index 6c8ef1d63838f3..00000000000000 --- a/.github/workflows/release-homebrew.yml +++ /dev/null @@ -1,122 +0,0 @@ -name: Update Homebrew Tap -on: - release: - types: [released] - -permissions: - id-token: write # required for Azure login via OIDC - -jobs: - release: - runs-on: ubuntu-latest - environment: release - steps: - - id: version - name: Compute version number - run: | - echo "result=$(echo $GITHUB_REF | sed -e "s/^refs\/tags\/v//")" >>$GITHUB_OUTPUT - - id: hash - name: Look up release asset digest - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GH_REPO: ${{ github.repository }} - TAG_NAME: v${{ steps.version.outputs.result }} - # Regex (Oniguruma) used by jq's `test()` to pick the macOS - # installer asset. Kept permissive to match `git-(.*)\.pkg` from - # the previous mjcheetham/asset-hash invocation. - ASSET_PATTERN: 'git-(.*)\.pkg' - run: | - set -euo pipefail - - # GitHub has been observed to occasionally serve the unicorn - # error page with a 200 status code for release-asset downloads, - # leading to bogus checksums when the asset is hashed locally - # (see microsoft/homebrew-git#102). Use the digest reported by - # the Releases API instead, and log every intermediate value so - # any future API misbehaviour can be diagnosed from the workflow - # run alone. - - echo "::group::Fetching release metadata" - echo "Repository: $GH_REPO" - echo "Tag: $TAG_NAME" - echo "Endpoint: repos/$GH_REPO/releases/tags/$TAG_NAME" - release_json=$(gh api \ - -H "Accept: application/vnd.github+json" \ - -H "X-GitHub-Api-Version: 2022-11-28" \ - "repos/$GH_REPO/releases/tags/$TAG_NAME") - jq '{id, tag_name, name, html_url, draft, prerelease, - published_at, asset_count: (.assets | length)}' \ - <<<"$release_json" - echo "::endgroup::" - - echo "::group::Release assets" - jq -r '.assets[] - | "\(.id)\t\(.name)\tsize=\(.size)\tdigest=\(.digest // "")"' \ - <<<"$release_json" - echo "::endgroup::" - - echo "::group::Matching asset (pattern: $ASSET_PATTERN)" - asset_json=$(jq --arg pat "$ASSET_PATTERN" ' - [ .assets[] | select(.name | test($pat)) ] as $matches - | if ($matches | length) == 0 then - error("no asset matches pattern \($pat)") - elif ($matches | length) > 1 then - error("multiple assets match pattern \($pat): " + - ([$matches[].name] | join(", "))) - else $matches[0] end' <<<"$release_json") - jq '{id, name, label, content_type, state, size, digest, - download_count, created_at, updated_at, - browser_download_url, url}' <<<"$asset_json" - echo "::endgroup::" - - digest=$(jq -r '.digest // ""' <<<"$asset_json") - case "$digest" in - sha256:*) - sha256=${digest#sha256:} - ;; - "") - echo "::error::Asset has no 'digest' field; GitHub API may" \ - "not have populated it for this release." >&2 - exit 1 - ;; - *) - echo "::error::Asset digest is not sha256: '$digest'" >&2 - exit 1 - ;; - esac - - if ! printf '%s' "$sha256" | grep -Eq '^[0-9a-f]{64}$'; then - echo "::error::Asset digest is not a 64-char hex string:" \ - "'$sha256'" >&2 - exit 1 - fi - - echo "Asset SHA-256: $sha256" - echo "result=$sha256" >>"$GITHUB_OUTPUT" - - name: Log into Azure - uses: azure/login@v3 - with: - client-id: ${{ secrets.AZURE_CLIENT_ID }} - tenant-id: ${{ secrets.AZURE_TENANT_ID }} - subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} - - name: Retrieve token - id: token - run: | - az keyvault secret show \ - --name ${{ secrets.HOMEBREW_TOKEN_SECRET_NAME }} \ - --vault-name ${{ secrets.AZURE_VAULT }} \ - --query "value" -o tsv >token && - # avoid outputting the token under `set -x` by using `sed` instead of `echo` - sed s/^/::add-mask::/ >$GITHUB_OUTPUT && - rm token - - name: Update scalar Cask - uses: mjcheetham/update-homebrew@v1.5.1 - with: - token: ${{ steps.token.outputs.result }} - tap: microsoft/git - name: microsoft-git - type: cask - version: ${{ steps.version.outputs.result }} - sha256: ${{ steps.hash.outputs.result }} - alwaysUsePullRequest: false diff --git a/.github/workflows/release-vfsforgit.yml b/.github/workflows/release-vfsforgit.yml deleted file mode 100644 index a96e183fa6df2a..00000000000000 --- a/.github/workflows/release-vfsforgit.yml +++ /dev/null @@ -1,98 +0,0 @@ -name: Update VFS for Git - -on: - release: - types: [released] - - workflow_dispatch: - inputs: - tag: - description: 'Tag name to release' - required: true - -permissions: - id-token: write # required for Azure login via OIDC - -env: - TAG_NAME: ${{ github.event.inputs.tag || github.event.release.tag_name }} - -jobs: - update: - runs-on: ubuntu-latest - environment: release - steps: - - name: Log into Azure - uses: azure/login@v3 - with: - client-id: ${{ secrets.AZURE_CLIENT_ID }} - tenant-id: ${{ secrets.AZURE_TENANT_ID }} - subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} - - - name: Checkout (for akv-secret action) - uses: actions/checkout@v6 - with: - sparse-checkout: .github/actions - - - name: Retrieve token - id: token - uses: ./.github/actions/akv-secret - with: - vault: ${{ secrets.AZURE_VAULT }} - secrets: | - ${{ secrets.VFSFORGIT_TOKEN_SECRET_NAME }} > $output:result - - # Create a PR to bump the default GIT_VERSION - - name: Create VFS for Git version bump PR - env: - # GH_TOKEN overrides the GITHUB_TOKEN provided by the actions runner, - # so that `gh` commands use the VFS for Git repo token from Key Vault. - GH_TOKEN: ${{ steps.token.outputs.result }} - run: | - # Configure gh as the git credential helper and force HTTPS protocol - # so that git clone/push authenticate using GH_TOKEN. - gh auth setup-git - gh config set git_protocol https - - REPO="microsoft/VFSForGit" - BRANCH="automation/gitrelease-$TAG_NAME" - FILE=".github/workflows/build.yaml" - - # Clone VFS for Git repo (sparse partial clone for efficiency) - gh repo clone "$REPO" vfsforgit -- --filter=blob:none --no-checkout --depth=1 - cd vfsforgit - git sparse-checkout set "$FILE" - git checkout - - # Create new branch - git checkout -b "$BRANCH" - - # Update the GIT_VERSION default in build.yaml - sed -i "/GIT_VERSION/s/|| '[^']*' }}/|| '$TAG_NAME' }}/" "$FILE" - - # Verify the change was made - if ! git diff --quiet "$FILE"; then - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - - git add "$FILE" - git commit -m "Update default Microsoft Git version to $TAG_NAME" - - # Push the new branch - git push origin "$BRANCH" - - # Create the PR - WORKFLOW_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" - RELEASE_URL="https://github.com/microsoft/git/releases/tag/$TAG_NAME" - PR_TITLE="Update default Microsoft Git version to $TAG_NAME" - PR_BODY="This PR was automatically created by the [microsoft/git release workflow]($WORKFLOW_URL) - to update the default Microsoft Git version to [\`$TAG_NAME\`]($RELEASE_URL)." - - PR_URL=$(gh pr create \ - --repo "$REPO" \ - --head "$BRANCH" \ - --title "$PR_TITLE" \ - --body "$PR_BODY") - echo "::notice::Created VFS for Git PR: $PR_URL" - else - echo "::warning::No changes detected in $FILE; GIT_VERSION may already be set to $TAG_NAME" - fi diff --git a/.github/workflows/release-winget.yml b/.github/workflows/release-winget.yml deleted file mode 100644 index 1a93dc3b352093..00000000000000 --- a/.github/workflows/release-winget.yml +++ /dev/null @@ -1,111 +0,0 @@ -name: "release-winget" -on: - release: - types: [released] - - workflow_dispatch: - inputs: - tag: - description: 'Tag name to release' - required: true - -permissions: - id-token: write # required for Azure login via OIDC - -env: - TAG_NAME: ${{ github.event.inputs.tag }} - -jobs: - release: - runs-on: windows-latest - environment: release - steps: - - name: Log into Azure - uses: azure/login@v3 - with: - client-id: ${{ secrets.AZURE_CLIENT_ID }} - tenant-id: ${{ secrets.AZURE_TENANT_ID }} - subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} - - - name: Publish manifest with winget-create - run: | - # Enabling stop on error and tracing - Set-PSDebug -Trace 2 - $ErrorActionPreference = "Stop" - $PSNativeCommandErrorActionPreference = "Stop" - - if ($env:TAG_NAME -eq "") { - # Get latest release - $github = Get-Content '${{ github.event_path }}' | ConvertFrom-Json - - # Set the tag name environment variable - $env:TAG_NAME = $github.release.tag_name - - # Get download URLs - $asset_x64 = $github.release.assets | Where-Object -Property name -match '64-bit.exe$' - $asset_arm64 = $github.release.assets | Where-Object -Property name -match 'arm64.exe$' - $asset_x64_url = $asset_x64.browser_download_url - $asset_arm64_url = $asset_arm64.browser_download_url - } else { - # Get release object by its tag - $env:GH_TOKEN = ${{ toJson(secrets.GITHUB_TOKEN) }} - $github = (gh release view -R microsoft/git $env:TAG_NAME --json tagName,assets --jq '{tag_name: .tagName, assets: .assets}') | ConvertFrom-Json - - # Get download URLs - $asset_x64 = $github.assets | Where-Object -Property name -match '64-bit.exe$' - $asset_arm64 = $github.assets | Where-Object -Property name -match 'arm64.exe$' - $asset_x64_url = $asset_x64.url - $asset_arm64_url = $asset_arm64.url - } - - # Remove 'v' and 'vfs' from the version - $env:TAG_NAME -match 'v(.*?)vfs\.(.*)' - $version = $Matches[1] + $Matches[2] - - # Download the token from Azure Key Vault and mask it in the logs - $env:WINGET_CREATE_GITHUB_TOKEN = az keyvault secret show --name ${{ secrets.WINGET_TOKEN_SECRET_NAME }} --vault-name ${{ secrets.AZURE_VAULT }} --query "value" -o tsv - Write-Host -NoNewLine "::add-mask::$env:WINGET_CREATE_GITHUB_TOKEN" - - # Download wingetcreate and create manifests - Invoke-WebRequest https://aka.ms/wingetcreate/latest -OutFile wingetcreate.exe - .\wingetcreate.exe update Microsoft.Git ` - -v $version ` - -o . ` - -u "$($asset_x64_url)|x64|machine" ` - "$($asset_x64_url)|x64|user" ` - "$($asset_arm64_url)|arm64|machine" ` - "$($asset_arm64_url)|arm64|user" - - # Sync the winget-pkgs fork with upstream before submitting, - # to avoid "The forked repository could not be synced with - # the upstream commits" errors from wingetcreate. - # If the fork does not exist yet, wingetcreate will create - # it fresh (and therefore up-to-date), so a 404 is fine. - # See https://docs.github.com/en/rest/branches/branches#sync-a-fork-branch-with-the-upstream-repository - $headers = @{ - Authorization = "token $env:WINGET_CREATE_GITHUB_TOKEN" - Accept = "application/vnd.github+json" - } - $user = (Invoke-RestMethod -Uri "https://api.github.com/user" -Headers $headers).login - try { - Invoke-RestMethod -Method Post ` - -Uri "https://api.github.com/repos/$user/winget-pkgs/merge-upstream" ` - -Headers $headers ` - -Body '{"branch":"master"}' ` - -ContentType "application/json" - Write-Host "Synced $user/winget-pkgs fork with upstream." - } catch { - if ($_.Exception.Response.StatusCode.value__ -eq 404) { - Write-Host "No fork found at $user/winget-pkgs; wingetcreate will create one." - } else { - throw - } - } - - # Submit the manifest to the winget-pkgs repository - $manifestDirectory = "$PWD\manifests\m\Microsoft\Git\$version" - $output = & .\wingetcreate.exe submit $manifestDirectory - Write-Host $output - $url = $output | Select-String -Pattern 'https://github\.com/microsoft/winget-pkgs/pull/\S+' | ForEach-Object { $_.Matches.Value } - Write-Host "::notice::Submitted ${env:TAG_NAME} to winget as $url" - shell: powershell