Skip to content
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

Dl/advanced analysis #17

Merged
merged 7 commits into from
Sep 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -234,4 +234,4 @@ This project is licensed under the terms of the license included in the [LICENSE

## Contact

For any queries or suggestions, please open an issue on the GitHub repository.
For any queries or suggestions, please open an issue on the GitHub repository.
46 changes: 46 additions & 0 deletions cmd/grabitsh/api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package grabitsh

import (
"os"
"path/filepath"
"regexp"
)

type APIInfo struct {
Files []string `json:"files"`
Swagger bool `json:"swagger"`
GraphQL bool `json:"graphql"`
Endpoints []string `json:"endpoints"`
HTTPMethods []string `json:"http_methods"`
}

func analyzeAPIStructure() APIInfo {
var apiInfo APIInfo

apiPatterns := []string{"*api*.go", "*controller*.rb", "*views*.py", "routes/*.js", "controllers/*.js"}
for _, pattern := range apiPatterns {
files, _ := filepath.Glob(pattern)
apiInfo.Files = append(apiInfo.Files, files...)
}

apiInfo.Swagger = fileExists("swagger.json") || fileExists("swagger.yaml")
apiInfo.GraphQL = fileExists("schema.graphql") || fileExists("schema.gql")

// Analyze API endpoints and HTTP methods
for _, file := range apiInfo.Files {
content, err := os.ReadFile(file)
if err != nil {
continue
}

// Extract endpoints (this is a simple example, you might need more sophisticated regex for your specific use case)
endpointRegex := regexp.MustCompile(`(GET|POST|PUT|DELETE|PATCH)\s+["']([^"']+)["']`)
matches := endpointRegex.FindAllStringSubmatch(string(content), -1)
for _, match := range matches {
apiInfo.HTTPMethods = appendUnique(apiInfo.HTTPMethods, match[1])
apiInfo.Endpoints = appendUnique(apiInfo.Endpoints, match[2])
}
}

return apiInfo
}
19 changes: 19 additions & 0 deletions cmd/grabitsh/architecture.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package grabitsh

func detectArchitecture() string {
if dirExists("services") || dirExists("microservices") {
return "Microservices"
} else if fileExists("serverless.yml") || fileExists("serverless.yaml") {
return "Serverless"
} else if dirExists("app") && dirExists("config") && dirExists("db") {
return "Monolithic (Rails-like)"
} else if fileExists("package.json") && fileExists("server.js") {
return "Monolithic (Node.js)"
} else if fileExists("pom.xml") || fileExists("build.gradle") {
return "Monolithic (Java)"
} else if fileExists("manage.py") && dirExists("apps") {
return "Monolithic (Django)"
}

return "Undetermined"
}
93 changes: 93 additions & 0 deletions cmd/grabitsh/cicd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package grabitsh

import (
"fmt"
"os"
"path/filepath"
"strings"
)

type Step struct {
Name string `json:"name"`
Description string `json:"description"`
}

type CICDSystem struct {
Name string `json:"name"`
File string `json:"file"`
Steps []Step `json:"steps"`
}

func analyzeCICDWorkflows() ([]CICDSystem, error) {
cicdSystems := []struct {
name string
files []string
}{
{"GitHub Actions", []string{".github/workflows/*.yml", ".github/workflows/*.yaml"}},
{"GitLab CI", []string{".gitlab-ci.yml"}},
{"Jenkins", []string{"Jenkinsfile"}},
{"CircleCI", []string{".circleci/config.yml"}},
{"Travis CI", []string{".travis.yml"}},
{"Azure Pipelines", []string{"azure-pipelines.yml"}},
{"Bitbucket Pipelines", []string{"bitbucket-pipelines.yml"}},
{"AWS CodeBuild", []string{"buildspec.yml"}},
{"Drone CI", []string{".drone.yml"}},
{"Semaphore", []string{".semaphore/semaphore.yml"}},
}

var results []CICDSystem

for _, system := range cicdSystems {
for _, filePattern := range system.files {
files, err := filepath.Glob(filePattern)
if err != nil {
return nil, fmt.Errorf("error globbing files: %w", err)
}
for _, file := range files {
content, err := os.ReadFile(file)
if err != nil {
return nil, fmt.Errorf("error reading file %s: %w", file, err)
}
steps, err := analyzeCICDSteps(string(content))
if err != nil {
return nil, fmt.Errorf("error analyzing steps in file %s: %w", file, err)
}
results = append(results, CICDSystem{
Name: system.name,
File: filepath.Base(file),
Steps: steps,
})
}
}
}

return results, nil
}

func analyzeCICDSteps(content string) ([]Step, error) {
var steps []Step

if strings.Contains(content, "npm test") || strings.Contains(content, "yarn test") {
steps = append(steps, Step{Name: "Testing", Description: "Runs tests"})
}
if strings.Contains(content, "npm run build") || strings.Contains(content, "yarn build") {
steps = append(steps, Step{Name: "Build", Description: "Builds the project"})
}
if strings.Contains(content, "docker build") || strings.Contains(content, "docker-compose") {
steps = append(steps, Step{Name: "Docker operations", Description: "Performs Docker operations"})
}
if strings.Contains(content, "deploy") || strings.Contains(content, "kubectl") {
steps = append(steps, Step{Name: "Deployment", Description: "Deploys the project"})
}
if strings.Contains(content, "lint") || strings.Contains(content, "eslint") {
steps = append(steps, Step{Name: "Linting", Description: "Runs linter"})
}
if strings.Contains(content, "security") || strings.Contains(content, "scan") {
steps = append(steps, Step{Name: "Security scanning", Description: "Performs security scanning"})
}
if strings.Contains(content, "coverage") || strings.Contains(content, "codecov") {
steps = append(steps, Step{Name: "Code coverage", Description: "Checks code coverage"})
}

return steps, nil
}
33 changes: 33 additions & 0 deletions cmd/grabitsh/code_quality.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package grabitsh

func analyzeCodeQuality() []string {
var tools []string

lintConfigs := map[string]string{
".eslintrc": "ESLint",
".rubocop.yml": "RuboCop",
".golangci.yml": "golangci-lint",
"pylintrc": "Pylint",
".checkstyle": "Checkstyle (Java)",
"tslint.json": "TSLint",
".stylelintrc": "Stylelint",
".prettierrc": "Prettier",
".scalafmt.conf": "Scalafmt",
}

for config, tool := range lintConfigs {
if fileExists(config) {
tools = append(tools, tool)
}
}

if fileExists("sonar-project.properties") {
tools = append(tools, "SonarQube")
}

if fileExists(".codeclimate.yml") {
tools = append(tools, "CodeClimate")
}

return tools
}
88 changes: 88 additions & 0 deletions cmd/grabitsh/database.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package grabitsh

import (
"os"
"path/filepath"
"strings"
)

type DatabaseInfo struct {
MigrationsPresent bool `json:"migrations_present"`
ConfigFiles []string `json:"config_files"`
ORMUsed bool `json:"orm_used"`
DatabaseTypes []string `json:"database_types"`
}

func analyzeDatabaseUsage() DatabaseInfo {
var dbInfo DatabaseInfo

dbInfo.MigrationsPresent = dirExists("migrations") || dirExists("db/migrate")

dbConfigFiles := []string{
"config/database.yml",
"knexfile.js",
"ormconfig.json",
"sequelize.config.js",
"database.json",
"dbconfig.json",
"mongo.config.js",
"redis.config.js",
}

for _, file := range dbConfigFiles {
if fileExists(file) {
dbInfo.ConfigFiles = append(dbInfo.ConfigFiles, file)
}
}

ormFiles := []string{
"models.py",
"*.model.ts",
"*.rb",
"entity/*.go",
"*.entity.ts",
"models/*.java",
"entities/*.cs",
}

for _, pattern := range ormFiles {
files, _ := filepath.Glob(pattern)
if len(files) > 0 {
dbInfo.ORMUsed = true
break
}
}

// Detect database types
dbTypes := map[string][]string{
"PostgreSQL": {"postgres", "postgresql", "pg"},
"MySQL": {"mysql", "mariadb"},
"SQLite": {"sqlite", "sqlite3"},
"MongoDB": {"mongodb", "mongo", "mongoose"},
"Redis": {"redis", "rediss"},
"Cassandra": {"cassandra", "cql"},
"Oracle": {"oracle", "orcl"},
"SQL Server": {"sqlserver", "mssql"},
"DB2": {"db2", "ibm"},
"Couchbase": {"couchbase"},
"Firebird": {"firebird"},
"ClickHouse": {"clickhouse"},
}

for dbType, keywords := range dbTypes {
for _, file := range dbInfo.ConfigFiles {
content, err := os.ReadFile(file)
if err != nil {
continue
}
for _, keyword := range keywords {
if strings.Contains(string(content), keyword) {
dbInfo.DatabaseTypes = appendUnique(dbInfo.DatabaseTypes, dbType)
break
}
}
}
}

return dbInfo
}
27 changes: 27 additions & 0 deletions cmd/grabitsh/dependency_management.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package grabitsh

func analyzeDependencyManagement() []string {
var tools []string

depManagement := map[string]string{
"package-lock.json": "npm",
"yarn.lock": "Yarn",
"Gemfile.lock": "Bundler (Ruby)",
"poetry.lock": "Poetry (Python)",
"go.sum": "Go Modules",
"composer.lock": "Composer (PHP)",
"Pipfile.lock": "Pipenv (Python)",
"pom.xml": "Maven (Java)",
"build.gradle": "Gradle (Java)",
"requirements.txt": "pip (Python)",
"Cargo.lock": "Cargo (Rust)",
}

for file, tool := range depManagement {
if fileExists(file) {
tools = append(tools, tool)
}
}

return tools
}
Loading
Loading