有時候我們想要在 Azure DevOps Services 上面刪除一些早期的 Pipeline (Build),但是刪除時卻會遇到 One or more builds associated with the requested pipeline(s) are retained by a release. The pipeline(s) and builds will not be deleted. 的問題,導致我們怎樣都無法刪除。這篇文章我打算來說明一下幾個重要觀念,以及如何才能成功刪除這些用不到的 Pipelines。
發生錯誤的過程
-
刪除 Pipeline (Build)
-
刪除時出現以下錯誤訊息
One or more builds associated with the requested pipeline(s) are retained by a release. The pipeline(s) and builds will not be deleted.
我簡單翻譯一下這段錯誤訊息:
-
One or more builds associated with the requested pipeline(s) are retained by a release.
你所要求刪除的 pipeline(s)
的一個或多個 builds
(建置) 被一個 release
(發行) 所保留(retained
)。
-
The pipeline(s) and builds will not be deleted.
這些 pipeline(s)
以及 builds
將不會被刪除。
我們在 Azure DevOps Services 之中的重要觀念如下:
-
一個 pipeline
會包含一個或多個 builds
(有時候 builds 也會說成 runs)
-
一個 release
可能會從 pipeline
取得 builds
來發行
-
所以 release
跟 pipeline
產生的 build
之間會有一個或多個 leases
(租約) 關係
-
在 release
之中可以對 builds
設定 Retain
(保留) 的條件
-
早期 release
的設定預設會永久保留所有的 builds
,但現在的 release
最多只會保留 365
天,而且在專案設定中有明確的預設值設定!
簡單來說,就是你只要有設定 release
(CD
),我們通常都會關聯一個 Pipelines (CI
) 的 build
(通常是最新版的 build artifact
),所以這些 builds
或 runs
會預設保留下來一段時間,保留多久是由一條一條的 lease
決定的。重點是,只要這些 builds
被保留住,你就無法刪除 pipeline
!
如何才能順利刪除 Pipeline
事實上,就算你手動刪除 Release 也是無法解鎖這些 Builds 的,因為刪除 Release 之後會被放到「資源回收匣」達 30 天,所以關聯的 Builds 依然無法被刪除。
所以重點就是如何讓這些 Builds 不要被保留(Retain),方法如下:
-
進入特定 Pipeline 並顯示所有 Builds,對每一個 Builds 選擇 View retention leases
(檢視保留租約) 設定
-
你可以在 Run retention 對話框看到這個 Build 的保留原因,並且可以按下 Remove all 刪除所有保留設定
-
當你把所有 Builds 的 Leases
都移除,就可以順利刪除 Pipeline 了!
是的,就是要一筆一筆刪除,有點麻煩!
批次刪除 Leases 的方法
如果要批次刪除,只能透過 Leases - REST API (Azure DevOps Build) 來刪除了。
我已經寫好一份了,超好用:
-
刪除特定專案下所有 Pipelines (Build Definition) 底下所有的 builds
底下所有的 leases
$personalAccessToken = "[PAT]"
$organization = "[OrgId]"
$project = "[ProjectId]"
$apiVersion = "6.0"
$token = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($personalAccessToken)"))
$header = @{authorization = "Basic $token"}
function DeleteLease($definitionId) {
$url = "https://dev.azure.com/$organization/$project/_apis/build/retention/leases?api-version=$($apiVersion)&definitionId=$definitionId"
$leases = (Invoke-RestMethod -Method GET -Uri $url -ContentType "application/json" -Headers $header )
foreach ($lease in $leases.value) {
$leaseId = $lease.leaseId
$url = "https://dev.azure.com/$organization/$project/_apis/build/retention/leases?ids=$($leaseId)&api-version=$($apiVersion)"
$ignore = Invoke-RestMethod -Method DELETE -Uri $url -ContentType "application/json" -Headers $header
Write-Host "DELETE $url"
}
}
$url = "https://dev.azure.com/$organization/$project/_apis/build/definitions?api-version=$apiVersion"
Write-Host $url
$buildDefinitions = Invoke-RestMethod -Uri $url -Method Get -ContentType "application/json" -Headers $header
foreach ($def in $builddefinitions.value) {
Write-Host $def.id $def.queueStatus $def.name
DeleteLease $def.id
}
-
刪除特定專案下特定一個 Pipelines (Build Definition) 底下所有 builds
的 leases
$personalAccessToken = "[PAT]"
$organization = "[OrgId]"
$project = "[ProjectId]"
$definitionId = "[BuildDefinitionId]"
$apiVersion = "6.0"
$token = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($personalAccessToken)"))
$header = @{authorization = "Basic $token"}
function DeleteLease($definitionId) {
$url = "https://dev.azure.com/$organization/$project/_apis/build/retention/leases?api-version=$($apiVersion)&definitionId=$definitionId"
$leases = (Invoke-RestMethod -Method GET -Uri $url -ContentType "application/json" -Headers $header )
foreach ($lease in $leases.value) {
$leaseId = $lease.leaseId
$url = "https://dev.azure.com/$organization/$project/_apis/build/retention/leases?ids=$($leaseId)&api-version=$($apiVersion)"
$ignore = Invoke-RestMethod -Method DELETE -Uri $url -ContentType "application/json" -Headers $header
Write-Host "DELETE $url"
}
}
$url = "https://dev.azure.com/$organization/$project/_apis/build/definitions?api-version=$apiVersion"
Write-Host $url
$buildDefinitions = Invoke-RestMethod -Uri $url -Method Get -ContentType "application/json" -Headers $header
DeleteLease $definitionId
你可以從網址列上取得 $definitionId
,如下圖示:
相關連結