583 lines
22 KiB
PowerShell
583 lines
22 KiB
PowerShell
Function Set-GiteaConfiguration {
|
|
[CmdletBinding()]
|
|
param(
|
|
[Parameter(Mandatory)]
|
|
[string]$giteaURL,
|
|
[Parameter(Mandatory)]
|
|
[string]$token,
|
|
[string]$defaultOwner,
|
|
[string]$defaultRepo,
|
|
[string]$defaultBranch = "main"
|
|
)
|
|
|
|
# Create configuration directory if it doesn't exist
|
|
$configDir = Join-Path -Path $env:USERPROFILE -ChildPath ".giteautils"
|
|
if (-not (Test-Path -Path $configDir)) {
|
|
New-Item -Path $configDir -ItemType Directory | Out-Null
|
|
}
|
|
|
|
# Save configuration
|
|
$config = @{
|
|
giteaURL = $giteaURL
|
|
token = $token
|
|
defaultOwner = $defaultOwner
|
|
defaultRepo = $defaultRepo
|
|
defaultBranch = $defaultBranch
|
|
}
|
|
|
|
$configPath = Join-Path -Path $configDir -ChildPath "config.xml"
|
|
$config | Export-Clixml -Path $configPath -Force
|
|
}
|
|
|
|
Function Get-GiteaConfiguration {
|
|
[CmdletBinding()]
|
|
param()
|
|
|
|
$configPath = Join-Path -Path $env:USERPROFILE -ChildPath ".giteautils\config.xml"
|
|
|
|
if (Test-Path -Path $configPath) {
|
|
return Import-Clixml -Path $configPath
|
|
}
|
|
else {
|
|
Write-Warning "Gitea configuration not found. Use Set-GiteaConfiguration to set up."
|
|
return $null
|
|
}
|
|
}
|
|
|
|
Function Get-GiteaFileContent {
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Retrieve the content of a file from a Gitea repository using the Gitea API.
|
|
|
|
.DESCRIPTION
|
|
This function retrieves the content of a file from a Gitea repository using the Gitea API. The function requires the URL of the Gitea server, the owner of the repository, the name of the repository, the branch to retrieve the file from, the path to the file, a personal access token, and an optional switch to decode the content of the file from Base64 encoding.
|
|
|
|
.PARAMETER giteaURL
|
|
The URL of the Gitea server.
|
|
|
|
.PARAMETER repoOwner
|
|
The owner of the repository.
|
|
|
|
.PARAMETER repoName
|
|
The name of the repository.
|
|
|
|
.PARAMETER branch
|
|
The branch to retrieve the file from. The default value is 'main'.
|
|
|
|
.PARAMETER filePath
|
|
The path to the file to retrieve. This parameter accepts pipeline input.
|
|
|
|
.PARAMETER token
|
|
A personal access token for the Gitea server.
|
|
|
|
.PARAMETER decode
|
|
A switch parameter to decode the content of the file from Base64 encoding.
|
|
.EXAMPLE
|
|
# Example 1: Retrieve the content of a single file from a Gitea repository
|
|
$file = Get-GiteaFileContent -repoOwner "cityofnorwich" -repoName "software-premierone" -filePath "README.md" -token "your_token"
|
|
|
|
.EXAMPLE
|
|
# Example 2: Retrieve the content of multiple files from a Gitea repository
|
|
$files = Get-GiteaFileContent -repoOwner "cityofnorwich" -repoName "software-premierone" -filePath @("README.md", "Manually Create Installer Package.ps1") -token "your_token"
|
|
|
|
.EXAMPLE
|
|
# Example 3: Retrieve the content of multiple files from a Gitea repository using pipeline input
|
|
$filesArray = @("README.md", "Manually Create Installer Package.ps1") | Get-GiteaFileContent -repoOwner "cityofnorwich" -repoName "software-premierone" -token "your_token"
|
|
#>
|
|
|
|
[CmdletBinding()]
|
|
param(
|
|
[Parameter(ValueFromPipelineByPropertyName)]
|
|
[string]$giteaURL = "https://gitea.norwichct.tech",
|
|
[Parameter(ValueFromPipelineByPropertyName)]
|
|
[string]$repoOwner,
|
|
[Parameter(ValueFromPipelineByPropertyName)]
|
|
[string]$repoName,
|
|
[Parameter(ValueFromPipelineByPropertyName)]
|
|
[string]$branch = "main",
|
|
[Parameter(ValueFromPipeline, ValueFromPipelineByPropertyName)]
|
|
[Alias('FullName', 'Path')]
|
|
[string[]]$filePath,
|
|
[string]$token,
|
|
[switch]$decode
|
|
)
|
|
|
|
begin {
|
|
# Use configuration if parameters aren't provided
|
|
if (-not $PSBoundParameters.ContainsKey('giteaURL') -or
|
|
-not $PSBoundParameters.ContainsKey('repoOwner') -or
|
|
-not $PSBoundParameters.ContainsKey('repoName') -or
|
|
-not $PSBoundParameters.ContainsKey('branch') -or
|
|
-not $PSBoundParameters.ContainsKey('token')) {
|
|
|
|
$config = Get-GiteaConfiguration
|
|
if ($config) {
|
|
if (-not $PSBoundParameters.ContainsKey('giteaURL')) { $giteaURL = $config.giteaURL }
|
|
if (-not $PSBoundParameters.ContainsKey('repoOwner')) { $repoOwner = $config.defaultOwner }
|
|
if (-not $PSBoundParameters.ContainsKey('repoName')) { $repoName = $config.defaultRepo }
|
|
if (-not $PSBoundParameters.ContainsKey('branch')) { $branch = $config.defaultBranch }
|
|
if (-not $PSBoundParameters.ContainsKey('token')) { $token = $config.token }
|
|
}
|
|
}
|
|
|
|
# Validate that we have all required parameters
|
|
$missingParams = @()
|
|
if (-not $giteaURL) { $missingParams += "giteaURL" }
|
|
if (-not $repoOwner) { $missingParams += "repoOwner" }
|
|
if (-not $repoName) { $missingParams += "repoName" }
|
|
if (-not $token) { $missingParams += "token" }
|
|
|
|
if ($missingParams.Count -gt 0) {
|
|
throw "Missing required parameters: $($missingParams -join ', '). Either provide them directly or set them with Set-GiteaConfiguration."
|
|
}
|
|
|
|
|
|
$results = @()
|
|
Write-Verbose "Parameters:"
|
|
Write-Verbose "giteaURL: $giteaURL"
|
|
Write-Verbose "repoOwner: $repoOwner"
|
|
Write-Verbose "repoName: $repoName"
|
|
Write-Verbose "branch: $branch"
|
|
Write-Verbose "token: $token"
|
|
Write-Verbose "decode: $decode"
|
|
|
|
$headers = @{
|
|
"Authorization" = "token $token"
|
|
"Accept" = "application/json"
|
|
}
|
|
}
|
|
|
|
process {
|
|
foreach ($file in $filePath) {
|
|
Write-Verbose "Processing file: $file"
|
|
$encodedFile = [System.Uri]::EscapeDataString($file)
|
|
Write-Verbose "Encoded file: $encodedFile"
|
|
$url = "$giteaURL"
|
|
$url += "/api/v1/repos"
|
|
$url += "/$repoOwner"
|
|
$url += "/$repoName"
|
|
$url += "/contents"
|
|
$url += "/$encodedFile"
|
|
$url += "?ref=$branch"
|
|
Write-Verbose "URL: $url"
|
|
|
|
try {
|
|
$fileContent = Invoke-RestMethod -Uri $url -Method Get -Headers $headers
|
|
|
|
$content = if ($decode) {
|
|
[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($fileContent.content))
|
|
} else {
|
|
$fileContent.content
|
|
}
|
|
|
|
$results += [PSCustomObject]@{
|
|
Path = $file
|
|
Content = $content
|
|
Size = $fileContent.size
|
|
SHA = $fileContent.sha
|
|
Success = $true
|
|
Error = $null
|
|
}
|
|
}
|
|
catch {
|
|
Write-Error "Failed to retrieve file '$file' from Gitea: $_"
|
|
$results += [PSCustomObject]@{
|
|
Path = $file
|
|
Content = $null
|
|
Size = $null
|
|
SHA = $null
|
|
Success = $false
|
|
Error = $_.Exception.Message
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
end {
|
|
return $results
|
|
}
|
|
}
|
|
|
|
Function Get-GiteaLFSConfiguration {
|
|
<#
|
|
.SYNOPSIS
|
|
Retrieves the LFS configuration for a Gitea repository.
|
|
|
|
.DESCRIPTION
|
|
This function retrieves the LFS configuration for a Gitea repository using the Gitea API. The function requires the URL of the Gitea server, the owner of the repository, the name of the repository, and a personal access token.
|
|
The function returns the LFS configuration details.
|
|
#>
|
|
[cmdletbinding()]
|
|
param(
|
|
[string]$giteaURL,
|
|
[string]$repoOwner,
|
|
[string]$repoName,
|
|
[string]$token
|
|
)
|
|
|
|
begin {
|
|
# Use configuration if parameters aren't provided
|
|
if (-not $PSBoundParameters.ContainsKey('giteaURL') -or
|
|
-not $PSBoundParameters.ContainsKey('repoOwner') -or
|
|
-not $PSBoundParameters.ContainsKey('repoName') -or
|
|
-not $PSBoundParameters.ContainsKey('token')) {
|
|
|
|
$config = Get-GiteaConfiguration
|
|
if ($config) {
|
|
if (-not $PSBoundParameters.ContainsKey('giteaURL')) { $giteaURL = $config.giteaURL }
|
|
if (-not $PSBoundParameters.ContainsKey('repoOwner')) { $repoOwner = $config.defaultOwner }
|
|
if (-not $PSBoundParameters.ContainsKey('repoName')) { $repoName = $config.defaultRepo }
|
|
if (-not $PSBoundParameters.ContainsKey('token')) { $token = $config.token }
|
|
}
|
|
}
|
|
|
|
# Validate that we have all required parameters
|
|
$missingParams = @()
|
|
if (-not $giteaURL) { $missingParams += "giteaURL" }
|
|
if (-not $repoOwner) { $missingParams += "repoOwner" }
|
|
if (-not $repoName) { $missingParams += "repoName" }
|
|
if (-not $token) { $missingParams += "token" }
|
|
|
|
if ($missingParams.Count -gt 0) {
|
|
throw "Missing required parameters: $($missingParams -join ', '). Either provide them directly or set them with Set-GiteaConfiguration."
|
|
}
|
|
}
|
|
|
|
process {
|
|
Write-Verbose "Parameters:"
|
|
Write-Verbose "giteaURL: $giteaURL"
|
|
Write-Verbose "repoOwner: $repoOwner"
|
|
Write-Verbose "repoName: $repoName"
|
|
Write-Verbose "token: $token"
|
|
|
|
$filePath = ".gitattributes"
|
|
|
|
try {
|
|
$LFSConfig = (Get-GiteaFileContent -filePath $filePath -giteaURL $giteaURL -repoOwner $repoOwner -repoName $repoName -branch "main" -token $token -decode -ErrorAction SilentlyContinue).content
|
|
$LFSConfig = $LFSConfig -replace "\r?\n", "`n" # Normalize line endings
|
|
# Get the extensions of files which are tracked by LFS
|
|
# Parse the LFS configuration file and extract extensions
|
|
$lfsExtensions = @()
|
|
foreach ($line in $LFSConfig.Split("`n")) {
|
|
if ($line -match '^\*\.([^\s]+)\s+filter=lfs') {
|
|
$extension = "." + $matches[1]
|
|
$lfsExtensions += $extension
|
|
}
|
|
}
|
|
$lfsExtensions = $lfsExtensions | Sort-Object -Unique
|
|
return $lfsExtensions
|
|
}
|
|
catch {
|
|
Write-Error "Failed to retrieve LFS configuration: $_"
|
|
return @()
|
|
}
|
|
}
|
|
}
|
|
|
|
Function Invoke-GiteaFileDownload {
|
|
<#
|
|
.SYNOPSIS
|
|
Downloads a file from a Gitea repository using a direct download URL.
|
|
|
|
.DESCRIPTION
|
|
This function downloads a file from a Gitea repository using a direct download URL. The function requires the download URL and a personal access token. You can optionally specify an output path and use the force switch to overwrite existing files.
|
|
|
|
.PARAMETER giteaURL
|
|
The URL of the Gitea server.
|
|
|
|
.PARAMETER downloadURL
|
|
The direct download URL for the file from the Gitea server.
|
|
|
|
.PARAMETER token
|
|
A personal access token for the Gitea server.
|
|
|
|
.PARAMETER outputPath
|
|
The path where the downloaded file should be saved. If not specified, the file will be saved in the current directory using the filename from the URL.
|
|
|
|
.PARAMETER force
|
|
A switch parameter to force overwriting of an existing file at the output path.
|
|
|
|
.EXAMPLE
|
|
# Example 1: Download a file to the current directory
|
|
Invoke-GiteaFileDownload -downloadURL "https://gitea.example.com/api/v1/repos/owner/repo/raw/path/to/file.txt" -token "your_token"
|
|
|
|
.EXAMPLE
|
|
# Example 2: Download a file to a specific location with force overwrite
|
|
Invoke-GiteaFileDownload -downloadURL "https://gitea.example.com/api/v1/repos/owner/repo/raw/path/to/file.txt" -token "your_token" -outputPath "C:\Downloads\file.txt" -force
|
|
|
|
.EXAMPLE
|
|
# Example 3: Download files in pipeline from Get-GiteaChildItem
|
|
Get-GiteaChildItem -path "docs" | Where-Object { $_.type -eq 'file' } | Invoke-GiteaFileDownload
|
|
#>
|
|
|
|
[cmdletbinding()]
|
|
param(
|
|
[Parameter(Mandatory, ValueFromPipelineByPropertyName)]
|
|
[string]$downloadURL,
|
|
[string]$token,
|
|
[Parameter(ValueFromPipelineByPropertyName)]
|
|
[string]$outputPath,
|
|
[switch]$force
|
|
)
|
|
|
|
begin {
|
|
# Use configuration if parameters aren't provided
|
|
if (-not $PSBoundParameters.ContainsKey('token')) {
|
|
|
|
$config = Get-GiteaConfiguration
|
|
if ($config) {
|
|
if (-not $PSBoundParameters.ContainsKey('token')) { $token = $config.token }
|
|
}
|
|
}
|
|
|
|
# Validate that we have the required token
|
|
if (-not $token) {
|
|
throw "Missing token parameter. Either provide it directly or set it with Set-GiteaConfiguration."
|
|
}
|
|
|
|
Write-Verbose "Parameters:"
|
|
Write-Verbose "token: $token (length: $(if($token){$token.Length}else{0}))"
|
|
|
|
# Create a WebClient to be reused
|
|
$webClient = New-Object System.Net.WebClient
|
|
$webClient.Headers.Add("Authorization", "token $token")
|
|
}
|
|
|
|
process {
|
|
Write-Verbose "Processing download URL: $downloadURL"
|
|
|
|
# If the output path is not specified, use the current directory and the file name from the download URL
|
|
$currentOutputPath = $outputPath
|
|
if (-not $currentOutputPath) {
|
|
# Get the file name from the download URL
|
|
$outputFileName = $downloadURL.Substring($downloadURL.LastIndexOf("/") + 1)
|
|
# Clean the file name by removing any query string parameters and HTML encoded characters
|
|
$outputFileName = [System.Uri]::UnescapeDataString($outputFileName.Split("?")[0])
|
|
|
|
# Append the outputFileName to the current location
|
|
$currentOutputPath = Join-Path -Path (Get-Location) -ChildPath $outputFileName
|
|
}
|
|
|
|
Write-Verbose "Output path: $currentOutputPath"
|
|
|
|
if((Test-Path -Path $currentOutputPath -PathType Leaf) -and (-not $force)) {
|
|
Write-Error "The file '$currentOutputPath' already exists. Use the -Force switch to overwrite the file."
|
|
return $false
|
|
}
|
|
|
|
try {
|
|
# Create the directory structure if it doesn't exist
|
|
$directory = Split-Path -Path $currentOutputPath -Parent
|
|
if (-not (Test-Path -Path $directory -PathType Container) -and $directory) {
|
|
New-Item -Path $directory -ItemType Directory -Force | Out-Null
|
|
}
|
|
|
|
# Download the file
|
|
Write-Verbose "Downloading from $downloadURL to $currentOutputPath"
|
|
|
|
# Use synchronous download
|
|
$webClient.DownloadFile($downloadURL, $currentOutputPath)
|
|
|
|
Write-Verbose "File downloaded successfully to $currentOutputPath"
|
|
return $true
|
|
}
|
|
catch {
|
|
Write-Error "Failed to download file from Gitea: $_"
|
|
return $false
|
|
}
|
|
}
|
|
|
|
end {
|
|
# Clean up resources
|
|
if ($webClient) {
|
|
$webClient.Dispose()
|
|
}
|
|
}
|
|
}
|
|
|
|
Function Get-GiteaChildItem {
|
|
<#
|
|
.SYNOPSIS
|
|
Lists files and directories in a Gitea repository path.
|
|
|
|
.DESCRIPTION
|
|
This function retrieves a list of files and directories from a specified path in a Gitea repository.
|
|
The results can be directly piped to Get-GiteaFileContent to retrieve file contents.
|
|
|
|
.PARAMETER giteaURL
|
|
The URL of the Gitea server.
|
|
|
|
.PARAMETER repoOwner
|
|
The owner of the repository.
|
|
|
|
.PARAMETER repoName
|
|
The name of the repository.
|
|
|
|
.PARAMETER Path
|
|
The path to list items from. This parameter accepts pipeline input.
|
|
|
|
.PARAMETER branch
|
|
The branch to retrieve the items from. The default value is 'main'.
|
|
|
|
.PARAMETER token
|
|
A personal access token for the Gitea server.
|
|
|
|
.EXAMPLE
|
|
# List items in the root directory of a repository
|
|
Get-GiteaChildItem -repoOwner "owner" -repoName "repo" -Path "" -token "your_token"
|
|
|
|
.EXAMPLE
|
|
# List items and pipe files to Get-GiteaFileContent to get their content
|
|
Get-GiteaChildItem -repoOwner "owner" -repoName "repo" -Path "docs" -token "your_token" |
|
|
Where-Object { $_.type -eq "file" } |
|
|
Get-GiteaFileContent -token "your_token" -decode
|
|
#>
|
|
|
|
[CmdletBinding()]
|
|
param(
|
|
[string]$giteaURL,
|
|
[Parameter(ValueFromPipelineByPropertyName)]
|
|
[string]$repoOwner,
|
|
[Parameter(ValueFromPipelineByPropertyName)]
|
|
[string]$repoName,
|
|
[Parameter(ValueFromPipeline, ValueFromPipelineByPropertyName)]
|
|
[Alias('FullName')]
|
|
[string[]]$Path,
|
|
[Parameter(ValueFromPipelineByPropertyName)]
|
|
[string]$branch = "main",
|
|
[string]$token
|
|
)
|
|
|
|
begin {
|
|
# Initialize results array
|
|
# This is used to store the results of the API calls later
|
|
# It is initialized here to avoid re-initializing it in the process block
|
|
$results = @()
|
|
|
|
# Use configuration if parameters aren't provided
|
|
if (-not $PSBoundParameters.ContainsKey('giteaURL') -or
|
|
-not $PSBoundParameters.ContainsKey('repoOwner') -or
|
|
-not $PSBoundParameters.ContainsKey('repoName') -or
|
|
-not $PSBoundParameters.ContainsKey('branch') -or
|
|
-not $PSBoundParameters.ContainsKey('token')) {
|
|
|
|
$config = Get-GiteaConfiguration
|
|
if ($config) {
|
|
if (-not $PSBoundParameters.ContainsKey('giteaURL')) { $giteaURL = $config.giteaURL }
|
|
if (-not $PSBoundParameters.ContainsKey('repoOwner')) { $repoOwner = $config.defaultOwner }
|
|
if (-not $PSBoundParameters.ContainsKey('repoName')) { $repoName = $config.defaultRepo }
|
|
if (-not $PSBoundParameters.ContainsKey('branch')) { $branch = $config.defaultBranch }
|
|
if (-not $PSBoundParameters.ContainsKey('token')) { $token = $config.token }
|
|
}
|
|
}
|
|
|
|
# Validate that we have all required parameters
|
|
$missingParams = @()
|
|
if (-not $giteaURL) { $missingParams += "giteaURL" }
|
|
if (-not $repoOwner) { $missingParams += "repoOwner" }
|
|
if (-not $repoName) { $missingParams += "repoName" }
|
|
if (-not $token) { $missingParams += "token" }
|
|
|
|
if ($missingParams.Count -gt 0) {
|
|
throw "Missing required parameters: $($missingParams -join ', '). Either provide them directly or set them with Set-GiteaConfiguration."
|
|
}
|
|
|
|
Write-Verbose "Parameters:"
|
|
Write-Verbose "giteaURL: $giteaURL"
|
|
Write-Verbose "repoOwner: $repoOwner"
|
|
Write-Verbose "repoName: $repoName"
|
|
Write-Verbose "Path: $Path"
|
|
Write-Verbose "token: $token"
|
|
|
|
$headers = @{
|
|
"Authorization" = "token $token"
|
|
"Accept" = "application/json"
|
|
}
|
|
|
|
# Load the GIT LFS configuration if needed
|
|
$lfsExtensions = Get-GiteaLFSConfiguration -giteaURL $giteaURL -repoOwner $repoOwner -repoName $repoName -token $token
|
|
}
|
|
|
|
process {
|
|
$paths = $path
|
|
foreach ($path in $paths) {
|
|
Write-Verbose "Processing path: $path"
|
|
$encodedPath = [System.Uri]::EscapeDataString($path)
|
|
Write-Verbose "Encoded path: $encodedPath"
|
|
$url = "$giteaURL"
|
|
$url += "/api/v1/repos"
|
|
$url += "/$repoOwner"
|
|
$url += "/$repoName"
|
|
$url += "/contents"
|
|
$url += "/$encodedPath"
|
|
$url += "?ref=$branch"
|
|
Write-Verbose "URL: $url"
|
|
|
|
try {
|
|
$response = Invoke-RestMethod -Uri $url -Method Get -Headers $headers
|
|
|
|
# Handle both single items and arrays
|
|
$items = if ($response -is [array]) { $response } else { @($response) }
|
|
|
|
foreach ($item in $items) {
|
|
# Check if the name ends with any of the LFS extensions
|
|
$isLFS = $false
|
|
foreach ($ext in $lfsExtensions) {
|
|
if ($item.name.EndsWith($ext, [System.StringComparison]::InvariantCultureIgnoreCase)) {
|
|
$isLFS = $true
|
|
break
|
|
}
|
|
}
|
|
if ($isLFS) {
|
|
$item.type = "lfs"
|
|
$item.download_url = "$giteaURL/api/v1/repos/$repoOwner/$repoName/media/$($item.path)"
|
|
}
|
|
|
|
$results += [PSCustomObject]@{
|
|
# Properties for direct pipeline binding with other functions in this module
|
|
filePath = $item.path # Maps to -filePath parameter
|
|
Path = $item.path # Also include original name (alias)
|
|
repoOwner = $repoOwner # Maps to -repoOwner parameter
|
|
repoName = $repoName # Maps to -repoName parameter
|
|
giteaURL = $giteaURL # Maps to -giteaURL parameter
|
|
downloadURL = $item.download_url # Maps to -downloadURL parameter
|
|
branch = $branch # Maps to -branch parameter
|
|
|
|
# Additional useful properties
|
|
type = $item.type # 'file' or 'dir'
|
|
name = $item.name
|
|
size = $item.size
|
|
sha = $item.sha
|
|
Success = $true
|
|
Error = $null
|
|
}
|
|
}
|
|
}
|
|
catch {
|
|
Write-Error "Failed to retrieve '$path' from Gitea: $_"
|
|
$results += [PSCustomObject]@{
|
|
filePath = $path
|
|
Path = $path
|
|
repoOwner = $repoOwner
|
|
repoName = $repoName
|
|
giteaURL = $giteaURL
|
|
branch = $branch
|
|
type = $null
|
|
name = $null
|
|
size = $null
|
|
sha = $null
|
|
downloadURL = $null
|
|
Success = $false
|
|
Error = $_.Exception.Message
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
end {
|
|
return $results
|
|
}
|
|
}
|
|
|
|
Export-ModuleMember -Function Set-GiteaConfiguration, Get-GiteaConfiguration, Get-GiteaFileContent, Invoke-GiteaFileDownload, Get-GiteaChildItem |