github.com/josephspurrier/go-swagger@v0.2.1-0.20221129144919-1f672a142a00/cmd/swagger/commands/diff.go (about)

     1  package commands
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"io"
     7  	"log"
     8  	"os"
     9  
    10  	"errors"
    11  
    12  	"github.com/go-openapi/loads"
    13  	"github.com/go-swagger/go-swagger/cmd/swagger/commands/diff"
    14  )
    15  
    16  // JSONFormat for json
    17  const JSONFormat = "json"
    18  
    19  // DiffCommand is a command that generates the diff of two swagger specs.
    20  //
    21  // There are no specific options for this expansion.
    22  type DiffCommand struct {
    23  	OnlyBreakingChanges bool   `long:"break" short:"b" description:"When present, only shows incompatible changes"`
    24  	Format              string `long:"format" short:"f" description:"When present, writes output as json" default:"txt" choice:"txt" choice:"json"`
    25  	IgnoreFile          string `long:"ignore" short:"i" description:"Exception file of diffs to ignore (copy output from json diff format)"  default:"none specified"`
    26  	Destination         string `long:"dest" short:"d" description:"Output destination file or stdout" default:"stdout"`
    27  	Args                struct {
    28  		OldSpec string `positional-arg-name:"{old spec}"`
    29  		NewSpec string `positional-arg-name:"{new spec}"`
    30  	} `required:"2" positional-args:"specs" description:"Input specs to be diff-ed"`
    31  }
    32  
    33  // Execute diffs the two specs provided
    34  func (c *DiffCommand) Execute(_ []string) error {
    35  	if c.Args.OldSpec == "" || c.Args.NewSpec == "" {
    36  		return errors.New(`missing arguments for diff command (use --help for more info)`)
    37  	}
    38  
    39  	c.printInfo()
    40  
    41  	var (
    42  		output io.WriteCloser
    43  		err    error
    44  	)
    45  	if c.Destination != "stdout" {
    46  		output, err = os.OpenFile(c.Destination, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600)
    47  		if err != nil {
    48  			return fmt.Errorf("%s: %w", c.Destination, err)
    49  		}
    50  		defer func() {
    51  			_ = output.Close()
    52  		}()
    53  	} else {
    54  		output = os.Stdout
    55  	}
    56  
    57  	diffs, err := c.getDiffs()
    58  	if err != nil {
    59  		return err
    60  	}
    61  
    62  	ignores, err := c.readIgnores()
    63  	if err != nil {
    64  		return err
    65  	}
    66  
    67  	diffs = diffs.FilterIgnores(ignores)
    68  	if len(ignores) > 0 {
    69  		log.Printf("Diff Report Ignored Items from IgnoreFile")
    70  		for _, eachItem := range ignores {
    71  			log.Printf("%s", eachItem.String())
    72  		}
    73  	}
    74  
    75  	var (
    76  		input io.Reader
    77  		warn  error
    78  	)
    79  	if c.Format != JSONFormat && c.OnlyBreakingChanges {
    80  		input, err, warn = diffs.ReportCompatibility()
    81  	} else {
    82  		input, err, warn = diffs.ReportAllDiffs(c.Format == JSONFormat)
    83  	}
    84  	if err != nil {
    85  		return err
    86  	}
    87  	_, err = io.Copy(output, input)
    88  	if err != nil {
    89  		return err
    90  	}
    91  	return warn
    92  }
    93  
    94  func (c *DiffCommand) readIgnores() (diff.SpecDifferences, error) {
    95  	ignoreFile := c.IgnoreFile
    96  	ignoreDiffs := diff.SpecDifferences{}
    97  
    98  	if ignoreFile == "none specified" || ignoreFile == "" {
    99  		return ignoreDiffs, nil
   100  	}
   101  	// Open our jsonFile
   102  	jsonFile, err := os.Open(ignoreFile)
   103  	if err != nil {
   104  		return nil, fmt.Errorf("%s: %w", ignoreFile, err)
   105  	}
   106  	defer func() {
   107  		_ = jsonFile.Close()
   108  	}()
   109  	byteValue, err := io.ReadAll(jsonFile)
   110  	if err != nil {
   111  		return nil, fmt.Errorf("reading %s: %w", ignoreFile, err)
   112  	}
   113  	err = json.Unmarshal(byteValue, &ignoreDiffs)
   114  	if err != nil {
   115  		return nil, err
   116  	}
   117  	return ignoreDiffs, nil
   118  }
   119  
   120  func (c *DiffCommand) getDiffs() (diff.SpecDifferences, error) {
   121  	oldSpecPath, newSpecPath := c.Args.OldSpec, c.Args.NewSpec
   122  	swaggerDoc1 := oldSpecPath
   123  	specDoc1, err := loads.Spec(swaggerDoc1)
   124  	if err != nil {
   125  		return nil, err
   126  	}
   127  
   128  	swaggerDoc2 := newSpecPath
   129  	specDoc2, err := loads.Spec(swaggerDoc2)
   130  	if err != nil {
   131  		return nil, err
   132  	}
   133  
   134  	return diff.Compare(specDoc1.Spec(), specDoc2.Spec())
   135  }
   136  
   137  func (c *DiffCommand) printInfo() {
   138  	log.Println("Run Config:")
   139  	log.Printf("Spec1: %s", c.Args.OldSpec)
   140  	log.Printf("Spec2: %s", c.Args.NewSpec)
   141  	log.Printf("ReportOnlyBreakingChanges (-c) :%v", c.OnlyBreakingChanges)
   142  	log.Printf("OutputFormat (-f) :%s", c.Format)
   143  	log.Printf("IgnoreFile (-i) :%s", c.IgnoreFile)
   144  	log.Printf("Diff Report Destination (-d) :%s", c.Destination)
   145  }