arch-go / arch-go

Architecture checks for Go projects
MIT License
158 stars 12 forks source link

Generate JSON report #72

Closed dadrus closed 3 days ago

dadrus commented 1 month ago

There is a need for a JSON report for the arch-go-action. Without it, it is pretty hard to add properly looking and formatted PR comments.

fdaines commented 1 month ago

Today arch-go uses an internal structure to represent the analysis result, we should be capable to use this structure for exporting the result in json format.

https://github.com/arch-go/arch-go/blob/5a0fac64f595819ff8f77956f4e6f585a4c39107/api/types.go#L13

fdaines commented 1 month ago

@DGuhr , @dadrus what do you think about the following structure for json report. Is't based on current Result structure content.

{
  "version": "X.Y.Z",
  "summary": {
    "timestamp": "2024-07-31T09:50:58.878616-04:00",
    "duration": 120692375,
    "pass": false
  },
  "compliance": {
    "pass": false,
    "total": 6,
    "passed": 4,
    "failed": 2,
    "rate": 67,
    "threshold": 100,
    "summary": [
      "rule X that failed",
      "rule Y that failed"
    ],
    "details": {
      "dependencies_rules": {
        "total": 1,
        "passed": 0,
        "failed": 1,
        "details": [
          {
            "rule": "Rule Description #1",
            "pass": false,
            "total": 1,
            "passed": 0,
            "failed": 1,
            "package_details": [
              {
                "package": "github.com/foo/bar/internal",
                "pass": true,
                "details": null
              },
              {
                "package": "github.com/foo/bar/internal/clients",
                "pass": false,
                "details": ["detail_1", "detail_2"]
              }
            ]
          },
          {
            "rule": "Rule Description #2",
            "pass": true,
            "total": 1,
            "passed": 0,
            "failed": 1,
            "package_details": [
              {
                "package": "github.com/foo/bar/internal",
                "pass": true,
                "details": null
              }
            ]
          }
        ]
      },
      "functions_rules": {
        "total": 1,
        "passed": 1,
        "failed": 0,
        "details": [
          {
            "rule": "Rule Description #3",
            "pass": true,
            "total": 1,
            "passed": 1,
            "failed": 0,
            "package_details": [
              {
                "package": "github.com/foo/bar/internal",
                "pass": true,
                "details": null
              },
              {
                "package": "github.com/foo/bar/internal/clients",
                "pass": true,
                "details": null
              }
            ]
          }
        ]
      },
      "contents_rules": {
        "total": 1,
        "passed": 0,
        "failed": 1,
        "details": [
          {
            "rule": "Rule Description #4",
            "pass": false,
            "total": 1,
            "passed": 0,
            "failed": 1,
            "package_details": [
              {
                "package": "github.com/foo/bar/internal/model",
                "pass": false,
                "details": ["foo", "bar"]
              }
            ]
          },
          {
            "rule": "Rule Description #5",
            "pass": true,
            "total": 1,
            "passed": 1,
            "failed": 0,
            "package_details": [
              {
                "package": "github.com/foo/bar/internal/clients",
                "pass": true,
                "details": null
              }
            ]
          }
        ]
      },
      "naming_rules": {
        "total": 1,
        "passed": 1,
        "failed": 0,
        "details": [
          {
            "rule": "Rule Description #6",
            "pass": true,
            "total": 1,
            "passed": 1,
            "failed": 0,
            "package_details": [
              {
                "package": "github.com/foo/bar/internal/model",
                "pass": true,
                "details": null
              }
            ]
          }
        ]
      }
    }
  },
  "coverage": {
    "rate": 80,
    "threshold": 100,
    "pass": false,
    "uncovered_packages": [
      "uncovered_package_1",
      "uncovered_package_2"
    ],
    "details": [
      {
        "package": "github.com/arch-go/arch-go",
        "contents_rules": 0,
        "dependencies_rules": 1,
        "functions_rules": 1,
        "naming_rules": 1,
        "covered": true
      },
      {
        "package": "github.com/arch-go/arch-go/foo/bar",
        "contents_rules": 0,
        "dependencies_rules": 0,
        "functions_rules": 0,
        "naming_rules": 0,
        "covered": false
      }
    ]
  }
}
dadrus commented 1 month ago

