refactor: move page meta to common meta module

This commit is contained in:
Rodweil, Theodor 2023-08-14 03:38:57 +02:00
parent 88aae9e3a6
commit 496d70360b
6 changed files with 804 additions and 186 deletions

291
src/Attachment.psm1 Executable file
View file

@ -0,0 +1,291 @@
#!/usr/bin/env pwsh
$ErrorActionPreference = "Stop"
function New-Attachment
{
<#
.SYNOPSIS
Add a new attachment
.DESCRIPTION
.OUTPUTS
When no $Title is provided and the $Manifest array only contains 1
page metadata, the ``Count`` attribute is faulty. Why? Don't know.
.EXAMPLE
Add-ConfluencePage `
-Host 'confluence.contoso.com' `
-Space 'TIARA' `
-Title 'Testitest' `
-Content @{}
#>
Param(
# confluence instance hostname
[Parameter(Mandatory)] [string]$Host,
# name of the Confluence space to publish to
[Parameter(Mandatory)] [string]$Space,
# title of page to be published
[Parameter()] [string]$Name,
# attachments manifest
[Parameter(Mandatory, ValueFromPipeline)]
[PSCustomObject[]]$Manifest,
# attachments manifest index, mandatory for ancestor lookup
[Parameter(Mandatory)] [Collections.Hashtable]$Index,
# pages manifest
[Parameter(Mandatory)]
[PSCustomObject[]]$PagesManifest,
# pages manifest index, mandatory for container page lookup
[Parameter(Mandatory)] [Collections.Hashtable]$PagesIndex,
# flag on whether to fail hard, or just continue
[Parameter()] [Switch]$Strict
)
Begin
{
$pat = Get-PersonalAccessToken $Host
}
Process
{
If ($Name -And $Manifest[$Index.$Name])
{
$Manifest = @(
$Manifest[$Index.$Name]
)
}
ForEach($attachmentMeta in $Manifest)
{
If ($Name -And $attachmentMeta.Name -ne $Name) {continue}
$containerPageMeta = $PagesManifest[
$PagesIndex."$($attachmentMeta.ContainerPageTitle)"
]
If (-Not $containerPageMeta)
{
throw (
"Get-AttachmentMeta: ``$($attachmentMeta.Name)``: " +
"unable to lookup metadata for container page " +
"title ``$($attachmentMeta.ContainerPageTitle)``." +
"This is fatal."
)
}
If (-Not $containerPageMeta.Id)
{
$errMsg = (
"Get-AttachmentMeta: ``$($attachmentMeta.Name)``: " +
"container page titled" +
"``$($attachmentMeta.ContainerPageTitle)`` " +
"has no id, which means that the page has " +
"(presumably) not yet been published."
)
If ($Strict) {throw $errMsg}
Write-Host "$errMsg Continuing nonetheless..."
$attachmentMeta
continue
}
ElseIf (-Not $attachmentMeta.Ref)
{
$errMsg = (
"``$($attachmentMeta.Name)``: no reference to local " +
'content for attachment .'
)
If ($Strict) {throw $errMsg}
Write-Host $errMsg
# not outputting the metadata, since it's invalid anyway
continue
}
ElseIf ($attachmentMeta.Id)
{
Write-Debug (
"New-Attachment: ``$($attacmentMeta.Name)``: skipping, " +
"already published ($($attachmentMeta.Id))"
)
$attachmentMeta
continue
}
Else
{
Write-Host (
"New-Attachment: ``$($attachmentMeta.Name)``: creating"
)
Try
{
$rawContent = [IO.File]::ReadAllBytes($attachmentMeta.Ref)
$content = [Text.Encoding]::GetEncoding(
'ISO-8859-1'
).GetString($rawContent)
}
Catch
{
$errMsg = "``New-Attachment: $($attachmentMeta.Name)``: $_"
If ($Strict) {throw $errMsg}
Write-Host $errMsg
continue
}
$boundary = [Guid]::NewGuid().ToString()
$LF = "`r`n";
$transportBody = (
"--$boundary",
(
"Content-Disposition: form-data; name=`"file`"; " +
"filename=`"$($attachmentMeta.Name)`""
),
"Content-Type: $($attachmentMeta.MimeType)$LF",
$content,
"--$boundary--$LF"
) -join $LF
$uri = (
"https://${Host}/rest/api/content/" +
"$($containerPageMeta.Id)/child/attachment"
)
Try
{
Invoke-WebRequest `
-Uri $uri `
-Method 'Post' `
-Headers @{
'Authorization' = "Bearer $pat"
'X-Atlassian-Token' = 'nocheck'
} `
-ContentType (
"multipart/form-data; boundary=`"$boundary`""
) `
-Body $transportBody `
-OutVariable rawResponse | Out-Null
}
Catch
{
$errMsg = "skipping ``$($attachmentMeta.Name)``: $($_)"
If ($Strict)
{
$_
throw $errMsg
}
Write-Host $errMsg
continue
}
$response = ($rawResponse.Content | ConvertFrom-JSON)
$attachmentMeta | Add-Member `
-NotePropertyName 'Id' `
-NotePropertyValue $response.id `
-Force
$attachmentMeta | Add-Member `
-NotePropertyName 'Version' `
-NotePropertyValue (
$response.version.number
) `
-Force
$contentHash = (Get-StringHash $content).Hash
$attachmentMeta | Add-Member `
-NotePropertyName 'Hash' `
-NotePropertyValue $contentHash `
-Force
If (
($Title -And $attachmentMeta.Title -eq $Name) -Or
$Manifest.Count -eq 1
)
{
# TODO: further research mechanism of expanding single item
# array pipelines. For now we have to apply the unary
# operator, otherwise we get a wrong count on the output
,@($attachmentMeta)
break
}
Else
{
$attachmentMeta
}
}
}
}
}
function Publish-Attachment
{
Param(
# confluence instance hostname
[Parameter(Mandatory)] [string]$Host,
# name of the Confluence space to publish to
[Parameter(Mandatory)] [string]$Space,
# title of page to be published
[Parameter()] [string]$Name,
# attachments manifest
[Parameter(Mandatory,ValueFromPipeline)]
[PSCustomObject[]]$Manifest,
# attachments manifest index, mandatory for ancestor lookup
[Parameter(Mandatory)] [Collections.Hashtable]$Index,
# pages manifest
[Parameter(Mandatory)]
[PSCustomObject[]]$PagesManifest,
# pages manifest index, mandatory for container page lookup
[Parameter(Mandatory)] [Collections.Hashtable]$PagesIndex,
# flag on whether to fail hard, or just continue
[Parameter()] [Switch]$Strict,
# flag on whether to force update of page, regardless of content
[Parameter()] [Switch]$Force
)
Process
{
$result = New-Attachment `
-Host $Host `
-Space $Space `
-Manifest $Manifest `
-Index $Index `
-PagesManifest $PagesManifest `
-PagesIndex $PagesIndex `
-Strict:$Strict
}
End
{
$result
}
}

340
src/Meta.psm1 Executable file
View file

@ -0,0 +1,340 @@
$ErrorActionPreference = "Stop"
function Get-PageMeta
{
<#
.SYNOPSIS
Get a Confluence page id
.DESCRIPTION
First, tries to retrieve from local page id index (cache) through
the local alias. If no cache hit, then polls the Confluence
instance host for the id by providing a space key and page title.
.EXAMPLE
Get-PageMeta `
-Host 'confluence.contoso.com' `
-Title 'Testitest' `
-Space 'TIARA' `
-CacheIndexFile 'confluence-page-cache.json'
#>
Param(
# Confluence instance hostname
[Parameter(Mandatory)] [string]$Host,
# Page title
[Parameter()] [string]$Title,
# Confluence space id
[Parameter(Mandatory)] [string]$Space,
# pages manifest
[Parameter(Mandatory, ValueFromPipeline)] [Array]$Manifest,
# page metadata index for faster lookup of single page
[Parameter()] [Collections.Hashtable]$Index,
# force to get metadata from remote
[Parameter()] [Switch]$Force,
# throw an exception on error
[Parameter()] [Switch]$Strict
)
Process
{
If ($Title -And $Index -And $Manifest[$Index.$Title].Id)
{
$Manifest[$Index.$Title]
return
}
ForEach ($pageMeta in $Manifest)
{
If ($Title -And $pageMeta.Title -ne $Title) {continue}
If ($pageMeta.Id -And -Not $Force)
{
Write-Debug (
"Get-PageMeta: ``$($pageMeta.Title)``: " +
"using locally cached metadata ($($pageMeta.Id))"
)
$pageMeta
}
Else
{
$escapedTitle = [Uri]::EscapeDataString($pageMeta.Title)
$query = (
"title=${escapedTitle}&spaceKey=${Space}&expand=version"
)
Invoke-WebRequest `
-Uri "https://${Host}/rest/api/content?$query" `
-Method 'Get' `
-Headers @{
'Authorization' = 'Bearer ' +
$(Get-PersonalAccessToken $Host)
} `
-OutVariable response | Out-Null
$results = ($response.Content | ConvertFrom-JSON).results
If ($results.Count -gt 1)
{
$errMsg = "error: more than one result for query: $query"
If ($Strict) {throw $errMsg}
Write-Host $errMsg
$pageMeta
continue
}
ElseIf ($results.Count -eq 1)
{
Write-Debug (
"Get-PageMetadata: ``$($pageMeta.Title)``: " +
"updating metadata through remote ($($results[0].id))"
)
$pageMeta | Add-Member `
-NotePropertyName Id `
-NotePropertyValue $results[0].id `
-Force
$pageMeta | Add-Member `
-NotePropertyName 'Version' `
-NotePropertyValue `
$results[0].version.number `
-Force
}
Else
{
Write-Debug (
"Get-PageMetadata: ``$($pageMeta.Title)``: " +
"no remote, using (partial) local"
)
If ($pageMeta.Version)
{
$pageMeta.PSObject.Properties.Remove('Version')
}
If ($pageMeta.Id)
{
$pageMeta.PSObject.Properties.Remove('Id')
}
}
If (-Not $pageMeta.Hash)
{
$content = Get-Content $pageMeta.Ref | Out-String
$hash = (Get-StringHash $content).Hash
$pageMeta | Add-Member `
-NotePropertyName 'Hash' `
-NotePropertyValue $hash `
-Force
}
$pageMeta
}
}
}
}
function Get-AttachmentMeta
{
<#
.SYNOPSIS
Get a Confluence page id
.DESCRIPTION
First, tries to retrieve from local page id index (cache) through
the local alias. If no cache hit, then polls the Confluence
instance host for the id by providing a space key and page title.
.EXAMPLE
Get-PageMeta `
-Host 'confluence.contoso.com' `
-Title 'Testitest' `
-Space 'TIARA' `
-CacheIndexFile 'confluence-page-cache.json'
#>
Param(
# Confluence instance hostname
[Parameter(Mandatory)] [string]$Host,
# Confluence space id
[Parameter(Mandatory)] [string]$Space,
# Attachment name
[Parameter()] [string]$Name,
# attachments manifest
[Parameter(Mandatory, ValueFromPipeline)] [Array]$Manifest,
# page metadata index for faster lookup of single page
[Parameter(Mandatory)] [Collections.Hashtable]$Index,
# pages manifest
[Parameter(Mandatory)] [Array]$PagesManifest,
# page metadata index for faster lookup of single page
[Parameter()] [Collections.Hashtable]$PagesIndex,
# force to get metadata from remote
[Parameter()] [Switch]$Force,
# throw an exception on error
[Parameter()] [Switch]$Strict
)
Begin
{
$pat = Get-PersonalAccessToken $Host
}
Process
{
If ($Name -And $Index -And $Manifest[$Index.$Name].Id)
{
$Manifest[$Index.$Name]
return
}
ForEach ($attachmentMeta in $Manifest)
{
If ($Name -And $attachmentMeta.Name -ne $Name) {continue}
$containerPageMeta = $PagesManifest[
$PagesIndex."$($attachmentMeta.ContainerPageTitle)"
]
If (-Not $containerPageMeta)
{
throw (
"Get-AttachmentMeta: ``$($attachmentMeta.Name)``: " +
"unable to lookup metadata for container page " +
"title ``$($attachmentMeta.ContainerPageTitle)``." +
"This is fatal."
)
}
If (-Not $containerPageMeta.Id)
{
$errMsg = (
"Get-AttachmentMeta: ``$($attachmentMeta.Name)``: " +
"container page titled" +
"``$($attachmentMeta.ContainerPageTitle)`` " +
"has no id, which means that the page has " +
"(presumably) not yet been published."
)
If ($Strict) {throw $errMsg}
Write-Host "$errMsg Continuing nonetheless..."
$attachmentMeta
continue
}
If ($attachmentMeta.Id -And -Not $Force)
{
Write-Debug (
"Get-AttachmentMeta: ``$($attachmentMeta.Name)``: " +
"using locally cached metadata ($($attachmentMeta.Id))"
)
$attachmentMeta
}
Else
{
$escapedName = [Uri]::EscapeDataString($attachmentMeta.Name)
$query = "filename=${escapedName}&expand=version"
$uri = (
"https://${Host}/rest/api/content/" +
"$($containerPageMeta.Id)/child/attachment?$query"
)
Invoke-WebRequest `
-Uri $uri `
-Method 'Get' `
-Headers @{
'Authorization' = "Bearer $pat"
} `
-OutVariable response | Out-Null
$results = ($response.Content | ConvertFrom-JSON).results
If ($results.Count -gt 1)
{
$errMsg = (
"Get-AttachmentMeta: ``$($attachmentMeta.Name)``: " +
"error: more than one result for query: $query"
)
If ($Strict) {throw $errMsg}
Write-Host $errMsg
$attachmentMeta
continue
}
ElseIf ($results.Count -eq 1)
{
Write-Debug (
"Get-AttachmentMeta: ``$($attachmentMeta.Name)``: " +
"updating metadata through remote ($($results[0].id))"
)
$attachmentMeta | Add-Member `
-NotePropertyName Id `
-NotePropertyValue $results[0].id `
-Force
$attachmentMeta | Add-Member `
-NotePropertyName 'Version' `
-NotePropertyValue `
$results[0].version.number `
-Force
}
Else
{
Write-Debug (
"Get-AttachmentMetadata: ``$($attachmentMeta.Name)``" +
": no remote, using (partial) local"
)
If ($attachmentMeta.Version)
{
$attachmentMeta.PSObject.Properties.Remove('Version')
}
If ($attachmentMeta.Id)
{
$attachmentMeta.PSObject.Properties.Remove('Id')
}
}
If (-Not $attachmentMeta.Hash)
{
$content = Get-Content $attachmentMeta.Ref | Out-String
$hash = (Get-StringHash $content).Hash
$attachmentMeta | Add-Member `
-NotePropertyName 'Hash' `
-NotePropertyValue $hash `
-Force
}
$attachmentMeta
}
}
}
}

View file

@ -64,7 +64,8 @@ Description = 'External Confluence publisher for xconfluencebuilder'
'Connection.psm1', 'Connection.psm1',
'Manifest.psm1', 'Manifest.psm1',
'Page.psm1', 'Page.psm1',
'PageMeta.psm1', 'Meta.psm1',
'Attachment.psm1',
'StringHelper.psm1' 'StringHelper.psm1'
) )

View file

@ -1,42 +1,17 @@
#!/usr/bin/env pwsh
<#
.SYNOPSIS
PowerShell Publisher for sphinxcontrib.confluencebuilder
.DESCRIPTION
- support for ancestral pages and containered attachments
- creates new pages if they don't exist
- updates existing pages and attachments if checksum mismatches
.EXAMPLE
Import-Module (Join-Path 'vendor' 'tiara.rodney'
'PSConfluencePublisher'
'PSConfluencePublisher'
'PSConfluencePublisher.psd1')
Register-PersonalAccessToken `
-Host 'confluence.contoso.com' `
-Token '123456789123456789'
Test-Connection confluence.contoso.com
Publish-All `
-Url 'https://confluence.contoso.com/display/TIARA/Testitest' `
-DumpIndex build/docs/confluence.out/data.json
.NOTES
- tested with PowerShell Core (PSVersion 7.3.6)
- tested with PowerShell Desktop (PSVersion 5.1.19041.3031)
#>
$ErrorActionPreference = "Stop" $ErrorActionPreference = "Stop"
function Initialize-Manifest function Initialize-Manifest
{ {
<# <#
.SYNOPSIS
Initialize a manifest (in-memory)
.DESCRIPTION
This function initializes a manifest by loading a serialized
manifest from the filesystem, generating indexes and sorting the
pages manifest, so that the ancestral relation defines the order in
which pages will be published.
#> #>
Param( Param(
# path of manifest to load # path of manifest to load
@ -50,27 +25,40 @@ function Initialize-Manifest
Process Process
{ {
Write-Debug 'loading manifest...' Write-Debug 'Initialize-Manifest: loading manifest...'
$manifest = Get-Manifest $literalPath $manifest = Get-Manifest $literalPath
Write-Debug 'creating pages manifest index...' Write-Debug 'Initialize-Manifest: creating pages manifest index...'
$pagesManifestIndex = New-PagesManifestIndex -Manifest $manifest.Pages $pagesManifestIndex = New-PagesManifestIndex -Manifest $manifest.Pages
Write-Debug 'creating ancestral page generation cache...' Write-Debug (
'Initialize-Manifest: creating ancestral page generation cache...'
)
$ancestralGenerationCache = New-AncestralPageGenerationCache ` $ancestralGenerationCache = New-AncestralPageGenerationCache `
-Manifest $manifest.Pages ` -Manifest $manifest.Pages `
-Index $pagesManifestIndex -Index $pagesManifestIndex
Write-Debug 'sorting pages manifest...' Write-Debug 'Initialize-Manifest: sorting pages manifest...'
Optimize-PagesManifest ` Optimize-PagesManifest `
-Manifest $manifest.Pages ` -Manifest $manifest.Pages `
-Lo 0 ` -Lo 0 `
-Hi ($manifest.Pages.Count - 1) ` -Hi ($manifest.Pages.Count - 1) `
-GenerationCache $ancestralGenerationCache | Out-Null -GenerationCache $ancestralGenerationCache | Out-Null
Write-Debug 'Initialize-Manifest: recreating pages manifest index...'
$pagesManifestIndex = New-PagesManifestIndex -Manifest $manifest.Pages
Write-Debug (
'Initialize-Manifest: creating attachments manifest index...'
)
$attachmentsManifestIndex = New-AttachmentsManifestIndex `
-Manifest $manifest.Attachments
} }
End End
@ -79,10 +67,8 @@ function Initialize-Manifest
'Path' = $literalPath 'Path' = $literalPath
'Manifest' = $manifest 'Manifest' = $manifest
'Index' = @{ 'Index' = @{
'Pages' = New-PagesManifestIndex ` 'Pages' = $pagesManifestIndex
-Manifest $manifest.Pages 'Attachments' = $attachmentsManifestIndex
'Attachments' = New-AttachmentsManifestIndex `
-Manifest $manifest.Attachments
} }
} }
} }
@ -91,9 +77,25 @@ function Initialize-Manifest
function Initialize-Connection function Initialize-Connection
{ {
<#
.SYNOPSIS
initialize a connection to a Confluence instance
.DESCRIPTION
This function registers a Personal Access Token (locally) and checks
connectivity to a Confluence instance. It also verifies, that the
Personal Access Tokens authenticates.
.NOTES
TODO: extend verification to also verify that write access to the
provided space is granted.
#>
Param( Param(
# hostname (or IP address) of Confluence instance
[Parameter(Mandatory)] [String]$Host, [Parameter(Mandatory)] [String]$Host,
# id of Confluence space
[Parameter(Mandatory)] [String]$Space, [Parameter(Mandatory)] [String]$Space,
# personal access token
[Parameter(Mandatory)] [String]$PersonalAccessToken [Parameter(Mandatory)] [String]$PersonalAccessToken
) )
@ -118,6 +120,23 @@ function Initialize-Connection
function Publish-Pages function Publish-Pages
{ {
<#
.SYNOPSIS
Publish pages to Confluence instance
.DESCRIPTION
This function publishes all (or one) pages as defined in the pages
manifest.
Since pipelining is supported within the low-level functions, this
function is basically just a wrapper.
.NOTE
TODO: Investigate on how we can pass-through the manifest as to
retain pipeline functionality throughout. Currently it is broken,
since the manifest isn't passed as a pieline input object from the
top (which is this function).
#>
Param( Param(
# connection object created through Initialize-Connection # connection object created through Initialize-Connection
[Parameter(Mandatory)] [Collections.Hashtable]$Connection, [Parameter(Mandatory)] [Collections.Hashtable]$Connection,
@ -133,11 +152,54 @@ function Publish-Pages
Process Process
{ {
$Manifest.Manifest.Pages | Publish-Page ` Publish-Page `
-Host $Connection.Host ` -Host $Connection.Host `
-Space $Connection.Space ` -Space $Connection.Space `
-Title $Title ` -Title $Title `
-Index $Manifest.Index.Pages ` -Index $Manifest.Index.Pages `
-Manifest $Manifest.Manifest.Pages `
-Strict:$Strict `
-Force:$Force | Out-Null
}
}
function Publish-Attachments
{
<#
.SYNOPSIS
Publish attachments to Confluence instance
.DESCRIPTION
This function publishes all (or one) attachments as defined in the
attachments manifest.
Since pipelining is supported within the low-level functions, this
function is basically just a wrapper.
#>
Param(
# connection object created through Initialize-Connection
[Parameter(Mandatory)] [Collections.Hashtable]$Connection,
# manifest object created through Initialize-Manifest
[Parameter(Mandatory)] [PSCustomObject]$Manifest,
#
[Parameter()] [Switch]$Strict,
#
[Parameter()] [Switch]$Force,
# name of attachment to be published
[Parameter()] [String]$Name
)
Process
{
Publish-Attachment `
-Host $Connection.Host `
-Space $Connection.Space `
-Name $Name `
-Manifest $Manifest.Manifest.Attachments `
-Index $Manifest.Index.Attachments `
-PagesManifest $Manifest.Manifest.Pages `
-PagesIndex $Manifest.Index.Pages `
-Strict:$Strict ` -Strict:$Strict `
-Force:$Force | Out-Null -Force:$Force | Out-Null
} }

View file

@ -38,7 +38,7 @@ function New-Page
# title of page to be published # title of page to be published
[Parameter()] [string]$Title, [Parameter()] [string]$Title,
# pages manifest # pages manifest
[Parameter(Mandatory)] [Parameter(Mandatory,ValueFromPipeline)]
[PSCustomObject[]]$Manifest, [PSCustomObject[]]$Manifest,
# pages manifest index, mandatory for ancestor lookup # pages manifest index, mandatory for ancestor lookup
[Parameter(Mandatory)] [Collections.Hashtable]$Index, [Parameter(Mandatory)] [Collections.Hashtable]$Index,
@ -123,7 +123,34 @@ function New-Page
'representation' = 'storage' 'representation' = 'storage'
} }
} }
} | ConvertTo-JSON -Depth 5 }
If ($pageMeta.AncestorTitle)
{
$ancestorPageMeta = $Manifest[
$Index."$($pageMeta.AncestorTitle)"
]
If (-Not $ancestorPageMeta)
{
Throw (
"ancestor (``$($ancestorPageMeta.Title)``) of " +
"``$($pageMeta.Title)`` does not have an id. " +
"This indicates, that the ancestor has not been " +
"published and therefore the pages manifest may " +
"not be in the correct order."
)
}
$transportBody.ancestors = @(
@{'id' = $ancestorPageMeta.Id}
)
}
$rawTransportBody = (
$transportBody | ConvertTo-JSON `
-WarningAction 'SilentlyContinue'
)
Try Try
{ {
@ -134,7 +161,7 @@ function New-Page
'Authorization' = "Bearer $pat" 'Authorization' = "Bearer $pat"
} ` } `
-ContentType "application/json" ` -ContentType "application/json" `
-Body $transportBody ` -Body $rawTransportBody `
-OutVariable rawResponse | Out-Null -OutVariable rawResponse | Out-Null
} }
@ -277,6 +304,8 @@ function Update-Page
Write-Host $errMsg Write-Host $errMsg
$pageMeta
continue continue
} }
@ -351,7 +380,34 @@ function Update-Page
'version' = @{ 'version' = @{
'number' = $version 'number' = $version
} }
} | ConvertTo-JSON -WarningAction 'SilentlyContinue' }
If ($pageMeta.AncestorTitle)
{
$ancestorPageMeta = $Manifest[
$Index."$($pageMeta.AncestorTitle)"
]
If (-Not $ancestorPageMeta)
{
Throw (
"ancestor (``$($ancestorPageMeta.Title)``) of " +
"``$($pageMeta.Title)`` does not have an id. " +
"This indicates, that the ancestor has not been " +
"published and therefore the pages manifest may " +
"not be in the correct order."
)
}
$transportBody.ancestors = @(
@{'id' = $ancestorPageMeta.Id}
)
}
$rawTransportBody = (
$transportBody | ConvertTo-JSON `
-WarningAction 'SilentlyContinue'
)
Try Try
{ {
@ -363,7 +419,7 @@ function Update-Page
'Authorization' = "Bearer $pat" 'Authorization' = "Bearer $pat"
} ` } `
-ContentType "application/json" ` -ContentType "application/json" `
-Body $transportBody ` -Body $rawTransportBody `
-OutVariable rawResponse | Out-Null -OutVariable rawResponse | Out-Null
} }
@ -430,7 +486,7 @@ function Publish-Page
# title of page to be published # title of page to be published
[Parameter()] [string]$Title, [Parameter()] [string]$Title,
# pages manifest # pages manifest
[Parameter(Mandatory, ValueFromPipeline)] [Parameter(Mandatory)]
[PSCustomObject[]]$Manifest, [PSCustomObject[]]$Manifest,
# pages manifest index, mandatory for ancestor lookup # pages manifest index, mandatory for ancestor lookup
[Parameter(Mandatory)] [Collections.Hashtable]$Index, [Parameter(Mandatory)] [Collections.Hashtable]$Index,

