Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
329 changes: 329 additions & 0 deletions azure-pipelines/roslyn-version-bump.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,329 @@
trigger: none
pr: none

parameters:
- name: createPullRequest
displayName: Create Pull Request
type: boolean
default: true
- name: targetBranch
displayName: Target Branch for PR
type: string
default: main

resources:
repositories:
- repository: 1ESPipelineTemplates
type: git
name: 1ESPipelineTemplates/1ESPipelineTemplates
ref: refs/tags/release
pipelines:
- pipeline: officialBuildCI
source: 327
project: internal
branch: refs/heads/main
trigger: none

variables:
- name: RoslynStartSHA
value: ""
- name: RoslynEndSHA
value: $(resources.pipeline.officialBuildCI.sourceCommit)
- name: RoslynBuildNumber
value: $(resources.pipeline.officialBuildCI.runName)
- name: RoslynBuildId
value: $(resources.pipeline.officialBuildCI.runID)
- name: RoslynVersion
value: ""

extends:
template: v1/1ES.Official.PipelineTemplate.yml@1ESPipelineTemplates
parameters:
pool:
name: AzurePipelines-EO
image: 1ESPT-Ubuntu22.04
os: linux
stages:
- stage: BumpRoslyn
displayName: Bump Roslyn Version
jobs:
- job: ProcessBump
displayName: Process Roslyn Bump
pool:
name: AzurePipelines-EO
image: 1ESPT-Ubuntu22.04
os: linux
templateContext:
type: releaseJob
isProduction: false
inputs:
- input: pipelineArtifact
pipeline: officialBuildCI
artifactName: AssetManifests
destinationPath: $(Pipeline.Workspace)/officialBuildCI/AssetManifests
steps:
- checkout: self
persistCredentials: true

- task: UseDotNet@2
displayName: Install .NET SDK
inputs:
version: 9.0.x

- task: Bash@3
displayName: Install tools
inputs:
targetType: inline
script: |
set -euo pipefail
# Install roslyn-tools
FEED="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json"
dotnet tool install -g Microsoft.RoslynTools --prerelease --add-source "$FEED"
echo "##vso[task.prependpath]$HOME/.dotnet/tools"

# Install jq for JSON parsing
sudo apt-get update && sudo apt-get install -y jq

- task: Bash@3
displayName: Extract Roslyn version from AssetManifests
inputs:
targetType: inline
script: |
set -euo pipefail

# The AssetManifests artifact is downloaded to this location
ASSET_MANIFEST_PATH="$(Pipeline.Workspace)/officialBuildCI/AssetManifests"

# Find OfficialBuild.xml
XML_FILE="$ASSET_MANIFEST_PATH/OfficialBuild.xml"

if [ ! -f "$XML_FILE" ]; then
echo "Error: OfficialBuild.xml not found at $XML_FILE"
ls -la "$ASSET_MANIFEST_PATH" || echo "AssetManifests directory not found"
exit 1
fi

# Extract version for Microsoft.CodeAnalysis package
VERSION=$(grep -oP 'Id="Microsoft\.CodeAnalysis"[^>]*Version="\K[^"]+' "$XML_FILE" | head -n1)

if [ -z "$VERSION" ]; then
# Try Microsoft.CodeAnalysis.Common
VERSION=$(grep -oP 'Id="Microsoft\.CodeAnalysis\.Common"[^>]*Version="\K[^"]+' "$XML_FILE" | head -n1)
fi

if [ -n "$VERSION" ]; then
echo "##vso[task.setvariable variable=RoslynVersion]$VERSION"
echo "Latest Roslyn version from AssetManifest: $VERSION"
else
echo "Error: Could not extract version from AssetManifest"
exit 1
fi

# Display the END SHA from pipeline resource
echo "Using END SHA from pipeline resource: $(RoslynEndSHA)"

- task: Bash@3
displayName: Get current Roslyn SHA from package
inputs:
targetType: inline
script: |
set -euo pipefail

# Read current version from package.json
CURRENT_VERSION=$(jq -r '.defaults.roslyn // empty' package.json)

if [ -z "$CURRENT_VERSION" ]; then
echo "No roslyn version in package.json, this is first run"
echo "##vso[task.setvariable variable=RoslynStartSHA]0000000000000000000000000000000000000000"
exit 0
fi

echo "Current Roslyn version: $CURRENT_VERSION"

# Download and extract commit SHA from NuGet package
TEMP_DIR=$(mktemp -d)
cd "$TEMP_DIR"

PACKAGE_NAME="microsoft.codeanalysis.common"
DOTNET_TOOLS_FEED="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/flat2"
PACKAGE_URL="$DOTNET_TOOLS_FEED/$PACKAGE_NAME/$CURRENT_VERSION/$PACKAGE_NAME.$CURRENT_VERSION.nupkg"

if curl -f -L -o package.nupkg "$PACKAGE_URL" 2>/dev/null; then
unzip -q package.nupkg
NUSPEC_FILE=$(find . -name "*.nuspec" -type f | head -n1)
if [ -n "$NUSPEC_FILE" ]; then
START_SHA=$(grep -oP 'repository[^>]*commit="\K[a-f0-9]{40}' "$NUSPEC_FILE" | head -n1 || echo "")
if [ -n "$START_SHA" ]; then
echo "##vso[task.setvariable variable=RoslynStartSHA]$START_SHA"
echo "Current Roslyn SHA: $START_SHA"
fi
fi
fi

cd - >/dev/null
rm -rf "$TEMP_DIR"

- task: Bash@3
displayName: Check if update needed
inputs:
targetType: inline
script: |
set -euo pipefail

