diff --git a/eng/common/pipelines/templates/jobs/archetype-spec-gen-sdk.yml b/eng/common/pipelines/templates/jobs/archetype-spec-gen-sdk.yml deleted file mode 100644 index 1b4d3376be89..000000000000 --- a/eng/common/pipelines/templates/jobs/archetype-spec-gen-sdk.yml +++ /dev/null @@ -1,236 +0,0 @@ -parameters: - - name: SpecRepoUrl - type: string - - name: SdkRepoUrl - type: string - - name: SpecRepoCommit - type: string - default: '$(Build.SourceBranch)' - - name: SdkRepoCommit - type: string - default: 'HEAD' - - name: ConfigType - type: string - values: - - 'TypeSpec' - - 'OpenAPI' - default: 'TypeSpec' - displayName: 'API specification type' - - name: ConfigPath - type: string - default: 'specification/contosowidgetmanager/Contoso.Management/tspconfig.yaml' - displayName: 'Path to API specification file (TypeSpec/OpenAPI)' - - name: SkipPullRequestCreation - type: boolean - default: false - -jobs: -- job: - displayName: 'SDK Generation' - - variables: - - template: /eng/pipelines/templates/variables/image.yml - - name: NodeVersion - value: '22.13.x' - - name: PythonVersion - value: '3.13' - - name: SpecGenSdkVersion - value: 'latest' - - name: SdkArtifactName - value: SDK_Artifact - - pool: - name: $(LINUXPOOL) - vmImage: $(LINUXVMIMAGE) - - steps: - - checkout: none - - - pwsh: | - $tspConfigPathPattern = '^specification\/([^\/]+\/)+tspconfig\.yaml$' - $readmePathPattern = '^specification\/([^\/]+\/){2,}readme\.md$' - if (('${{ parameters.ConfigType }}' -eq 'TypeSpec') -and ('${{ parameters.ConfigPath }}' -notmatch $tspConfigPathPattern)) { - Write-Host "##vso[task.logissue type=error]'ConfigPath' must be a valid 'tspconfig.yaml' file path when 'ConfigType' is set to 'TypeSpec'. For example, 'specification/contosowidgetmanager/Contoso.Management/tspconfig.yaml'" - Exit 1 - } elseif (('${{ parameters.ConfigType }}' -eq 'OpenAPI') -and ('${{ parameters.ConfigPath }}' -notmatch $readmePathPattern)) { - Write-Host "##vso[task.logissue type=error]'ConfigPath' must be a valid 'readme.md' file path when 'ConfigType' is set to 'OpenAPI'. For example, 'specification/appplatform/resource-manager/readme.md'" - Exit 1 - } - $urlPattern = '^https://github\.com/(?[^/]+)/(?[^/]+)' - if ('${{ parameters.SpecRepoUrl }}' -match $urlPattern) { - $specRepoOwner = $Matches['organization'] - Write-Host "##vso[task.setvariable variable=SpecRepoOwner]$specRepoOwner" - Write-Host "SpecRepoOwner variable set to: $specRepoOwner" - - $specRepoName = $Matches['repository'] - Write-Host "##vso[task.setvariable variable=SpecRepoName]$specRepoName" - Write-Host "SpecRepoName variable set to: $specRepoName" - - $specRepoDirectory = "$(System.DefaultWorkingDirectory)/$specRepoName" - Write-Host "##vso[task.setvariable variable=SpecRepoDirectory]$specRepoDirectory" - Write-Host "SpecRepoDirectory variable set to: $specRepoDirectory" - } - - if ('${{ parameters.SdkRepoUrl }}' -match $urlPattern) { - if ('${{ parameters.SpecRepoUrl }}'.EndsWith('-pr') -and (-not '${{ parameters.SdkRepoUrl }}'.EndsWith('-pr'))) { - Write-Host "##vso[task.logissue type=error]SdkRepoUrl must be a private repository if SpecRepoUrl is a private repository." - Exit 1 - } - - $sdkRepoOwner = $Matches['organization'] - Write-Host "##vso[task.setvariable variable=SdkRepoOwner]$sdkRepoOwner" - Write-Host "SdkRepoOwner variable set to: $sdkRepoOwner" - - $sdkRepoName = $Matches['repository'] - Write-Host "##vso[task.setvariable variable=SdkRepoName]$sdkRepoName" - Write-Host "SdkRepoName variable set to: $sdkRepoName" - - $sdkRepoDirectory = "$(System.DefaultWorkingDirectory)/$sdkRepoName" - Write-Host "##vso[task.setvariable variable=SdkRepoDirectory]$sdkRepoDirectory" - Write-Host "SdkRepoDirectory variable set to: $sdkRepoDirectory" - } - - if ([string]::IsNullOrEmpty($SpecRepoOwner) -or [string]::IsNullOrEmpty($SpecRepoName) -or [string]::IsNullOrEmpty($SdkRepoOwner) -or [string]::IsNullOrEmpty($SdkRepoName)) { - Write-Host "##vso[task.logissue type=error]One or more required variables is empty or invalid. Ensure that SpecRepoUrl and SdkRepoUrl are set to valid GitHub repository URLs." - Exit 1 - } - - displayName: "Create Run Time Variables" - - - template: /eng/common/pipelines/templates/steps/sparse-checkout.yml - parameters: - Paths: - - '/*' - - '!sdk/**/test-recordings/*' - - '!sdk/**/recordings/*' - - '!sdk/**/SessionRecords/*' - - '!sdk/**/session-records/*' - Repositories: - - Name: $(SpecRepoOwner)/$(SpecRepoName) - Commitish: ${{ parameters.SpecRepoCommit }} - WorkingDirectory: $(SpecRepoDirectory) - - Name: $(SdkRepoOwner)/$(SdkRepoName) - Commitish: ${{ parameters.SdkRepoCommit }} - WorkingDirectory: $(SdkRepoDirectory) - SkipCheckoutNone: true - - - script: | - if [ "${{ parameters.SpecRepoCommit }}" = "$(Build.SourceBranch)" ]; then - cd $(SpecRepoDirectory) - default_commit=$(git rev-parse HEAD) - echo "##vso[task.setvariable variable=SpecRepoCommit]$default_commit" - echo "SpecRepoCommit variable set to default commit: $default_commit" - else - echo "##vso[task.setvariable variable=SpecRepoCommit]${{ parameters.SpecRepoCommit }}" - echo "SpecRepoCommit variable set to: ${{ parameters.SpecRepoCommit }}" - fi - displayName: 'Set SpecRepoCommit variable' - - - task: NodeTool@0 - inputs: - versionSpec: $(NodeVersion) - displayName: 'Install Node.js' - - - task: UsePythonVersion@0 - inputs: - versionSpec: $(PythonVersion) - - - script: | - npm install -g @azure-tools/spec-gen-sdk@$(SpecGenSdkVersion) - displayName: 'Install spec-gen-sdk' - - - script: | - optional_params="" - sdk_gen_info="sdk generation from Config : " - - if [ "${{ parameters.ConfigType }}" = "TypeSpec" ]; then - optional_params="$optional_params --tsp-config-relative-path ${{ parameters.ConfigPath }}" - sdk_gen_info="$sdk_gen_info '${{ parameters.ConfigPath }}'," - else - optional_params="$optional_params --readme-relative-path ${{ parameters.ConfigPath }}" - sdk_gen_info="$sdk_gen_info '${{ parameters.ConfigPath }}'," - fi - - if [ "$(Build.Reason)" = "PullRequest" ]; then - optional_params="$optional_params --n=$(System.PullRequest.PullRequestNumber)" - specPrUrl="${{ parameters.SpecRepoUrl }}/pull/$(System.PullRequest.PullRequestNumber)" - sdk_gen_info="$sdk_gen_info spec PR: $specPrUrl" - fi - - sdk_gen_info="$sdk_gen_info and CommitSHA: '$(SpecRepoCommit)', in SpecRepo: '${{ parameters.SpecRepoUrl }}'" - echo "##vso[task.setvariable variable=GeneratedSDKInformation]$sdk_gen_info" - echo "Generated SDK Information : $sdk_gen_info" - - spec-gen-sdk \ - --scp "$(SpecRepoDirectory)" \ - --sdp "$(SdkRepoDirectory)" \ - --wf "$(System.DefaultWorkingDirectory)" \ - -l "$(SdkRepoName)" \ - -c "$(SpecRepoCommit)" \ - -t $true \ - $optional_params - displayName: 'Generate SDK' - - - task: PublishPipelineArtifact@1 - displayName: Publish SDK Artifact to Pipeline Artifacts - inputs: - artifactName: $(sdkArtifactName) - targetPath: "$(System.DefaultWorkingDirectory)/generatedSdkArtifacts" - - - task: PowerShell@2 - displayName: Add label to the spec PR - condition: and(eq(variables['Build.Reason'], 'PullRequest'), ne(variables['BreakingChangeLabel'], ''), eq(variables['BreakingChangeLabelAction'], 'add')) - inputs: - pwsh: true - workingDirectory: $(SdkRepoDirectory) - filePath: $(SdkRepoDirectory)/eng/common/scripts/Add-IssueLabels.ps1 - arguments: > - -RepoOwner $(SpecRepoOwner) - -RepoName $(SpecRepoName) - -IssueNumber "$(System.PullRequest.PullRequestNumber)" - -Labels $(BreakingChangeLabel) - -AuthToken "$(azuresdk-github-pat)" - - - task: PowerShell@2 - displayName: Remove label from the spec PR - condition: and(eq(variables['Build.Reason'], 'PullRequest'), ne(variables['BreakingChangeLabel'], ''), eq(variables['BreakingChangeLabelAction'], 'remove')) - inputs: - pwsh: true - workingDirectory: $(SdkRepoDirectory) - filePath: $(SdkRepoDirectory)/eng/common/scripts/Remove-IssueLabel.ps1 - arguments: > - -RepoOwner $(SpecRepoOwner) - -RepoName $(SpecRepoName) - -IssueNumber "$(System.PullRequest.PullRequestNumber)" - -LabelName $(BreakingChangeLabel) - -AuthToken "$(azuresdk-github-pat)" - - - ${{ if eq(parameters.SkipPullRequestCreation, false) }}: - - template: /eng/common/pipelines/templates/steps/git-push-changes.yml - parameters: - BaseRepoBranch: $(PrBranch)-$(Build.BuildId) - BaseRepoOwner: azure-sdk - CommitMsg: $(GeneratedSDKInformation) - TargetRepoOwner: $(SdkRepoOwner) - TargetRepoName: $(SdkRepoName) - PushArgs: "--force" - WorkingDirectory: $(SdkRepoDirectory) - ScriptDirectory: $(SdkRepoDirectory)/eng/common/scripts - - - task: PowerShell@2 - displayName: Create pull request - condition: and(succeeded(), eq(variables['HasChanges'], 'true'), ne(variables['Build.Reason'], 'PullRequest')) - inputs: - pwsh: true - workingDirectory: $(SdkRepoDirectory) - filePath: $(SdkRepoDirectory)/eng/common/scripts/Submit-PullRequest.ps1 - arguments: > - -RepoOwner "$(SdkRepoOwner)" - -RepoName "$(SdkRepoName)" - -BaseBranch "main" - -PROwner "azure-sdk" - -PRBranch "$(PrBranch)-$(Build.BuildId)" - -AuthToken "$(azuresdk-github-pat)" - -PRTitle "$(PrTitle)-generated-from-$(Build.DefinitionName)-$(Build.BuildId)" - -PRBody "$(GeneratedSDKInformation)" - -OpenAsDraft $true diff --git a/eng/common/pipelines/templates/stages/archetype-spec-gen-sdk.yml b/eng/common/pipelines/templates/stages/archetype-spec-gen-sdk.yml new file mode 100644 index 000000000000..f97b3c9c054c --- /dev/null +++ b/eng/common/pipelines/templates/stages/archetype-spec-gen-sdk.yml @@ -0,0 +1,256 @@ +parameters: + - name: SpecRepoUrl + type: string + - name: SdkRepoUrl + type: string + - name: SpecRepoCommit + type: string + default: '$(Build.SourceBranch)' + - name: SdkRepoCommit + type: string + default: 'HEAD' + - name: ConfigType + type: string + values: + - 'TypeSpec' + - 'OpenAPI' + default: 'TypeSpec' + displayName: 'API specification type' + - name: ConfigPath + type: string + default: 'specification/contosowidgetmanager/Contoso.Management/tspconfig.yaml' + displayName: 'Path to API specification file (TypeSpec/OpenAPI)' + - name: SkipPullRequestCreation + type: boolean + default: false + +extends: + template: /eng/pipelines/templates/stages/1es-redirect.yml + parameters: + stages: + - stage: Build + displayName: 'SDK Generation' + jobs: + - job: + displayName: 'SDK Generation' + + variables: + - template: /eng/pipelines/templates/variables/image.yml + - name: NodeVersion + value: '22.13.x' + - name: PythonVersion + value: '3.13' + - name: SpecGenSdkVersion + value: 'latest' + - name: SdkArtifactName + value: SDK_Artifact + + pool: + name: $(LINUXPOOL) + vmImage: $(LINUXVMIMAGE) + os: linux + + templateContext: + outputParentDirectory: $(System.DefaultWorkingDirectory)/out + outputs: + - output: pipelineArtifact + displayName: Publish SDK artifacts to Pipeline Artifacts + condition: and(ne(variables['ValidationResult'], ''), eq(variables['HasSDKArtifact'], 'true')) + artifactName: $(sdkArtifactName) + targetPath: "$(System.DefaultWorkingDirectory)/out/generatedSdkArtifacts" + - output: pipelineArtifact + displayName: Publish API View artifacts to Pipeline Artifacts + condition: and(ne(variables['ValidationResult'], ''), eq(variables['HasApiViewArtifact'], 'true')) + artifactName: $(ArtifactName) + targetPath: "$(System.DefaultWorkingDirectory)/out/sdkApiViewArtifacts" + - output: pipelineArtifact + displayName: Publish logs to Pipeline Artifacts + condition: ne(variables['ValidationResult'], '') + artifactName: "spec-gen-sdk-logs" + targetPath: "$(System.DefaultWorkingDirectory)/out/logs" + + steps: + - checkout: none + + - pwsh: | + $tspConfigPathPattern = '^specification\/([^\/]+\/)+tspconfig\.yaml$' + $readmePathPattern = '^specification\/([^\/]+\/){2,}readme\.md$' + if (('${{ parameters.ConfigType }}' -eq 'TypeSpec') -and ('${{ parameters.ConfigPath }}' -notmatch $tspConfigPathPattern)) { + Write-Host "##vso[task.logissue type=error]'ConfigPath' must be a valid 'tspconfig.yaml' file path when 'ConfigType' is set to 'TypeSpec'. For example, 'specification/contosowidgetmanager/Contoso.Management/tspconfig.yaml'" + Exit 1 + } elseif (('${{ parameters.ConfigType }}' -eq 'OpenAPI') -and ('${{ parameters.ConfigPath }}' -notmatch $readmePathPattern)) { + Write-Host "##vso[task.logissue type=error]'ConfigPath' must be a valid 'readme.md' file path when 'ConfigType' is set to 'OpenAPI'. For example, 'specification/appplatform/resource-manager/readme.md'" + Exit 1 + } + $urlPattern = '^https://github\.com/(?[^/]+)/(?[^/]+)' + if ('${{ parameters.SpecRepoUrl }}' -match $urlPattern) { + $specRepoOwner = $Matches['organization'] + Write-Host "##vso[task.setvariable variable=SpecRepoOwner]$specRepoOwner" + Write-Host "SpecRepoOwner variable set to: $specRepoOwner" + + $specRepoName = $Matches['repository'] + Write-Host "##vso[task.setvariable variable=SpecRepoName]$specRepoName" + Write-Host "SpecRepoName variable set to: $specRepoName" + + $specRepoDirectory = "$(System.DefaultWorkingDirectory)/$specRepoName" + Write-Host "##vso[task.setvariable variable=SpecRepoDirectory]$specRepoDirectory" + Write-Host "SpecRepoDirectory variable set to: $specRepoDirectory" + } + + if ('${{ parameters.SdkRepoUrl }}' -match $urlPattern) { + if ('${{ parameters.SpecRepoUrl }}'.EndsWith('-pr') -and (-not '${{ parameters.SdkRepoUrl }}'.EndsWith('-pr'))) { + Write-Host "##vso[task.logissue type=error]SdkRepoUrl must be a private repository if SpecRepoUrl is a private repository." + Exit 1 + } + + $sdkRepoOwner = $Matches['organization'] + Write-Host "##vso[task.setvariable variable=SdkRepoOwner]$sdkRepoOwner" + Write-Host "SdkRepoOwner variable set to: $sdkRepoOwner" + + $sdkRepoName = $Matches['repository'] + Write-Host "##vso[task.setvariable variable=SdkRepoName]$sdkRepoName" + Write-Host "SdkRepoName variable set to: $sdkRepoName" + + $sdkRepoDirectory = "$(System.DefaultWorkingDirectory)/$sdkRepoName" + Write-Host "##vso[task.setvariable variable=SdkRepoDirectory]$sdkRepoDirectory" + Write-Host "SdkRepoDirectory variable set to: $sdkRepoDirectory" + } + + if ([string]::IsNullOrEmpty($SpecRepoOwner) -or [string]::IsNullOrEmpty($SpecRepoName) -or [string]::IsNullOrEmpty($SdkRepoOwner) -or [string]::IsNullOrEmpty($SdkRepoName)) { + Write-Host "##vso[task.logissue type=error]One or more required variables is empty or invalid. Ensure that SpecRepoUrl and SdkRepoUrl are set to valid GitHub repository URLs." + Exit 1 + } + + displayName: "Create Run Time Variables" + + - template: /eng/common/pipelines/templates/steps/sparse-checkout.yml + parameters: + Paths: + - '/*' + - '!sdk/**/test-recordings/*' + - '!sdk/**/recordings/*' + - '!sdk/**/SessionRecords/*' + - '!sdk/**/session-records/*' + Repositories: + - Name: $(SpecRepoOwner)/$(SpecRepoName) + Commitish: ${{ parameters.SpecRepoCommit }} + WorkingDirectory: $(SpecRepoDirectory) + - Name: $(SdkRepoOwner)/$(SdkRepoName) + Commitish: ${{ parameters.SdkRepoCommit }} + WorkingDirectory: $(SdkRepoDirectory) + SkipCheckoutNone: true + + - script: | + if [ "${{ parameters.SpecRepoCommit }}" = "$(Build.SourceBranch)" ]; then + cd $(SpecRepoDirectory) + default_commit=$(git rev-parse HEAD) + echo "##vso[task.setvariable variable=SpecRepoCommit]$default_commit" + echo "SpecRepoCommit variable set to default commit: $default_commit" + else + echo "##vso[task.setvariable variable=SpecRepoCommit]${{ parameters.SpecRepoCommit }}" + echo "SpecRepoCommit variable set to: ${{ parameters.SpecRepoCommit }}" + fi + displayName: 'Set SpecRepoCommit variable' + + - task: NodeTool@0 + inputs: + versionSpec: $(NodeVersion) + displayName: 'Install Node.js' + + - task: UsePythonVersion@0 + inputs: + versionSpec: $(PythonVersion) + + - script: | + npm install -g @azure-tools/spec-gen-sdk@$(SpecGenSdkVersion) + displayName: 'Install spec-gen-sdk' + + - script: | + optional_params="" + sdk_gen_info="sdk generation from Config : " + + if [ "${{ parameters.ConfigType }}" = "TypeSpec" ]; then + optional_params="$optional_params --tsp-config-relative-path ${{ parameters.ConfigPath }}" + sdk_gen_info="$sdk_gen_info '${{ parameters.ConfigPath }}'," + else + optional_params="$optional_params --readme-relative-path ${{ parameters.ConfigPath }}" + sdk_gen_info="$sdk_gen_info '${{ parameters.ConfigPath }}'," + fi + + if [ "$(Build.Reason)" = "PullRequest" ]; then + optional_params="$optional_params --n=$(System.PullRequest.PullRequestNumber)" + specPrUrl="${{ parameters.SpecRepoUrl }}/pull/$(System.PullRequest.PullRequestNumber)" + sdk_gen_info="$sdk_gen_info spec PR: $specPrUrl" + fi + + sdk_gen_info="$sdk_gen_info and CommitSHA: '$(SpecRepoCommit)', in SpecRepo: '${{ parameters.SpecRepoUrl }}'" + echo "##vso[task.setvariable variable=GeneratedSDKInformation]$sdk_gen_info" + echo "Generated SDK Information : $sdk_gen_info" + + spec-gen-sdk \ + --scp "$(SpecRepoDirectory)" \ + --sdp "$(SdkRepoDirectory)" \ + --wf "$(System.DefaultWorkingDirectory)" \ + -l "$(SdkRepoName)" \ + -c "$(SpecRepoCommit)" \ + -t $true \ + $optional_params + displayName: 'Generate SDK' + + - task: PowerShell@2 + displayName: Add label to the spec PR + condition: and(eq(variables['Build.Reason'], 'PullRequest'), ne(variables['BreakingChangeLabel'], ''), eq(variables['BreakingChangeLabelAction'], 'add')) + inputs: + pwsh: true + workingDirectory: $(SdkRepoDirectory) + filePath: $(SdkRepoDirectory)/eng/common/scripts/Add-IssueLabels.ps1 + arguments: > + -RepoOwner $(SpecRepoOwner) + -RepoName $(SpecRepoName) + -IssueNumber "$(System.PullRequest.PullRequestNumber)" + -Labels $(BreakingChangeLabel) + -AuthToken "$(azuresdk-github-pat)" + + - task: PowerShell@2 + displayName: Remove label from the spec PR + condition: and(eq(variables['Build.Reason'], 'PullRequest'), ne(variables['BreakingChangeLabel'], ''), eq(variables['BreakingChangeLabelAction'], 'remove')) + inputs: + pwsh: true + workingDirectory: $(SdkRepoDirectory) + filePath: $(SdkRepoDirectory)/eng/common/scripts/Remove-IssueLabel.ps1 + arguments: > + -RepoOwner $(SpecRepoOwner) + -RepoName $(SpecRepoName) + -IssueNumber "$(System.PullRequest.PullRequestNumber)" + -LabelName $(BreakingChangeLabel) + -AuthToken "$(azuresdk-github-pat)" + + - ${{ if eq(parameters.SkipPullRequestCreation, false) }}: + - template: /eng/common/pipelines/templates/steps/git-push-changes.yml + parameters: + BaseRepoBranch: $(PrBranch)-$(Build.BuildId) + BaseRepoOwner: azure-sdk + CommitMsg: $(GeneratedSDKInformation) + TargetRepoOwner: $(SdkRepoOwner) + TargetRepoName: $(SdkRepoName) + PushArgs: "--force" + WorkingDirectory: $(SdkRepoDirectory) + ScriptDirectory: $(SdkRepoDirectory)/eng/common/scripts + + - task: PowerShell@2 + displayName: Create pull request + condition: and(succeeded(), eq(variables['HasChanges'], 'true'), ne(variables['Build.Reason'], 'PullRequest')) + inputs: + pwsh: true + workingDirectory: $(SdkRepoDirectory) + filePath: $(SdkRepoDirectory)/eng/common/scripts/Submit-PullRequest.ps1 + arguments: > + -RepoOwner "$(SdkRepoOwner)" + -RepoName "$(SdkRepoName)" + -BaseBranch "main" + -PROwner "azure-sdk" + -PRBranch "$(PrBranch)-$(Build.BuildId)" + -AuthToken "$(azuresdk-github-pat)" + -PRTitle "$(PrTitle)-generated-from-$(Build.DefinitionName)-$(Build.BuildId)" + -PRBody "$(GeneratedSDKInformation)" + -OpenAsDraft $true