Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion modules/har/pkg/har/migrate/adapter/har/adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ package har

import (
"context"
"errors"
"fmt"
"io"
"net/http"
"net/url"
"path"
"strings"

adp "github.com/harness/cli/modules/har/pkg/har/migrate/adapter"
Expand Down Expand Up @@ -112,10 +114,21 @@ func (a *harAdapter) UploadFile(
err = a.client.uploadDartFile(registry, artifactName, version, f, file)
case types.RAW:
err = a.client.uploadRawFile(registry, f, file)
case types.DEBIAN:
err = a.client.uploadDebianFile(registry, f, file, metadata)
case types.PUPPET:
err = a.client.uploadPuppetFile(registry, f, file)
case types.CONAN:
err = a.client.uploadConanFile(registry, file, metadata)
default:
return fmt.Errorf("unsupported artifact type for upload: %s", artifactType)
}
if err != nil {
if errors.Is(err, types.ErrArtifactAlreadyExists) {
return err
}
a.logger.Error().Err(err).Msgf("Failed to upload file %s to registry: %s", f.Uri, registry)
return fmt.Errorf("failed to upload file %s to registry: %s, %v", f.Uri, registry, err)
return fmt.Errorf("failed to upload file %s to registry: %s, %w", f.Uri, registry, err)
}
return nil
}
Expand All @@ -133,6 +146,10 @@ func (a *harAdapter) VersionExists(ctx context.Context, p types.Package, registr
if artifactType == types.HELM_LEGACY {
artifactType = types.HELM
}
if artifactType == types.HELM_HTTP {
// HAR stores the chart by its leaf name; nested names like "team-a/abc" must resolve to "abc".
pkg = path.Base(pkg)
}
return a.client.artifactVersionExists(ctx, registryRef, pkg, version, artifactType)
}

