Repository: jd-apprentice/Scruticode
Pull request #16: feat(parse): #3 read langs and platforms
Author: login: jd-apprentice
Labels: name: enhancement
description: New feature or request
Created: 2025-03-26T00:55:03Z | Merged: 2025-03-26T16:20:00Z

Added function to read langs and platforms
Quite improvements for readability in general
InitConfig was not being handled properly

Remember to not use the `init` function.

https://stackoverflow.com/questions/56039154/is-it-really-bad-to-use-init-functions-in-go#56039373
https://leighmcculloch.com/posts/tool-go-check-no-globals-no-inits/

The linter will complain.


Diff:
diff --git a/Makefile b/Makefile
index 66ea234..2ce682e 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-all: clear lint test imports build start
+all: lint test imports build start
 
 ### Development
 
@@ -27,17 +27,25 @@ lint-fix: path
 	golangci-lint run --fix
 
 clear:
+	if [ -d "./bin" ]; then \
+		rm -rf ./bin; \
+	fi
+
+	if [ -f "$$HOME/.config/scruticode/settings.toml" ]; then \
+		rm $$HOME/.config/scruticode/settings.toml; \
+	fi
+
+clear-bin:
 	rm -rf ./bin
-	rm ~/.config/scruticode/settings.toml
 
 cache:
 	go clean -modcache
 
 ## https://github.com/golang-standards/project-layout/issues/113#issuecomment-1336514449
-build: clear fmt
+build: clear-bin fmt
 	GOARCH=amd64 go build -o ./bin/ScrutiCode ./src/main.go
 
-build-arm: clear fmt
+build-arm: clear-bin fmt
 	GOARCH=arm64 go build -o ./bin/ScrutiCode ./src/main.go
 
 test:
diff --git a/src/config/base.go b/src/config/base.go
index 3a44c82..9bfcbc3 100644
--- a/src/config/base.go
+++ b/src/config/base.go
@@ -2,10 +2,10 @@ package config
 
 import (
 	"Scruticode/src/constants"
+	"Scruticode/src/functions"
 	"log"
 	"os"
 	"os/user"
-	"path/filepath"
 )
 
 // This function should read a file located in $HOME/.config/scruticode/settings.toml
@@ -19,23 +19,8 @@ func ReadConfigFile() string {
 	}
 
 	filePath := usr.HomeDir + constants.ConfigFilePath
-	dirPath := filepath.Dir(filePath)
-
 	if _, errPath := os.Stat(filePath); os.IsNotExist(errPath) {
-		errCreateFolder := os.MkdirAll(dirPath, constants.DefaultFilePermissions)
-		if errCreateFolder != nil {
-			log.Println(constants.ErrMessageDirectory, errCreateFolder)
-
-			return ""
-		}
-
-		file, errCreateFile := os.Create(filePath)
-		if errCreateFile != nil {
-			log.Println(constants.ErrMessageFile, errCreateFile)
-
-			return ""
-		}
-		defer file.Close()
+		functions.InitConfigFile()
 	}
 
 	content, errReadFile := os.ReadFile(filePath)
