robots/issue-creator/sources/triage-filer.go
func parseTriageData(jsonIn []byte) (*triageData, error) {
	var data triageData
	if err := json.Unmarshal(jsonIn, &data); err != nil {
		return nil, err
	}

	if data.Builds.Cols.Started == nil {
		return nil, fmt.Errorf("triage data json is missing the builds.cols.started key")
	}
	if data.Builds.JobsRaw == nil {
		return nil, fmt.Errorf("triage data is missing the builds.jobs key")
	}
	if data.Builds.JobPaths == nil {
		return nil, fmt.Errorf("triage data is missing the builds.job_paths key")
	}
	if data.Clustered == nil {
		return nil, fmt.Errorf("triage data is missing the clustered key")
	}
	// Populate 'Jobs' with the BuildIndexer for each job.
	data.Builds.Jobs = make(map[string]BuildIndexer)
	for jobID, mapper := range data.Builds.JobsRaw {
		switch mapper := mapper.(type) {
		case []interface{}:
			// In this case mapper is a 3 member array. 0:first buildnum, 1:number of builds, 2:start index.
			data.Builds.Jobs[jobID] = ContigIndexer{
				startBuild: int(mapper[0].(float64)),
				count:      int(mapper[1].(float64)),
				startRow:   int(mapper[2].(float64)),
			}
		case map[string]interface{}:
			// In this case mapper is a dictionary.
			data.Builds.Jobs[jobID] = DictIndexer(mapper)
		default:
			return nil, fmt.Errorf("the build number to row index mapping for job '%s' is not an accepted type. Type is: %v", jobID, reflect.TypeOf(mapper))
		}
	}
	return &data, nil
}
func parseTriageData(jsonIn []byte) (*triageData, error) {
	var data triageData
	if err := json.Unmarshal(jsonIn, &data); err != nil {
		return nil, err
	}

	if data.Builds.Cols.Started == nil {
		return nil, fmt.Errorf("triage data json is missing the builds.cols.started key")
	}
	if data.Builds.JobsRaw == nil {
		return nil, fmt.Errorf("triage data is missing the builds.jobs key")
	}
	if data.Builds.JobPaths == nil {
		return nil, fmt.Errorf("triage data is missing the builds.job_paths key")
	}
	if data.Clustered == nil {
		return nil, fmt.Errorf("triage data is missing the clustered key")
	}
	// Populate 'Jobs' with the BuildIndexer for each job.
	data.Builds.Jobs = make(map[string]BuildIndexer)
	for jobID, mapper := range data.Builds.JobsRaw {
		switch mapper := mapper.(type) {
		case []interface{}:
			// In this case mapper is a 3 member array. 0:first buildnum, 1:number of builds, 2:start index.
			data.Builds.Jobs[jobID] = ContigIndexer{
				startBuild: int(mapper[0].(float64)),
				count:      int(mapper[1].(float64)),
				startRow:   int(mapper[2].(float64)),
			}
		case map[string]interface{}:
			// In this case mapper is a dictionary.
			data.Builds.Jobs[jobID] = DictIndexer(mapper)
		default:
			return nil, fmt.Errorf("the build number to row index mapping for job '%s' is not an accepted type. Type is: %v", jobID, reflect.TypeOf(mapper))
		}
	}
	return &data, nil
}
// parseTriageData unmarshals raw json data into a triageData struct and creates a BuildIndexer for
// every job.