Migrate pipelines - Best Effort
This commit is contained in:
parent
4e7cf06abf
commit
111f06ddf6
6 changed files with 620 additions and 5 deletions
|
|
@ -4,11 +4,36 @@ import (
|
|||
"encoding/base64"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-resty/resty/v2"
|
||||
)
|
||||
|
||||
type Pipeline struct {
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Folder string `json:"folder"`
|
||||
URL string `json:"url"`
|
||||
}
|
||||
|
||||
type BuildDefinition struct {
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Process struct {
|
||||
Type int `json:"type"`
|
||||
YamlFilename string `json:"yamlFilename"` // for YAML pipelines
|
||||
} `json:"process"`
|
||||
Variables map[string]struct {
|
||||
Value string `json:"value"`
|
||||
IsSecret bool `json:"isSecret"`
|
||||
} `json:"variables"`
|
||||
Repository struct {
|
||||
URL string `json:"url"`
|
||||
Name string `json:"name"`
|
||||
} `json:"repository"`
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
client *resty.Client
|
||||
organization string
|
||||
|
|
@ -79,3 +104,96 @@ func (c *Client) GetAuthenticatedURL(remoteURL, pat string) string {
|
|||
}
|
||||
return remoteURL
|
||||
}
|
||||
|
||||
// GetBuildDefinitions gets pipeline definitions for a project
|
||||
func (c *Client) GetBuildDefinitions(project string) ([]BuildDefinition, error) {
|
||||
url := fmt.Sprintf("https://dev.azure.com/%s/%s/_apis/build/definitions", c.organization, project)
|
||||
|
||||
var result struct {
|
||||
Count int `json:"count"`
|
||||
Value []BuildDefinition `json:"value"`
|
||||
}
|
||||
|
||||
resp, err := c.client.R().
|
||||
SetQueryParam("api-version", "7.0").
|
||||
SetQueryParam("includeAll", "true").
|
||||
SetResult(&result).
|
||||
Get(url)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to fetch build definitions: %w", err)
|
||||
}
|
||||
|
||||
if resp.StatusCode() != 200 {
|
||||
return nil, fmt.Errorf("Azure API returned %d: %s", resp.StatusCode(), resp.String())
|
||||
}
|
||||
|
||||
return result.Value, nil
|
||||
}
|
||||
|
||||
// GetPipelineContent fetches the azure-pipelines.yml content from repository
|
||||
func (c *Client) GetPipelineContent(repoURL, branch, filePath string) (string, error) {
|
||||
// Azure DevOps Repos API for file content
|
||||
// Extract project and repo name from URL
|
||||
// URL format: https://dev.azure.com/org/project/_git/repo
|
||||
|
||||
// For this example, construct the items API URL
|
||||
parts := strings.Split(repoURL, "/_git/")
|
||||
if len(parts) != 2 {
|
||||
return "", fmt.Errorf("cannot parse repo URL: %s", repoURL)
|
||||
}
|
||||
|
||||
base := parts[0]
|
||||
repoName := parts[1]
|
||||
|
||||
url := fmt.Sprintf("%s/_apis/sourceProviders/TfsGit/filecontents?repository=%s&commitOrBranch=%s&path=%s&api-version=7.0",
|
||||
base, repoName, branch, filePath)
|
||||
|
||||
resp, err := c.client.R().
|
||||
Get(url)
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if resp.StatusCode() != 200 {
|
||||
// Try alternative: get via Git API (Items endpoint)
|
||||
return "", fmt.Errorf("file not found or access denied")
|
||||
}
|
||||
|
||||
return string(resp.Body()), nil
|
||||
}
|
||||
|
||||
// GetPipelineVariables gets variables for a specific build definition
|
||||
func (c *Client) GetPipelineVariables(project string, definitionID int) (map[string]string, error) {
|
||||
url := fmt.Sprintf("https://dev.azure.com/%s/%s/_apis/build/definitions/%d/variables",
|
||||
c.organization, project, definitionID)
|
||||
|
||||
var result struct {
|
||||
Count int `json:"count"`
|
||||
Value map[string]struct {
|
||||
Value string `json:"value"`
|
||||
IsSecret bool `json:"isSecret"`
|
||||
} `json:"value"`
|
||||
}
|
||||
|
||||
resp, err := c.client.R().
|
||||
SetQueryParam("api-version", "7.0").
|
||||
SetResult(&result).
|
||||
Get(url)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if resp.StatusCode() != 200 {
|
||||
return nil, fmt.Errorf("failed to get variables: %d", resp.StatusCode())
|
||||
}
|
||||
|
||||
vars := make(map[string]string)
|
||||
for k, v := range result.Value {
|
||||
vars[k] = v.Value // Note: secrets won't have values via API unless explicitly allowed
|
||||
}
|
||||
|
||||
return vars, nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue