Skip to content
Closed
Show file tree
Hide file tree
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
98 changes: 98 additions & 0 deletions azure-pipelines/dotnet-vscode-csharp-insertion.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
trigger: none
pr: none

parameters:
- name: targetBranch
displayName: Target Branch for PR
type: string
default: main

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

variables:
- name: RoslynEndSHA
value: $(resources.pipeline.officialBuildCI.sourceCommit)
- name: RoslynBuildNumber
value: $(resources.pipeline.officialBuildCI.runName)
- name: RoslynBuildId
value: $(resources.pipeline.officialBuildCI.runID)
- template: dotnet-variables.yml

extends:
template: v1/1ES.Unofficial.PipelineTemplate.yml@1ESPipelineTemplates
parameters:
pool:
name: netcore1espool-internal
image: 1es-ubuntu-2204
os: linux
stages:
- stage: BumpRoslyn
displayName: Bump Roslyn Version
jobs:
- job: ProcessBump
displayName: Process Roslyn Bump
pool:
name: netcore1espool-internal
image: 1es-ubuntu-2204
os: linux
steps:
- checkout: self
persistCredentials: true

- task: UseDotNet@2
displayName: Install .NET SDK
inputs:
version: $(defaultDotnetVersion)

- template: install-node.yml

- task: DownloadPipelineArtifact@2
displayName: Download Asset Manifests
inputs:
source: specific
project: internal
pipeline: dotnet-roslyn-official
runVersion: specific
runId: $(RoslynBuildId)
artifact: AssetManifests
path: $(Pipeline.Workspace)/AssetManifests

- pwsh: |
npm ci
npm install
npm install -g gulp
gulp installDependencies
displayName: 'Install npm dependencies and gulp'
- checkout: RoslynMirror
displayName: 'Checkout Roslyn repository'
path: roslyn

- script: |
echo "Installing roslyn-tools..."
dotnet tool install -g Microsoft.RoslynTools --prerelease --add-source https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json
echo "Verifying roslyn-tools installation..."
dotnet tool list -g
roslyn-tools --version
displayName: 'Install roslyn-tools CLI'

- task: Npm@1
displayName: Run Roslyn insertion
inputs:
command: custom
customCommand: 'run gulp -- insertion:roslyn --assetManifestPath=$(Pipeline.Workspace)/AssetManifests --roslynRepoPath=$(Pipeline.Workspace)/roslyn --roslynEndSHA=$(RoslynEndSHA) --roslynBuildNumber=$(RoslynBuildNumber) --roslynBuildId=$(RoslynBuildId) --targetBranch=${{ parameters.targetBranch }} --githubPAT=$(BotAccount-dotnet-bot-repo-PAT) --dryRun=false'


1 change: 1 addition & 0 deletions gulpfile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ require('./tasks/debuggerTasks');
require('./tasks/snapTasks');
require('./tasks/signingTasks');
require('./tasks/profilingTasks');
require('./tasks/insertionTasks');
require('./tasks/componentUpdateTasks');
56 changes: 2 additions & 54 deletions tasks/createTagsTasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,10 @@
*--------------------------------------------------------------------------------------------*/

import * as gulp from 'gulp';
import * as fs from 'fs';
import minimist from 'minimist';
import { Octokit } from '@octokit/rest';
import { allNugetPackages, NugetPackageInfo, platformSpecificPackages } from './offlinePackagingTasks';
import { PlatformInformation } from '../src/shared/platform';
import path from 'path';
import { allNugetPackages } from './offlinePackagingTasks';
import { getCommitFromNugetAsync } from './gitTasks';

