diff --git a/.azure-pipelines/build.yml b/.azure-pipelines/build.yml index 647a3678..c23d2f55 100644 --- a/.azure-pipelines/build.yml +++ b/.azure-pipelines/build.yml @@ -1,3 +1,6 @@ +name: vscode-documentdb-$(Date:yyyy-MM-dd).$(Rev:r) +appendCommitMessageToRunName: false + # Trigger the build whenever `main` or `next` is updated trigger: - next @@ -87,27 +90,44 @@ extends: ob_sdl_codeql_compiled_enabled: true steps: - task: ComponentGovernanceComponentDetection@0 - displayName: 'Component Governance - Component Detection' + displayName: '๐Ÿ›ก๏ธ Component Governance - Component Detection' + - task: notice@0 - displayName: "\U0001F449 Generate NOTICE file" + displayName: '๐Ÿ“„ Generate NOTICE file' + continueOnError: true # the notice@0 task is unreliable and sometimes fails the build unexpectedly due to random outages + retryCountOnTaskFailure: 6 inputs: - outputfile: $(Build.SourcesDirectory)/NOTICE.html + outputfile: $(Build.SourcesDirectory)/NOTICE.generated.html outputformat: html + - task: PowerShell@2 + displayName: 'โš ๏ธ Check NOTICE file generation' + condition: always() + inputs: + pwsh: true + targetType: 'inline' + script: | + if (Test-Path "$(Build.SourcesDirectory)/NOTICE.generated.html") { + Move-Item -Force "$(Build.SourcesDirectory)/NOTICE.generated.html" "$(Build.SourcesDirectory)/NOTICE.html" + Write-Output "โœ… NOTICE.html generated successfully" + } else { + Write-Host "##vso[task.logissue type=warning]NOTICE.html was not generated. The notice@0 task may have failed. Using committed version." + } + - task: NodeTool@0 - displayName: "\U0001F449 Using Node.js" + displayName: '๐Ÿ“ฆ Using Node.js' inputs: versionSource: fromFile versionFilePath: .nvmrc - task: npmAuthenticate@0 - displayName: "\U0001F449 Authenticate to npm registry" + displayName: '๐Ÿ” Authenticate to npm registry' condition: succeeded() inputs: workingFile: '$(Build.SourcesDirectory)/.azure-pipelines/.npmrc' - task: Npm@1 - displayName: "\U0001F449 Install Dependencies" + displayName: 'โฌ‡๏ธ Install Dependencies' condition: succeeded() inputs: command: custom @@ -115,7 +135,7 @@ extends: workingDir: $(Build.SourcesDirectory) - task: Npm@1 - displayName: "\U0001F449 Build" + displayName: '๐Ÿ”จ Build' condition: succeeded() inputs: command: custom @@ -123,7 +143,7 @@ extends: workingDir: $(Build.SourcesDirectory) - task: Npm@1 - displayName: "\U0001F449 Package" + displayName: '๐Ÿ“ฆ Package' condition: succeeded() inputs: command: custom @@ -131,14 +151,15 @@ extends: workingDir: $(Build.SourcesDirectory) - pwsh: npm i -g @vscode/vsce --userconfig $(Build.SourcesDirectory)/.azure-pipelines/.npmrc - displayName: "\U0001F449 Install vsce" + displayName: 'โฌ‡๏ธ Install vsce' condition: succeeded() # Find the vsix and set the vsix file name variable # Fails with an error if more than one .vsix file is found, or if no .vsix file is found - task: PowerShell@2 - displayName: "\U0001F50D Find VSIX File" + displayName: '๐Ÿ” Find VSIX File' inputs: + pwsh: true targetType: 'inline' script: | # Get all .vsix files in the current directory @@ -147,10 +168,12 @@ extends: # Check if more than one .vsix file is found if ($vsixFiles.Count -gt 1) { - Write-Error "[Error] More than one .vsix file found: $($vsixFiles.Name -join ', ')" + Write-Host "##vso[task.logissue type=error]More than one .vsix file found: $($vsixFiles.Name -join ', ')" + Write-Host "##vso[task.complete result=Failed;]" exit 1 } elseif ($vsixFiles.Count -eq 0) { - Write-Error "[Error] No .vsix files found in $(Build.SourcesDirectory)" + Write-Host "##vso[task.logissue type=error]No .vsix files found in $(Build.SourcesDirectory)" + Write-Host "##vso[task.complete result=Failed;]" exit 1 } else { # Set the pipeline variable @@ -163,18 +186,20 @@ extends: ## Sign the extension using OneBranch signing task ## see for VS Code specifics: https://aka.ms/vsm-ms-publisher-sign#cai-teams-sign-using-onebranch - script: vsce generate-manifest -i $(vsixFileName) -o extension.manifest - displayName: "\U0001F5DD Generate extension manifest for signing" + displayName: '๐Ÿ“ Generate extension manifest for signing' condition: and(succeeded(), ${{ eq(parameters.isOfficialBuild, true) }}) - task: PowerShell@2 - displayName: "\U0001F408 Prepare manifest for signing" + displayName: '๐Ÿˆ Prepare manifest for signing' condition: and(succeeded(), ${{ eq(parameters.isOfficialBuild, true) }}) inputs: + pwsh: true targetType: 'inline' script: | # Verify extension.manifest exists before proceeding if (-not (Test-Path "extension.manifest")) { - Write-Error "[Error] extension.manifest file not found. Cannot proceed with signing." + Write-Host "##vso[task.logissue type=error]extension.manifest file not found. Cannot proceed with signing." + Write-Host "##vso[task.complete result=Failed;]" exit 1 } @@ -182,7 +207,7 @@ extends: Get-ChildItem -Path "$(Build.SourcesDirectory)" -Filter "extension.*" | ForEach-Object { Write-Output $_.FullName } - task: onebranch.pipeline.signing@1 # https://aka.ms/obpipelines/signing - displayName: "\U0001F5DD Sign VSIX package" + displayName: 'โœ๏ธ Sign VSIX package' # Only sign if isOfficialBuild is true condition: and(succeeded(), ${{ eq(parameters.isOfficialBuild, true) }}) inputs: @@ -193,9 +218,10 @@ extends: #use_testsign: true # Set to true for test signing for development purposes, default is false - task: PowerShell@2 - displayName: "\U0001F396 Verify VSIX signature" + displayName: '๐Ÿ”’ Verify VSIX signature' condition: and(succeeded(), ${{ eq(parameters.isOfficialBuild, true) }}) inputs: + pwsh: true targetType: 'inline' failOnStderr: true script: | @@ -205,7 +231,8 @@ extends: # Check if the vsce command failed to execute if ($LastExitCode -ne 0) { - Write-Error "[Error] VSIX signature verification command failed with exit code $LastExitCode." + Write-Host "##vso[task.logissue type=error]VSIX signature verification command failed with exit code $LastExitCode" + Write-Host "##vso[task.complete result=Failed;]" exit 1 } @@ -216,17 +243,18 @@ extends: if ($exitCodeValue -eq "Success") { Write-Output "[Success] VSIX signature verification succeeded." } elseif ($exitCodeValue -eq "UnhandledException") { - Write-Error "[Error] VSIX signature verification failed with UnhandledException." + Write-Host "##vso[task.logissue type=error]VSIX signature verification failed with UnhandledException" + Write-Host "##vso[task.complete result=Failed;]" exit 1 } else { Write-Warning "[Warning] VSIX signature verification completed with unexpected exit code: $exitCodeValue" } } else { - Write-Warning "[Warning] Could not parse exit code from vsce verify-signature output. Raw output: $output" + Write-Warning "[Warning] Could not parse exit code from vsce verify-signature output." } - task: CopyFiles@2 - displayName: "\U0001F449 Copy packages and vsix to staging directory" + displayName: '๐Ÿ“‚ Copy packages and vsix to staging directory' inputs: # Uploading the package.json so we can publish later without cloning the source # Files related to signing: @@ -245,7 +273,7 @@ extends: condition: and(succeeded(), ne(variables['System.PullRequest.IsFork'], 'True')) - task: Npm@1 - displayName: "\U0001F449 Test" + displayName: '๐Ÿงช Test' inputs: command: custom customCommand: test diff --git a/.azure-pipelines/release.yml b/.azure-pipelines/release.yml index 68735d1e..d69d25b1 100644 --- a/.azure-pipelines/release.yml +++ b/.azure-pipelines/release.yml @@ -1,306 +1,304 @@ +name: vscode-documentdb-${{ parameters.publishVersion }}-$(Date:yyyy-MM-dd).$(Rev:r) +appendCommitMessageToRunName: false + parameters: - # The intended extension version to publish. - # This is used to verify the version in package.json matches the version to publish to avoid accidental publishing. - - name: publishVersion - displayName: "Publish Version" - type: string - - # Customize the environment to associate the deployment with. - # Useful to control which group of people should be required to approve the deployment. - # Deprecated on OneBranch pipelines, use `ob_release_environment` variable and ApprovalService instead. - #- name: environmentName - # type: string - # default: AzCodeDeploy - - # When true, skips the deployment job which actually publishes the extension - - name: dryRun - displayName: "Dry Run without publishing" - type: boolean - default: true - - - name: "debug" - displayName: "Enable debug output" - type: boolean - default: false + # The intended extension version to publish. + # This is used to verify the version in package.json matches the version to publish to avoid accidental publishing. + - name: publishVersion + displayName: 'Publish Version (e.g. 1.2.3)' + type: string + default: '' + + # Customize the environment to associate the deployment with. + # Useful to control which group of people should be required to approve the deployment. + # Deprecated on OneBranch pipelines, use `ob_release_environment` variable and ApprovalService instead. + #- name: environmentName + # type: string + # default: AzCodeDeploy + + # When true, skips the deployment job which actually publishes the extension + - name: dryRun + displayName: 'Dry Run without publishing' + type: boolean + default: true + + - name: 'debug' + displayName: 'Enable debug output' + type: boolean + default: false resources: - repositories: - - repository: templates - type: git - name: OneBranch.Pipelines/GovernedTemplates - ref: refs/heads/main - pipelines: - - pipeline: build # Alias for your build pipeline source - project: "CosmosDB" - source: '\VSCode Extensions\vscode-documentdb Build VSIX' # name of the pipeline that produces the artifacts + repositories: + - repository: templates + type: git + name: OneBranch.Pipelines/GovernedTemplates + ref: refs/heads/main + pipelines: + - pipeline: build # Alias for your build pipeline source + project: 'CosmosDB' + source: '\VSCode Extensions\vscode-documentdb Build VSIX' # name of the pipeline that produces the artifacts variables: - system.debug: ${{ parameters.debug }} - # Required by MicroBuild template - TeamName: "Desktop Tools" - WindowsContainerImage: "onebranch.azurecr.io/windows/ltsc2022/vse2022:latest" # Docker image which is used to build the project https://aka.ms/obpipelines/containers + system.debug: ${{ parameters.debug }} + # Required by MicroBuild template + TeamName: 'Desktop Tools' + WindowsContainerImage: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' # Docker image which is used to build the project https://aka.ms/obpipelines/containers extends: - template: v2/OneBranch.Official.CrossPlat.yml@templates - - parameters: - # remove for release pipeline? - cloudvault: # https://aka.ms/obpipelines/cloudvault - enabled: false - globalSdl: # https://aka.ms/obpipelines/sdl - asyncSdl: - enabled: false - tsa: - enabled: false # onebranch publish all sdl results to TSA. If TSA is disabled all SDL tools will forced into'break' build mode. - #configFile: '$(Build.SourcesDirectory)/.azure-pipelines/compliance/tsaoptions.json' - credscan: - suppressionsFile: $(Build.SourcesDirectory)/.azure-pipelines/compliance/CredScanSuppressions.json - policheck: - break: true # always break the build on policheck issues. You can disable it by setting to 'false' - suppression: - suppressionFile: $(Build.SourcesDirectory)/.config/guardian/.gdnsuppress - codeql: - excludePathPatterns: "**/.vscode-test, dist" # Exclude .vscode-test and dist directories from CodeQL alerting - compiled: - ${{ if eq(variables['Build.SourceBranch'], 'refs/heads/main') }}: - enabled: true - ${{ else }}: + template: v2/OneBranch.Official.CrossPlat.yml@templates + + parameters: + # remove for release pipeline? + cloudvault: # https://aka.ms/obpipelines/cloudvault enabled: false - tsaEnabled: false # See 'Codeql.TSAEnabled' in the Addition Options section below - componentgovernance: - ignoreDirectories: $(Build.SourcesDirectory)/.vscode-test - featureFlags: - linuxEsrpSigning: true - WindowsHostVersion: - Version: 2022 - # end of remove for release pipeline - - release: - category: NonAzure # NonAzure category is used to indicate that this is not an Azure service - - stages: - ## Uncomment this stage to validate the service connection and retrieve the user ID of the Azure DevOps Service Connection user. - ## NOTE: this has to be a separate stage with pool type 'windows' to ensure that the Azure CLI task can run successfully, - ## which is not supported on 'release' pool type. - ## See https://aka.ms/VSM-MS-Publisher-Automate for more details. - #- stage: ValidateServiceConnection - # displayName: Validate Service Connection - # jobs: - # - job: ValidateServiceConnection - # displayName: "\U00002713 Validate Service Connection" - # pool: - # type: windows - # variables: - # ob_outputDirectory: '$(Build.ArtifactStagingDirectory)' # this directory is uploaded to pipeline artifacts, reddog and cloudvault. More info at https://aka.ms/obpipelines/artifacts - # steps: - # # Get the user ID of the Azure DevOps Service Connection user to use for publishing - # - task: AzureCLI@2 - # displayName: 'Get AzDO User ID' - # inputs: - # azureSubscription: 'CosmosDB VSCode Publishing' - # scriptType: pscore - # scriptLocation: inlineScript - # inlineScript: | - # az rest -u https://app.vssps.visualstudio.com/_apis/profile/profiles/me --resource 499b84ac-1321-427f-aa17-267ca6975798 - ## END of ValidateServiceConnection stage - - - stage: Release - displayName: Release extension - variables: - - name: ob_release_environment - #value: Test # should be Test, PPE or Production - value: Production # should be Test, PPE or Production - jobs: - - job: ReleaseValidation - displayName: "\U00002713 Validate Artifacts" - templateContext: - inputs: - - input: pipelineArtifact - pipeline: build - targetPath: $(System.DefaultWorkingDirectory) - artifactName: drop_BuildStage_Main - pool: - type: release - variables: - ob_outputDirectory: "$(Build.ArtifactStagingDirectory)" # this directory is uploaded to pipeline artifacts, reddog and cloudvault. More info at https://aka.ms/obpipelines/artifacts - steps: - # Modify the build number to include repo name, extension version, and if dry run is true - - task: PowerShell@2 - displayName: "\U0001F449 Prepend version from package.json to build number" - env: - dryRun: ${{ parameters.dryRun }} - inputs: - targetType: "inline" - script: | - # Get the version from package.json - $packageJsonPath = "$(System.DefaultWorkingDirectory)/package.json" - if (-not (Test-Path $packageJsonPath)) { - Write-Error "[Error] package.json not found at $packageJsonPath" - exit 1 - } - - $packageJson = Get-Content $packageJsonPath | ConvertFrom-Json - $npmVersionString = $packageJson.version - if (-not $npmVersionString) { - Write-Error "[Error] Version not found in package.json" - exit 1 - } - - $isDryRun = "$env:dryRun" - $currentBuildNumber = "$(Build.BuildId)" - - $repoName = "$(Build.Repository.Name)" - $repoNameParts = $repoName -split '/' - $repoNameWithoutOwner = $repoNameParts[-1] - - $dryRunSuffix = "" - if ($isDryRun -eq 'True') { - Write-Output "Dry run was set to True. Adding 'dry' to the build number." - $dryRunSuffix = "-dry" - } - - $newBuildNumber = "$repoNameWithoutOwner-$npmVersionString$dryRunSuffix-$currentBuildNumber" - Write-Output "Setting build number to: $newBuildNumber" - Write-Output "##vso[build.updatebuildnumber]$newBuildNumber" - - # For safety, verify the version in package.json matches the version to publish entered by the releaser - # If they don't match, this step fails - - task: PowerShell@2 - displayName: "\U0001F449 Verify publish version" - env: - publishVersion: ${{ parameters.publishVersion }} - inputs: - targetType: "inline" - script: | - # Get the version from package.json - $packageJsonPath = "$(System.DefaultWorkingDirectory)/package.json" - if (-not (Test-Path $packageJsonPath)) { - Write-Error "[Error] package.json not found at $packageJsonPath" - exit 1 - } - - $packageJson = Get-Content $packageJsonPath | ConvertFrom-Json - $npmVersionString = $packageJson.version - $publishVersion = "$env:publishVersion" - - Write-Output "Package.json version: $npmVersionString" - Write-Output "Requested publish version: $publishVersion" - - # Validate both versions are semantic versions - $semverPattern = '^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$' - if ($npmVersionString -notmatch $semverPattern) { - Write-Error "[Error] Version in package.json ($npmVersionString) is not a valid semantic version" - exit 1 - } - if ($publishVersion -notmatch $semverPattern) { - Write-Error "[Error] Publish version ($publishVersion) is not a valid semantic version" - exit 1 - } - - if ($npmVersionString -eq $publishVersion) { - Write-Output "[Success] Publish version matches package.json version. Proceeding with release." - } else { - Write-Error "[Error] Publish version '$publishVersion' doesn't match version found in package.json '$npmVersionString'. Cancelling release." - exit 1 - } - - # Find the vsix to release and set the vsix file name variable - # Fails with an error if more than one .vsix file is found, or if no .vsix file is found - - task: PowerShell@2 - displayName: "\U0001F449 Find and Set .vsix File Variable" - name: setVsixFileNameStep - inputs: - targetType: "inline" - script: | - # Get all .vsix files in the current directory - Write-Output "Searching for .vsix files in: $(System.DefaultWorkingDirectory)" - Write-Output "Directory contents:" - Get-ChildItem -Path $(System.DefaultWorkingDirectory) -File | Where-Object { $_.Extension -in @('.vsix', '.json', '.p7s', '.manifest') } | Select-Object Name, Length, LastWriteTime | Format-Table - - $vsixFiles = Get-ChildItem -Path $(System.DefaultWorkingDirectory) -Filter *.vsix -File - - # Check if more than one .vsix file is found - if ($vsixFiles.Count -gt 1) { - Write-Error "[Error] More than one .vsix file found: $($vsixFiles.Name -join ', ')" - exit 1 - } elseif ($vsixFiles.Count -eq 0) { - Write-Error "[Error] No .vsix files found in $(System.DefaultWorkingDirectory)" - exit 1 - } else { - # Set the pipeline variable - $vsixFileName = $vsixFiles.Name - $vsixFileSize = [math]::Round($vsixFiles.Length / 1MB, 2) - Write-Output "##vso[task.setvariable variable=vsixFileName;isOutput=true]$vsixFileName" - Write-Output "[Success] Found .vsix file: $vsixFileName (${vsixFileSize} MB)" - } - - - task: PowerShell@2 - displayName: "\U0001F449 Verify Publishing Files" - inputs: - targetType: "inline" - script: | - $vsixFileName = "$(setVsixFileNameStep.vsixFileName)" - if (-not $vsixFileName) { - Write-Error "[Error] vsixFileName variable not defined." - exit 1 - } - - $vsixPath = "$(System.DefaultWorkingDirectory)/$vsixFileName" - $manifestPath = "$(System.DefaultWorkingDirectory)/extension.manifest" - $signaturePath = "$(System.DefaultWorkingDirectory)/extension.signature.p7s" - - Write-Output "Validating required files for publishing:" - - if (Test-Path -Path $vsixPath) { - $vsixSize = [math]::Round((Get-Item $vsixPath).Length / 1MB, 2) - Write-Output "โœ“ VSIX file found: $vsixFileName (${vsixSize} MB)" - } else { - Write-Error "[Error] The specified VSIX file does not exist: $vsixPath" - exit 1 - } - - if (Test-Path -Path $manifestPath) { - Write-Output "โœ“ Manifest file found: extension.manifest" - } else { - Write-Warning "[Warning] Manifest file not found: $manifestPath" - } - - if (Test-Path -Path $signaturePath) { - Write-Output "โœ“ Signature file found: extension.signature.p7s" - } else { - Write-Warning "[Warning] Signature file not found: $signaturePath" - } - - Write-Output "[Success] $vsixFileName is ready for publishing." - - - job: PublishExtension - displayName: "\U00002713 Publish Extension" - condition: and(succeeded(), ${{ eq(parameters.dryRun, false) }}) - dependsOn: ReleaseValidation - pool: - type: release - variables: - vsixFileName: $[ dependencies.ReleaseValidation.outputs['setVsixFileNameStep.vsixFileName'] ] - templateContext: - inputs: - - input: pipelineArtifact - pipeline: build - targetPath: $(System.DefaultWorkingDirectory) - artifactName: drop_BuildStage_Main - workflow: vsce - vsce: - serviceConnection: "CosmosDB VSCode Publishing" # azureRM service connection for the managed identity used to publish the extension. Only this publishing auth method is supported. - vsixPath: "$(vsixFileName)" # Path to VSIX file in artifact - #preRelease: true # default false. Whether the extension is a pre-release. - signaturePath: $(System.DefaultWorkingDirectory)/extension.signature.p7s # optional - manifestPath: $(System.DefaultWorkingDirectory)/extension.manifest # optional - useCustomVSCE: true # for the time being, you must supply a feed in your project with @vscode/vsce@3.3.2 - feed: - organization: msdata - project: CosmosDB - feedName: vscode-documentdb - steps: - # we need a noop step otherwise the vsce template won't run - - pwsh: Write-Output "Done" - condition: ${{ eq(parameters.dryRun, true) }} # noop this condition is always false - displayName: "\U0001F449 Post-Publishing" + globalSdl: # https://aka.ms/obpipelines/sdl + asyncSdl: + enabled: false + tsa: + enabled: false # onebranch publish all sdl results to TSA. If TSA is disabled all SDL tools will forced into'break' build mode. + #configFile: '$(Build.SourcesDirectory)/.azure-pipelines/compliance/tsaoptions.json' + credscan: + suppressionsFile: $(Build.SourcesDirectory)/.azure-pipelines/compliance/CredScanSuppressions.json + policheck: + break: true # always break the build on policheck issues. You can disable it by setting to 'false' + suppression: + suppressionFile: $(Build.SourcesDirectory)/.config/guardian/.gdnsuppress + codeql: + excludePathPatterns: '**/.vscode-test, dist' # Exclude .vscode-test and dist directories from CodeQL alerting + compiled: + ${{ if eq(variables['Build.SourceBranch'], 'refs/heads/main') }}: + enabled: true + ${{ else }}: + enabled: false + tsaEnabled: false # See 'Codeql.TSAEnabled' in the Addition Options section below + componentgovernance: + ignoreDirectories: $(Build.SourcesDirectory)/.vscode-test + featureFlags: + linuxEsrpSigning: true + WindowsHostVersion: + Version: 2022 + # end of remove for release pipeline + + release: + category: NonAzure # NonAzure category is used to indicate that this is not an Azure service + + stages: + ## Uncomment this stage to validate the service connection and retrieve the user ID of the Azure DevOps Service Connection user. + ## NOTE: this has to be a separate stage with pool type 'windows' to ensure that the Azure CLI task can run successfully, + ## which is not supported on 'release' pool type. + ## See https://aka.ms/VSM-MS-Publisher-Automate for more details. + #- stage: ValidateServiceConnection + # displayName: Validate Service Connection + # jobs: + # - job: ValidateServiceConnection + # displayName: "\U00002713 Validate Service Connection" + # pool: + # type: windows + # variables: + # ob_outputDirectory: '$(Build.ArtifactStagingDirectory)' # this directory is uploaded to pipeline artifacts, reddog and cloudvault. More info at https://aka.ms/obpipelines/artifacts + # steps: + # # Get the user ID of the Azure DevOps Service Connection user to use for publishing + # - task: AzureCLI@2 + # displayName: 'Get AzDO User ID' + # inputs: + # azureSubscription: 'CosmosDB VSCode Publishing' + # scriptType: pscore + # scriptLocation: inlineScript + # inlineScript: | + # az rest -u https://app.vssps.visualstudio.com/_apis/profile/profiles/me --resource 499b84ac-1321-427f-aa17-267ca6975798 + ## END of ValidateServiceConnection stage + + - stage: Release + displayName: Release extension + variables: + - name: ob_release_environment + # Controls approval gate: Test for dry runs, Production for real releases + ${{ if eq(parameters.dryRun, true) }}: + value: Test + ${{ else }}: + value: Production + jobs: + - job: ReleaseValidation + displayName: 'โš–๏ธ Validate Artifacts' + templateContext: + inputs: + - input: pipelineArtifact + pipeline: build + targetPath: $(System.DefaultWorkingDirectory) + artifactName: drop_BuildStage_Main + pool: + type: release + variables: + ob_outputDirectory: '$(Build.ArtifactStagingDirectory)' # this directory is uploaded to pipeline artifacts, reddog and cloudvault. More info at https://aka.ms/obpipelines/artifacts + steps: + - task: PowerShell@2 + displayName: '๐Ÿ” Find Publishing Files' + name: findPublishingFilesStep + inputs: + pwsh: true + targetType: 'inline' + script: | + $publishVersion = "${{ parameters.publishVersion }}" + if ([string]::IsNullOrWhiteSpace($publishVersion)) { + Write-Host "##vso[task.logissue type=error]publishVersion parameter is required but not provided" + Write-Host "##vso[task.complete result=Failed;]" + exit 1 + } + + $vsixFiles = Get-ChildItem -Path $(System.DefaultWorkingDirectory) -Filter *.vsix -File + $errors = @() + + if ($vsixFiles.Count -gt 1) { $errors += "Multiple .vsix files found: $($vsixFiles.Name -join ', ')" } + elseif ($vsixFiles.Count -eq 0) { $errors += "No .vsix files found" } + if (-not (Test-Path "$(System.DefaultWorkingDirectory)/extension.manifest")) { $errors += "Manifest file not found: extension.manifest" } + if (-not (Test-Path "$(System.DefaultWorkingDirectory)/extension.signature.p7s")) { $errors += "Signature file not found: extension.signature.p7s" } + + if ($errors) { + $errors | ForEach-Object { Write-Host "##vso[task.logissue type=error]$_" } + Write-Host "##vso[task.complete result=Failed;]" + exit 1 + } + + $vsixFileName = $vsixFiles.Name + $vsixFileSize = [math]::Round($vsixFiles.Length / 1MB, 2) + Write-Output "##vso[task.setvariable variable=vsixFileName;isOutput=true]$vsixFileName" + Write-Output "โœ… VSIX: $vsixFileName (${vsixFileSize} MB)" + Write-Output "โœ… Manifest: extension.manifest" + Write-Output "โœ… Signature: extension.signature.p7s" + + - task: PowerShell@2 + displayName: '๐Ÿ“– Extract Metadata from VSIX' + name: extractMetadataStep + inputs: + pwsh: true + targetType: 'inline' + script: | + $ErrorActionPreference = "Stop" + $vsixPath = "$(System.DefaultWorkingDirectory)/$(findPublishingFilesStep.vsixFileName)" + + Add-Type -AssemblyName System.IO.Compression.FileSystem + $zip = [System.IO.Compression.ZipFile]::OpenRead($vsixPath) + + # Extract package.json from inside the VSIX + $pkgEntry = $zip.Entries | Where-Object { $_.FullName -eq 'extension/package.json' } | Select-Object -First 1 + if (-not $pkgEntry) { + Write-Host "##vso[task.logissue type=error]extension/package.json not found in VSIX" + Write-Host "##vso[task.complete result=Failed;]" + exit 1 + } + $pkgReader = New-Object System.IO.StreamReader($pkgEntry.Open()) + $pkg = $pkgReader.ReadToEnd() | ConvertFrom-Json + $pkgReader.Close() + + # Extract vsixmanifest + $manifestEntry = $zip.Entries | Where-Object { $_.FullName -eq 'extension.vsixmanifest' } | Select-Object -First 1 + if (-not $manifestEntry) { + Write-Host "##vso[task.logissue type=error]extension.vsixmanifest not found in VSIX" + Write-Host "##vso[task.complete result=Failed;]" + exit 1 + } + $manifestReader = New-Object System.IO.StreamReader($manifestEntry.Open()) + [xml]$manifest = $manifestReader.ReadToEnd() + $manifestReader.Close() + + $zip.Dispose() + + # Set output variables + $version = $pkg.version + $name = $pkg.name + $manifestVer = $manifest.PackageManifest.Metadata.Identity.Version + + Write-Output "##vso[task.setvariable variable=version;isOutput=true]$version" + Write-Output "##vso[task.setvariable variable=name;isOutput=true]$name" + Write-Output "##vso[task.setvariable variable=manifestVersion;isOutput=true]$manifestVer" + + Write-Output "Extension: $name" + Write-Output "Version: $version" + Write-Output "Manifest Version: $manifestVer" + + - task: PowerShell@2 + displayName: 'โœ… Validate Publish Version' + inputs: + pwsh: true + targetType: 'inline' + script: | + if ("${{ parameters.publishVersion }}" -ne "$(extractMetadataStep.version)") { + Write-Host "##vso[task.logissue type=error]Publish version mismatch: expected '${{ parameters.publishVersion }}', got '$(extractMetadataStep.version)'" + Write-Host "##vso[task.complete result=Failed;]" + exit 1 + } + Write-Output "โœ… Publish version: $(extractMetadataStep.version)" + + - task: PowerShell@2 + displayName: 'โœ… Validate VSIX Filename' + inputs: + pwsh: true + targetType: 'inline' + script: | + $expected = "$(extractMetadataStep.name)-$(extractMetadataStep.version).vsix" + $actual = "$(findPublishingFilesStep.vsixFileName)" + + if ($actual -ne $expected) { + Write-Host "##vso[task.logissue type=error]VSIX filename mismatch: expected '$expected', got '$actual'" + Write-Host "##vso[task.complete result=Failed;]" + exit 1 + } + + Write-Output "โœ… Filename valid: $actual" + + - task: PowerShell@2 + displayName: 'โœ… Validate Manifest Consistency' + inputs: + pwsh: true + targetType: 'inline' + script: | + $ErrorActionPreference = "Stop" + $vsixVersion = "$(extractMetadataStep.version)" + $vsixManifestVersion = "$(extractMetadataStep.manifestVersion)" + + $artifactPkg = Get-Content "$(System.DefaultWorkingDirectory)/package.json" -Raw | ConvertFrom-Json + $artifactVersion = $artifactPkg.version + + $errors = @() + if ($vsixManifestVersion -ne $vsixVersion) { $errors += "VSIX internal version mismatch: package.json=$vsixVersion, vsixmanifest=$vsixManifestVersion" } + if ($artifactVersion -ne $vsixVersion) { $errors += "Artifact version mismatch: artifact=$artifactVersion, VSIX=$vsixVersion" } + + if ($errors) { + $errors | ForEach-Object { Write-Host "##vso[task.logissue type=error]$_" } + Write-Host "##vso[task.complete result=Failed;]" + exit 1 + } + + Write-Output "โœ… Manifest consistency validated (version=$vsixVersion)" + + - job: PublishExtension + displayName: '๐Ÿš€ Publish Extension' + condition: and(succeeded(), ${{ eq(parameters.dryRun, false) }}) + dependsOn: ReleaseValidation + pool: + type: release + variables: + vsixFileName: $[ dependencies.ReleaseValidation.outputs['findPublishingFilesStep.vsixFileName'] ] + templateContext: + inputs: + - input: pipelineArtifact + pipeline: build + targetPath: $(System.DefaultWorkingDirectory) + artifactName: drop_BuildStage_Main + workflow: vsce + vsce: + serviceConnection: 'CosmosDB VSCode Publishing' # azureRM service connection for the managed identity used to publish the extension. Only this publishing auth method is supported. + vsixPath: '$(vsixFileName)' # Path to VSIX file in artifact + #preRelease: true # default false. Whether the extension is a pre-release. + signaturePath: $(System.DefaultWorkingDirectory)/extension.signature.p7s # required - validated by ReleaseValidation job + manifestPath: $(System.DefaultWorkingDirectory)/extension.manifest # required - validated by ReleaseValidation job + useCustomVSCE: true # for the time being, you must supply a feed in your project with @vscode/vsce@3.3.2 + feed: + organization: msdata + project: CosmosDB + feedName: vscode-documentdb + steps: + # we need a noop step otherwise the vsce template won't run + - pwsh: Write-Output "Done" + condition: ${{ eq(parameters.dryRun, true) }} # noop - this condition is always false when this job runs + displayName: '๐Ÿ“ข Post-Publishing' diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f802d21..1a90485f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Change Log -## 0.7.1 +## 0.7.2 ### Improvements @@ -15,6 +15,10 @@ - **Dependency Updates**: Updates `minimatch` (3.1.2 โ†’ 3.1.4), `qs`, and `body-parser` to address security vulnerabilities. [#505](https://github.com/microsoft/vscode-documentdb/pull/505), [#514](https://github.com/microsoft/vscode-documentdb/pull/514) +## 0.7.1 _skipped_ + +Version 0.7.1 was reserved for an internal validation build and was not released on the Marketplace. + ## 0.7.0 ### New Features diff --git a/docs/index.md b/docs/index.md index 1f379d95..febd9810 100644 --- a/docs/index.md +++ b/docs/index.md @@ -65,7 +65,7 @@ The User Manual provides guidance on using DocumentDB for VS Code. It contains d Explore the history of updates and improvements to the DocumentDB for VS Code extension. Each release brings new features, enhancements, and fixes to improve your experience. -- [0.7](./release-notes/0.7), [0.7.1](./release-notes/0.7#patch-release-v071) +- [0.7](./release-notes/0.7), [0.7.2](./release-notes/0.7#patch-release-v072) - [0.6](./release-notes/0.6), [0.6.1](./release-notes/0.6#patch-release-v061), [0.6.2](./release-notes/0.6#patch-release-v062), [0.6.3](./release-notes/0.6#patch-release-v063) - [0.5](./release-notes/0.5), [0.5.1](./release-notes/0.5#patch-release-v051), [0.5.2](./release-notes/0.5#patch-release-v052) - [0.4](./release-notes/0.4), [0.4.1](./release-notes/0.4#patch-release-v041) diff --git a/docs/release-notes/0.7.md b/docs/release-notes/0.7.md index d2ceccd9..4f4e5d8a 100644 --- a/docs/release-notes/0.7.md +++ b/docs/release-notes/0.7.md @@ -203,11 +203,13 @@ See the full changelog entry for this release: --- -## Patch Release v0.7.1 +## Patch Release v0.7.2 This patch release improves data migration discoverability, adds reconnect prompts for error recovery, introduces an experimental AI query generation setting, and includes security dependency updates. -### What's Changed in v0.7.1 +> **Note:** Version 0.7.1 was reserved for internal validation and was not published as a public release. + +### What's Changed in v0.7.2 #### ๐Ÿ’  **Data Migration Discoverability** ([#515](https://github.com/microsoft/vscode-documentdb/pull/515)) @@ -242,4 +244,4 @@ Updated `minimatch` (3.1.2 โ†’ 3.1.4), `qs` and `body-parser` to address securit ### Changelog See the full changelog entry for this release: -โžก๏ธ [CHANGELOG.md#071](https://github.com/microsoft/vscode-documentdb/blob/main/CHANGELOG.md#071) +โžก๏ธ [CHANGELOG.md#072](https://github.com/microsoft/vscode-documentdb/blob/main/CHANGELOG.md#072) diff --git a/package-lock.json b/package-lock.json index 9253e448..ade59941 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "vscode-documentdb", - "version": "0.7.1", + "version": "0.7.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "vscode-documentdb", - "version": "0.7.1", + "version": "0.7.2", "license": "SEE LICENSE IN LICENSE.md", "dependencies": { "@azure/arm-compute": "^22.4.0", diff --git a/package.json b/package.json index f5abc638..e0287804 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "vscode-documentdb", - "version": "0.7.1", + "version": "0.7.2", "releaseNotesUrl": "https://github.com/microsoft/vscode-documentdb/discussions/489", "aiKey": "0c6ae279ed8443289764825290e4f9e2-1a736e7c-1324-4338-be46-fc2a58ae4d14-7255", "publisher": "ms-azuretools",