{"id":13709674,"url":"https://github.com/flowdev/spaghetti-cutter","last_synced_at":"2025-12-24T09:12:26.172Z","repository":{"id":57525076,"uuid":"251427882","full_name":"flowdev/spaghetti-cutter","owner":"flowdev","description":"Command line tool for CI/CD pipelines that helps to prevent Go spaghetti code (a.k.a. big ball of mud).","archived":false,"fork":false,"pushed_at":"2024-06-20T09:45:33.000Z","size":390,"stargazers_count":50,"open_issues_count":1,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-05-06T18:47:41.769Z","etag":null,"topics":["go","golang","monolith","software-architecture","software-design","technical-debt"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/flowdev.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-03-30T21:04:02.000Z","updated_at":"2025-01-11T20:10:16.000Z","dependencies_parsed_at":"2024-11-13T20:32:35.460Z","dependency_job_id":"c8bc2cce-95e2-472a-991a-4e06bb83f597","html_url":"https://github.com/flowdev/spaghetti-cutter","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/flowdev/spaghetti-cutter","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flowdev%2Fspaghetti-cutter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flowdev%2Fspaghetti-cutter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flowdev%2Fspaghetti-cutter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flowdev%2Fspaghetti-cutter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/flowdev","download_url":"https://codeload.github.com/flowdev/spaghetti-cutter/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flowdev%2Fspaghetti-cutter/sbom","scorecard":{"id":404314,"data":{"date":"2025-08-11","repo":{"name":"github.com/flowdev/spaghetti-cutter","commit":"63c57be5d659ed792ab39b24b87ae3c100000583"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.7,"checks":[{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'main'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Signed-Releases","score":0,"reason":"Project has not signed or included provenance with any releases.","details":["Warn: release artifact v0.9.5 not signed: https://api.github.com/repos/flowdev/spaghetti-cutter/releases/39678220","Warn: release artifact v0.9 not signed: https://api.github.com/repos/flowdev/spaghetti-cutter/releases/26530977","Warn: release artifact v0.9.5 does not have provenance: https://api.github.com/repos/flowdev/spaghetti-cutter/releases/39678220","Warn: release artifact v0.9 does not have provenance: https://api.github.com/repos/flowdev/spaghetti-cutter/releases/26530977"],"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-18T20:49:59.302Z","repository_id":57525076,"created_at":"2025-08-18T20:49:59.302Z","updated_at":"2025-08-18T20:49:59.302Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":27999524,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-12-24T02:00:07.193Z","response_time":83,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["go","golang","monolith","software-architecture","software-design","technical-debt"],"created_at":"2024-08-02T23:00:43.643Z","updated_at":"2025-12-24T09:12:26.151Z","avatar_url":"https://github.com/flowdev.png","language":"Go","funding_links":[],"categories":["Repositories"],"sub_categories":[],"readme":"![spaghetti cutter](./spaghetti-cutter.jpg \"spaghetti cutter\")\n\n# spaghetti-cutter - Win The Fight Against Spaghetti Code\n\n![CircleCI](https://img.shields.io/circleci/build/github/flowdev/spaghetti-cutter/master)\n[![Test Coverage](https://api.codeclimate.com/v1/badges/91d98c13ac5390ba6116/test_coverage)](https://codeclimate.com/github/flowdev/spaghetti-cutter/test_coverage)\n[![Maintainability](https://api.codeclimate.com/v1/badges/91d98c13ac5390ba6116/maintainability)](https://codeclimate.com/github/flowdev/spaghetti-cutter/maintainability)\n[![Go Report Card](https://goreportcard.com/badge/github.com/flowdev/spaghetti-cutter)](https://goreportcard.com/report/github.com/flowdev/spaghetti-cutter)\n![GitHub release (latest by date)](https://img.shields.io/github/v/release/flowdev/spaghetti-cutter)\n![Twitter URL](https://img.shields.io/twitter/url?style=social\u0026url=https%3A%2F%2Fgithub.com%2Fflowdev%2Fspaghetti-cutter)\n\n\n## Overview\n\n`spaghetti-cutter` is a command line tool for CI/CD pipelines (and dev machines)\nthat helps to prevent Go spaghetti code (a.k.a. big ball of mud).\n\nThankfully in the Go world circular dependencies between packages are already prevented by the compiler.\nSo this tool has to care only about additional undesired dependencies.\n\nI gave a talk that includes the motivation for this tool and some (old) usage examples:\n[![Microservices - The End of Software Design](https://img.youtube.com/vi/ev0dD12bxmg/0.jpg)](https://www.youtube.com/watch?v=ev0dD12bxmg \"Microservices - The End of Software Design\")\n\nAdditionally this tool documents the structure of a project in it's\n[configuration](./.spaghetti-cutter.hjson).\n\n\n## Usage\n\nYou can simply call it with `go run github.com/flowdev/spaghetti-cutter@latest`\nfrom anywhere inside your project.\n\nThe possible command line options are:\n```\nUsage of spaghetti-cutter:\n  -e    don't report errors and don't exit with an error (shorthand)\n  -noerror\n        don't report errors and don't exit with an error\n  -r string\n        root directory of the project (shorthand) (default \".\")\n  -root string\n        root directory of the project (default \".\")\n```\n\nIf no `--root` option is given the root directory is found\nby crawling up the directory tree starting at the current working directory.\nThe first directory that contains the configuration file `.spaghetti-cutter.hjson`\nwill be taken as project root.\n\nThe output looks like:\n```\n2020/09/10 09:37:08 INFO - configuration 'allowOnlyIn': `github.com/hjson/**`: `x/config` ; `golang.org/x/tools**`: `parse*`, `x/pkgs*`\n2020/09/10 09:37:08 INFO - configuration 'allowAdditionally': `*_test`: `parse`\n2020/09/10 09:37:08 INFO - configuration 'god': `main`\n2020/09/10 09:37:08 INFO - configuration 'tool': `x/*`\n2020/09/10 09:37:08 INFO - configuration 'db': ...\n2020/09/10 09:37:08 INFO - configuration 'size': 1024\n2020/09/10 09:37:08 INFO - configuration 'noGod': false\n2020/09/10 09:37:08 INFO - root package: github.com/flowdev/spaghetti-cutter\n2020/09/10 09:37:08 INFO - Size of package 'x/config': 699\n2020/09/10 09:37:08 INFO - Size of package 'x/pkgs': 134\n2020/09/10 09:37:08 INFO - Size of package 'deps': 401\n2020/09/10 09:37:08 INFO - Size of package 'parse': 109\n2020/09/10 09:37:08 INFO - Size of package 'size': 838\n2020/09/10 09:37:08 INFO - Size of package 'x/dirs': 86\n2020/09/10 09:37:08 INFO - Size of package '/': 202\n2020/09/10 09:37:08 INFO - No errors found.\n```\n\nFirst the configuration values and the root package are reported.\nSo you can easily ensure that the correct configuration file is taken.\n\nAll package sizes are reported and last but not least any violations found.\nSince no error was found the return code is 0.\n\nA typical error message would be:\n```\n2020/09/10 10:31:14 ERROR - domain package 'pkg/shopping' isn't allowed to import package 'pkg/cart'\n```\n\nThe return code is 1.\nFrom the output you can see that\n- the package `pkg/shopping` is recognized as standard domain package,\n- it imports the `pkg/cart` package and\n- there is no `allowAdditionally` configuration to allow this.\n\nYou can fix that by adding a bit of configuration.\n\nOther non-zero return codes are possible for technical problems (unparsable code: 6, ...).\nIf used properly in the build pipeline a non-zero return code will stop the\nbuild and the problem has to be fixed first.\nSo undesired imports (spaghetti relationships) are prevented.\n\n\n## Standard Use Case: Web API\n\nThis tool was especially created with Web APIs in mind as that is what about\n95% of all Gophers do according to my own completely unscientifical research.\n\nSo it offers special handling for the following cases:\n- Tools: Tool packages are allowed to be used everywhere else except in other\n  tool packages. But they aren't allowed to import any other internal packages.\n- Tool sub-packages: Sub-packages of tool packages aren't allowed to import any\n  other internal package like tool packages. Additionally they aren't allowed\n  to be used anywhere else in the project. So you should use explicit\n  configuration with explanations as comments (what the sub-packages contain\n  and why they exist at all).\n- Database: DB packages are allowed to be used in standard (business) packages.\n  Of course they can use tool packages but nothing else.  Domain data\n  structures should be in a tool package.\n- Database sub-packages: Sub-packages of DB packages are allowed to only import\n  tool packages like DB packages. Additionally they aren't allowed to be used\n  anywhere else in the project. So you should use explicit configuration with\n  explanations as comments (what the sub-packages contain and why they exist at\n  all).\n- God: A god package can see and use everything. You should use this with great\n  care. `main` is the only default god package used if no explicit\n  configuration is given. You should only rarely add more.  You can switch\n  `main` to a standard package with the `noGod` configuration key. This makes\n  sense if you have got multiple `main` packages with different dependencies.\n\nThese cases needn't be used and can be overridden with explicit configuration.\n\n\n## Configuration\n\nIt is mandatory to use a HJSON configuration file `.spaghetti-cutter.hjson` in\nthe root directory of your project.\nThis serves multiple purposes:\n- It helps the `spaghetti-cutter` to find the root directory of your project.\n- It saves you from retyping command line options again and again.\n- It is valuable documentation especially for developers new to the project.\n\nThe configuration can have the following elements:\n- `tool`, `db` and `god` for tool, database and god packages as discussed above.\n- `allowOnlyIn`: for restricting a package to be used only in some packages\n  (allow \"key\" package only in \"value\" packages).\n- `allowAdditionally`: for allowing additional dependencies (for \"key\" package\n  allow additionally \"value\" packages).\n- `size`: the maximum allowed size/complexity of a package. Default is `2048`.\n- `noGod`: `main` won't be god package.\n\nThe size configuration key prevents a clever developer from just thowing all of\nthe spaghetti code into a single package.\nWith the `spaghetti-cutter` such things will become obvious and you can put\nthem as technical dept into your back log.\n\nThis is a simple example configuration file:\n```hjson\n{\n\t\"tool\": [\"x/*\"]\n}\n```\nAll packages directly under `x` are tool packages that can be used everywhere else in the project.\n\nA slightly different variant is:\n```hjson\n{\n\t\"tool\": [\"x/**\"]\n}\n```\nAll packages under `x` are tool packages that can be used everywhere else in the project.\nSo the `**` makes all sub-packages tool packages, too.\nIn most cases one level is enough.\n\nMultiple values are possible for a single key.\nSo this is another valid configuration file:\n```hjson\n{\n\t\"tool\": [\"x/*\", \"parse\"]\n}\n```\n\n`*`, `**` and multiple values are allowed for the `tool`, `db`, `god`,\n`allowOnlyIn` and `allowAdditionally` values.\n`*` and `**` are supported for `allowOnlyIn` and `allowAdditionally` keys, too.\n\nSo a full example looks like this:\n```hjson\n{\n\t\"allowOnlyIn\": {\n\t\t\"github.com/lib/pq\": [\"main\"]\n\t\t\"github.com/jmoiron/sqlx\": [\"pkg/model\", \"pkg/postgres\"]\n\t},\n\t\"allowAdditonally\": {\"pkg/shopping\": [\"pkg/catalogue\", \"pkg/cart\"]},\n\t\"tool\": [\"pkg/x/*\"],\n\t\"db\": [\"pkg/model\", \"pkg/postgres\"],\n\t\"god\": [\"cmd/**\"],\n\t\"size\": 1024\n}\n```\nThe `god` line shouldn't be necessary as all packages under `cmd/` should be `main` packages.\n\nThe case with multiple executables with different dependencies is interesting, too:\n```hjson\n{\n\t\"tool\": [\"pkg/x/*\"],\n\t\"db\": [\"pkg/model\", \"pkg/postgres\"],\n\t\"allowAdditionally\": {\n\t\t\"cmd/front-end\": [\"pkg/shopping\"],\n\t\t\"cmd/back-end\": [\"pkg/catalogue\"],\n\t\t\"pkg/shopping\": [\"pkg/catalogue\", \"pkg/cart\"]\n\t},\n\t\"noGod\": true,\n\t\"size\": 1024\n}\n```\nHere we have got a front-end application for the shopping experience and a\nback-end application for updating the catalogue.\n\nFinally you can use variables in the key/value maps:\n```hjson\n{\n\t\"allowAdditonally\": {\"pkg/$*/db\": [\"pkg/$1/model\"]},\n}\n```\nIn this example there are big \"modules\" that each have their own database,\nmodel and tool packages.\nCross \"module\" access can be easily prevented with only one line of\nconfiguration as the `$1` in the value has to be the same as the `$*` in the\nkey.\nYou can use `$**` similarly.\nMultiple variables are possible and they can be used as `$1` ... `$9` in the\nvalues (`$1` refering to the first `$*` and `$9` to the ninth `$**` in the key).\nThe maximum of `9` should be big enough for really complex projects and\nhelps to find configuration errors.\n\n\n## Installation\n\nOf course you can just head over to the\n[latest release](https://github.com/flowdev/spaghetti-cutter/releases/latest)\nand grab a pre-built binary for your OS.\nBut that is difficult to keep in sync when collaborating with others in a team.\n\nA much better way is to just do: `go run github.com/flowdev/spaghetti-cutter@latest`\nIf you use an explicit version and use it in multiple places the next approach is better.\n\nA great approach for big projects goes this way:\n\nFirst include the latest version in your `go.mod` file, e.g.:\n```\nrequire (\n\tgithub.com/flowdev/spaghetti-cutter v0.9.9\n)\n```\n\nNow add a file like the following to your main package.\n\n```Go\n//+build tools\n\npackage main\n\nimport (\n    _ \"github.com/flowdev/spaghetti-cutter\"\n)\n```\n\nThis ensures that the package is indeed fetched and built but not included in\nthe main or test executables. This is the\n[canonical workaround](https://github.com/golang/go/wiki/Modules#how-can-i-track-tool-dependencies-for-a-module)\nto keep everything in sync and lean.\nHere is a [talk by Robert Radestock](https://www.youtube.com/watch?v=PhBhwgYFuw0)\nabout this topic.\n\nFinally you can run `go mod vendor` if that is what you like.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fflowdev%2Fspaghetti-cutter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fflowdev%2Fspaghetti-cutter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fflowdev%2Fspaghetti-cutter/lists"}