github.com/mentimeter/morty@v1.2.2-0.20221012065510-5596adecd154/mortems/mortems.go (about)

     1  package mortems
     2  
     3  import (
     4  	_ "embed"
     5  	"encoding/json"
     6  	"fmt"
     7  	"strings"
     8  )
     9  
    10  //go:embed install_morty
    11  var installScriptContent string
    12  
    13  type MortemCollector struct {
    14  	Repo            RepoFileService
    15  	Reporter        ReportingService
    16  	previousMortems []MortemData
    17  	nextMortems     []MortemData
    18  }
    19  
    20  func NewMortemCollector(fileService RepoFileService) MortemCollector {
    21  	return MortemCollector{fileService, nil, []MortemData{}, []MortemData{}}
    22  }
    23  
    24  func NewMortemReportingCollector(fileService RepoFileService, reportingService ReportingService) MortemCollector {
    25  	return MortemCollector{fileService, reportingService, []MortemData{}, []MortemData{}}
    26  }
    27  
    28  func (m *MortemCollector) Check() (RepoFiles, error) {
    29  	newFiles := RepoFiles{}
    30  
    31  	existingFiles, err := m.Repo.GetFiles()
    32  	if err != nil {
    33  		return RepoFiles{}, err
    34  	}
    35  
    36  	templatePath := "post-mortems/template.md"
    37  	templateFile := existingFiles.GetFile(templateContent)
    38  
    39  	if templateFile == nil || templateFile.GetContent() != templateContent {
    40  		newFiles.AddFile(templatePath, templateContent)
    41  	}
    42  
    43  	howToPath := "post-mortems/README.md"
    44  	howToFile := existingFiles.GetFile(howToPath)
    45  
    46  	if howToFile == nil || howToFile.GetContent() != howToContent {
    47  		newFiles.AddFile(howToPath, howToContent)
    48  	}
    49  
    50  	installScriptPath := "install_morty"
    51  	installScriptFile := existingFiles.GetFile(installScriptPath)
    52  
    53  	if installScriptFile == nil || installScriptFile.GetContent() != installScriptContent {
    54  		newFiles.AddExecutableFile(installScriptPath, installScriptContent)
    55  	}
    56  
    57  	databasePath := "mortems.json"
    58  	modifiedDatabase := false
    59  
    60  	databaseFile := existingFiles.GetFile(databasePath)
    61  	if databaseFile == nil {
    62  		modifiedDatabase = true
    63  		databaseFile = &File{
    64  			Path:    databasePath,
    65  			Mode:    "100644",
    66  			Type:    "blob",
    67  			Content: "[]",
    68  		}
    69  	}
    70  
    71  	databaseBytes := []byte(databaseFile.GetContent())
    72  
    73  	err = json.Unmarshal(databaseBytes, &m.previousMortems)
    74  	if err != nil {
    75  		return RepoFiles{}, fmt.Errorf("could not load database from file: %w", err)
    76  	}
    77  
    78  	for _, file := range existingFiles.Files {
    79  		if strings.HasPrefix(file.GetPath(), "post-mortems/") &&
    80  			!strings.HasPrefix(file.GetPath(), "post-mortems/images/") &&
    81  			file.GetPath() != howToPath &&
    82  			file.GetPath() != templatePath {
    83  			modifiedDatabase = true
    84  
    85  			mortem, err := NewMortemData(file.GetContent(), file.GetPath())
    86  			if err != nil {
    87  				return RepoFiles{}, fmt.Errorf("could not parse data from mortem %s: %w", file.GetPath(), err)
    88  			}
    89  
    90  			m.nextMortems = append(m.nextMortems, mortem)
    91  		}
    92  	}
    93  
    94  	readmePath := "README.md"
    95  	readmeFile := existingFiles.GetFile(readmePath)
    96  	readmeContent := GenerateReadme(m.nextMortems)
    97  
    98  	if readmeFile == nil || readmeFile.GetContent() != readmeContent {
    99  		newFiles.AddFile(readmePath, readmeContent)
   100  	}
   101  
   102  	databaseBytes, err = json.Marshal(m.nextMortems)
   103  	if err != nil {
   104  		return RepoFiles{}, fmt.Errorf("could not marshal database to json: %w", err)
   105  	}
   106  
   107  	databaseString := string(databaseBytes)
   108  
   109  	if modifiedDatabase {
   110  		newFiles.AddFile(databasePath, databaseString)
   111  	}
   112  
   113  	return newFiles, nil
   114  
   115  }
   116  
   117  func (m *MortemCollector) Collect() error {
   118  	newFiles, err := m.Check()
   119  	if err != nil {
   120  		return fmt.Errorf("could not check files, there might be a parsing error: %w", err)
   121  	}
   122  
   123  	if m.Reporter != nil {
   124  		toReport := diffMortems(m.previousMortems, m.nextMortems)
   125  		for _, report := range toReport {
   126  
   127  			m.Reporter.ReportSeverity(report.Severity)
   128  			m.Reporter.ReportDetect(report.Detect, report.Severity)
   129  			m.Reporter.ReportResolve(report.Resolve, report.Severity)
   130  			m.Reporter.ReportDowntime(report.Downtime, report.Severity)
   131  		}
   132  	}
   133  
   134  	if newFiles.Size() > 0 {
   135  		err := m.Repo.CommitNewFiles(&newFiles)
   136  		if err != nil {
   137  			return fmt.Errorf("could not commit new files: %w", err)
   138  		}
   139  	}
   140  
   141  	return nil
   142  }
   143  
   144  func diffMortems(old []MortemData, new []MortemData) []MortemData {
   145  	diff := []MortemData{}
   146  	for _, newMortem := range new {
   147  		exists := false
   148  		for _, oldMortem := range old {
   149  			if oldMortem == newMortem {
   150  				exists = true
   151  			}
   152  		}
   153  		if !exists {
   154  			diff = append(diff, newMortem)
   155  		}
   156  	}
   157  
   158  	return diff
   159  }