-
Notifications
You must be signed in to change notification settings - Fork 48
Fix Dependabot config indentation issue #2140
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,10 +3,12 @@ package dependabot | |
import ( | ||
"bufio" | ||
"encoding/json" | ||
"errors" | ||
"fmt" | ||
"strings" | ||
|
||
dependabot "github.com/paulvollmer/dependabot-config-go" | ||
"gopkg.in/yaml.v2" | ||
"gopkg.in/yaml.v3" | ||
) | ||
|
||
type UpdateDependabotConfigResponse struct { | ||
|
@@ -27,29 +29,79 @@ type UpdateDependabotConfigRequest struct { | |
Content string | ||
} | ||
|
||
// getIndentation returns the indentation level of the first list found in a given YAML string. | ||
// If the YAML string is empty or invalid, or if no list is found, it returns an error. | ||
func getIndentation(dependabotConfig string) (int, error) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
// Initialize an empty YAML node | ||
t := yaml.Node{} | ||
|
||
// Unmarshal the YAML string into the node | ||
err := yaml.Unmarshal([]byte(dependabotConfig), &t) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
if err != nil { | ||
return 0, fmt.Errorf("unable to parse yaml: %w", err) | ||
} | ||
|
||
// Retrieve the top node of the YAML document | ||
topNode := t.Content | ||
if len(topNode) == 0 { | ||
return 0, errors.New("file provided is empty or invalid") | ||
} | ||
|
||
// Check for the first list and its indentation level | ||
for _, n := range topNode[0].Content { | ||
if n.Value == "" && n.Tag == "!!seq" { | ||
// Return the column of the first list found | ||
return n.Column, nil | ||
} | ||
} | ||
|
||
// Return an error if no list was found | ||
return 0, errors.New("no list found in yaml") | ||
} | ||
|
||
// UpdateDependabotConfig is used to update dependabot configuration and returns an UpdateDependabotConfigResponse. | ||
func UpdateDependabotConfig(dependabotConfig string) (*UpdateDependabotConfigResponse, error) { | ||
var updateDependabotConfigRequest UpdateDependabotConfigRequest | ||
json.Unmarshal([]byte(dependabotConfig), &updateDependabotConfigRequest) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
// Handle error in json unmarshalling | ||
err := json.Unmarshal([]byte(dependabotConfig), &updateDependabotConfigRequest) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to unmarshal JSON from dependabotConfig: %v", err) | ||
} | ||
|
||
inputConfigFile := []byte(updateDependabotConfigRequest.Content) | ||
configMetadata := dependabot.New() | ||
err := configMetadata.Unmarshal(inputConfigFile) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
err = configMetadata.Unmarshal(inputConfigFile) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
if err != nil { | ||
return nil, err | ||
return nil, fmt.Errorf("failed to unmarshal dependabot config: %v", err) | ||
} | ||
|
||
indentation := 3 | ||
|
||
response := new(UpdateDependabotConfigResponse) | ||
response.FinalOutput = updateDependabotConfigRequest.Content | ||
response.OriginalInput = updateDependabotConfigRequest.Content | ||
response.IsChanged = false | ||
|
||
// Using strings.Builder for efficient string concatenation | ||
var finalOutput strings.Builder | ||
finalOutput.WriteString(response.FinalOutput) | ||
|
||
if updateDependabotConfigRequest.Content == "" { | ||
if len(updateDependabotConfigRequest.Ecosystems) == 0 { | ||
return response, nil | ||
} | ||
response.FinalOutput = "version: 2\nupdates:" | ||
finalOutput.WriteString("version: 2\nupdates:") | ||
} else { | ||
response.FinalOutput += "\n" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
if !strings.HasSuffix(response.FinalOutput, "\n") { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
finalOutput.WriteString("\n") | ||
} | ||
indentation, err = getIndentation(string(inputConfigFile)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
if err != nil { | ||
return nil, fmt.Errorf("failed to get indentation: %v", err) | ||
} | ||
} | ||
|
||
for _, Update := range updateDependabotConfigRequest.Ecosystems { | ||
updateAlreadyExist := false | ||
for _, update := range configMetadata.Updates { | ||
|
@@ -58,37 +110,56 @@ func UpdateDependabotConfig(dependabotConfig string) (*UpdateDependabotConfigRes | |
break | ||
} | ||
} | ||
if !updateAlreadyExist { | ||
item := dependabot.Update{} | ||
item.PackageEcosystem = Update.PackageEcosystem | ||
item.Directory = Update.Directory | ||
|
||
schedule := dependabot.Schedule{} | ||
schedule.Interval = Update.Interval | ||
|
||
item.Schedule = schedule | ||
items := []dependabot.Update{} | ||
items = append(items, item) | ||
if !updateAlreadyExist { | ||
item := dependabot.Update{ | ||
PackageEcosystem: Update.PackageEcosystem, | ||
Directory: Update.Directory, | ||
Schedule: dependabot.Schedule{Interval: Update.Interval}, | ||
} | ||
items := []dependabot.Update{item} | ||
addedItem, err := yaml.Marshal(items) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
data := string(addedItem) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to marshal update items: %v", err) | ||
} | ||
|
||
data = addIndentation(data) | ||
data, err := addIndentation(string(addedItem), indentation) | ||
if err != nil { | ||
return nil, err | ||
return nil, fmt.Errorf("failed to add indentation: %v", err) | ||
} | ||
response.FinalOutput = response.FinalOutput + data | ||
finalOutput.WriteString(data) | ||
response.IsChanged = true | ||
} | ||
} | ||
|
||
// Set FinalOutput to the built string | ||
response.FinalOutput = finalOutput.String() | ||
|
||
return response, nil | ||
} | ||
|
||
func addIndentation(data string) string { | ||
// addIndentation adds a certain number of spaces to the start of each line in the input string. | ||
// It returns a new string with the added indentation. | ||
func addIndentation(data string, indentation int) (string, error) { | ||
scanner := bufio.NewScanner(strings.NewReader(data)) | ||
finalData := "\n" | ||
var finalData strings.Builder | ||
|
||
// Create the indentation string | ||
spaces := strings.Repeat(" ", indentation-1) | ||
|
||
finalData.WriteString("\n") | ||
|
||
// Add indentation to each line | ||
for scanner.Scan() { | ||
finalData += " " + scanner.Text() + "\n" | ||
finalData.WriteString(spaces) | ||
finalData.WriteString(scanner.Text()) | ||
finalData.WriteString("\n") | ||
} | ||
|
||
// Check for scanning errors | ||
if err := scanner.Err(); err != nil { | ||
return "", fmt.Errorf("error during scanning: %w", err) | ||
} | ||
return finalData | ||
|
||
return finalData.String(), nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
version: 2 | ||
updates: | ||
- package-ecosystem: github-actions | ||
directory: "/" | ||
schedule: | ||
interval: daily |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
version: 2 | ||
updates: | ||
- package-ecosystem: github-actions | ||
directory: "/" | ||
schedule: | ||
interval: daily | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,4 +4,4 @@ updates: | |
# Files stored in `app` directory | ||
directory: "/app" | ||
schedule: | ||
interval: "daily" | ||
interval: "daily" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
version: 2 | ||
updates: | ||
- package-ecosystem: github-actions | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
directory: "/" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
schedule: | ||
interval: daily | ||
|
||
- package-ecosystem: npm | ||
directory: /sample | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
schedule: | ||
interval: daily |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
version: 2 | ||
updates: | ||
- package-ecosystem: github-actions | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
directory: "/" | ||
schedule: | ||
interval: daily | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
- package-ecosystem: npm | ||
directory: /sample | ||
schedule: | ||
interval: daily |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The yaml.v2 package has been recommended for deprecation and current code can be updated to use yaml.v3. Update import from gopkg.in/yaml.v2 to gopkg.in/yaml.v3 code line:"gopkg.in/yaml.v2"