View file

@ -1,132 +0,0 @@
$ErrorActionPreference = "Stop"
function Get-PageMeta
{
<#
.SYNOPSIS
Get a Confluence page id
.DESCRIPTION
First, tries to retrieve from local page id index (cache) through
the local alias. If no cache hit, then polls the Confluence
instance host for the id by providing a space key and page title.
.EXAMPLE
Get-PageMeta `
-Host 'confluence.contoso.com' `
-Title 'Testitest' `
-Space 'TIARA' `
-CacheIndexFile 'confluence-page-cache.json'
#>
Param(
# Confluence instance hostname
[Parameter(Mandatory)] [string] $Host,
# Page title
[Parameter()] [string] $Title,
# Confluence space id
[Parameter(Mandatory)] [string] $Space,
# pages manifest
[Parameter(Mandatory, ValueFromPipeline)] [Array] $Manifest,
# page metadata index for faster lookup of single page
[Parameter()] [Collections.Hashtable] $Index,
# force to get metadata from remote
[Parameter()] [Switch] $Force = $false,
# throw an exception on error
[Parameter()] [Switch] $Strict = $true
)
Process
{
If ($Title -And $Index -And $Manifest[$Index.$Title].Id)
{
$Manifest[$Index.$Title]
return
}
ForEach ($pageMeta in $Manifest)
{
If ($Title -And $pageMeta.Title -ne $Title) {continue}
If ($pageMeta.Id -And -Not $Force)
{
Write-Debug "local (cache): $($pageMeta.Title) ($($pageMeta.Id))"
$pageMeta
}
Else
{
$escapedTitle = [Uri]::EscapeDataString($pageMeta.Title)
$query = (
"title=${escapedTitle}&spaceKey=${Space}&expand=version"
)
Invoke-WebRequest `
-Uri "https://${Host}/rest/api/content?$query" `
-Method 'Get' `
-Headers @{
'Authorization' = 'Bearer ' +
$(Get-PersonalAccessToken $Host)
} `
-OutVariable response | Out-Null
$results = ($response.Content | ConvertFrom-JSON).results
If ($results.Count -gt 1)
{
$errMsg = "error: more than one result for query: $query"
If ($Strict) {throw $errMsg}
Write-Host $errMsg
$pageMeta
continue
}
ElseIf ($results.Count -eq 1)
{
Write-Debug (
"Get-PageMetadata: ``$($pageMeta.Title)``: " +
"updating metadata through remote ($($results[0].id))"
)
$pageMeta | Add-Member `
-NotePropertyName Id `
-NotePropertyValue $results[0].id `
-Force
$pageMeta | Add-Member `
-NotePropertyName 'Version' `
-NotePropertyValue `
$results[0].version.number `
-Force
}
Else
{
Write-Debug "local: $($pageMeta.Title) (no remote)"
}
If (-Not $pageMeta.Hash)
{
$content = Get-Content $pageMeta.Ref | Out-String
$hash = (Get-StringHash $content).Hash
$pageMeta | Add-Member `
-NotePropertyName 'Hash' `
-NotePropertyValue $hash `
-Force
}
$pageMeta
}
}
}
}