I think this structure is perfectly fine. Thank you! :smile:

fdaines commented 4 weeks ago

Perfect, I'll be working on this feature.

fdaines commented 3 weeks ago

Because of our json format standard I had to change a little bit the proposed structure, replacing some attributes from snake_case to camelCase. The final version is:

{
  "version": "X.Y.Z",
  "summary": {
    "timestamp": "2024-07-31T09:50:58.878616-04:00",
    "duration": 120692375,
    "pass": false
  },
  "compliance": {
    "pass": false,
    "total": 6,
    "passed": 4,
    "failed": 2,
    "rate": 67,
    "threshold": 100,
    "summary": [
      "rule X that failed",
      "rule Y that failed"
    ],
    "details": {
      "dependenciesRules": {
        "total": 1,
        "passed": 0,
        "failed": 1,
        "details": [
          {
            "rule": "Rule Description #1",
            "pass": false,
            "total": 1,
            "passed": 0,
            "failed": 1,
            "packageDetails": [
              {
                "package": "github.com/foo/bar/internal",
                "pass": true,
                "details": null
              },
              {
                "package": "github.com/foo/bar/internal/clients",
                "pass": false,
                "details": ["detail_1", "detail_2"]
              }
            ]
          },
          {
            "rule": "Rule Description #2",
            "pass": true,
            "total": 1,
            "passed": 0,
            "failed": 1,
            "packageDetails": [
              {
                "package": "github.com/foo/bar/internal",
                "pass": true,
                "details": null
              }
            ]
          }
        ]
      },
      "functionsRules": {
        "total": 1,
        "passed": 1,
        "failed": 0,
        "details": [
          {
            "rule": "Rule Description #3",
            "pass": true,
            "total": 1,
            "passed": 1,
            "failed": 0,
            "packageDetails": [
              {
                "package": "github.com/foo/bar/internal",
                "pass": true,
                "details": null
              },
              {
                "package": "github.com/foo/bar/internal/clients",
                "pass": true,
                "details": null
              }
            ]
          }
        ]
      },
      "contentsRules": {
        "total": 1,
        "passed": 0,
        "failed": 1,
        "details": [
          {
            "rule": "Rule Description #4",
            "pass": false,
            "total": 1,
            "passed": 0,
            "failed": 1,
            "packageDetails": [
              {
                "package": "github.com/foo/bar/internal/model",
                "pass": false,
                "details": ["foo", "bar"]
              }
            ]
          },
          {
            "rule": "Rule Description #5",
            "pass": true,
            "total": 1,
            "passed": 1,
            "failed": 0,
            "packageDetails": [
              {
                "package": "github.com/foo/bar/internal/clients",
                "pass": true,
                "details": null
              }
            ]
          }
        ]
      },
      "namingRules": {
        "total": 1,
        "passed": 1,
        "failed": 0,
        "details": [
          {
            "rule": "Rule Description #6",
            "pass": true,
            "total": 1,
            "passed": 1,
            "failed": 0,
            "packageDetails": [
              {
                "package": "github.com/foo/bar/internal/model",
                "pass": true,
                "details": null
              }
            ]
          }
        ]
      }
    }
  },
  "coverage": {
    "rate": 80,
    "threshold": 100,
    "pass": false,
    "uncoveredPackages": [
      "uncovered_package_1",
      "uncovered_package_2"
    ],
    "details": [
      {
        "package": "github.com/arch-go/arch-go",
        "contentsRules": 0,
        "dependenciesRules": 1,
        "functionsRules": 1,
        "namingRules": 1,
        "covered": true
      },
      {
        "package": "github.com/arch-go/arch-go/foo/bar",
        "contentsRules": 0,
        "dependenciesRules": 0,
        "functionsRules": 0,
        "namingRules": 0,
        "covered": false
      }
    ]
  }
}