diff --git a/.scripts/clean-autopr.ts b/.scripts/clean-autopr.ts index 71015f352064..d1860e2c47ae 100644 --- a/.scripts/clean-autopr.ts +++ b/.scripts/clean-autopr.ts @@ -5,46 +5,53 @@ */ import { exec as execWithCallback } from "child_process"; -import { getAuthenticatedClient } from "./github"; -import { PullRequestsGetAllParams } from "@octokit/rest"; +import Octokit from "@octokit/rest"; -const _repositoryOwner = "Azure"; +export function getToken(): string { + const token: string = process.env.SDK_GEN_GITHUB_TOKEN || ""; + _validatePersonalAccessToken(token); + + return token; +} + +function _validatePersonalAccessToken(token: string): void { + if (!token) { + const text = + `Github personal access token was not found as a script parameter or as an + environmental variable. Please visit https://github.com/settings/tokens, + generate new token with "repo" scope and pass it with -token switch or set + it as environmental variable named SDK_GEN_GITHUB_TOKEN.` + + console.error(text); + } +} + +export function getAuthenticatedClient(): Octokit { + const octokit = new Octokit({ auth: getToken()}); + return octokit; +} async function cleanBranches() { const octokit = getAuthenticatedClient(); - const params: PullRequestsGetAllParams = { - owner: _repositoryOwner, + const params: Octokit.PullsListParams = { + owner: "Azure", repo: "azure-sdk-for-js", - state: "open" + state: "open", + per_page: 100 } - let pullRequestsResponse = await octokit.pullRequests.getAll(params); - - do { - const autoPullRequests = pullRequestsResponse.data.filter(pr => pr.title.startsWith("[AutoPR")).map(pr => pr.head.ref); - console.log(JSON.stringify(autoPullRequests, undefined, " ")); - console.log(JSON.stringify(autoPullRequests.length, undefined, " ")); - - for (const branch of autoPullRequests) { - try { - await exec(`git push origin :${branch}`); - } catch (err) { - console.log(`Branch ${branch} doesn't exist. Skipping. Error: [${err}]`); - } - } + let pullRequestsResponse = await octokit.pulls.list(params); + const autoPullRequests = pullRequestsResponse.data.filter(pr => pr.title.startsWith("[AutoPR")).map(pr => pr.head.ref); + console.log(JSON.stringify(autoPullRequests, undefined, " ")); + console.log(`Found ${autoPullRequests.length} branches`); - if (octokit.hasFirstPage(pullRequestsResponse)) { - pullRequestsResponse = await octokit.getNextPage(pullRequestsResponse); - } else { - break; + for (const branch of autoPullRequests) { + try { + await exec(`git push origin :${branch}`); + } catch (err) { + console.log(`Branch ${branch} doesn't exist. Skipping. Error: [${err}]`); } - } while (true); -} - -try { - cleanBranches(); -} catch (err) { - console.error(err); + } } async function exec(command: string): Promise { @@ -59,3 +66,9 @@ async function exec(command: string): Promise { }); }); } + +try { + cleanBranches(); +} catch (err) { + console.error(err); +} diff --git a/.scripts/git.ts b/.scripts/git.ts deleted file mode 100644 index 6c0cc46e9819..000000000000 --- a/.scripts/git.ts +++ /dev/null @@ -1,321 +0,0 @@ -/** - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for - * license information. - */ - -import { Cred, Index, Merge, Oid, Reference, Repository, Reset, Signature, StatusFile, Branch as NodeBranch, MergeOptions } from "nodegit"; -import { Logger } from "./logger"; - -export type ValidateFunction = (statuses: StatusFile[]) => boolean; -export type ValidateEachFunction = (path: string, matchedPatter: string) => number; - -export enum BranchLocation { - Local = "heads", - Remote = "remotes" -} - -export class Branch { - static LocalMaster = new Branch("master", BranchLocation.Local); - static RemoteMaster = new Branch("master", BranchLocation.Remote); - - constructor(public name: string, public location: BranchLocation, public remote: string = "origin") { - } - - shorthand(): string { - return `${this.remote}/${this.name}`; - } - - fullName(): string { - if (this.name.startsWith("refs")) { - return this.name; - } - - return `refs/${this.location}/${this.remote}/${this.name}`; - } - - fullNameWithoutRemote(): string { - if (this.name.startsWith("refs")) { - return this.name; - } - - return `refs/${this.location}/${this.name}`; - } - - convertTo(location: BranchLocation): Branch { - if (this.location == location) { - return this; - } - - return new Branch(this.name, location, this.remote); - } - - toRemote(): Branch { - return this.convertTo(BranchLocation.Remote); - } - - toLocal(): Branch { - return this.convertTo(BranchLocation.Local); - } - - static fromReference(reference: Reference) { - const fullName = reference.name(); - const parts = fullName.split("/"); - return new Branch(parts.slice(2).join("/"), reference.isRemote() ? BranchLocation.Remote : BranchLocation.Local); - } -} - -const _logger = Logger.get(); -const _lockMap: { [key: string]: boolean } = {} - -function isLocked(repositoryPath: string): boolean { - return !!_lockMap[repositoryPath]; -} - -function lock(repositoryPath: string) { - _lockMap[repositoryPath] = true; -} - -function unlock(repositoryPath: string) { - _lockMap[repositoryPath] = false; -} - -async function waitUntilUnlocked(repositoryPath: string): Promise { - _logger.logTrace("Waiting for the repository to be unlocked"); - - return new Promise((resolve) => { - const wait = () => { - setTimeout(() => { - _logger.logTrace(`Repository is ${isLocked(repositoryPath) ? "locked" : "unlocked"}`); - - if (isLocked(repositoryPath)) { - wait(); - } else { - resolve(); - } - }, 50); - } - - wait(); - }); -} - -export async function waitAndLockGitRepository(repository: Repository): Promise { - _logger.logTrace("Waiting to lock the repository"); - const repositoryPath = repository.path(); - - await waitUntilUnlocked(repositoryPath); - if (!isLocked(repositoryPath)) { - lock(repositoryPath); - return isLocked(repositoryPath); - } - - return waitAndLockGitRepository(repository); -} - -export function unlockGitRepository(repository: Repository) { - _logger.logTrace("Unlocking the repository"); - unlock(repository.path()); -} - -export async function openRepository(repositoryPath: string): Promise { - _logger.logTrace(`Opening Git repository located in ${repositoryPath}`); - return Repository.open(repositoryPath) -} - -export async function validateRepositoryStatus(repository: Repository): Promise { - const status = await repository.getStatus(); - _logger.logTrace(`Current repository status: ${JSON.stringify(status)}`); - - if (status && status.length > 0) { - return Promise.reject(`Not committed changes exist in ${repository.path()} repository`); - } - - _logger.logTrace(`Status of the repository validated successfully`); -} - -export async function getValidatedRepository(repositoryPath: string): Promise { - const repository = await openRepository(repositoryPath); - await validateRepositoryStatus(repository); - await repository.fetchAll(); - return repository; -} - -export async function mergeBranch(repository: Repository, toBranch: Branch, fromBranch: Branch, mergeOptions?: MergeOptions): Promise { - _logger.logTrace(`Merging "${fromBranch.fullName()}" to "${toBranch.fullName()}" branch in ${repository.path()} repository`); - try { - return repository.mergeBranches(toBranch.name, fromBranch.shorthand(), Signature.default(repository), Merge.PREFERENCE.NONE, mergeOptions); - } catch (error) { - throw new Error(`Probable merge conflicts. Error: ${error}`); - } -} - -export async function mergeMasterIntoBranch(repository: Repository, toBranch: Branch, mergeOptions?: MergeOptions): Promise { - return mergeBranch(repository, toBranch, Branch.RemoteMaster, mergeOptions); -} - -export async function pullBranch(repository: Repository, localBranch: Branch, mergeOptions?: MergeOptions): Promise { - _logger.logTrace(`Pulling "${localBranch.fullName()}" branch in ${repository.path()} repository`); - - await repository.fetchAll(); - _logger.logTrace(`Fetched all successfully`); - - const remoteBranch = new Branch(localBranch.name, BranchLocation.Remote, localBranch.remote); - await mergeBranch(repository, localBranch, remoteBranch, mergeOptions); - - const index = await repository.index(); - if (index.hasConflicts()) { - throw new Error(`Conflict while pulling ${remoteBranch.fullName()}`); - } - - _logger.logTrace(`Merged "${remoteBranch.fullName()}" to "${localBranch.fullName()}" successfully without any conflicts`); -} - -export async function pullMaster(repository: Repository): Promise { - return pullBranch(repository, Branch.LocalMaster); -} - -export async function createNewBranch(repository: Repository, branchName: string, checkout?: boolean): Promise { - _logger.logTrace(`Create new branch "${branchName}" in ${repository.path()} repository`); - - const headCommit = await repository.getHeadCommit(); - const branchPromise = repository.createBranch(branchName, headCommit, false); - _logger.logTrace(`Created new branch "${branchName}" successfully`); - - if (!checkout) { - return branchPromise; - } else { - const branch = await branchPromise; - return checkoutBranch(repository, branch.shorthand()); - } -} - -export async function checkoutRemoteBranch(repository: Repository, remoteBranch: Branch): Promise { - _logger.logTrace(`Checking out "${remoteBranch.fullName()}" remote branch`); - - const branchNames = await repository.getReferenceNames(Reference.TYPE.LISTALL); - const localBranch = remoteBranch.toLocal(); - const branchExists = branchNames.some(name => name === localBranch.fullNameWithoutRemote()); - _logger.logTrace(`Branch exists: ${branchExists}`); - - let branchRef: Reference; - if (branchExists) { - branchRef = await checkoutBranch(repository, remoteBranch.name); - } else { - branchRef = await createNewBranch(repository, remoteBranch.name); - await NodeBranch.setUpstream(branchRef, remoteBranch.shorthand()); - const commit = await repository.getReferenceCommit(remoteBranch.name); - await checkoutBranch(repository, branchRef); - await Reset.reset(repository, commit as any, Reset.TYPE.HARD, {}); - } - - return branchRef; -} - -export async function rebaseBranch(repository: Repository, localBranch: Branch): Promise { - return repository.rebaseBranches( - localBranch.name, - Branch.RemoteMaster.shorthand(), - "", - repository.defaultSignature(), - (_: any) => {}); -} - -function getCurrentDateSuffix(): string { - const now = new Date(); - return `${now.getFullYear()}-${now.getMonth() + 1}-${now.getDate()}-${now.getMilliseconds()}`; -} - -export async function createNewUniqueBranch(repository: Repository, branchPrefix: string, checkout?: boolean): Promise { - return createNewBranch(repository, `${branchPrefix}-${getCurrentDateSuffix()}`, checkout); -} - -export async function checkoutBranch(repository: Repository, branchName: string | Reference): Promise { - _logger.logTrace(`Checking out "${branchName}" branch`); - return repository.checkoutBranch(branchName); -} - -export async function checkoutMaster(repository: Repository): Promise { - return checkoutBranch(repository, "master"); -} - -export async function refreshRepository(repository: Repository) { - await repository.fetchAll(); - await pullMaster(repository); - return checkoutMaster(repository); -} - -export async function commitChanges(repository: Repository, commitMessage: string, validateStatus?: ValidateFunction, validateEach?: string | ValidateEachFunction): Promise { - _logger.logTrace(`Committing changes in "${repository.path()}" repository`); - - validateStatus = validateStatus || ((_) => true); - validateEach = validateEach || ((_, __) => 0); - - const status = await repository.getStatus(); - if (!validateStatus(status)) { - return Promise.reject("Unknown changes present in the repository"); - } - - const index = await repository.refreshIndex(); - if (typeof validateEach === "string") { - const folderName = validateEach; - validateEach = (path) => { - return path.startsWith(folderName) ? 0 : 1; - } - } - - await index.addAll("*", Index.ADD_OPTION.ADD_CHECK_PATHSPEC, validateEach); - - await index.write(); - const oid = await index.writeTree(); - - const head = await repository.getHeadCommit(); - const author = Signature.default(repository); - - return repository.createCommit("HEAD", author, author, commitMessage, oid, [head]); -} - -export async function pushBranch(repository: Repository, localBranch: Branch, forcePush?: boolean): Promise { - const remote = await repository.getRemote("origin"); - const refSpec = `${forcePush ? "+" : ""}refs/heads/${localBranch.name}:refs/heads/${localBranch.name}`; - _logger.logTrace(`Pushing to ${refSpec}`); - - return new Promise((resolve, reject) => { - remote.push([refSpec], { - callbacks: { - credentials: () => { - return Cred.userpassPlaintextNew(getToken(), "x-oauth-basic"); - } - } - }).then(result => { - resolve(result); - }).catch(error => { - _logger.logError(error); - reject(error); - }) - }); -} - -export async function commitAndPush(repository: Repository, localBranch: Branch, commitMessage: string, validate?: ValidateFunction, validateEach?: string | ValidateEachFunction, forcePush?: boolean): Promise { - await commitChanges(repository, commitMessage, validate, validateEach); - await pushBranch(repository, localBranch, forcePush); -} - -export function getToken(): string { - const token: string = process.env.SDK_GEN_GITHUB_TOKEN || ""; - _validatePersonalAccessToken(token); - - return token; -} - -function _validatePersonalAccessToken(token: string): void { - if (!token) { - const text = - `Github personal access token was not found as a script parameter or as an - environmental variable. Please visit https://github.com/settings/tokens, - generate new token with "repo" scope and pass it with -token switch or set - it as environmental variable named SDK_GEN_GITHUB_TOKEN.` - - _logger.logError(text); - } -} diff --git a/.scripts/github.ts b/.scripts/github.ts deleted file mode 100644 index 8fbcf6f4b0e4..000000000000 --- a/.scripts/github.ts +++ /dev/null @@ -1,184 +0,0 @@ -/** - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for - * license information. - */ - -import Octokit, { PullRequestsCreateParams, PullRequestsCreateReviewRequestParams, PullRequestsCreateReviewRequestResponse, PullRequestsGetAllParams, PullRequestsGetAllResponse, PullRequestsGetAllResponseItem, PullRequestsGetParams, PullRequestsUpdateParams, Response } from '@octokit/rest'; -import { Reference, Repository } from 'nodegit'; -import { Branch, commitChanges, createNewUniqueBranch, getToken, pushBranch, ValidateEachFunction, ValidateFunction } from './git'; -import { Logger } from './logger'; -import * as path from "path"; - -const _repositoryOwner = "Azure"; -const _logger = Logger.get(); - -export function getAuthenticatedClient(): Octokit { - const octokit = new Octokit(); - octokit.authenticate({ type: "token", token: getToken() }); - return octokit; -} - -export async function createPullRequest(repositoryName: string, pullRequestTitle: string, body: string, sourceBranchName: string, destinationBranchName: string = "master"): Promise> { - const octokit = getAuthenticatedClient(); - const prOptions: PullRequestsCreateParams = { - owner: _repositoryOwner, - repo: repositoryName, - title: pullRequestTitle, - head: sourceBranchName, - base: destinationBranchName, - body: body - }; - - return new Promise>((resolve, reject) => { - octokit.pullRequests.create(prOptions, (error, response) => { - if (error) { - reject(error); - } else { - resolve(response); - } - }); - }); -} - -export async function listPullRequests(repositoryName: string, state?: "open" | "closed" | "all"): Promise> { - const octokit = getAuthenticatedClient(); - const params: PullRequestsGetAllParams = { - owner: _repositoryOwner, - repo: repositoryName, - state: state - } - - return new Promise>((resolve, reject) => { - octokit.pullRequests.getAll(params, (error, result) => { - if (error) { - reject(error); - } else { - resolve(result); - } - }); - }); -} - -export async function findPullRequest(repositoryName: string, branchName: string, state?: "open" | "closed" | "all"): Promise { - const allPullRequests = await listPullRequests(repositoryName, state); - return allPullRequests.data.find(el => el.head.ref === branchName); -} - -export async function requestPullRequestReview(repositoryName: string, prId: number): Promise> { - const octokit = getAuthenticatedClient(); - const params: PullRequestsCreateReviewRequestParams = { - owner: _repositoryOwner, - repo: repositoryName, - number: prId, - reviewers: ["daschult", "amarzavery", "sergey-shandar"] - }; - - return new Promise>((resolve, reject) => { - octokit.pullRequests.createReviewRequest(params, (error, response) => { - if (error) { - reject(error); - } else { - resolve(response); - } - }); - }); -} - -export async function commitAndCreatePullRequest( - repository: Repository, - packageName: string, - commitMessage: string, - repositoryName: string, - pullRequestTitle: string, - pullRequestDescription: string, - validate?: ValidateFunction, - validateEach?: string | ValidateEachFunction): Promise { - await createNewUniqueBranch(repository, `generated/${packageName}`, true); - - await commitChanges(repository, commitMessage, validate, validateEach); - const newBranchRef: Reference = await repository.getCurrentBranch(); - const newBranch: Branch = Branch.fromReference(newBranchRef); - _logger.logInfo(`Committed changes successfully on ${newBranch.name} branch`); - - await pushBranch(repository, newBranch); - _logger.logInfo(`Pushed changes successfully to ${newBranch.name} branch`); - - const pullRequestResponse = await createPullRequest(repositoryName, pullRequestTitle, pullRequestDescription, newBranchRef.name()); - _logger.logInfo(`Created pull request successfully - ${pullRequestResponse.data.html_url}`); - - const reviewResponse = await requestPullRequestReview(repositoryName, pullRequestResponse.data.number); - _logger.logInfo(`Requested preview on pull request successfully - ${reviewResponse.data.html_url}`); - - return reviewResponse.data.html_url; -} - -export async function getDataFromPullRequest(pullRequestUrl: string): Promise<{ packageName: string | undefined, branchName: string, prId: number }> { - const octokit: Octokit = getAuthenticatedClient(); - const params: Octokit.PullRequestsGetParams = parsePullRequestUrl(pullRequestUrl); - const pullRequest: Octokit.Response = await octokit.pullRequests.get(params); - const branchName: string = pullRequest.data.head.ref; - const files: Octokit.Response = await octokit.pullRequests.getFiles(params); - const rootPath: string = getRootFolder(files.data.map(i => i.filename)); - const packageJson = require(path.join(rootPath, "package.json")); - const packageName: string | undefined = packageJson.name; - - _logger.logTrace(`Found "${packageName}" package name and ${branchName} branch name`) - return { packageName: packageName, branchName: branchName, prId: params.number }; -} - -function parsePullRequestUrl(pullRequestUrl: string): PullRequestsGetParams { - const parts = pullRequestUrl.split("/"); - const hostIndex = parts.indexOf("github.com") - const owner = parts[hostIndex + 1]; - const repositoryName = parts[hostIndex + 2]; - const resourceIndex = parts.indexOf("pull"); - const id = Number.parseInt(parts[resourceIndex + 1]); - - return { - number: id, - owner: owner, - repo: repositoryName - }; -} - -function getRootFolder(changedFiles: string[]): string { - const pathsParts = changedFiles.map(changedFile => changedFile.split("/")); - let commonParts = []; - if (changedFiles.length == 1) { - const parts = pathsParts[0]; - commonParts = parts.slice(0, parts.length - 1); - } else { - const partCount = Math.max(...pathsParts.map(arr => arr.length)); - - for (let partIndex = 0; partIndex < partCount; partIndex++) { - const part = pathsParts[0][partIndex]; - const partArray = pathsParts.map(p => p[partIndex]); - - if (partArray.every(p => p === part)) { - commonParts.push(part); - continue; - } - - break; - } - } - - const commonPath = commonParts.join("/"); - _logger.logTrace(`Found "${commonPath}" common path for files in the pull request`) - - return commonPath; -} - -export async function forcePrDiffRefresh(repositoryName: string, pullRequestId: number) { - const octokit = getAuthenticatedClient(); - const params: PullRequestsUpdateParams = { - owner: _repositoryOwner, - repo: repositoryName, - number: pullRequestId, - base: "force-pr-diff-update" - } - await octokit.pullRequests.update(params) - params.base = "master"; - return octokit.pullRequests.update(params) -} diff --git a/.scripts/gulp.ts b/.scripts/gulp.ts index 5738030f4d21..fd81192b3b24 100644 --- a/.scripts/gulp.ts +++ b/.scripts/gulp.ts @@ -4,19 +4,13 @@ * license information. */ -import { PullRequestsGetAllResponseItem } from "@octokit/rest"; import { execSync } from "child_process"; import fs from "fs"; import * as path from "path"; -import { SdkType } from "./commandLine"; import { contains, npmInstall } from "./common"; -import { Branch, BranchLocation, checkoutRemoteBranch, commitAndPush, getValidatedRepository, mergeMasterIntoBranch, refreshRepository, unlockGitRepository, ValidateFunction, waitAndLockGitRepository, checkoutBranch } from "./git"; -import { commitAndCreatePullRequest, findPullRequest, forcePrDiffRefresh, requestPullRequestReview } from "./github"; import { Logger } from "./logger"; -import { findMissingSdks, findSdkDirectory, saveContentToFile, getPackageInformationFromPackageJsons, PackageInfo } from "./packages"; -import { copyExistingNodeJsReadme, findReadmeTypeScriptMdFilePaths, getAbsolutePackageFolderPathFromReadmeFileContents, getPackageNamesFromReadmeTypeScriptMdFileContents, getSinglePackageName, updateMainReadmeFile, updateTypeScriptReadmeFile } from "./readme"; -import { Version } from "./version"; -import { Merge } from 'nodegit'; +import { getPackageInformationFromPackageJsons, PackageInfo } from "./packages"; +import { findReadmeTypeScriptMdFilePaths, getAbsolutePackageFolderPathFromReadmeFileContents, getPackageNamesFromReadmeTypeScriptMdFileContents } from "./readme"; import { NPMViewResult, NPMScope } from "@ts-common/azure-js-dev-tools"; const _logger = Logger.get(); @@ -90,161 +84,6 @@ export async function generateSdk(azureRestAPISpecsRoot: string, azureSDKForJSRe } } -export async function generateTsReadme(packageName: string, sdkType: SdkType, azureRestApiSpecsRepositoryPath: string, specDirectory?: string, skipSpecificationGeneration?: boolean): Promise<{ pullRequestUrl?: string, typescriptReadmePath?: string }> { - if (skipSpecificationGeneration) { - _logger.log(`Skipping spec generation`); - return {}; - } - - const azureRestApiSpecRepository = await getValidatedRepository(azureRestApiSpecsRepositoryPath); - _logger.log(`Found azure-rest-api-specs repository in ${azureRestApiSpecsRepositoryPath}`); - - await refreshRepository(azureRestApiSpecRepository); - _logger.log(`Refreshed ${azureRestApiSpecsRepositoryPath} repository successfully`); - - const sdkPath: string = specDirectory || await findSdkDirectory(azureRestApiSpecsRepositoryPath, packageName, sdkType); - _logger.log(`Found specification in ${sdkPath}`); - - await waitAndLockGitRepository(azureRestApiSpecRepository); - const typescriptReadmePath: string = await copyExistingNodeJsReadme(sdkPath); - _logger.log(`Copied readme file successfully`); - - const newContent: string = await updateTypeScriptReadmeFile(typescriptReadmePath, sdkType); - _logger.log(`Generated content of the new TypeScript readme file successfully`); - - await saveContentToFile(typescriptReadmePath, newContent); - _logger.log(`Content saved successfully to ${typescriptReadmePath}`); - - const readmeFilePath = path.resolve(sdkPath, "readme.md"); - const updatedReadmeContent: string = await updateMainReadmeFile(readmeFilePath); - _logger.log(`Updated content of the readme file successfully`); - - await saveContentToFile(readmeFilePath, updatedReadmeContent); - _logger.log(`Content saved successfully to ${readmeFilePath}`); - - const relativeReadmePath = typescriptReadmePath.replace(`${azureRestApiSpecsRepositoryPath}${path.sep}specification${path.sep}`, ""); - const pullRequestTitle = `Add ${relativeReadmePath}` - const pullRequestDescription = "Auto generated"; - const validate: ValidateFunction = statuses => statuses.length == 2; - - const pullRequestUrl = await commitAndCreatePullRequest(azureRestApiSpecRepository, packageName, pullRequestTitle, "azure-rest-api-specs", pullRequestTitle, pullRequestDescription, validate, `specification/${packageName}`); - await unlockGitRepository(azureRestApiSpecRepository); - - return { pullRequestUrl: pullRequestUrl, typescriptReadmePath: typescriptReadmePath }; -} - -export async function generateMissingSdk(azureSdkForJsRepoPath: string, packageName: string, sdkType: SdkType, azureRestApiSpecsRepositoryPath: string, skipSpecGeneration?: boolean, skipSdkGeneration?: boolean): Promise { - const readmeGenerationResult = await generateTsReadme(packageName, sdkType, azureRestApiSpecsRepositoryPath, undefined, skipSpecGeneration); - if (skipSdkGeneration) { - _logger.log(`Skipping sdk generation`); - return ""; - } - - if (readmeGenerationResult.typescriptReadmePath) { - const generatedPackageName = await getSinglePackageName(readmeGenerationResult.typescriptReadmePath); - packageName = generatedPackageName; - } - - const azureSdkForJsRepository = await getValidatedRepository(azureSdkForJsRepoPath); - await refreshRepository(azureSdkForJsRepository); - _logger.log(`Refreshed ${azureSdkForJsRepoPath} repository successfully`); - - await waitAndLockGitRepository(azureSdkForJsRepository); - await generateSdk(azureRestApiSpecsRepositoryPath, azureSdkForJsRepoPath, packageName); - _logger.log(`Generated ${packageName} SDK successfully`); - - const pullRequestTitle = `Generate ${packageName} package`; - const pullRequestDescription = - `Auto generated. Matching specification pull request - ${readmeGenerationResult.pullRequestUrl}\n\n\n -\`\`\` -${_logger.getCapturedText()} -\`\`\`` - - const validate: ValidateFunction = changes => changes.length > 0; - - const pullRequestUrl = await commitAndCreatePullRequest(azureSdkForJsRepository, packageName, pullRequestTitle, "azure-sdk-for-js", pullRequestTitle, pullRequestDescription, validate, `packages/${packageName}`); - await unlockGitRepository(azureSdkForJsRepository); - - return pullRequestUrl; -} - -export async function generateAllMissingSdks(azureSdkForJsRepoPath: string, azureRestApiSpecsRepository: string, skipSpecGeneration: boolean, skipSdkGeneration: boolean) { - const missingSdks = await findMissingSdks(azureRestApiSpecsRepository); - _logger.log(`Found ${missingSdks.length} missing specifications`); - - for (const missingSdk of missingSdks) { - try { - await generateMissingSdk(azureSdkForJsRepoPath, missingSdk.sdkName, missingSdk.sdkType, azureRestApiSpecsRepository, skipSpecGeneration, skipSdkGeneration); - } catch (error) { - _logger.logError(error); - continue; - } - } -} - -export async function regenerate(branchName: string, packageName: string, azureSdkForJsRepoPath: string, azureRestAPISpecsPath: string, pullRequestId: number, skipVersionBump?: boolean, requestReview?: boolean) { - const azureSdkForJsRepository = await getValidatedRepository(azureSdkForJsRepoPath); - const currentBranch = await azureSdkForJsRepository.getCurrentBranch(); - await refreshRepository(azureSdkForJsRepository); - _logger.log(`Refreshed ${azureSdkForJsRepository.path()} repository successfully`); - - const remoteBranch = new Branch(branchName, BranchLocation.Remote); - await checkoutRemoteBranch(azureSdkForJsRepository, remoteBranch); - _logger.log(`Checked out ${branchName} branch`); - - const localBranch = remoteBranch.convertTo(BranchLocation.Local); - await mergeMasterIntoBranch(azureSdkForJsRepository, localBranch, { fileFavor: Merge.FILE_FAVOR.THEIRS }); - _logger.log(`Merged master into ${localBranch.shorthand()} successfully`); - - if (skipVersionBump) { - _logger.log("Skipping version bump"); - } else { - await bumpMinorVersion(azureSdkForJsRepoPath, packageName); - _logger.log(`Successfully updated version in package.json`); - } - - const azureRestAPISpecsRepository = await getValidatedRepository(azureRestAPISpecsPath); - await refreshRepository(azureRestAPISpecsRepository); - _logger.log(`Refreshed ${azureRestAPISpecsRepository.path()} repository successfully`); - - await generateSdk(azureRestAPISpecsPath, azureSdkForJsRepoPath, packageName) - _logger.log(`Generated sdk successfully`); - - await commitAndPush(azureSdkForJsRepository, localBranch, `Regenerated "${packageName}" SDK.`, undefined, `packages/${packageName}`); - _logger.log(`Committed and pushed the changes successfully`); - - await forcePrDiffRefresh("azure-sdk-for-js", pullRequestId); - _logger.logDebug(`Force refreshed pull request successfully`); - - if (requestReview) { - if (!pullRequestId) { - const pullRequest: PullRequestsGetAllResponseItem | undefined = await findPullRequest("azure-sdk-for-js", branchName, "open"); - if (pullRequest) { - pullRequestId = pullRequest.id; - } - } - await requestPullRequestReview("azure-sdk-for-js", pullRequestId); - _logger.log(`Requested review on PR ${pullRequestId} successfully`); - } else { - _logger.log("Skipping review requesting"); - } - - await checkoutBranch(azureSdkForJsRepository, currentBranch); -} - -async function bumpMinorVersion(azureSdkForJsRepoPath: string, packageName: string) { - const pathToPackageJson = path.resolve(azureSdkForJsRepoPath, "sdk", packageName, "package.json"); - const packageJsonContent = await fs.promises.readFile(pathToPackageJson); - const packageJson = JSON.parse(packageJsonContent.toString()); - const versionString = packageJson.version; - const version = Version.parse(versionString); - version.bumpMinor(); - _logger.log(`Updating package.json version from ${versionString} to ${version.toString()}`); - - packageJson.version = version.toString(); - await saveContentToFile(pathToPackageJson, JSON.stringify(packageJson, undefined, " ")); -} - function getPackageConfig(azureSdkForJsRoot: string, packageInfo: PackageInfo, include?: RegExp, exclude?: RegExp): { content: any; path: string } | undefined { if (!include) { include = /.*/; diff --git a/gulpfile.ts b/gulpfile.ts index 827f291cb15d..45b89a164e81 100644 --- a/gulpfile.ts +++ b/gulpfile.ts @@ -11,10 +11,9 @@ import * as path from "path"; import PluginError from "plugin-error"; import { Argv, CommandLineOptions, getCommandLineOptions } from "./.scripts/commandLine"; import { endsWith, getPackageFolderPaths, packagesToIgnore } from "./.scripts/common"; -import { getDataFromPullRequest } from "./.scripts/github"; -import { generateAllMissingSdks, generateMissingSdk, generateSdk, generateTsReadme, regenerate, setAutoPublish, setVersion } from "./.scripts/gulp"; +import { generateSdk, setAutoPublish, setVersion } from "./.scripts/gulp"; import { Logger } from "./.scripts/logger"; -import { findMissingSdks, findWrongPackages } from "./.scripts/packages"; +import { findMissingSdks } from "./.scripts/packages"; import { getPackageFolderPathFromPackageArgument } from "./.scripts/readme"; enum PackagesToPack { @@ -315,148 +314,6 @@ gulp.task("find-missing-sdks", async () => { } }); -gulp.task("generate-readme", async () => { - interface GenerateReadmeOptions { - dir: string | undefined; - }; - - try { - _logger.log(`Passed arguments: ${Argv.print()}`); - const argv: (GenerateReadmeOptions & Argv.PackageOptions & Argv.RepositoryOptions) - = Argv.construct(Argv.Options.Package, Argv.Options.Repository) - .options({ - "spec-directory": { - alias: "dir", - description: "Forces generating readme in the specified directory" - } - }) - .usage("Example: gulp generate-readme --package @azure/arm-mariadb --type rm") - .argv as any; - - await generateTsReadme(argv.package, argv.type, argv.azureRestAPISpecsRoot, argv.dir); - } - catch (error) { - _logger.logError(error); - } -}); - -gulp.task("generate-missing-sdk", async () => { - try { - _logger.log(`Passed arguments: ${Argv.print()}`); - const argv: (Argv.PackageOptions & Argv.RepositoryOptions & Argv.GenerateOptions) - = Argv.construct(Argv.Options.Package, Argv.Options.Repository, Argv.Options.Generate) - .usage("gulp generate-missing-sdk --package @azure/arm-mariadb --type rm") - .argv as any; - - await generateMissingSdk(argv.azureSDKForJSRepoRoot, argv.package, argv.type, argv.azureRestAPISpecsRoot, argv["skip-spec"], argv["skip-sdk"]); - } - catch (error) { - _logger.logError(error); - } -}); - -gulp.task("generate-all-missing-sdks", async () => { - try { - _logger.log(`Passed arguments: ${Argv.print()}`); - const argv: (Argv.RepositoryOptions & Argv.GenerateOptions) - = Argv.construct(Argv.Options.Repository, Argv.Options.Generate) - .usage("Example: gulp find-missing-sdks") - .argv as any; - - await generateAllMissingSdks(argv.azureSDKForJSRepoRoot, argv.azureRestAPISpecsRoot, argv["skip-spec"], argv["skip-sdk"]); - } catch (error) { - _logger.logError(error); - } -}); - -gulp.task("regenerate", async () => { - interface RegenerateOptions { - branch: string | undefined; - package: string | undefined; - "pull-request": string | undefined; - "skip-version-bump": boolean | undefined; - "request-review": boolean | undefined; - }; - - const argv: (RegenerateOptions & Argv.RepositoryOptions) - = Argv.construct(Argv.Options.Repository) - .options({ - "branch": { - alias: "b", - string: true, - description: "Name of the AutoPR branch", - implies: "package" - }, - "package": { - alias: "p", - string: true, - description: "Name of the regenerated package" - }, - "pull-request": { - alias: "pr", - string: true, - description: "URL to GitHub pull request", - conflicts: ["branch"] - }, - "skip-version-bump": { - boolean: true, - description: "Determines if version bumping should be skipped" - }, - "request-review": { - boolean: true, - description: "Determines if review should be automatically requested on matching pull request" - } - }) - .usage("Example: gulp regenerate --branch 'restapi_auto_daschult/sql'") - .argv as any; - - try { - const pullRequestUrl: string | undefined = argv["pull-request"]; - - let pullRequestData: { packageName: string | undefined; branchName: string; prId: number; } | undefined; - if (pullRequestUrl) { - pullRequestData = await getDataFromPullRequest(pullRequestUrl); - } - - if (!pullRequestData) { - throw new Error(`Could not get pull request data for pull request "${pullRequestUrl}".`); - } - - const branchName = argv.branch || pullRequestData.branchName; - if (!branchName) { - throw new Error("Unable to find the name of the branch. Please specify the --branch parameter"); - } - - const packageName: string | undefined = argv.package || pullRequestData.packageName; - if (!packageName) { - throw new Error("Unable to find the name of the package. Please specify the --package parameter"); - } - - regenerate(branchName, packageName, argv.azureSDKForJSRepoRoot, argv.azureRestAPISpecsRoot, pullRequestData.prId, argv["skip-version-bump"], argv["request-review"]) - } catch (error) { - _logger.logError(error); - } -}); - -gulp.task("find-wrong-packages", async () => { - _logger.log(`Passed arguments: ${Argv.print()}`); - const argv: (Argv.RepositoryOptions & Argv.GenerateOptions) - = Argv.construct(Argv.Options.Repository, Argv.Options.Generate) - .usage("Example: gulp find-missing-sdks") - .argv as any; - - const incorrectPackages = await findWrongPackages(argv.azureRestAPISpecsRoot, argv.azureSDKForJSRepoRoot); - - _logger.log(`Found ${incorrectPackages.length} incorrect packages`.red); - for (const incorrectPackage of incorrectPackages) { - _logger.log(`${incorrectPackage.package.name}`.bgRed); - _logger.log(` Reason: ${incorrectPackage.message}`); - _logger.log(` Output path: ${incorrectPackage.package.outputPath}`.gray); - _logger.log(` Readme path: ${incorrectPackage.package.readmePath}`.gray); - _logger.log(); - } -}); - gulp.task("set-autopublish", async () => { _logger.log(`Passed arguments: ${Argv.print()}`); const argv: Argv.RepositoryOptions & Argv.FilterOptions diff --git a/package.json b/package.json index 48f193c231fa..9e085122985b 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "preinstall": "node common/scripts/rush-welcome.js" }, "devDependencies": { - "@octokit/rest": "15.17.0", + "@octokit/rest": "^16.26.0", "@ts-common/azure-js-dev-tools": "^0.7.0", "@types/glob": "^7.1.1", "@types/gulp": "^4.0.0", @@ -49,7 +49,6 @@ "gulp": "^4.0.0", "js-yaml": "^3.12.0", "minimist": "^1.2.0", - "nodegit": "^0.24.0", "npm-run-all": "^4.1.5", "path": "^0.12.7", "plugin-error": "^1.0.1",