diff --git a/src/functions/options/readme.go b/src/functions/options/readme.go
index a2b59f9..dd2d91c 100644
--- a/src/functions/options/readme.go
+++ b/src/functions/options/readme.go
@@ -10,7 +10,7 @@ import (
 func Readme() types.BaseResponse {
 	// LOGIC
 	if _, err := os.Stat(constants.ReadmeFilePath); os.IsNotExist(err) {
-		utils.LoggerError(constants.FileNotFound, constants.ReadmeFilePath)
+		utils.LoggerErrorFile(constants.FileNotFound, constants.ReadmeFilePath)
 
 		return types.BaseResponse{
 			Status: constants.QualityCheckFailed,
@@ -18,7 +18,7 @@ func Readme() types.BaseResponse {
 	}
 
 	// LOG
-	utils.LoggerDebug(constants.FileFound, constants.ReadmeFilePath)
+	utils.LoggerDebugFile(constants.FileFound, constants.ReadmeFilePath)
 
 	// RESPONSE
 	return types.BaseResponse{
diff --git a/src/functions/process.go b/src/functions/process.go
index d739d83..8f2349c 100644
--- a/src/functions/process.go
+++ b/src/functions/process.go
@@ -3,6 +3,8 @@ package functions
 import (
 	"Scruticode/src/constants"
 	"Scruticode/src/functions/options"
+	"Scruticode/src/functions/utils"
+	"Scruticode/src/functions/validations"
 	"Scruticode/src/types"
 	"log"
 	"strings"
@@ -76,12 +78,21 @@ func processKeyValues(keyValues []string) {
 		"dast":                 func() { log.Println("action for dast") },
 	}
 
+	const emptyAsString = ""
 	for _, pair := range keyValues {
 		key, value := parseKeyValuePair(pair)
-		if key == "" {
+		if key == emptyAsString {
 			continue
 		}
 
+		keyAsString := utils.ToAbsoluteString(value)
+		keyLangOrPlatform := key == "langs" || key == "platforms"
+
+		if keyLangOrPlatform {
+			validations.ExtraLangConfig(keyAsString)
+			validations.ExtraPlatformConfig(keyAsString)
+		}
+
 		if isActionEnabled(value) {
 			action, exists := actions[key]
 			if !exists {
diff --git a/src/functions/utils/conversions.go b/src/functions/utils/conversions.go
new file mode 100644
index 0000000..915eebe
--- /dev/null
+++ b/src/functions/utils/conversions.go
@@ -0,0 +1,11 @@
+package utils
+
+import "strings"
+
+func ToAbsoluteString(value string) string {
+	removeBrackets := strings.Trim(value, "[]")
+	removeDobleQuotes := strings.Trim(removeBrackets, `"`)
+	stringValue := strings.TrimSpace(removeDobleQuotes)
+
+	return stringValue
+}
diff --git a/src/functions/utils/logger.go b/src/functions/utils/logger.go
index 4c29c55..0d4fa6a 100644
--- a/src/functions/utils/logger.go
+++ b/src/functions/utils/logger.go
@@ -2,10 +2,10 @@ package utils
 
 import "log"
 
-func LoggerError(message, file string) {
+func LoggerErrorFile(message, file string) {
 	log.Fatalf("%s: %s\n", message, file)
 }
 
-func LoggerDebug(message string, file string) {
+func LoggerDebugFile(message string, file string) {
 	log.Printf("%s: %s\n", message, file)
 }
diff --git a/src/functions/validations/parse.go b/src/functions/validations/parse.go
new file mode 100644
index 0000000..5747cb2
--- /dev/null
+++ b/src/functions/validations/parse.go
@@ -0,0 +1,65 @@
+package validations
+
+import (
+	"log"
+	"slices"
+)
+
+func isValueAllowed(value string, allowedValues []string) bool {
+	return slices.Contains(allowedValues, value)
+}
+
+func extraConfig(value string, allowedValues []string, handler func(string)) {
+	if !isValueAllowed(value, allowedValues) {
+		return
+	}
+	handler(value)
+}
+
+func langHandler(lang string) {
+	switch lang {
+	case "golang":
+		{
+			log.Println("action for golang")
+		}
+	case "python":
+		{
+			log.Println("action for python")
+		}
+	case "typescript":
+		{
+			log.Println("action for typescript")
+		}
+	case "javascript":
+		{
+			log.Println("action for javascript")
+		}
+	}
+}
+
+func platformHandler(platform string) {
+	switch platform {
+	case "github":
+		{
+			log.Println("action for github")
+		}
+	case "gitlab":
+		{
+			log.Println("action for gitlab")
+		}
+	case "azuredevops":
+		{
+			log.Println("action for azuredevops")
+		}
+	}
+}
+
+func ExtraLangConfig(lang string) {
+	var supportedLanguages = []string{"golang", "typescript", "javascript", "python"}
+	extraConfig(lang, supportedLanguages, langHandler)
+}
+
+func ExtraPlatformConfig(platform string) {
+	var supportedPlatforms = []string{"github", "gitlab", "azuredevops"}
+	extraConfig(platform, supportedPlatforms, platformHandler)
+}
diff --git a/src/main.go b/src/main.go
index 8dae847..fd12f1c 100644
--- a/src/main.go
+++ b/src/main.go
@@ -9,6 +9,5 @@ import (
 func main() {
 	configuration := config.ReadConfigFile()
 	functions.ProcessConfigFile(configuration)
-	functions.InitConfigFile()
 	arguments.Generate()
 }


Reviews:
user: login: jd-apprentice
state: COMMENTED
author_association: OWNER
submitted_at: 2025-03-26T01:06:16Z
user: login: brahianpdev
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-26T11:58:59Z
user: login: brahianpdev
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-26T12:02:07Z
user: login: brahianpdev
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-26T12:09:02Z
user: login: brahianpdev
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-26T12:10:28Z
user: login: brahianpdev
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-26T12:11:32Z
user: login: brahianpdev
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-26T12:15:50Z
user: login: jd-apprentice
state: COMMENTED
author_association: OWNER
submitted_at: 2025-03-26T12:41:14Z
user: login: jd-apprentice
state: COMMENTED
author_association: OWNER
submitted_at: 2025-03-26T12:41:57Z
user: login: jd-apprentice
state: COMMENTED
author_association: OWNER
submitted_at: 2025-03-26T12:42:38Z
user: login: jd-apprentice
state: COMMENTED
author_association: OWNER
submitted_at: 2025-03-26T12:43:13Z
user: login: jd-apprentice
state: COMMENTED
author_association: OWNER
submitted_at: 2025-03-26T12:46:12Z
user: login: jd-apprentice
state: COMMENTED
author_association: OWNER
submitted_at: 2025-03-26T13:45:21Z
user: login: jd-apprentice
state: COMMENTED
author_association: OWNER
submitted_at: 2025-03-26T13:46:28Z
user: login: jd-apprentice
state: COMMENTED
author_association: OWNER
submitted_at: 2025-03-26T13:47:44Z

Review comments:
diff_hunk: @@ -0,0 +1,11 @@
+package utils
+
+import "strings"
+
+func ToAbsoluteString(value string) string {
+	removeBrackets := strings.Trim(value, "[]")
+	removeDobleQuotes := strings.Trim(removeBrackets, `"`)
+	stringLang := strings.TrimSpace(removeDobleQuotes)
path: src/functions/utils/conversions.go
user: login: jd-apprentice
body: stringLang is wrong, it should be `stringValue`
created_at: 2025-03-26T01:06:16Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,53 @@
+package validations
+
+import (
+	"log"
+	"slices"
+)
+
+func isValueAllowed(value string, allowedValues []string) bool {
+	return slices.Contains(allowedValues, value)
+}
+
+func extraConfig(value string, allowedValues []string, handler func(string)) {
+	if !isValueAllowed(value, allowedValues) {
+		return
+	}
+	handler(value)
+}
+
+func langHandler(lang string) {
+	switch lang {
+	case "golang":
+		{
+			log.Println("action for golang")
+		}
+	case "python":
+		{
+			log.Println("action for python")
+		}
+	case "typescript":
+	case "javascript":
path: src/functions/validations/parse.go
user: login: brahianpdev
body: Falta el Print, en caso de no necesitar definirlo, utilizar el `default` del switch [ref](https://go.dev/tour/flowcontrol/9)

_Sucede lo mismo en otros lugares, pero me falta contexto para saber si se quiere o no imprimir el msg para cada case_
created_at: 2025-03-26T11:58:59Z
author_association: COLLABORATOR
diff_hunk: @@ -1,5 +1,6 @@
 package constants
 
 const (
-	TrueAsString = "true"
+	TrueAsString  = "true"
path: src/constants/strings.go
user: login: brahianpdev
body: Tener los `=` a la misma "altura" es una buena práctica de Go, o gusto personal? Sobre un espacio
created_at: 2025-03-26T12:02:07Z
author_association: COLLABORATOR
diff_hunk: @@ -78,10 +80,18 @@ func processKeyValues(keyValues []string) {
 
 	for _, pair := range keyValues {
 		key, value := parseKeyValuePair(pair)
-		if key == "" {
+		if key == constants.EmptyAsString {
path: src/functions/process.go
user: login: brahianpdev
body: ```suggestion
		if key == constants.EmptyAsString {
```
No entendí la necesidad de este cambio, dentro de constants, EmptyAsString es literalmente `""`, exactamente lo mismo que se tenía en la versión anterior... Sólo se invoca desde este lugar, va ser reutilizado por N lugares? Sería necesario cuando (valga la redundancia) se vea la necesidad de utilizar la util por todos lados, no ahora que solo es utilizado en `process.go` 
created_at: 2025-03-26T12:09:02Z
author_association: COLLABORATOR
diff_hunk: @@ -78,10 +80,18 @@ func processKeyValues(keyValues []string) {
 
 	for _, pair := range keyValues {
 		key, value := parseKeyValuePair(pair)
-		if key == "" {
+		if key == constants.EmptyAsString {
 			continue
 		}
 
+		keyAsString := utils.ToAbsoluteString(value)
+		keyIsLangOrPlatform := key == "langs" || key == "platforms"
path: src/functions/process.go
user: login: brahianpdev
body: ```suggestion
		keyLangOrPlatform := key == "langs" || key == "platforms"
```
created_at: 2025-03-26T12:10:28Z
author_association: COLLABORATOR
diff_hunk: @@ -78,10 +80,18 @@ func processKeyValues(keyValues []string) {
 
 	for _, pair := range keyValues {
 		key, value := parseKeyValuePair(pair)
-		if key == "" {
+		if key == constants.EmptyAsString {
 			continue
 		}
 
+		keyAsString := utils.ToAbsoluteString(value)
+		keyIsLangOrPlatform := key == "langs" || key == "platforms"
path: src/functions/process.go
user: login: brahianpdev
body: No hace mucho sentido que la variable sea "is", cuando en el uso, pregutamos lo mismo con `if` nuevamente:
```go
if (keyLangOrPlatform) // Es lang o plataforma... Sino queda "is" "is"
```
created_at: 2025-03-26T12:11:31Z
author_association: COLLABORATOR
diff_hunk: @@ -6,9 +6,10 @@ import (
 	"Scruticode/src/functions/arguments"
 )
 
+// https://stackoverflow.com/questions/56039154/is-it-really-bad-to-use-init-functions-in-go#56039373
+// https://leighmcculloch.com/posts/tool-go-check-no-globals-no-inits/
path: src/main.go
user: login: brahianpdev
body: ```suggestion
// https://stackoverflow.com/questions/56039154/is-it-really-bad-to-use-init-functions-in-go#56039373
// https://leighmcculloch.com/posts/tool-go-check-no-globals-no-inits/
```
Estos enlaces deberían estar en la descripción del template del PR con una breve explicación o simplemente referenciados, pero tenerlos aquí no aportará a futuro, habrán 2 links asociados a buenas o malas prácticas de Go, pero no tendrás `init functions` en el archivo main... 
created_at: 2025-03-26T12:15:50Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,53 @@
+package validations
+
+import (
+	"log"
+	"slices"
+)
+
+func isValueAllowed(value string, allowedValues []string) bool {
+	return slices.Contains(allowedValues, value)
+}
+
+func extraConfig(value string, allowedValues []string, handler func(string)) {
+	if !isValueAllowed(value, allowedValues) {
+		return
+	}
+	handler(value)
+}
+
+func langHandler(lang string) {
+	switch lang {
+	case "golang":
+		{
+			log.Println("action for golang")
+		}
+	case "python":
+		{
+			log.Println("action for python")
+		}
+	case "typescript":
+	case "javascript":
path: src/functions/validations/parse.go
user: login: jd-apprentice
body: Seria un TODO, no lo puse por que Sonarqube se suele quejar cuando dejas un TODO.
created_at: 2025-03-26T12:41:14Z
author_association: OWNER
diff_hunk: @@ -1,5 +1,6 @@
 package constants
 
 const (
-	TrueAsString = "true"
+	TrueAsString  = "true"
path: src/constants/strings.go
user: login: jd-apprentice
body: Estoy pensando que se me cambio solo con algun linteo u por que otro string es mas largo y se acomodo a ese mismo nivel?
created_at: 2025-03-26T12:41:57Z
author_association: OWNER
diff_hunk: @@ -78,10 +80,18 @@ func processKeyValues(keyValues []string) {
 
 	for _, pair := range keyValues {
 		key, value := parseKeyValuePair(pair)
-		if key == "" {
+		if key == constants.EmptyAsString {
path: src/functions/process.go
user: login: jd-apprentice
body: Si esta medio alpedo solo me dio tock por que no tenia nombre, a lo sumo tendria que ir como variable en el mismo archivo
created_at: 2025-03-26T12:42:38Z
author_association: OWNER
diff_hunk: @@ -78,10 +80,18 @@ func processKeyValues(keyValues []string) {
 
 	for _, pair := range keyValues {
 		key, value := parseKeyValuePair(pair)
-		if key == "" {
+		if key == constants.EmptyAsString {
 			continue
 		}
 
+		keyAsString := utils.ToAbsoluteString(value)
+		keyIsLangOrPlatform := key == "langs" || key == "platforms"
path: src/functions/process.go
user: login: jd-apprentice
body: Valid
created_at: 2025-03-26T12:43:13Z
author_association: OWNER
diff_hunk: @@ -6,9 +6,10 @@ import (
 	"Scruticode/src/functions/arguments"
 )
 
+// https://stackoverflow.com/questions/56039154/is-it-really-bad-to-use-init-functions-in-go#56039373
+// https://leighmcculloch.com/posts/tool-go-check-no-globals-no-inits/
path: src/main.go
user: login: jd-apprentice
body: Pensaba que si lo dejo en el PR se van a perder mientras que si quedan en el main me queda de recordatorio de no usar la funcion init que crea side effects con variables globales (cosa que habia hecho pero un linter se quejo)
created_at: 2025-03-26T12:46:12Z
author_association: OWNER
diff_hunk: @@ -6,9 +6,10 @@ import (
 	"Scruticode/src/functions/arguments"
 )
 
+// https://stackoverflow.com/questions/56039154/is-it-really-bad-to-use-init-functions-in-go#56039373
+// https://leighmcculloch.com/posts/tool-go-check-no-globals-no-inits/
path: src/main.go
user: login: jd-apprentice
body: Ahi lo dejo en la PR igual
created_at: 2025-03-26T13:45:21Z
author_association: OWNER
diff_hunk: @@ -78,10 +80,18 @@ func processKeyValues(keyValues []string) {
 
 	for _, pair := range keyValues {
 		key, value := parseKeyValuePair(pair)
-		if key == "" {
+		if key == constants.EmptyAsString {
path: src/functions/process.go
user: login: jd-apprentice
body: Por ahora lo dejo en el mismo archivo (me sigue dando tock que no tenga nombre)
created_at: 2025-03-26T13:46:28Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,53 @@
+package validations
+
+import (
+	"log"
+	"slices"
+)
+
+func isValueAllowed(value string, allowedValues []string) bool {
+	return slices.Contains(allowedValues, value)
+}
+
+func extraConfig(value string, allowedValues []string, handler func(string)) {
+	if !isValueAllowed(value, allowedValues) {
+		return
+	}
+	handler(value)
+}
+
+func langHandler(lang string) {
+	switch lang {
+	case "golang":
+		{
+			log.Println("action for golang")
+		}
+	case "python":
+		{
+			log.Println("action for python")
+		}
+	case "typescript":
+	case "javascript":
path: src/functions/validations/parse.go
user: login: jd-apprentice
body: Les dejo los print a todos a falta de TODO
created_at: 2025-03-26T13:47:44Z
author_association: OWNER

PR comments:
user: login: sonarqubecloud[bot]
created_at: 2025-03-26T13:48:49Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=jd-apprentice_Scruticode&pullRequest=16) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=jd-apprentice_Scruticode&pullRequest=16&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=jd-apprentice_Scruticode&pullRequest=16&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=jd-apprentice_Scruticode&pullRequest=16&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=jd-apprentice_Scruticode&pullRequest=16&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=jd-apprentice_Scruticode&pullRequest=16&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=jd-apprentice_Scruticode&pullRequest=16)


author_association: NONE