echo "START SHA: $(RoslynStartSHA)"
echo "END SHA: $(RoslynEndSHA)"
echo "New Roslyn Version: $(RoslynVersion)"

if [ "$(RoslynStartSHA)" = "$(RoslynEndSHA)" ]; then
echo "No new commits to process"
echo "##vso[task.setvariable variable=SkipUpdate]true"
else
echo "Update needed: $(RoslynStartSHA)..$(RoslynEndSHA)"
echo "##vso[task.setvariable variable=SkipUpdate]false"
fi

- task: Bash@3
displayName: Clone Roslyn repository
condition: ne(variables['SkipUpdate'], 'true')
inputs:
targetType: inline
script: |
git clone --no-tags --filter=blob:none --depth=500 https://github.com/dotnet/roslyn.git roslyn

- task: Bash@3
displayName: Setup auth for roslyn-tools
condition: ne(variables['SkipUpdate'], 'true')
inputs:
targetType: inline
script: |
set -euo pipefail
mkdir -p "$HOME/.roslyn-tools"
JSON=$(printf '{"GitHubToken":"$(System.AccessToken)","DevDivAzureDevOpsToken":"","DncEngAzureDevOpsToken":""}')
printf '%s' "$JSON" | base64 | tr -d '\n' > "$HOME/.roslyn-tools/settings"

- task: Bash@3
displayName: Generate PR list
condition: ne(variables['SkipUpdate'], 'true')
inputs:
targetType: inline
script: |
set -euo pipefail
cd roslyn

# Run pr-finder with VSCode label
OUTPUT=$(roslyn-tools pr-finder \
-s "$(RoslynStartSHA)" \
-e "$(RoslynEndSHA)" \
--format changelog \
--label VSCode 2>/dev/null || echo "")

if [ -z "$OUTPUT" ]; then
echo "(no PRs with required labels)" > ../pr-changelog.txt
else
printf "%s\n" "$OUTPUT" > ../pr-changelog.txt
fi

cd ..
cat pr-changelog.txt

- task: Bash@3
displayName: Update CHANGELOG and package.json
condition: ne(variables['SkipUpdate'], 'true')
inputs:
targetType: inline
script: |
set -euo pipefail

# Update package.json with new Roslyn version from AssetManifest
jq --arg ver "$(RoslynVersion)" '.defaults.roslyn = $ver' package.json > package.json.tmp
mv package.json.tmp package.json

# Update CHANGELOG.md
PR_LIST=$(cat pr-changelog.txt | sed 's/^/ /')

# Read the current CHANGELOG
CHANGELOG_CONTENT=$(cat CHANGELOG.md)

# Find and update the Roslyn bump line
echo "$CHANGELOG_CONTENT" | awk -v version="$(RoslynVersion)" -v prs="$PR_LIST" '
/^\* Bump Roslyn to/ {
print "* Bump Roslyn to " version " (PR: [#TBD](TBD))"
if (prs != " (no PRs with required labels)") {
print prs
}
next
}
/^ \*/ && prev ~ /^\* Bump Roslyn to/ {
next
}
{
prev = $0
print
}
' > CHANGELOG.md.tmp

mv CHANGELOG.md.tmp CHANGELOG.md

- task: Bash@3
displayName: Create and push branch
condition: ne(variables['SkipUpdate'], 'true')
inputs:
targetType: inline
script: |
set -euo pipefail

# Configure git
git config user.name "Azure Pipelines"
git config user.email "azuredevops@microsoft.com"

# Create branch using the first 8 chars of END SHA for shorter branch name
SHORT_SHA=$(echo "$(RoslynEndSHA)" | cut -c1-8)
BRANCH_NAME="roslyn-bump/$SHORT_SHA"
git checkout -b "$BRANCH_NAME"

# Commit changes
git add package.json CHANGELOG.md
git commit -m "Bump Roslyn to $(RoslynVersion)"

# Push branch
git push origin "$BRANCH_NAME"

echo "##vso[task.setvariable variable=PrBranch]$BRANCH_NAME"

- task: Bash@3
displayName: Create Pull Request
condition: and(ne(variables['SkipUpdate'], 'true'), eq('${{ parameters.createPullRequest }}', 'true'))
inputs:
targetType: inline
script: |
set -euo pipefail

# Create PR using Azure DevOps REST API
PR_TITLE="Bump Roslyn to $(RoslynVersion)"
PR_DESCRIPTION="Manual Roslyn version bump triggered by $(Build.RequestedFor).\n\n**Version:** \`$(RoslynVersion)\`\n**Commit Range:** \`$(RoslynStartSHA)...$(RoslynEndSHA)\`\n**Azure DevOps Build:** [$(RoslynBuildNumber)](https://dev.azure.com/dnceng/internal/_build/results?buildId=$(RoslynBuildId))\n\nSee CHANGELOG.md for included PRs."

# You would need to use Azure DevOps REST API or GitHub API here
# This is a placeholder for the actual PR creation
echo "Pull request would be created with:"
echo "Title: $PR_TITLE"
echo "Branch: $(PrBranch)"
echo "Target: ${{ parameters.targetBranch }}"
echo "Description: $PR_DESCRIPTION"
/^\* Bump Roslyn to/ {
print "* Bump Roslyn to " version " (PR: [#TBD](TBD))"
if (prs != " (no PRs with required labels)") {
print prs
}
next
}
/^ \*/ && prev ~ /^\* Bump Roslyn to/ {
next
}
{
prev = $0
print
}
' > CHANGELOG.md.tmp

mv CHANGELOG.md.tmp CHANGELOG.md