Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DPG best-practice and automation template #28016

Merged
merged 30 commits into from
May 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
c44d193
Add request condition argument check
chunyu3 Jan 28, 2022
5731c4c
resolve build failure
chunyu3 Jan 29, 2022
03ffbd4
remove unused import
chunyu3 Jan 29, 2022
b39897b
remove unused Azure.Core dependency
chunyu3 Feb 23, 2022
c24ceb7
move eng template to sdk
chunyu3 Apr 6, 2022
07b6e6f
update sample template to DPG + growup
chunyu3 Apr 6, 2022
cadd39f
update test cases
chunyu3 Apr 6, 2022
a53fe5c
remove the templates from eng directory
chunyu3 Apr 6, 2022
cc3fa4b
update Azure.ServiceTemplate.Template
chunyu3 Apr 6, 2022
3b03b73
merge Azure.ServiceTemplate.Template with Azure.Template
chunyu3 Apr 12, 2022
985522c
update api
chunyu3 Apr 12, 2022
b9db6ac
resolve rebase conflict
chunyu3 Apr 12, 2022
0d2e4ad
complete Azure.Template to match DPG guideline
chunyu3 Apr 13, 2022
9b30311
refine template samples
chunyu3 Apr 15, 2022
42fe66a
update template content
chunyu3 Apr 18, 2022
b63d110
remove project file in template content
chunyu3 Apr 20, 2022
74755ca
refine snippet in Readme
chunyu3 Apr 20, 2022
ff05a55
resolve inner scope conflict issule
chunyu3 Apr 20, 2022
0bca6eb
refine test
chunyu3 Apr 20, 2022
6dd92af
remove duplicate snippet
chunyu3 Apr 20, 2022
d056b57
update template sample
chunyu3 Apr 20, 2022
31768a0
update script to use the Azure.Template
chunyu3 Apr 21, 2022
cd456af
add function to update ci.yml
chunyu3 Apr 21, 2022
1577d27
remove log in script
chunyu3 Apr 21, 2022
55e1add
resolve comments
chunyu3 Apr 21, 2022
ec265d2
use actual type instead of var
chunyu3 Apr 24, 2022
0ebb050
resolve comments
chunyu3 Apr 26, 2022
96df97d
refine readme files, add error checking in outer script
chunyu3 Apr 29, 2022
cb009d5
add Azure.Template as the content of template
chunyu3 May 6, 2022
f4fc1d0
move .content folder out of Azure.Template
chunyu3 May 6, 2022
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
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ sdk\<service name>\<package name>\CHANGELOG.md
- `<service name>` - Should be the short name for the azure service. e.g. deviceupdate
- `<package name>` - Should be the name of the shipping package, or an abbreviation that distinguishes the given shipping artifact for the given service. It will be `Azure.<group>.<service>`, e.g. Azure.IoT.DeviceUpdate

