Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,17 @@
"detail": "Clean output directories.",
"command": "Invoke-Build Clean",
"problemMatcher": []
},
{
"label": "Update template docs",
"detail": "Generate template markdown docs.",
"type": "shell",
"command": "Invoke-Build UpdateTemplateDocs",
"problemMatcher": [],
"presentation": {
"clear": true,
"panel": "dedicated"
}
}
]
}
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@

What's changed since v0.1.0:

- New features:
- Template outputs are added to generated document. [#28](https://github.com/Azure/PSDocs.Azure/issues/28)
- Bug fixes:
- Fixed snippet with short relative template causes exception. [#26](https://github.com/Azure/PSDocs.Azure/issues/26)
- Fixed cannot bind argument when metadata name is not set. [#35](https://github.com/Azure/PSDocs.Azure/issues/35)

## v0.1.0

Expand Down
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,16 @@ For example:
}
},
"resources": [
]
],
"outputs": {
"resourceId": {
"type": "string",
"value": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]",
"metadata": {
"description": "A unique resource identifier for the storage account."
}
}
}
}
```

Expand All @@ -108,6 +117,7 @@ Field | Scope | Type | Description
`description` | Parameter | `string` | Used as the description for the parameter.
`example` | Parameter | `string`, `boolean`, `object`, or `array` | An example use of the parameter. The example is included in the JSON snippet. If an example is not included the default value is used instead.
`ignore` | Parameter | `boolean` | When `true` the parameter is not included in the JSON snippet.
`description` | Output | `string` | Used as the description for the output.

An example of an Azure Storage Account template with metadata included is available [here](templates/storage/v1/template.json).

Expand Down
10 changes: 10 additions & 0 deletions pipeline.build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,16 @@ task TestModule ModuleDependencies, Pester, PSScriptAnalyzer, {
}
}

task UpdateTemplateDocs Build, {
Import-Module (Join-Path -Path $PWD -ChildPath 'out/modules/PSDocs.Azure')

# Scan for Azure template file recursively in the templates/ directory
Get-AzDocTemplateFile -Path templates/ | ForEach-Object {
$template = Get-Item -Path $_.TemplateFile;
Invoke-PSDocument -Module PSDocs.Azure -OutputPath $template.Directory.FullName -InputObject $template.FullName;
}
}

# Synopsis: Run script analyzer
task Analyze Build, PSScriptAnalyzer, {
Invoke-ScriptAnalyzer -Path out/modules/PSDocs.Azure;
Expand Down
78 changes: 66 additions & 12 deletions src/PSDocs.Azure/docs/Azure.Template.Doc.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,22 @@ function global:GetTemplateParameter {
process {
$template = Get-Content -Path $Path -Raw | ConvertFrom-Json;
foreach ($property in $template.parameters.PSObject.Properties) {
[PSCustomObject]@{
$result = [PSCustomObject]@{
Name = $property.Name
Description = $property.Value.metadata.description
DefaultValue = $property.Value.defaultValue
AllowedValues = $property.Value.allowedValues
Description = ''
DefaultValue = $Null
AllowedValues = $Null
}
if ([bool]$property.Value.PSObject.Properties['metadata'] -and [bool]$property.Value.metadata.PSObject.Properties['description']) {
$result.Description = $property.Value.metadata.description;
}
if ([bool]$property.Value.PSObject.Properties['defaultValue']) {
$result.DefaultValue = $property.Value.defaultValue;
}
if ([bool]$property.Value.PSObject.Properties['allowedValues']) {
$result.AllowedValues = $property.Value.allowedValues;
}
$result;
}
}
}
Expand Down Expand Up @@ -52,8 +62,9 @@ function global:GetTemplateExample {
}
foreach ($property in $template.parameters.PSObject.Properties) {
$propertyValue = $Null;
$hasMetadata = [bool]$property.Value.PSObject.Properties['metadata'];

if ($True -eq $property.Value.metadata.ignore) {
if ($hasMetadata -and [bool]$property.Value.metadata.PSObject.Properties['ignore'] -and $True -eq $property.Value.metadata.ignore) {
continue;
}

Expand All @@ -70,10 +81,10 @@ function global:GetTemplateExample {
continue;
}

if ($Null -ne $property.Value.metadata.example) {
if ($hasMetadata -and [bool]$property.Value.metadata.PSObject.Properties['example'] -and $Null -ne $property.Value.metadata.example) {
$propertyValue = $property.Value.metadata.example;
}
elseif ($Null -ne $property.Value.defaultValue) {
elseif ([bool]$property.Value.PSObject.Properties['defaultValue'] -and $Null -ne $property.Value.defaultValue) {
$propertyValue = $property.Value.defaultValue;
}
elseif ($property.Value.type -eq 'array') {
Expand Down Expand Up @@ -106,7 +117,33 @@ function global:GetTemplateMetadata {
[String]$Path
)
process {
return (Get-Content -Path $Path -Raw | ConvertFrom-Json).metadata;
$template = Get-Content -Path $Path -Raw | ConvertFrom-Json;
if ([bool]$template.PSObject.Properties['metadata']) {
return $template.metadata;
}
}
}

# A function to import outputs
function global:GetTemplateOutput {
[CmdletBinding()]
param (
[Parameter(Mandatory = $True)]
[String]$Path
)
process {
$template = Get-Content -Path $Path -Raw | ConvertFrom-Json;
foreach ($property in $template.outputs.PSObject.Properties) {
$output = [PSCustomObject]@{
Name = $property.Name
Type = $property.Value.type
Description = ''
}
if ([bool]$property.Value.PSObject.Properties['metadata'] -and [bool]$property.Value.metadata.PSObject.Properties['description']) {
$output.Description = $property.Value.metadata.description
}
$output;
}
}
}

Expand All @@ -117,16 +154,25 @@ Document 'README' {
$templatePath = $InputObject;
$parameters = GetTemplateParameter -Path $templatePath;
$metadata = GetTemplateMetadata -Path $templatePath;
$outputs = GetTemplateOutput -Path $templatePath;

# Set document title
Title $metadata.name
if ($Null -ne $metadata -and [bool]$metadata.PSObject.Properties['name']) {
Title $metadata.name
}
else {
Title $LocalizedData.DefaultTitle
}

# Write opening line
$metadata.Description
if ($Null -ne $metadata -and [bool]$metadata.PSObject.Properties['description']) {
$metadata.description
}

# Add each parameter to a table
# Add table and detail for each parameter
Section $LocalizedData.Parameters {
$parameters | Table -Property @{ Name = $LocalizedData.ParameterName; Expression = { $_.Name }}, $LocalizedData.Description
$parameters | Table -Property @{ Name = $LocalizedData.ParameterName; Expression = { $_.Name }},
@{ Name = $LocalizedData.Description; Expression = { $_.Description }}

foreach ($parameter in $parameters) {
Section $parameter.Name {
Expand All @@ -145,6 +191,14 @@ Document 'README' {
}
}

# Add table for outputs
Section $LocalizedData.Outputs {
$outputs | Table -Property @{ Name = $LocalizedData.Name; Expression = { $_.Name }},
@{ Name = $LocalizedData.Type; Expression = { $_.Type }},
@{ Name = $LocalizedData.Description; Expression = { $_.Description }}
}

# Insert snippet
$example = GetTemplateExample -Path $templatePath;
Section $LocalizedData.Snippets {
$example | Code 'json'
Expand Down
4 changes: 4 additions & 0 deletions src/PSDocs.Azure/en/PSDocs-strings.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@
@{
Parameters = 'Parameters'
Snippets = 'Snippets'
Outputs = 'Outputs'
DefaultValue = "- Default value: {0}"
AllowedValues = "- Allowed values: {0}"
ParameterName = 'Parameter name'
Description = 'Description'
Type = 'Type'
Name = 'Name'
DefaultTitle = 'Azure template'
}
11 changes: 9 additions & 2 deletions templates/storage/v1/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Parameter name | Description
-------------- | -----------
storageAccountName | Required. The name of the Storage Account.
location | Optional. The Azure region to deploy to.
sku | Optional. Crease the Storage Account as LRS or GRS.
sku | Optional. Create the Storage Account as LRS or GRS.
suffixLength | Optional. Determine how many additional characters are added to the storage account name as a suffix.
containers | Optional. An array of storage containers to create on the storage account.
lifecycleRules | Optional. An array of lifecycle management policies for the storage account.
Expand All @@ -33,7 +33,7 @@ Optional. The Azure region to deploy to.

### sku

Optional. Crease the Storage Account as LRS or GRS.
Optional. Create the Storage Account as LRS or GRS.

- Default value: `Standard_LRS`

Expand Down Expand Up @@ -95,6 +95,13 @@ Optional. Set to the objectId of Azure Key Vault to delegated permission for use

Optional. Tags to apply to the resource.

## Outputs

Name | Type | Description
---- | ---- | -----------
blobEndpoint | string | A URI to the blob storage endpoint.
resourceId | string | A unique resource identifier for the storage account.

## Snippets

```json
Expand Down
20 changes: 18 additions & 2 deletions templates/storage/v1/template.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"Standard_GRS"
],
"metadata": {
"description": "Optional. Crease the Storage Account as LRS or GRS."
"description": "Optional. Create the Storage Account as LRS or GRS."
}
},
"suffixLength": {
Expand Down Expand Up @@ -346,5 +346,21 @@
"principalType": "ServicePrincipal"
}
}
]
],
"outputs": {
"blobEndpoint": {
"type": "string",
"value": "[reference(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2019-06-01').primaryEndpoints.blob]",
"metadata": {
"description": "A URI to the blob storage endpoint."
}
},
"resourceId": {
"type": "string",
"value": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]",
"metadata": {
"description": "A unique resource identifier for the storage account."
}
}
}
}
10 changes: 10 additions & 0 deletions tests/PSDocs.Azure.Tests/Azure.Common.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,16 @@ Describe 'PSDocs' -Tag 'PSDocs', 'Common' {
$result | Should -Not -BeNullOrEmpty;
}

It 'With basic template' {
$invokeParams = @{
Module = 'PSDocs.Azure'
OutputPath = $outputPath
InputObject = (Join-Path -Path $rootPath -ChildPath 'tests/PSDocs.Azure.Tests/basic.template.json')
}
$result = Invoke-PSDocument @invokeParams;
$result | Should -Not -BeNullOrEmpty;
}

It 'With relative path' {
Push-Location -Path (Join-Path -Path $rootPath -ChildPath 'templates/storage/v1/');
try {
Expand Down
Loading