mirror of
https://github.com/SAP/jenkins-library.git
synced 2024-12-12 10:55:20 +02:00
Add schema patch step in go (#1683)
Co-authored-by: Stephan Aßmus <stephan.assmus@sap.com>
This commit is contained in:
parent
6dfd83d246
commit
be01dd3869
59
cmd/jsonApplyPatch.go
Normal file
59
cmd/jsonApplyPatch.go
Normal file
@ -0,0 +1,59 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"github.com/SAP/jenkins-library/pkg/log"
|
||||
"github.com/SAP/jenkins-library/pkg/piperutils"
|
||||
"github.com/SAP/jenkins-library/pkg/telemetry"
|
||||
"github.com/evanphx/json-patch"
|
||||
)
|
||||
|
||||
func jsonApplyPatch(config jsonApplyPatchOptions, telemetryData *telemetry.CustomData) {
|
||||
err := runJsonApplyPatch(&config, &piperutils.Files{})
|
||||
if err != nil {
|
||||
log.Entry().WithError(err).Fatal("step execution failed")
|
||||
}
|
||||
}
|
||||
|
||||
func runJsonApplyPatch(config *jsonApplyPatchOptions, fileUtils piperutils.FileUtils) error {
|
||||
schema, err := fileUtils.FileRead(config.Input)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
patchFile, err := fileUtils.FileRead(config.Patch)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
patcher, err := jsonpatch.DecodePatch(patchFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
patchedSchema, err := patcher.Apply(schema)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
formattedJson, err := formatJson(patchedSchema)
|
||||
if err != nil {
|
||||
// Ignore error and just use original result.
|
||||
formattedJson = patchedSchema
|
||||
}
|
||||
|
||||
err = fileUtils.FileWrite(config.Output, formattedJson, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func formatJson(input []byte) ([]byte, error) {
|
||||
var output bytes.Buffer
|
||||
err := json.Indent(&output, input, "", " ")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return output.Bytes(), nil
|
||||
}
|
125
cmd/jsonApplyPatch_generated.go
Normal file
125
cmd/jsonApplyPatch_generated.go
Normal file
@ -0,0 +1,125 @@
|
||||
// Code generated by piper's step-generator. DO NOT EDIT.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/SAP/jenkins-library/pkg/config"
|
||||
"github.com/SAP/jenkins-library/pkg/log"
|
||||
"github.com/SAP/jenkins-library/pkg/telemetry"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type jsonApplyPatchOptions struct {
|
||||
Input string `json:"input,omitempty"`
|
||||
Patch string `json:"patch,omitempty"`
|
||||
Output string `json:"output,omitempty"`
|
||||
}
|
||||
|
||||
// JsonApplyPatchCommand Patches a json with a patch file
|
||||
func JsonApplyPatchCommand() *cobra.Command {
|
||||
const STEP_NAME = "jsonApplyPatch"
|
||||
|
||||
metadata := jsonApplyPatchMetadata()
|
||||
var stepConfig jsonApplyPatchOptions
|
||||
var startTime time.Time
|
||||
|
||||
var createJsonApplyPatchCmd = &cobra.Command{
|
||||
Use: STEP_NAME,
|
||||
Short: "Patches a json with a patch file",
|
||||
Long: `This steps patches a json file with patch file using the json patch standard.
|
||||
This step can, e.g., be used if there is a json schema which needs to be patched.`,
|
||||
PreRunE: func(cmd *cobra.Command, args []string) error {
|
||||
startTime = time.Now()
|
||||
log.SetStepName(STEP_NAME)
|
||||
log.SetVerbose(GeneralConfig.Verbose)
|
||||
|
||||
path, _ := os.Getwd()
|
||||
fatalHook := &log.FatalHook{CorrelationID: GeneralConfig.CorrelationID, Path: path}
|
||||
log.RegisterHook(fatalHook)
|
||||
|
||||
err := PrepareConfig(cmd, &metadata, STEP_NAME, &stepConfig, config.OpenPiperFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(GeneralConfig.HookConfig.SentryConfig.Dsn) > 0 {
|
||||
sentryHook := log.NewSentryHook(GeneralConfig.HookConfig.SentryConfig.Dsn, GeneralConfig.CorrelationID)
|
||||
log.RegisterHook(&sentryHook)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
telemetryData := telemetry.CustomData{}
|
||||
telemetryData.ErrorCode = "1"
|
||||
handler := func() {
|
||||
telemetryData.Duration = fmt.Sprintf("%v", time.Since(startTime).Milliseconds())
|
||||
telemetry.Send(&telemetryData)
|
||||
}
|
||||
log.DeferExitHandler(handler)
|
||||
defer handler()
|
||||
telemetry.Initialize(GeneralConfig.NoTelemetry, STEP_NAME)
|
||||
jsonApplyPatch(stepConfig, &telemetryData)
|
||||
telemetryData.ErrorCode = "0"
|
||||
log.Entry().Info("SUCCESS")
|
||||
},
|
||||
}
|
||||
|
||||
addJsonApplyPatchFlags(createJsonApplyPatchCmd, &stepConfig)
|
||||
return createJsonApplyPatchCmd
|
||||
}
|
||||
|
||||
func addJsonApplyPatchFlags(cmd *cobra.Command, stepConfig *jsonApplyPatchOptions) {
|
||||
cmd.Flags().StringVar(&stepConfig.Input, "input", os.Getenv("PIPER_input"), "File path to the json file which schould be patched.")
|
||||
cmd.Flags().StringVar(&stepConfig.Patch, "patch", os.Getenv("PIPER_patch"), "File path to the patch which should be applied to the json file.")
|
||||
cmd.Flags().StringVar(&stepConfig.Output, "output", os.Getenv("PIPER_output"), "File path to destination of the patched json file.")
|
||||
|
||||
cmd.MarkFlagRequired("input")
|
||||
cmd.MarkFlagRequired("patch")
|
||||
cmd.MarkFlagRequired("output")
|
||||
}
|
||||
|
||||
// retrieve step metadata
|
||||
func jsonApplyPatchMetadata() config.StepData {
|
||||
var theMetaData = config.StepData{
|
||||
Metadata: config.StepMetadata{
|
||||
Name: "jsonApplyPatch",
|
||||
Aliases: []config.Alias{},
|
||||
},
|
||||
Spec: config.StepSpec{
|
||||
Inputs: config.StepInputs{
|
||||
Parameters: []config.StepParameters{
|
||||
{
|
||||
Name: "input",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"PARAMETERS"},
|
||||
Type: "string",
|
||||
Mandatory: true,
|
||||
Aliases: []config.Alias{},
|
||||
},
|
||||
{
|
||||
Name: "patch",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"PARAMETERS"},
|
||||
Type: "string",
|
||||
Mandatory: true,
|
||||
Aliases: []config.Alias{},
|
||||
},
|
||||
{
|
||||
Name: "output",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"PARAMETERS"},
|
||||
Type: "string",
|
||||
Mandatory: true,
|
||||
Aliases: []config.Alias{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
return theMetaData
|
||||
}
|
16
cmd/jsonApplyPatch_generated_test.go
Normal file
16
cmd/jsonApplyPatch_generated_test.go
Normal file
@ -0,0 +1,16 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestJsonApplyPatchCommand(t *testing.T) {
|
||||
|
||||
testCmd := JsonApplyPatchCommand()
|
||||
|
||||
// only high level testing performed - details are tested in step generation procudure
|
||||
assert.Equal(t, "jsonApplyPatch", testCmd.Use, "command name incorrect")
|
||||
|
||||
}
|
82
cmd/jsonApplyPatch_test.go
Normal file
82
cmd/jsonApplyPatch_test.go
Normal file
@ -0,0 +1,82 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/SAP/jenkins-library/pkg/mock"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var schema = []byte(`
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "SAP Cloud SDK pipeline_config JSON schema",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"general": {
|
||||
"type": [
|
||||
"object",
|
||||
"null"
|
||||
],
|
||||
"properties": {
|
||||
"productiveBranch": {
|
||||
"type": "string",
|
||||
"default": "master"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
var patch = []byte(`
|
||||
[
|
||||
{
|
||||
"op": "add",
|
||||
"path": "/properties/general/properties/gitCredentialsId",
|
||||
"value": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
]
|
||||
`)
|
||||
|
||||
var patchedSchema = []byte(`{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "SAP Cloud SDK pipeline_config JSON schema",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"general": {
|
||||
"type": [
|
||||
"object",
|
||||
"null"
|
||||
],
|
||||
"properties": {
|
||||
"productiveBranch": {
|
||||
"type": "string",
|
||||
"default": "master"
|
||||
},
|
||||
"gitCredentialsId": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}`)
|
||||
|
||||
func TestSchemaPatch(t *testing.T) {
|
||||
t.Run("default", func(t *testing.T) {
|
||||
options := jsonApplyPatchOptions{
|
||||
Input: "schema.json",
|
||||
Patch: "patch.json",
|
||||
Output: "output.json",
|
||||
}
|
||||
filesMock := mock.FilesMock{}
|
||||
filesMock.AddFile("schema.json", schema)
|
||||
filesMock.AddFile("patch.json", patch)
|
||||
err := runJsonApplyPatch(&options, &filesMock)
|
||||
assert.NoError(t, err)
|
||||
patchedSchemaResult, err := filesMock.FileRead("output.json")
|
||||
assert.NoError(t, err)
|
||||
assert.JSONEq(t, string(patchedSchema), string(patchedSchemaResult))
|
||||
})
|
||||
}
|
@ -88,6 +88,7 @@ func Execute() {
|
||||
rootCmd.AddCommand(GctsDeployCommand())
|
||||
rootCmd.AddCommand(MalwareExecuteScanCommand())
|
||||
rootCmd.AddCommand(GctsCloneRepositoryCommand())
|
||||
rootCmd.AddCommand(JsonApplyPatchCommand())
|
||||
|
||||
addRootFlags(rootCmd)
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
|
1
go.mod
1
go.mod
@ -11,6 +11,7 @@ require (
|
||||
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 // indirect
|
||||
github.com/bmatcuk/doublestar v1.3.1
|
||||
github.com/containerd/containerd v1.3.4 // indirect
|
||||
github.com/evanphx/json-patch v4.5.0+incompatible
|
||||
github.com/getsentry/sentry-go v0.6.1
|
||||
github.com/ghodss/yaml v1.0.0
|
||||
github.com/go-git/go-git/v5 v5.1.0
|
||||
|
2
go.sum
2
go.sum
@ -253,6 +253,8 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw=
|
||||
github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/evanphx/json-patch v4.5.0+incompatible h1:ouOWdg56aJriqS0huScTkVXPC5IcNrDCXZ6OoTAWu7M=
|
||||
github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
||||
|
27
resources/metadata/jsonApplyPatch.yaml
Normal file
27
resources/metadata/jsonApplyPatch.yaml
Normal file
@ -0,0 +1,27 @@
|
||||
metadata:
|
||||
name: jsonApplyPatch
|
||||
description: Patches a json with a patch file
|
||||
longDescription: |-
|
||||
This steps patches a json file with patch file using the json patch standard.
|
||||
This step can, e.g., be used if there is a json schema which needs to be patched.
|
||||
spec:
|
||||
inputs:
|
||||
params:
|
||||
- name: input
|
||||
type: string
|
||||
description: File path to the json file which schould be patched.
|
||||
mandatory: true
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- name: patch
|
||||
type: string
|
||||
description: File path to the patch which should be applied to the json file.
|
||||
mandatory: true
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- name: output
|
||||
type: string
|
||||
description: File path to destination of the patched json file.
|
||||
mandatory: true
|
||||
scope:
|
||||
- PARAMETERS
|
Loading…
Reference in New Issue
Block a user