@@ -3,10 +3,12 @@ package dependabot
33import (
44 "bufio"
55 "encoding/json"
6+ "errors"
7+ "fmt"
68 "strings"
79
810 dependabot "github.com/paulvollmer/dependabot-config-go"
9- "gopkg.in/yaml.v2 "
11+ "gopkg.in/yaml.v3 "
1012)
1113
1214type UpdateDependabotConfigResponse struct {
@@ -27,29 +29,79 @@ type UpdateDependabotConfigRequest struct {
2729 Content string
2830}
2931
32+ // getIndentation returns the indentation level of the first list found in a given YAML string.
33+ // If the YAML string is empty or invalid, or if no list is found, it returns an error.
34+ func getIndentation (dependabotConfig string ) (int , error ) {
35+ // Initialize an empty YAML node
36+ t := yaml.Node {}
37+
38+ // Unmarshal the YAML string into the node
39+ err := yaml .Unmarshal ([]byte (dependabotConfig ), & t )
40+ if err != nil {
41+ return 0 , fmt .Errorf ("unable to parse yaml: %w" , err )
42+ }
43+
44+ // Retrieve the top node of the YAML document
45+ topNode := t .Content
46+ if len (topNode ) == 0 {
47+ return 0 , errors .New ("file provided is empty or invalid" )
48+ }
49+
50+ // Check for the first list and its indentation level
51+ for _ , n := range topNode [0 ].Content {
52+ if n .Value == "" && n .Tag == "!!seq" {
53+ // Return the column of the first list found
54+ return n .Column , nil
55+ }
56+ }
57+
58+ // Return an error if no list was found
59+ return 0 , errors .New ("no list found in yaml" )
60+ }
61+
62+ // UpdateDependabotConfig is used to update dependabot configuration and returns an UpdateDependabotConfigResponse.
3063func UpdateDependabotConfig (dependabotConfig string ) (* UpdateDependabotConfigResponse , error ) {
3164 var updateDependabotConfigRequest UpdateDependabotConfigRequest
32- json .Unmarshal ([]byte (dependabotConfig ), & updateDependabotConfigRequest )
65+
66+ // Handle error in json unmarshalling
67+ err := json .Unmarshal ([]byte (dependabotConfig ), & updateDependabotConfigRequest )
68+ if err != nil {
69+ return nil , fmt .Errorf ("failed to unmarshal JSON from dependabotConfig: %v" , err )
70+ }
71+
3372 inputConfigFile := []byte (updateDependabotConfigRequest .Content )
3473 configMetadata := dependabot .New ()
35- err : = configMetadata .Unmarshal (inputConfigFile )
74+ err = configMetadata .Unmarshal (inputConfigFile )
3675 if err != nil {
37- return nil , err
76+ return nil , fmt . Errorf ( "failed to unmarshal dependabot config: %v" , err )
3877 }
3978
79+ indentation := 3
80+
4081 response := new (UpdateDependabotConfigResponse )
4182 response .FinalOutput = updateDependabotConfigRequest .Content
4283 response .OriginalInput = updateDependabotConfigRequest .Content
4384 response .IsChanged = false
4485
86+ // Using strings.Builder for efficient string concatenation
87+ var finalOutput strings.Builder
88+ finalOutput .WriteString (response .FinalOutput )
89+
4590 if updateDependabotConfigRequest .Content == "" {
4691 if len (updateDependabotConfigRequest .Ecosystems ) == 0 {
4792 return response , nil
4893 }
49- response . FinalOutput = "version: 2\n updates:"
94+ finalOutput . WriteString ( "version: 2\n updates:" )
5095 } else {
51- response .FinalOutput += "\n "
96+ if ! strings .HasSuffix (response .FinalOutput , "\n " ) {
97+ finalOutput .WriteString ("\n " )
98+ }
99+ indentation , err = getIndentation (string (inputConfigFile ))
100+ if err != nil {
101+ return nil , fmt .Errorf ("failed to get indentation: %v" , err )
102+ }
52103 }
104+
53105 for _ , Update := range updateDependabotConfigRequest .Ecosystems {
54106 updateAlreadyExist := false
55107 for _ , update := range configMetadata .Updates {
@@ -58,37 +110,56 @@ func UpdateDependabotConfig(dependabotConfig string) (*UpdateDependabotConfigRes
58110 break
59111 }
60112 }
61- if ! updateAlreadyExist {
62- item := dependabot.Update {}
63- item .PackageEcosystem = Update .PackageEcosystem
64- item .Directory = Update .Directory
65113
66- schedule := dependabot.Schedule {}
67- schedule .Interval = Update .Interval
68-
69- item .Schedule = schedule
70- items := []dependabot.Update {}
71- items = append (items , item )
114+ if ! updateAlreadyExist {
115+ item := dependabot.Update {
116+ PackageEcosystem : Update .PackageEcosystem ,
117+ Directory : Update .Directory ,
118+ Schedule : dependabot.Schedule {Interval : Update .Interval },
119+ }
120+ items := []dependabot.Update {item }
72121 addedItem , err := yaml .Marshal (items )
73- data := string (addedItem )
122+ if err != nil {
123+ return nil , fmt .Errorf ("failed to marshal update items: %v" , err )
124+ }
74125
75- data = addIndentation (data )
126+ data , err : = addIndentation (string ( addedItem ), indentation )
76127 if err != nil {
77- return nil , err
128+ return nil , fmt . Errorf ( "failed to add indentation: %v" , err )
78129 }
79- response . FinalOutput = response . FinalOutput + data
130+ finalOutput . WriteString ( data )
80131 response .IsChanged = true
81132 }
82133 }
83134
135+ // Set FinalOutput to the built string
136+ response .FinalOutput = finalOutput .String ()
137+
84138 return response , nil
85139}
86140
87- func addIndentation (data string ) string {
141+ // addIndentation adds a certain number of spaces to the start of each line in the input string.
142+ // It returns a new string with the added indentation.
143+ func addIndentation (data string , indentation int ) (string , error ) {
88144 scanner := bufio .NewScanner (strings .NewReader (data ))
89- finalData := "\n "
145+ var finalData strings.Builder
146+
147+ // Create the indentation string
148+ spaces := strings .Repeat (" " , indentation - 1 )
149+
150+ finalData .WriteString ("\n " )
151+
152+ // Add indentation to each line
90153 for scanner .Scan () {
91- finalData += " " + scanner .Text () + "\n "
154+ finalData .WriteString (spaces )
155+ finalData .WriteString (scanner .Text ())
156+ finalData .WriteString ("\n " )
157+ }
158+
159+ // Check for scanning errors
160+ if err := scanner .Err (); err != nil {
161+ return "" , fmt .Errorf ("error during scanning: %w" , err )
92162 }
93- return finalData
163+
164+ return finalData .String (), nil
94165}
0 commit comments