Skip to content

Commit b805051

Browse files
committed
Merge branch 'microsoft-powershell-platyps' of https://github.com/Gijsreyn/FabricTools into microsoft-powershell-platyps
2 parents ad87a56 + 72b105c commit b805051

23 files changed

+391
-481
lines changed

CHANGELOG.md

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2323
- `Remove-FabricWorkspaceFromStage`,
2424
- `Start-FabricDeploymentPipelineStage`
2525
- Added private function `Get-FabricContinuationToken` to facilitate pagination
26-
- Added new build automation task `Generate_help_from_built_module`
26+
- `Invoke-FabricRestMethod` handles throttling (error 429) by pausing and repeating the request (#88)
2727

2828
### Changed
2929

@@ -33,16 +33,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3333
- `Get-FabricSqlDatabase` accepts Workspace as a pipeline, handles errors correctly and can filter by name (#117).
3434
- Applied splatting for several parameters in `Invoke-FabricRestMethod` and output results in debug mode
3535
- `Remove-FabricSQLDatabase` uses unified function to handle API results
36-
- Changed the `documentation` folder to `docs/<locale>`
37-
- Code-fenced blocks included in function examples
38-
39-
Updated the `WorkspaceId`, `CapacitiesIds`,`CapacityId`,`CopyJobId`,`datamartId`,`DataPipelineId`,`DataWarehouseGUID`,`DomainId`,`EnvironmentId`,`EventhouseId`,`EventstreamId`,`ExternalDataShareId`,`ItemId`,`KQLDashboardId`,`KQLDatabaseId`,`KQLQuerysetId`,`LakehouseId`,`MirroredDatabaseId`,`MirroredWarehouseId`,`MLExperimentId`,`MLModelId`,`NotebookId`,`operationId`,`PaginatedReportId`,`ParentDomainId`,`parentEventhouseId`,`PrincipalId`,`ReflexId`,`ReportId`,`SemanticModelId`,`SparkCustomPoolId`,`SparkJobDefinitionId`,`SQLDatabaseId`,`SQLEndpointId`,`subscriptionID`,`UserId`,`WarehouseId`,`WorkspaceGUID`,`WorkspaceId`,`WorkspaceIds`,and `WorkspaceRoleAssignmentId` parameters to the datatype GUID [#125](https://github.com/dataplat/FabricTools/issues/125)
36+
- Updated the `WorkspaceId`, `CapacitiesIds`,`CapacityId`,`CopyJobId`,`datamartId`,`DataPipelineId`,`DataWarehouseGUID`,`DomainId`,`EnvironmentId`,`EventhouseId`,`EventstreamId`,`ExternalDataShareId`,`ItemId`,`KQLDashboardId`,`KQLDatabaseId`,`KQLQuerysetId`,`LakehouseId`,`MirroredDatabaseId`,`MirroredWarehouseId`,`MLExperimentId`,`MLModelId`,`NotebookId`,`operationId`,`PaginatedReportId`,`ParentDomainId`,`parentEventhouseId`,`PrincipalId`,`ReflexId`,`ReportId`,`SemanticModelId`,`SparkCustomPoolId`,`SparkJobDefinitionId`,`SQLDatabaseId`,`SQLEndpointId`,`subscriptionID`,`UserId`,`WarehouseId`,`WorkspaceGUID`,`WorkspaceId`,`WorkspaceIds`, and `WorkspaceRoleAssignmentId` parameters to the datatype GUID [#125](https://github.com/dataplat/FabricTools/issues/125)
37+
- Internal function `Invoke-FabricRestMethod`: (#143)
38+
- handles API response, no need to use `Test-FabricApiResponse` from parent public function
39+
- handles pagination automatically (when `-HandleResponse` is provided)
40+
- All Deployment Pipeline functions raise an error when an exception is caught. Used splatting for params.
41+
- Refactored SQL Database functions to use enhanced capability in `Invoke-FabricRestMethod`. Used splatting for params.
42+
- `Write-Message` uses PSFramework function for logging, which logs function name (#84)
4043

4144
### Fixed
4245

4346
- Enhanced logic in unified function `Test-FabricApiResponse` to handle API results and moved it to private functions
44-
- Fixed bug in `Get-FabricLongRunningOperation` - Uri was incorectly created (#131)
47+
- Fixed bug in `Get-FabricLongRunningOperation` - Uri was incorrectly created (#131)
4548
- Fixed bug in `Get-FabricLongRunningOperationResult` - uses correct statusCode (#131)
49+
- Fixed misleading message from `Remove-FabricWarehouse` (#145)
50+
- Fixed `Start-FabricDeploymentPipelineStage` that supports `-NoWait` correctly
4651

4752
### Deprecated
4853

helper/build-and-test.ps1

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ Invoke-ScriptAnalyzer -Path .\source\Public\**
2121
$tests = Invoke-Pester .\tests\ -PassThru
2222
$tests.Tests | where Result -eq 'Failed' | Measure-Object | Select-Object -ExpandProperty Count
2323
$tests.Tests | where Result -eq 'Failed' | ft -Property ExpandedName, ErrorRecord
24-
$tests.Tests | where Result -eq 'Failed' | ft -Property Name, Result, ErrorRecord -AutoSize
24+
$tests.Tests | where Result -eq 'Failed' | ft -Property Path, Result, ErrorRecord -AutoSize
2525

26-
$e = $tests.Tests | where Result -eq 'Failed' | Select-Object -First 1
26+
$e = $tests.Tests | where Result -eq 'Failed' | Select-Object -Last 1
2727
$e.ErrorRecord

source/Private/Get-FabricContinuationToken.ps1

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,14 @@ Author: Kamil Nowinski
2222
#>
2323
[CmdletBinding()]
2424
param (
25-
[Parameter(Mandatory = $true)]
25+
[Parameter(Mandatory = $false)]
2626
[object]$Response
2727
)
2828

2929
$continuationToken = $null
3030
if ($null -ne $Response) {
3131
# Update the continuation token if present
32-
if ($Response.PSObject.Properties.Match("continuationToken")) {
32+
if ($Response.PSObject.Properties.Match("continuationToken") -and $Response.continuationToken -ne $null) {
3333
$continuationToken = $Response.continuationToken
3434
Write-Message -Message "New continuation token: $continuationToken" -Level Debug
3535
} else {

source/Private/Test-FabricApiResponse.ps1

Lines changed: 70 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,26 @@ function Test-FabricApiResponse {
1010
.PARAMETER Response
1111
The response body from the API call.
1212
13+
.PARAMETER ResponseHeader
14+
The response headers from the API call. This is used to retrieve operation IDs and other metadata.
15+
16+
.PARAMETER StatusCode
17+
The HTTP status code returned by the API call. This is used to determine how to handle the response.
18+
19+
.PARAMETER Operation
20+
The operation being performed by parent function (e.g., 'New', 'Update', 'Remove', 'Get'). It helps in logging appropriate messages.
21+
This parameter is optional and can be used to customize the logging message based on the operation type.
22+
1323
.PARAMETER ObjectIdOrName
1424
The name or ID of the resource being operated.
1525
1626
.PARAMETER TypeName
1727
The type of resource being operated (default: 'Fabric Item').
1828
29+
.PARAMETER SuccessMessage
30+
A custom success message to log upon successful completion of the operation. This overrides the default message based on Operation, TypeName, ObjectIdOrName.
31+
This parameter is optional and can be used to provide a specific success message for the operation.
32+
1933
.PARAMETER NoWait
2034
If specified, the function will not wait for the operation to complete and will return immediately.
2135
@@ -33,48 +47,61 @@ function Test-FabricApiResponse {
3347
- This function is designed to be used within the context of a Fabric API client.
3448
- It requires the `Write-Message` function to log messages at different levels (Info, Debug, Error).
3549
- The function handles long-running operations by checking the status of the operation and retrieving the result if it has succeeded.
50+
- Supports handling of API rate limiting (HTTP 429) by waiting for the specified retry duration before returning a command to repeat the request.
3651
3752
Author: Kamil Nowinski
3853
3954
#>
4055

4156
[CmdletBinding()]
4257
param (
43-
[Parameter(Mandatory = $false)]
58+
[Parameter(Mandatory = $false)] # Response is $null when Response Code is 202
4459
$Response,
4560

61+
[Parameter(Mandatory = $true)]
62+
$ResponseHeader,
63+
64+
[Parameter(Mandatory = $true)]
65+
$StatusCode,
66+
67+
[Parameter(Mandatory = $false)]
68+
$Operation,
69+
4670
[Parameter(Mandatory = $false)]
4771
[string] $ObjectIdOrName,
4872

4973
[Parameter(Mandatory = $false)]
5074
[string] $TypeName = 'Fabric Item',
5175

76+
[Parameter(Mandatory = $false)]
77+
[string] $SuccessMessage,
78+
5279
[Parameter(Mandatory = $false)]
5380
[switch] $NoWait = $false
5481
)
5582

56-
Write-Message -Message "[Test-FabricApiResponse]::Begin" -Level Debug
83+
Write-Message -Message "::Begin" -Level Debug
5784

58-
$responseHeader = $script:responseHeader
59-
$statusCode = $script:statusCode
85+
#$responseHeader = $script:responseHeader
86+
#$statusCode = $script:statusCode
6087
$result = $null
61-
62-
$verb = (Get-PSCallStack)[1].Command.Split('-')[0]
63-
Write-Message -Message "Testing API response for '$verb' operation. StatusCode: $statusCode." -Level Debug
88+
Write-Message -Message "Testing API response for '$Operation' operation. StatusCode: $statusCode." -Level Debug
6489

6590
switch ($statusCode) {
6691
200 {
67-
$result = $null
92+
if ($Operation -eq 'Get') {
93+
$result = $Response
94+
}
6895
}
6996
201 {
7097
$result = $Response
7198
}
7299
202 {
73-
Write-Message -Message "$verb Request for $TypeName '$ObjectIdOrName' accepted. Provisioning in progress!" -Level Info
100+
Write-Message -Message "$Operation Request for $TypeName '$ObjectIdOrName' accepted. Provisioning in progress!" -Level Info
74101
[string]$operationId = $responseHeader["x-ms-operation-id"]
75102

76103
if ($NoWait) {
77-
Write-Message -Message "NoWait parameter is set. Operation ID: $operationId" -Level Info
104+
Write-Message -Message "NoWait parameter is set. Operation ID: $operationId" -Level Debug
78105
Write-Message -Message "Run to check the progress: Get-FabricLongRunningOperationResult -operationId '$operationId'" -Level Verbose
79106
return [PSCustomObject]@{
80107
Location = $responseHeader["Location"]
@@ -83,26 +110,35 @@ function Test-FabricApiResponse {
83110
}
84111
}
85112

86-
Write-Message -Message "[Test-FabricApiResponse] Operation ID: '$operationId'" -Level Debug
87-
Write-Message -Message "[Test-FabricApiResponse] Getting Long Running Operation status" -Level Debug
113+
Write-Message -Message "Operation ID: '$operationId'" -Level Debug
114+
Write-Message -Message "Getting Long Running Operation status" -Level Debug
88115

89116
$operationStatus = Get-FabricLongRunningOperation -operationId $operationId
90-
Write-Message -Message "[Test-FabricApiResponse] Long Running Operation status: $operationStatus" -Level Debug
117+
Write-Message -Message "Long Running Operation status: $operationStatus" -Level Debug
91118
# Handle operation result
92119
if ($operationStatus.status -eq "Succeeded") {
93120
Write-Message -Message "Operation Succeeded" -Level Debug
94-
Write-Message -Message "Getting Long Running Operation result" -Level Debug
121+
Write-Message -Message "Getting Long Running Operation result" -Level Verbose
95122

96123
$operationResult = Get-FabricLongRunningOperationResult -operationId $operationId
97-
Write-Message -Message "Long Running Operation status: $operationResult" -Level Debug
124+
#Write-Message -Message "Long Running Operation status: $operationResult" -Level Debug
98125

99126
return $operationResult
100127
} else {
101-
Write-Message -Message "Operation failed. Status: $($operationStatus)" -Level Debug
128+
#Write-Message -Message "Operation failed. Status: $($operationStatus)" -Level Debug
102129
Write-Message -Message "Operation failed. Status: $($operationStatus)" -Level Error
103130
return $operationStatus
104131
}
105132
}
133+
429 {
134+
Write-Message -Message "API rate limit exceeded. Status Code: $statusCode ($($Response.errorCode))" -Level Warning
135+
Write-Message -Message "$($Response.message). Waiting $($responseHeader['Retry-After']) seconds..." -Level Warning
136+
$retryAfter = $responseHeader['Retry-After']
137+
$retryAfterStr = $retryAfter[0].ToString()
138+
$retryAfterInt = [int]$retryAfterStr
139+
Start-Sleep -Seconds $retryAfterInt
140+
return "Command:Repeat"
141+
}
106142
default {
107143
Write-Message -Message "Test-FabricApiResponse::default" -Level Debug
108144
Write-Message -Message "Unexpected response code: $statusCode from the API." -Level Error
@@ -115,16 +151,29 @@ function Test-FabricApiResponse {
115151
}
116152
}
117153

118-
switch ($verb) {
154+
# if (FeatureFlag.IsEnabled('FabricToolsVerboseLogging')) { # This is placeholder for verbose logging feature flag being implemented soon
155+
$TypeName= $TypeName.Substring(0, 1).ToUpper() + $TypeName.Substring(1)
156+
157+
if ($SuccessMessage) {
158+
$Operation = "Custom"
159+
}
160+
161+
# Try to get Name of Id from the response when new item is created
162+
if ($Operation -eq 'New' -and -not $ObjectIdOrName) {
163+
$ObjectIdOrName = $Response.DisplayName ? $Response.DisplayName : $Response.id
164+
}
165+
switch ($Operation) {
119166
'New' { $msg = "$TypeName '$ObjectIdOrName' created successfully."; $level = 'Info' }
120167
'Update' { $msg = "$TypeName '$ObjectIdOrName' updated successfully."; $level = 'Info' }
121168
'Remove' { $msg = "$TypeName '$ObjectIdOrName' deleted successfully."; $level = 'Info' }
122-
'Get' { $msg = "Successfully retrieved $TypeName details."; $level = 'Debug' }
123-
default { $msg = "Received $statusCode status code for $verb operation on $TypeName '$ObjectIdOrName'."; $level = 'Info' }
169+
'Get' { $msg = "Successfully retrieved $TypeName details."; $level = 'Debug' }
170+
'Custom' { $msg = "$SuccessMessage"; $level = 'Info' }
171+
default { $msg = "Received $statusCode status code for $Operation operation on $TypeName '$ObjectIdOrName'."; $level = 'Info' }
124172
}
125173
Write-Message -Message $msg -Level $level
126-
Write-Message -Message "[Test-FabricApiResponse]::End" -Level Debug
174+
# }
127175

128-
$result
176+
Write-Message -Message "::End" -Level Debug
129177

178+
$result
130179
}

source/Private/Write-Message.ps1

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -54,17 +54,18 @@ function Write-Message {
5454
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
5555

5656
# Construct log message
57-
$logMessage = "[$timestamp] [$Level] $Message"
57+
$logMessage = $Message
58+
$fn = (Get-PSCallStack)[1].Command
5859

5960
# Write log message to console with colors
6061
switch ($Level) {
61-
"Message" { Write-Host $logMessage -ForegroundColor White }
62-
"Info" { Write-Host $logMessage -ForegroundColor Green }
63-
"Error" { Write-Error $logMessage }
64-
"Warning" { Write-Warning $logMessage }
65-
"Critical" { Write-Host $logMessage -ForegroundColor Red } # Or maybe Stop-PSFunction here?
66-
"Verbose" { Write-Verbose $logMessage }
67-
"Debug" { Write-Debug $logMessage }
62+
"Message" { Write-PSFMessage -Message $logMessage -FunctionName $fn -Level Host }
63+
"Info" { Write-PSFMessage -Message $logMessage -FunctionName $fn -Level Important }
64+
"Error" { Write-PSFMessage -Message $logMessage -FunctionName $fn -Level Error }
65+
"Warning" { Write-PSFMessage -Message $logMessage -FunctionName $fn -Level Warning }
66+
"Critical" { Write-PSFMessage -Message $logMessage -FunctionName $fn -Level Critical }
67+
"Verbose" { Write-PSFMessage -Message $logMessage -FunctionName $fn -Level Verbose }
68+
"Debug" { Write-PSFMessage -Message $logMessage -FunctionName $fn -Level Debug }
6869
}
6970

7071
# Optionally write log message to a file
@@ -77,7 +78,7 @@ function Write-Message {
7778
}
7879
}
7980
} catch {
80-
Write-Host "[ERROR] An unexpected error occurred: $_" -ForegroundColor Red
81+
Stop-PSFFunction -Message "An unexpected error occurred while writing the message to log file." -ErrorRecord $_ -Level Error
8182
}
8283
}
8384
}

source/Public/Deployment Pipeline/Add-FabricWorkspaceToStage.ps1

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,15 +65,23 @@ Author: Kamil Nowinski
6565
}
6666

6767
# Step 4: Make the API request and validate response
68-
$response = Invoke-FabricRestMethod -Uri $apiEndpointUrl -Method Post -Body $requestBody
69-
Test-FabricApiResponse -Response $response
68+
$apiParameters = @{
69+
Uri = $apiEndpointUrl
70+
Method = 'POST'
71+
Body = $requestBody
72+
HandleResponse = $true
73+
TypeName = "deployment pipeline stage"
74+
ObjectIdOrName = $StageId
75+
SuccessMessage = "Successfully assigned workspace to deployment pipeline stage."
76+
}
77+
$response = Invoke-FabricRestMethod @apiParameters
7078

7179
# Step 5: Return results
72-
Write-Message -Message "Successfully assigned workspace to deployment pipeline stage." -Level Info
7380
$response
81+
7482
} catch {
7583
# Step 6: Error handling
7684
$errorDetails = $_.Exception.Message
77-
Write-Message -Message "Failed to assign workspace to deployment pipeline stage. Error: $errorDetails" -Level Error
85+
Write-Error -Message "Failed to assign workspace to deployment pipeline stage. Error: $errorDetails"
7886
}
7987
}

0 commit comments

Comments
 (0)