Skip to content

Instantly share code, notes, and snippets.

@pabrodez
Last active December 22, 2024 13:10
Show Gist options
  • Save pabrodez/69b3f41d24617ebafa26fdf78a0ef5c9 to your computer and use it in GitHub Desktop.
Save pabrodez/69b3f41d24617ebafa26fdf78a0ef5c9 to your computer and use it in GitHub Desktop.
Output SpiceDb schema differences on a Azure DevOps pipeline (omitted go.mod and go.sum for brevity)
package main
import (
"encoding/json"
"fmt"
"log"
"os"
"strings"
"github.com/authzed/spicedb/pkg/development"
"github.com/authzed/spicedb/pkg/diff"
"github.com/authzed/spicedb/pkg/diff/namespace"
)
func main() {
if len(os.Args) != 3 {
log.Fatal("Usage: go run main.go <schema1> <schema2>")
}
prevSchema, currSchema := os.Args[1], os.Args[2]
diffedSchemas, err := compareSchemasFromStrings(prevSchema, currSchema)
if err != nil {
log.Fatalf("Error comparing schemas: %v", err)
}
changes := analyzeSchemaChanges(diffedSchemas)
if changes.hasChanges() {
printSchemaChanges(changes)
fmt.Printf("##vso[task.setvariable variable=hasDifferences;isOutput=true]true\n")
} else {
fmt.Println("No changes detected between the schemas.")
fmt.Printf("##vso[task.setvariable variable=hasDifferences;isOutput=true]false\n")
}
}
func compareSchemasFromStrings(schemaStr1, schemaStr2 string) (*diff.SchemaDiff, error) {
compiledSchema1, _, err := development.CompileSchema(schemaStr1)
if err != nil {
return nil, fmt.Errorf("error compiling schema1: %w", err)
}
compiledSchema2, _, err := development.CompileSchema(schemaStr2)
if err != nil {
return nil, fmt.Errorf("error compiling schema2: %w", err)
}
diffableSchema1 := diff.NewDiffableSchemaFromCompiledSchema(compiledSchema1)
diffableSchema2 := diff.NewDiffableSchemaFromCompiledSchema(compiledSchema2)
diffedSchemas, err := diff.DiffSchemas(diffableSchema1, diffableSchema2)
if err != nil {
return nil, fmt.Errorf("error diffing schemas: %w", err)
}
return diffedSchemas, nil
}
type schemaChanges struct {
addedNamespaces []string
removedNamespaces []string
changedNamespaces map[string][]namespace.Delta
}
func (sc schemaChanges) hasChanges() bool {
return len(sc.addedNamespaces) > 0 || len(sc.removedNamespaces) > 0 || len(sc.changedNamespaces) > 0
}
func analyzeSchemaChanges(diffedSchemas *diff.SchemaDiff) schemaChanges {
changes := schemaChanges{
addedNamespaces: diffedSchemas.AddedNamespaces,
removedNamespaces: diffedSchemas.RemovedNamespaces,
changedNamespaces: make(map[string][]namespace.Delta),
}
for nsName, nsDiff := range diffedSchemas.ChangedNamespaces {
changes.changedNamespaces[nsName] = nsDiff.Deltas()
}
return changes
}
func printSchemaChanges(changes schemaChanges) {
prettyPrintSchemaChanges(changes)
fmt.Println("\nDetailed JSON output of changed Namespaces:")
changedNsDeltasJSON, err := json.MarshalIndent(changes.changedNamespaces, "", " ")
if err != nil {
log.Fatalf("Error marshaling changed namespaces to JSON: %v", err)
}
fmt.Println(string(changedNsDeltasJSON))
}
func prettyPrintSchemaChanges(changes schemaChanges) {
fmt.Print("Schema Changes Summary:")
fmt.Println(strings.Repeat("=", 30))
fmt.Printf("Added Namespaces (%d):", len(changes.addedNamespaces))
for _, ns := range changes.addedNamespaces {
fmt.Printf(" + %s\n", ns)
}
fmt.Println()
fmt.Printf("Removed Namespaces (%d):", len(changes.removedNamespaces))
for _, ns := range changes.removedNamespaces {
fmt.Printf(" - %s\n", ns)
}
fmt.Println()
fmt.Printf("Changed Namespaces (%d):", len(changes.changedNamespaces))
for nsName, deltas := range changes.changedNamespaces {
fmt.Printf(" * %s:\n", nsName)
for _, delta := range deltas {
actionStr := "-"
switch {
case strings.Contains(string(delta.Type), "added"):
actionStr = "+"
case strings.Contains(string(delta.Type), "removed"):
actionStr = "-"
case strings.Contains(string(delta.Type), "changed"):
actionStr = "~"
}
fmt.Printf(" %s %s: %s\n", actionStr, delta.Type, delta.RelationName)
}
}
}
trigger: none
jobs:
- job: RunComparison
steps:
- task: GoTool@0
inputs:
version: '1.23.4'
- script: |
CURRENT_COMMIT=$(git rev-parse HEAD)
PREVIOUS_COMMIT=$(git rev-parse HEAD~1)
CURRENT_CONTENT=$(git show $CURRENT_COMMIT:./schema.zed)
PREVIOUS_CONTENT=$(git show $PREVIOUS_COMMIT:./schema.zed)
go run main.go "$PREVIOUS_CONTENT" "$CURRENT_CONTENT"
name: goRunDiff
displayName: 'Compare Schema versions'
- script: |
echo "The value of hasDifferences is: $(goRunDiff.hasDifferences)"
displayName: 'Print hasDifferences Variable'
- job: ManualValidation
dependsOn: RunComparison
pool: server
condition: eq(dependencies.RunComparison.outputs['goRunDiff.hasDifferences'], 'true')
steps:
- task: ManualValidation@0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment