2022-04-19 19:55:35 +03:00
// Copyright 2022 The Gitea Authors. All rights reserved.
2022-11-27 21:20:29 +03:00
// SPDX-License-Identifier: MIT
2022-04-19 19:55:35 +03:00
package helm
import (
"archive/tar"
"compress/gzip"
"io"
"strings"
2022-12-31 14:49:37 +03:00
"code.gitea.io/gitea/modules/util"
2022-04-19 19:55:35 +03:00
"code.gitea.io/gitea/modules/validation"
"github.com/hashicorp/go-version"
2022-11-21 11:36:59 +03:00
"gopkg.in/yaml.v3"
2022-04-19 19:55:35 +03:00
)
var (
// ErrMissingChartFile indicates a missing Chart.yaml file
2022-12-31 14:49:37 +03:00
ErrMissingChartFile = util . NewInvalidArgumentErrorf ( "Chart.yaml file is missing" )
2022-04-19 19:55:35 +03:00
// ErrInvalidName indicates an invalid package name
2022-12-31 14:49:37 +03:00
ErrInvalidName = util . NewInvalidArgumentErrorf ( "package name is invalid" )
2022-04-19 19:55:35 +03:00
// ErrInvalidVersion indicates an invalid package version
2022-12-31 14:49:37 +03:00
ErrInvalidVersion = util . NewInvalidArgumentErrorf ( "package version is invalid" )
2022-04-19 19:55:35 +03:00
// ErrInvalidChart indicates an invalid chart
2022-12-31 14:49:37 +03:00
ErrInvalidChart = util . NewInvalidArgumentErrorf ( "chart is invalid" )
2022-04-19 19:55:35 +03:00
)
// Metadata for a Chart file. This models the structure of a Chart.yaml file.
type Metadata struct {
APIVersion string ` json:"api_version" yaml:"apiVersion" `
Type string ` json:"type,omitempty" yaml:"type,omitempty" `
Name string ` json:"name" yaml:"name" `
Version string ` json:"version" yaml:"version" `
AppVersion string ` json:"app_version,omitempty" yaml:"appVersion,omitempty" `
Home string ` json:"home,omitempty" yaml:"home,omitempty" `
Sources [ ] string ` json:"sources,omitempty" yaml:"sources,omitempty" `
Description string ` json:"description,omitempty" yaml:"description,omitempty" `
Keywords [ ] string ` json:"keywords,omitempty" yaml:"keywords,omitempty" `
Maintainers [ ] * Maintainer ` json:"maintainers,omitempty" yaml:"maintainers,omitempty" `
Icon string ` json:"icon,omitempty" yaml:"icon,omitempty" `
Condition string ` json:"condition,omitempty" yaml:"condition,omitempty" `
Tags string ` json:"tags,omitempty" yaml:"tags,omitempty" `
Deprecated bool ` json:"deprecated,omitempty" yaml:"deprecated,omitempty" `
Annotations map [ string ] string ` json:"annotations,omitempty" yaml:"annotations,omitempty" `
KubeVersion string ` json:"kube_version,omitempty" yaml:"kubeVersion,omitempty" `
Dependencies [ ] * Dependency ` json:"dependencies,omitempty" yaml:"dependencies,omitempty" `
}
type Maintainer struct {
Name string ` json:"name,omitempty" yaml:"name,omitempty" `
Email string ` json:"email,omitempty" yaml:"email,omitempty" `
URL string ` json:"url,omitempty" yaml:"url,omitempty" `
}
type Dependency struct {
2023-07-04 21:36:08 +03:00
Name string ` json:"name" yaml:"name" `
Version string ` json:"version,omitempty" yaml:"version,omitempty" `
Repository string ` json:"repository" yaml:"repository" `
Condition string ` json:"condition,omitempty" yaml:"condition,omitempty" `
Tags [ ] string ` json:"tags,omitempty" yaml:"tags,omitempty" `
Enabled bool ` json:"enabled,omitempty" yaml:"enabled,omitempty" `
ImportValues [ ] any ` json:"import_values,omitempty" yaml:"import-values,omitempty" `
Alias string ` json:"alias,omitempty" yaml:"alias,omitempty" `
2022-04-19 19:55:35 +03:00
}
// ParseChartArchive parses the metadata of a Helm archive
func ParseChartArchive ( r io . Reader ) ( * Metadata , error ) {
gzr , err := gzip . NewReader ( r )
if err != nil {
return nil , err
}
defer gzr . Close ( )
tr := tar . NewReader ( gzr )
for {
hd , err := tr . Next ( )
if err == io . EOF {
break
}
if err != nil {
return nil , err
}
if hd . Typeflag != tar . TypeReg {
continue
}
if hd . FileInfo ( ) . Name ( ) == "Chart.yaml" {
if strings . Count ( hd . Name , "/" ) != 1 {
continue
}
return ParseChartFile ( tr )
}
}
return nil , ErrMissingChartFile
}
// ParseChartFile parses a Chart.yaml file to retrieve the metadata of a Helm chart
func ParseChartFile ( r io . Reader ) ( * Metadata , error ) {
var metadata * Metadata
if err := yaml . NewDecoder ( r ) . Decode ( & metadata ) ; err != nil {
return nil , err
}
if metadata . APIVersion == "" {
return nil , ErrInvalidChart
}
if metadata . Type != "" && metadata . Type != "application" && metadata . Type != "library" {
return nil , ErrInvalidChart
}
if metadata . Name == "" {
return nil , ErrInvalidName
}
if _ , err := version . NewSemver ( metadata . Version ) ; err != nil {
return nil , ErrInvalidVersion
}
if ! validation . IsValidURL ( metadata . Home ) {
metadata . Home = ""
}
return metadata , nil
}