We will use dotnet project template [Azure.ServiceTemplate.Template](https://github.com/Azure/azure-sdk-for-net/blob/3ac301ac6435c818ad7a9946ab1c4023cee236ff/eng/templates) to automatically create the project.
We will use dotnet project template [Azure.Template](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/template/Azure.Template) to automatically create the project.

You can run `eng\scripts\automation\Invoke-DataPlaneGenerateSDKPackage.ps1` to generate the starting SDK client library package directly as following:

Expand All @@ -80,12 +80,13 @@ pwsh /home/azure-sdk-for-net/eng/scripts/automation/Invoke-DataPlaneGenerateSDKP
- For `- namespace`, please use one of the pre-approved namespace groups on the [.NET Azure SDK Guidelines Approved Namespaces list](https://azure.github.io/azure-sdk/dotnet_introduction.html#dotnet-namespaces-approved-list). This value will also provide the name for the shipped package, and should be of the form `Azure.<group>.<service>`.
- `-inputfiles` takes the address of the Open API spec files, separated by semicolon if there is more than one file. The Open API spec file can be local file, e.g. ./swagger/compute.json, or the web address of the file in the `azure-rest-api-specs` repo. When pointing to a file in the `azure-rest-api-specs` repo, make sure to include the commit id in the URI, i.e. `https://github.com/Azure/azure-rest-api-specs/blob/73a0fa453a93bdbe8885f87b9e4e9fef4f0452d0/specification/webpubsub/data-plane/WebPubSub/stable/2021-10-01/webpubsub.json`. This ensures that you can choose the time to upgrade to new swagger file versions.
- `-readme` takes the address of the readme configuration file. The configuration can be local file, e.g. ./swagger/readme.md or the web address of the file in the `azure-rest-api-specs` repo, i.e. `https://github.com/Azure/azure-rest-api-specs/blob/23dc68e5b20a0e49dd3443a4ab177d9f2fcc4c2b/specification/deviceupdate/data-plane/readme.md`
- You need to provide one of `-inputfiles` and `-readme` parameters. If you provide both, `-inputfiles` will be ignored.
- `-securityScope` designates the authentication scope to use if your library supports **Token Credential** authentication.
- `-securityHeaderName` designates the key to use if your library supports **Azure Key Credential** authentication.

When you run the `eng\scripts\automation\Invoke-DataPlaneGenerateSDKPackage.ps1` script, it will:

- Create a project folder, install template files from `eng/templates/Azure.ServiceTemplate.Template`, and create `.csproj` and `.sln` files for your new library.
- Create a project folder, install template files from `sdk/template/Azure.Template`, and create `.csproj` and `.sln` files for your new library.

These files are created following the guidance for the [Azure SDK Repo Structure](https://github.com/Azure/azure-sdk/blob/master/docs/policies/repostructure.md).

Expand All @@ -111,8 +112,7 @@ Here is the step by step process to add tests:requirements

- Add other client parameters in `<client-name>ClientTestEnvironment.cs`
- Update `<client-name>ClientTest.cs`.
- Comment-out the 'CreateClient' method, and update the new `<service>Client` statement.
- remove all the template project tests, and write the tests according to the commented Test method template. Please refer to [Using the TestFramework](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/core/Azure.Core.TestFramework/README.md) to add tests.
- Please refer to [Using the TestFramework](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/core/Azure.Core.TestFramework/README.md) to add tests.

**Note**:

Expand All @@ -131,13 +131,13 @@ You will update all the `Sample<sample_number>_<scenario>.md` and README.md file

### Snippets

Snippets are the great way to reuse the sample code. Snippets allow us to verify that the code in our samples and READMEs is always up to date, and passes unit tests. We have added the snippet [here](https://github.com/Azure/azure-sdk-for-net/blob/3ac301ac6435c818ad7a9946ab1c4023cee236ff/eng/templates/Azure.ServiceTemplate.Template/tests/Samples/Sample1_CreateResource.cs#L32) in a sample and used it in the [README](https://github.com/Azure/azure-sdk-for-net/blob/3ac301ac6435c818ad7a9946ab1c4023cee236ff/eng/templates/Azure.ServiceTemplate.Template/README.md#create-resource). Please refer to [Updating Sample Snippets](https://github.com/Azure/azure-sdk-for-net/blob/main/CONTRIBUTING.md#updating-sample-snippets) to add snippets in your samples.
Snippets are the great way to reuse the sample code. Snippets allow us to verify that the code in our samples and READMEs is always up to date, and passes unit tests. We have added the snippet [here](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/template/Azure.Template/tests/Samples/Sample1_HelloWorld.cs#L21) in a sample and used it in the [README](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/template/Azure.Template/README.md#get-secret). Please refer to [Updating Sample Snippets](https://github.com/Azure/azure-sdk-for-net/blob/main/CONTRIBUTING.md#updating-sample-snippets) to add snippets in your samples.

### README

README.md file instructions are listed in `Azure.<group>.<service>/README.md` file. Please add/update the README.md file as per your library.

**Learn more:** to understand more about README, see the [README.md](https://github.com/Azure/azure-sdk-for-net/blob/3ac301ac6435c818ad7a9946ab1c4023cee236ff/eng/templates/Azure.ServiceTemplate.Template/README.md). Based on that [here](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/keyvault/Azure.Security.KeyVault.Keys/README.md) is an example.
**Learn more:** to understand more about README, see the [README.md](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/template/Azure.Template/README.md). Based on that [here](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/keyvault/Azure.Security.KeyVault.Keys/README.md) is an example.

### Changelog

Expand All @@ -151,7 +151,7 @@ You can add convienice APIs by adding a customization layer on top of the genera

If other modifications are needed to the generated API, you can consider making them directly to the Open API specification, which will have the benefit of making the changes to the library in all languages you generate the library in. As a last resort, you can add modifications with swagger transforms in the `autorest.md` file. [AnomalyDetector autorest.md](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/anomalydetector/Azure.AI.AnomalyDetector/src/autorest.md) shows and example of how this can be accomplished.

Once you've made changes to the public API, you will need to run the `eng\scripts\Export-API.ps1` script to update the public API listing. This will generate a file in the library's directory similar to the example found in [eng\templates\Azure.ServiceTemplate.Template\api\Azure.ServiceTemplate.Template.netstandard2.0.cs](https://github.com/Azure/azure-sdk-for-net/blob/bb0fbccfc33dd27d1ec6f0870022824d47181e61/sdk/template-dpg/Azure.ServiceTemplate.Template/api/Azure.ServiceTemplate.Template.netstandard2.0.cs).
Once you've made changes to the public API, you will need to run the `eng\scripts\Export-API.ps1` script to update the public API listing. This will generate a file in the library's directory similar to the example found in [sdk\template\Azure.Template\api\Azure.Template.netstandard2.0.cs](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/template/Azure.Template/api/Azure.Template.netstandard2.0.cs).

e.g. Running the script for a project in `sdk\deviceupdate` would look like this:

Expand Down
88 changes: 77 additions & 11 deletions eng/scripts/automation/GenerateAndBuildLib.ps1
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#Requires -Version 7.0

$CI_YAML_FILE = "ci.yml"
function Get-SwaggerInfo()
{
param(
Expand Down Expand Up @@ -85,6 +85,30 @@ function Update-AutorestConfigFile() {
exit 1
}
}

function Update-CIYmlFile() {
param (
[string]$ciFilePath,
[string]$artifact
)
if (Test-Path -Path $ciFilePath) {
$packageRex = "name *: $artifact"
if ((Get-Content $ciFilePath | Select-String -Pattern $packageRex).Matches.Success) {
Write-Host "CI already enabled."
} else {
$safeName = $artifact.Replace('.', '')
$artifactsBlockRex = "Artifacts *:"
$startNum = (Get-Content $ciFilePath | Select-String -Pattern $artifactsBlockRex).LineNumber[0]
$fileContent = Get-Content -Path $ciFilePath
$fileContent[$startNum - 1] += ([Environment]::NewLine + " - " + "name: $artifact" + [Environment]::NewLine + " safeName: $safeName")
$fileContent | Set-Content $ciFilePath
}
} else {
Write-Error "ci.yml doesn't exist."
exit 1
}
}

function New-DataPlanePackageFolder() {
param(
[string]$service,
Expand All @@ -103,41 +127,50 @@ function New-DataPlanePackageFolder() {
$inputfile = ""
$fileArray = $inputfiles.Split(";")
if (($inputfiles -ne "") -And ($fileArray.Length -gt 0)) {
$inputfile = "- " + $fileArray[0];
for ($i = 1; $i -lt $fileArray.Count ; $i++) {
for ($i = 0; $i -lt $fileArray.Count ; $i++) {
$inputfile = $inputfile + [Environment]::NewLine + "- " + $fileArray[$i]
}
}

$serviceFolder = (Join-Path $sdkPath "sdk" $service)
if (!(Test-Path -Path $serviceFolder)) {
Write-Host "service folder does not exist! create the folder $serviceFolder"
New-Item -Path $serviceFolder -ItemType Directory
}
$projectFolder=(Join-Path $sdkPath "sdk" $service $namespace)
$ciymlFilePath =(Join-Path $sdkPath "sdk" $service $CI_YAML_FILE)
$apifolder = (Join-Path $projectFolder "api")
Write-Host "projectFolder:$projectFolder, apifolder:$apifolder"
if ((Test-Path -Path $projectFolder) -And (Test-Path -Path $apifolder)) {
Write-Host "Path exists!"
# update the input-file url if needed.
$file = (Join-Path $projectFolder "src" $AUTOREST_CONFIG_FILE)
Update-AutorestConfigFile -autorestFilePath $file -inputfile $inputfile -readme $readme
Update-CIYmlFile -ciFilePath $ciymlFilePath -artifact $namespace
} else {
Write-Host "Path doesn't exist. create template."
if ($inputfile -eq "" -And $readme -eq "") {
Write-Error "Error: input file should not be empty."
exit 1
}
dotnet new -i $sdkPath/eng/templates/Azure.ServiceTemplate.Template
dotnet new -i $sdkPath/sdk/template
Write-Host "Create project folder $projectFolder"
New-Item -Path $projectFolder -ItemType Directory
Push-Location $projectFolder
if (Test-Path -Path $projectFolder) {
Remove-Item -Path $projectFolder -ItemType Directory
}

Push-Location $serviceFolder
$namespaceArray = $namespace.Split(".")
if ( $namespaceArray.Count -lt 3) {
Write-Error "Error: invalid namespace name."
exit 1
}

$libraryName = $namespaceArray[-1]
$clientName = $namespaceArray[-1]
$groupName = $namespaceArray[1]
$dotnetNewCmd = "dotnet new dataplane --libraryName $libraryName --groupName $groupName --includeCI true --force"
$dotnetNewCmd = "dotnet new azsdkdpg --name $namespace --clientName $clientName --groupName $groupName --serviceDirectory $service --force"
if ($inputfile -ne "") {
$dotnetNewCmd = $dotnetNewCmd + " --swagger $inputfile"
$dotnetNewCmd = $dotnetNewCmd + " --swagger '$inputfile'"
}
if ($securityScope -ne "") {
$dotnetNewCmd = $dotnetNewCmd + " --securityScopes $securityScope";
Expand All @@ -147,13 +180,21 @@ function New-DataPlanePackageFolder() {
$dotnetNewCmd = $dotnetNewCmd + " --securityHeaderName $securityHeaderName";
}

# dotnet new dataplane --libraryName $libraryName --swagger $inputfile --securityScopes $securityScope --securityHeaderName $securityHeaderName --includeCI true --force
if (Test-Path -Path $ciymlFilePath) {
Write-Host "ci.yml already exists. update it to include the new serviceDirectory."
Update-CIYmlFile -ciFilePath $ciymlFilePath -artifact $namespace

$dotnetNewCmd = $dotnetNewCmd + " --includeCI false"
}
# dotnet new azsdkdpg --name $namespace --clientName $clientName --groupName $groupName --serviceDirectory $service --swagger $inputfile --securityScopes $securityScope --securityHeaderName $securityHeaderName --includeCI true --force
Write-Host "Invote dotnet new command: $dotnetNewCmd"
Invoke-Expression $dotnetNewCmd

$file = (Join-Path $projectFolder "src" $AUTOREST_CONFIG_FILE)
Update-AutorestConfigFile -autorestFilePath $file -inputfile $inputfile -readme $readme
Update-AutorestConfigFile -autorestFilePath $file -readme $readme
Pop-Location
# dotnet sln
Push-Location $projectFolder
dotnet sln remove src\$namespace.csproj
dotnet sln add src\$namespace.csproj
dotnet sln remove tests\$namespace.Tests.csproj
Expand Down Expand Up @@ -244,6 +285,26 @@ function Invoke-Generate() {
$sdkfolder = $sdkfolder -replace "\\", "/"
Push-Location $sdkfolder/src
dotnet build /t:GenerateCode
if ( !$? ) {
Write-Error "Failed to generate sdk."
Pop-Location
exit 1
}
Pop-Location
}

function Invoke-Build() {
param(
[string]$sdkfolder= ""
)
$sdkfolder = $sdkfolder -replace "\\", "/"
Push-Location $sdkfolder
dotnet build
if ( !$? ) {
Write-Error "Failed to build sdk. exit code: $?"
Pop-Location
exit 1
}
Pop-Location
}

Expand All @@ -254,6 +315,11 @@ function Invoke-Pack() {
$sdkfolder = $sdkfolder -replace "\\", "/"
Push-Location $sdkfolder
dotnet pack
if ( !$? ) {
Write-Error "Failed to build sdk package. exit code: $?"
Pop-Location
exit 1
}
Pop-Location
}
function Get-ResourceProviderFromReadme($readmeFile) {
Expand Down
11 changes: 9 additions & 2 deletions eng/scripts/automation/Invoke-DataPlaneGenerateSDKPackage.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,16 @@ $outputJson = Get-Content $outputJsonFile | Out-String | ConvertFrom-Json
$projectFolder = $outputJson.projectFolder
Write-Host "projectFolder:$projectFolder"
Remove-Item $outputJsonFile
# Generate Code
Invoke-Generate -sdkfolder $projectFolder
if ( $? -ne $True) {
Write-Error "Failed to create generate sdk."
if ( !$? ) {
Write-Error "Failed to generate sdk."
exit 1
}
# Build
Invoke-Build -sdkfolder $projectFolder
if ( !$? ) {
Write-Error "Failed to build sdk. exit code: $?"
exit 1
}
# Generate APIs
Expand Down
11 changes: 5 additions & 6 deletions eng/scripts/automation/Invoke-GenerateAndBuild.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ if ( $serviceType -eq "resource-manager" ) {
Write-Host "Data-plane SDK Generation is not implemented currently."
exit 1
}
if ( $? -ne $True) {
if ( !$? ) {
Write-Error "Failed to create sdk project folder. exit code: $?"
exit 1
}
Expand All @@ -39,12 +39,11 @@ $projectFolder = $newpackageoutputJson.projectFolder
$path = $newpackageoutputJson.path
Write-Host "projectFolder:$projectFolder"
Remove-Item $newpackageoutput

# Generate Code
Invoke-Generate -sdkfolder $projectFolder
if ( $? -ne $True) {
Write-Error "Failed to generate sdk. exit code: $?"
exit 1
}
# Build
Invoke-Build -sdkfolder $projectFolder

$outputJson = [PSCustomObject]@{
packages = @([pscustomobject]@{packageName="$packageName"; result='succeeded'; path=@("$path");packageFolder="$path"})
}
Expand Down
Loading