Expand Down
188 changes: 187 additions & 1 deletion modules/har/pkg/har/migrate/adapter/har/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ func (c *client) uploadRawFile(registry string, f *types.File, file io.ReadClose
fileUri := strings.TrimPrefix(f.Uri, "/")
defer file.Close()

_, err := c.pkgClient.UploadGenericFileToPathWithBodyWithResponse(
resp, err := c.pkgClient.UploadGenericFileToPathWithBodyWithResponse(
context.Background(),
c.accountID,
registry,
Expand All @@ -158,6 +158,12 @@ func (c *client) uploadRawFile(registry string, f *types.File, file io.ReadClose
if err != nil {
return fmt.Errorf("failed to upload raw file '%s': %w", fileUri, err)
}
if resp.StatusCode() == http2.StatusConflict {
return types.ErrArtifactAlreadyExists
}
if resp.StatusCode() < 200 || resp.StatusCode() > 299 {
return fmt.Errorf("failed to upload raw file '%s', status %d", fileUri, resp.StatusCode())
}

return nil
}
Expand Down Expand Up @@ -814,6 +820,9 @@ func (c *client) artifactVersionExists(
if err != nil {
return false, fmt.Errorf("failed to get artifact versions: %w", err)
}
if response.StatusCode() == http2.StatusNotFound {
return false, nil
}
if response.StatusCode() != http2.StatusOK {
return false, fmt.Errorf("failed to get artifact versions: %s", response.Status())
}
Expand Down Expand Up @@ -902,3 +911,180 @@ func (c *client) createGoVersion(

return nil
}

func (c *client) uploadDebianFile(
registry string,
f *types.File,
file io.ReadCloser,
metadata map[string]interface{},
) error {
distribution, _ := metadata["distribution"].(string)
component, _ := metadata["component"].(string)
fileType, _ := metadata["fileType"].(string)
packageName, _ := metadata["packageName"].(string)
version, _ := metadata["version"].(string)

if distribution == "" {
return fmt.Errorf("distribution is required in metadata for debian upload")
}
if component == "" {
return fmt.Errorf("component is required in metadata for debian upload")
}
if fileType == "" {
fileType = "deb"
}
if fileType == "src" {
if packageName == "" {
return fmt.Errorf("packageName is required in metadata for debian src upload")
}
if version == "" {
return fmt.Errorf("version is required in metadata for debian src upload")
}
}

endpoint := fileType // "deb", "dsc", or "src"
baseURL := fmt.Sprintf("%s/pkg/%s/%s/debian/%s?distribution=%s&component=%s",
c.url, c.accountID, registry, endpoint,
strings.ReplaceAll(distribution, " ", "%20"),
strings.ReplaceAll(component, " ", "%20"),
)
if fileType == "src" {
baseURL += "&package=" + packageName + "&version=" + version
}

pr, pw := io.Pipe()
writer := multipart.NewWriter(pw)
go func() {
defer pw.Close()
defer writer.Close()
part, err := writer.CreateFormFile("file", f.Name)
if err != nil {
pw.CloseWithError(err)
return
}
if _, err := io.Copy(part, file); err != nil {
pw.CloseWithError(err)
}
}()

req, err := http2.NewRequest(http2.MethodPut, baseURL, pr)
if err != nil {
return fmt.Errorf("failed to create request: %w", err)
}
req.Header.Set("Content-Type", writer.FormDataContentType())
resp, err := c.client.Do(req)
if err != nil {
return fmt.Errorf("failed to upload debian file '%s': %w", f.Name, err)
}
defer resp.Body.Close()
if resp.StatusCode < 200 || resp.StatusCode > 299 {
body, _ := io.ReadAll(resp.Body)
return fmt.Errorf("failed to upload debian file '%s', status %d: %s", f.Name, resp.StatusCode, string(body))
}
return nil
}

func (c *client) uploadPuppetFile(
registry string,
f *types.File,
file io.ReadCloser,
) error {
uploadURL := fmt.Sprintf("%s/pkg/%s/%s/puppet/upload", c.url, c.accountID, registry)

pr, pw := io.Pipe()
writer := multipart.NewWriter(pw)
go func() {
defer pw.Close()
defer writer.Close()
part, err := writer.CreateFormFile("file", f.Name)
if err != nil {
pw.CloseWithError(err)
return
}
if _, err := io.Copy(part, file); err != nil {
pw.CloseWithError(err)
}
}()

req, err := http2.NewRequest(http2.MethodPut, uploadURL, pr)
if err != nil {
return fmt.Errorf("failed to create request: %w", err)
}
req.Header.Set("Content-Type", writer.FormDataContentType())
resp, err := c.client.Do(req)
if err != nil {
return fmt.Errorf("failed to upload puppet file '%s': %w", f.Name, err)
}
defer resp.Body.Close()
if resp.StatusCode < 200 || resp.StatusCode > 299 {
body, _ := io.ReadAll(resp.Body)
return fmt.Errorf("failed to upload puppet file '%s', status %d: %s", f.Name, resp.StatusCode, string(body))
}
return nil
}

func (c *client) uploadConanFile(
registry string,
file io.ReadCloser,
metadata map[string]interface{},
) error {
defer file.Close()

name, _ := metadata["name"].(string)
version, _ := metadata["version"].(string)
rrev, _ := metadata["rrev"].(string)
filename, _ := metadata["filename"].(string)
user, _ := metadata["user"].(string)
channel, _ := metadata["channel"].(string)
sha1, _ := metadata["sha1"].(string)
layer, _ := metadata["layer"].(string)
pkgid, _ := metadata["pkgid"].(string)
prev, _ := metadata["prev"].(string)

if name == "" || version == "" || rrev == "" || filename == "" {
return fmt.Errorf("uploadConanFile: missing required metadata fields (name=%q, version=%q, rrev=%q, filename=%q)",
name, version, rrev, filename)
}
if layer == "package" && (pkgid == "" || prev == "") {
return fmt.Errorf("uploadConanFile: package layer requires pkgid and prev (pkgid=%q, prev=%q)", pkgid, prev)
}

if user == "" {
user = "_"
}
if channel == "" {
channel = "_"
}

var uploadURL string
if layer == "package" {
uploadURL = fmt.Sprintf("%s/pkg/%s/%s/conan/v2/conans/%s/%s/%s/%s/revisions/%s/packages/%s/revisions/%s/files/%s",
c.url, c.accountID, registry, name, version, user, channel, rrev, pkgid, prev, filename)
} else {
uploadURL = fmt.Sprintf("%s/pkg/%s/%s/conan/v2/conans/%s/%s/%s/%s/revisions/%s/files/%s",
c.url, c.accountID, registry, name, version, user, channel, rrev, filename)
}

req, err := http2.NewRequest(http2.MethodPut, uploadURL, file)
if err != nil {
return fmt.Errorf("failed to create request: %w", err)
}
req.Header.Set("Content-Type", "application/octet-stream")
if sha1 != "" {
req.Header.Set("X-Checksum-Sha1", sha1)
}

resp, err := c.client.Do(req)
if err != nil {
return fmt.Errorf("failed to upload conan file '%s': %w", filename, err)
}
defer resp.Body.Close()
if resp.StatusCode == http2.StatusConflict {
return types.ErrArtifactAlreadyExists
}
if resp.StatusCode < 200 || resp.StatusCode > 299 {
body, _ := io.ReadAll(resp.Body)
return fmt.Errorf("failed to upload conan file '%s', status %d: %s", filename, resp.StatusCode, string(body))
}
return nil
}
Loading
Loading