drone/app/pipeline/converter/jsonnet/jsonnet.go
Patrick Wolf d789e5775e feat: [CODE-2402] : Update all occurences of 'gitness' to 'harness' within comments and markdown. Updated the logo reference (did not delete the Gitness logo directory yet). No active code changes except display strings. (#2684)
* Apply suggestion from code review
* updating images for signin and register page.
* fix: lint
* fix: logo update
* revert golangci
* Adding more strings and updated the logo. Still need to update the signin page images
* Apply suggestion from code review

Updating harness logo to use Open Source logo
* Update all occurences of 'gitness' to 'harness' within comments and markdown. Updated the logo reference (did not delete the Gitness logo directory yet).  No active code changes except display strings.
2024-09-25 00:13:28 +00:00

223 lines
6.3 KiB
Go

// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package jsonnet
import (
"bytes"
"context"
"errors"
"fmt"
"path"
"strconv"
"strings"
"github.com/harness/gitness/app/pipeline/file"
"github.com/harness/gitness/types"
"github.com/google/go-jsonnet"
)
const repo = "repo."
const build = "build."
const param = "param."
var noContext = context.Background()
type importer struct {
repo *types.Repository
execution *types.Execution
// jsonnet does not cache file imports and may request
// the same file multiple times. We cache the files to
// duplicate API calls.
cache map[string]jsonnet.Contents
// limit the number of outbound requests. github limits
// the number of api requests per hour, so we should
// make sure that a single build does not abuse the api
// by importing dozens of files.
limit int
// counts the number of outbound requests. if the count
// exceeds the limit, the importer will return errors.
count int
fileService file.Service
}
func (i *importer) Import(importedFrom, importedPath string) (contents jsonnet.Contents, foundAt string, err error) {
if i.cache == nil {
i.cache = map[string]jsonnet.Contents{}
}
// the import is relative to the imported from path. the
// imported path must resolve to a filepath relative to
// the root of the repository.
importedPath = path.Join(
path.Dir(importedFrom),
importedPath,
)
if strings.HasPrefix(importedFrom, "../") {
err = fmt.Errorf("jsonnet: cannot resolve import: %s", importedPath)
return contents, foundAt, err
}
// if the contents exist in the cache, return the
// cached item.
var ok bool
if contents, ok = i.cache[importedPath]; ok {
return contents, importedPath, nil
}
defer func() {
i.count++
}()
// if the import limit is exceeded log an error message.
if i.limit > 0 && i.count >= i.limit {
return contents, foundAt, errors.New("jsonnet: import limit exceeded")
}
find, err := i.fileService.Get(noContext, i.repo, importedPath, i.execution.Ref)
if err != nil {
return contents, foundAt, err
}
i.cache[importedPath] = jsonnet.MakeContents(string(find.Data))
return i.cache[importedPath], importedPath, err
}
func Parse(
repo *types.Repository,
repoIsPublic bool,
pipeline *types.Pipeline,
execution *types.Execution,
file *file.File,
fileService file.Service,
limit int,
) (string, error) {
vm := jsonnet.MakeVM()
vm.MaxStack = 500
vm.StringOutput = false
vm.ErrorFormatter.SetMaxStackTraceSize(20)
if fileService != nil && limit > 0 {
vm.Importer(
&importer{
repo: repo,
execution: execution,
limit: limit,
fileService: fileService,
},
)
}
// map execution/repo/pipeline parameters
if execution != nil {
mapBuild(execution, vm)
}
if repo != nil {
mapRepo(repo, pipeline, vm, repoIsPublic)
}
jsonnetFile := file
jsonnetFileName := pipeline.ConfigPath
// convert the jsonnet file to yaml
buf := new(bytes.Buffer)
docs, err := vm.EvaluateAnonymousSnippetStream(jsonnetFileName, string(jsonnetFile.Data))
if err != nil {
doc, err2 := vm.EvaluateAnonymousSnippet(jsonnetFileName, string(jsonnetFile.Data))
if err2 != nil {
return "", err
}
docs = append(docs, doc)
}
// the jsonnet vm returns a stream of yaml documents
// that need to be combined into a single yaml file.
for _, doc := range docs {
buf.WriteString("---")
buf.WriteString("\n")
buf.WriteString(doc)
}
return buf.String(), nil
}
// mapBuild populates build variables available to jsonnet templates.
// Since we want to maintain compatibility with drone, the older format
// needs to be maintained (even if the variables do not exist in Harness).
func mapBuild(v *types.Execution, vm *jsonnet.VM) {
vm.ExtVar(build+"event", string(v.Event))
vm.ExtVar(build+"action", string(v.Action))
vm.ExtVar(build+"environment", v.Deploy)
vm.ExtVar(build+"link", v.Link)
vm.ExtVar(build+"branch", v.Target)
vm.ExtVar(build+"source", v.Source)
vm.ExtVar(build+"before", v.Before)
vm.ExtVar(build+"after", v.After)
vm.ExtVar(build+"target", v.Target)
vm.ExtVar(build+"ref", v.Ref)
vm.ExtVar(build+"commit", v.After)
vm.ExtVar(build+"ref", v.Ref)
vm.ExtVar(build+"title", v.Title)
vm.ExtVar(build+"message", v.Message)
vm.ExtVar(build+"source_repo", v.Fork)
vm.ExtVar(build+"author_login", v.Author)
vm.ExtVar(build+"author_name", v.AuthorName)
vm.ExtVar(build+"author_email", v.AuthorEmail)
vm.ExtVar(build+"author_avatar", v.AuthorAvatar)
vm.ExtVar(build+"sender", v.Sender)
fromMap(v.Params, vm)
}
// mapBuild populates repo level variables available to jsonnet templates.
// Since we want to maintain compatibility with drone 2.x, the older format
// needs to be maintained (even if the variables do not exist in Harness).
func mapRepo(v *types.Repository, p *types.Pipeline, vm *jsonnet.VM, publicRepo bool) {
namespace := v.Path
idx := strings.LastIndex(v.Path, "/")
if idx != -1 {
namespace = v.Path[:idx]
}
// TODO [CODE-1363]: remove after identifier migration.
vm.ExtVar(repo+"uid", v.Identifier)
vm.ExtVar(repo+"identifier", v.Identifier)
vm.ExtVar(repo+"name", v.Identifier)
vm.ExtVar(repo+"namespace", namespace)
vm.ExtVar(repo+"slug", v.Path)
vm.ExtVar(repo+"git_http_url", v.GitURL)
vm.ExtVar(repo+"git_ssh_url", v.GitURL)
vm.ExtVar(repo+"link", v.GitURL)
vm.ExtVar(repo+"branch", v.DefaultBranch)
vm.ExtVar(repo+"config", p.ConfigPath)
vm.ExtVar(repo+"private", strconv.FormatBool(!publicRepo))
vm.ExtVar(repo+"visibility", "internal")
vm.ExtVar(repo+"active", strconv.FormatBool(true))
vm.ExtVar(repo+"trusted", strconv.FormatBool(true))
vm.ExtVar(repo+"protected", strconv.FormatBool(false))
vm.ExtVar(repo+"ignore_forks", strconv.FormatBool(false))
vm.ExtVar(repo+"ignore_pull_requests", strconv.FormatBool(false))
}
func fromMap(m map[string]string, vm *jsonnet.VM) {
for k, v := range m {
vm.ExtVar(build+param+k, v)
}
}