interface CreateTagsOptions {
releaseVersion: string;
Expand Down Expand Up @@ -194,53 +192,3 @@ function logWarning(message: string): void {
function logError(message: string): void {
console.log(`##vso[task.logissue type=error]${message}`);
}

async function getCommitFromNugetAsync(packageInfo: NugetPackageInfo): Promise<string | null> {
const packageJsonString = fs.readFileSync('./package.json').toString();
const packageJson = JSON.parse(packageJsonString);
const packageVersion = packageJson['defaults'][packageInfo.packageJsonName];
if (!packageVersion) {
logError(`Can't find ${packageInfo.packageJsonName} version in package.json`);
return null;
}

const platform = await PlatformInformation.GetCurrent();
const vsixPlatformInfo = platformSpecificPackages.find(
(p) => p.platformInfo.platform === platform.platform && p.platformInfo.architecture === platform.architecture
)!;

const packageName = packageInfo.getPackageName(vsixPlatformInfo);
console.log(`${packageName} version is ${packageVersion}`);

// Nuget package should exist under out/.nuget/ since we have run the install dependencies task.
// Package names are always lower case in the .nuget folder.
const packageDir = path.join('out', '.nuget', packageName.toLowerCase(), packageVersion);
const nuspecFiles = fs.readdirSync(packageDir).filter((file) => file.endsWith('.nuspec'));

if (nuspecFiles.length === 0) {
logError(`No .nuspec file found in ${packageDir}`);
return null;
}

if (nuspecFiles.length > 1) {
logError(`Multiple .nuspec files found in ${packageDir}`);
return null;
}

const nuspecFilePath = path.join(packageDir, nuspecFiles[0]);
const nuspecFile = fs.readFileSync(nuspecFilePath).toString();
const results = /commit="(.*)"/.exec(nuspecFile);
if (results == null || results.length == 0) {
logError('Failed to find commit number from nuspec file');
return null;
}

if (results.length != 2) {
logError('Unexpected regex match result from nuspec file.');
return null;
}

const commitNumber = results[1];
console.log(`commitNumber is ${commitNumber}`);
return commitNumber;
}
134 changes: 133 additions & 1 deletion tasks/gitTasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,29 @@
*--------------------------------------------------------------------------------------------*/

import { spawnSync } from 'child_process';
import * as fs from 'fs';
import * as path from 'path';
import { Octokit } from '@octokit/rest';
import { NugetPackageInfo, platformSpecificPackages } from './offlinePackagingTasks';
import { PlatformInformation } from '../src/shared/platform';

export interface GitOptions {
commitSha: string;
targetRemoteRepo: string;
baseBranch: string;
}

export interface BranchAndPROptions extends GitOptions {
githubPAT: string;
dryRun: boolean;
newBranchName: string;
userName?: string;
email?: string;
}

export function logError(message: string): void {
console.log(`##vso[task.logissue type=error]${message}`);
}

/**
* Execute a git command with optional logging
Expand Down Expand Up @@ -55,7 +77,7 @@ export async function createCommit(branch: string, files: string[], commitMessag
* Check if a branch exists on the remote repository
*/
export async function doesBranchExist(remoteAlias: string, branch: string): Promise<boolean> {
const lsRemote = await git(['ls-remote', remoteAlias, 'refs/head/' + branch]);
const lsRemote = await git(['ls-remote', remoteAlias, 'refs/heads/' + branch]);
return lsRemote.trim() !== '';
}

Expand Down Expand Up @@ -146,3 +168,113 @@ export async function createPullRequest(
return null;
}
}

export async function getCommitFromNugetAsync(packageInfo: NugetPackageInfo): Promise<string | null> {
try {
const packageJsonString = fs.readFileSync('./package.json').toString();
const packageJson = JSON.parse(packageJsonString);
const packageVersion = packageJson['defaults'][packageInfo.packageJsonName];
if (!packageVersion) {
logError(`Can't find ${packageInfo.packageJsonName} version in package.json`);
return null;
}

const platform = await PlatformInformation.GetCurrent();
const vsixPlatformInfo = platformSpecificPackages.find(
(p) => p.platformInfo.platform === platform.platform && p.platformInfo.architecture === platform.architecture
)!;

const packageName = packageInfo.getPackageName(vsixPlatformInfo);
console.log(`${packageName} version is ${packageVersion}`);

// Nuget package should exist under out/.nuget/ since we have run the install dependencies task.
// Package names are always lower case in the .nuget folder.
const packageDir = path.join('out', '.nuget', packageName.toLowerCase(), packageVersion);
const nuspecFiles = fs.readdirSync(packageDir).filter((file) => file.endsWith('.nuspec'));

if (nuspecFiles.length === 0) {
logError(`No .nuspec file found in ${packageDir}`);
return null;
}

if (nuspecFiles.length > 1) {
logError(`Multiple .nuspec files found in ${packageDir}`);
return null;
}

const nuspecFilePath = path.join(packageDir, nuspecFiles[0]);
const nuspecFile = fs.readFileSync(nuspecFilePath).toString();
const results = /commit="(.*?)"/.exec(nuspecFile);
if (results == null || results.length === 0) {
logError('Failed to find commit number from nuspec file');
return null;
}

if (results.length !== 2) {
logError('Unexpected regex match result from nuspec file.');
return null;
}

const commitNumber = results[1];
console.log(`commitNumber is ${commitNumber}`);
return commitNumber;
} catch (error) {
logError(`Error getting commit from NuGet package: ${error}`);
if (error instanceof Error && error.stack) {
console.log(`##[debug]${error.stack}`);
}
throw error;
}
}

export async function createBranchAndPR(
options: BranchAndPROptions,
title: string,
commitMessage: string,
body?: string
): Promise<number | null> {
const { githubPAT, targetRemoteRepo, baseBranch, dryRun, userName, email, newBranchName } = options;

// Configure git user credentials
await configureGitUser(userName, email);

// Create branch and commit changes
await createCommit(newBranchName, ['.'], commitMessage);

if (dryRun !== true) {
// Push branch to remote
await pushBranch(newBranchName, githubPAT, 'dotnet', targetRemoteRepo);
} else {
console.log('[DRY RUN] Would have pushed branch to remote');
}

// Check for existing PR and create new one if needed
const existingPRUrl = await findPRByTitle(githubPAT, 'dotnet', targetRemoteRepo, title);
if (existingPRUrl) {
console.log('Pull request with the same name already exists. Skip creation.');
return null;
}

if (dryRun !== true) {
const prUrl = await createPullRequest(
githubPAT,
'dotnet',
targetRemoteRepo,
newBranchName,
title,
body || title,
baseBranch
);

if (prUrl) {
console.log(`Created pull request: ${prUrl}.`);
// Extract PR number from URL (format: https://github.com/owner/repo/pull/123)
const prNumberMatch = prUrl.match(/\/pull\/(\d+)$/);
return prNumberMatch ? parseInt(prNumberMatch[1], 10) : null;
}
return null;
} else {
console.log(`[DRY RUN] Would have created PR with title: "${title}" and body: "${body || title}"`);
return null;
}
}
Loading