compare.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. package dashdiffs
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "github.com/grafana/grafana/pkg/bus"
  6. "github.com/grafana/grafana/pkg/components/simplejson"
  7. "github.com/grafana/grafana/pkg/models"
  8. diff "github.com/yudai/gojsondiff"
  9. deltaFormatter "github.com/yudai/gojsondiff/formatter"
  10. )
  11. type DiffType int
  12. const (
  13. DiffJSON DiffType = iota
  14. DiffBasic
  15. DiffDelta
  16. )
  17. var (
  18. // ErrUnsupportedDiffType occurs when an invalid diff type is used.
  19. ErrUnsupportedDiffType = errors.New("dashdiff: unsupported diff type")
  20. // ErrNilDiff occurs when two compared interfaces are identical.
  21. ErrNilDiff = errors.New("dashdiff: diff is nil")
  22. )
  23. type Options struct {
  24. OrgId int64
  25. DashboardId int64
  26. BaseVersion int
  27. NewVersion int
  28. DiffType DiffType
  29. }
  30. type Result struct {
  31. Delta []byte `json:"delta"`
  32. }
  33. // CompareDashboardVersionsCommand computes the JSON diff of two versions,
  34. // assigning the delta of the diff to the `Delta` field.
  35. func GetVersionDiff(options *Options) (*Result, error) {
  36. baseVersionQuery := models.GetDashboardVersionQuery{
  37. DashboardId: options.DashboardId,
  38. Version: options.BaseVersion,
  39. }
  40. if err := bus.Dispatch(&baseVersionQuery); err != nil {
  41. return nil, err
  42. }
  43. newVersionQuery := models.GetDashboardVersionQuery{
  44. DashboardId: options.DashboardId,
  45. Version: options.NewVersion,
  46. }
  47. if err := bus.Dispatch(&newVersionQuery); err != nil {
  48. return nil, err
  49. }
  50. left, jsonDiff, err := getDiff(baseVersionQuery.Result, newVersionQuery.Result)
  51. if err != nil {
  52. return nil, err
  53. }
  54. result := &Result{}
  55. switch options.DiffType {
  56. case DiffDelta:
  57. deltaOutput, err := deltaFormatter.NewDeltaFormatter().Format(jsonDiff)
  58. if err != nil {
  59. return nil, err
  60. }
  61. result.Delta = []byte(deltaOutput)
  62. case DiffJSON:
  63. jsonOutput, err := NewJSONFormatter(left).Format(jsonDiff)
  64. if err != nil {
  65. return nil, err
  66. }
  67. result.Delta = []byte(jsonOutput)
  68. case DiffBasic:
  69. basicOutput, err := NewBasicFormatter(left).Format(jsonDiff)
  70. if err != nil {
  71. return nil, err
  72. }
  73. result.Delta = basicOutput
  74. default:
  75. return nil, ErrUnsupportedDiffType
  76. }
  77. return result, nil
  78. }
  79. // getDiff computes the diff of two dashboard versions.
  80. func getDiff(originalDash, newDash *models.DashboardVersion) (interface{}, diff.Diff, error) {
  81. leftBytes, err := simplejson.NewFromAny(originalDash).Encode()
  82. if err != nil {
  83. return nil, nil, err
  84. }
  85. rightBytes, err := simplejson.NewFromAny(newDash).Encode()
  86. if err != nil {
  87. return nil, nil, err
  88. }
  89. jsonDiff, err := diff.New().Compare(leftBytes, rightBytes)
  90. if err != nil {
  91. return nil, nil, err
  92. }
  93. if !jsonDiff.Modified() {
  94. return nil, nil, ErrNilDiff
  95. }
  96. left := make(map[string]interface{})
  97. err = json.Unmarshal(leftBytes, &left)
  98. return left, jsonDiff, nil
  99. }