| 43 | } |
| 44 | |
| 45 | func (c *JacocoCrafter) Craft(ctx context.Context, filePath string) (*api.Attestation_Material, error) { |
| 46 | f, err := os.Open(filePath) |
| 47 | if err != nil { |
| 48 | return nil, fmt.Errorf("can't open the file: %w", err) |
| 49 | } |
| 50 | defer f.Close() |
| 51 | |
| 52 | bytes, err := io.ReadAll(f) |
| 53 | if err != nil { |
| 54 | return nil, fmt.Errorf("can't read the file: %w", err) |
| 55 | } |
| 56 | |
| 57 | var report jacoco.Report |
| 58 | |
| 59 | if err := xml.Unmarshal(bytes, &report); err != nil { |
| 60 | return nil, fmt.Errorf("invalid Jacoco report file: %w", ErrInvalidMaterialType) |
| 61 | } |
| 62 | |
| 63 | if len(report.Counters) == 0 { |
| 64 | return nil, fmt.Errorf("invalid Jacoco report file, no counters found: %w", ErrInvalidMaterialType) |
| 65 | } |
| 66 | // At least "instruction" counter should be available according to the documentation |
| 67 | // https://www.eclemma.org/jacoco/trunk/doc/counters.html |
| 68 | if !slices.ContainsFunc(report.Counters, func(counter *jacoco.Counter) bool { |
| 69 | return counter.Type == "INSTRUCTION" |
| 70 | }) { |
| 71 | return nil, fmt.Errorf("invalid Jacoco report file: %w", ErrInvalidMaterialType) |
| 72 | } |
| 73 | return uploadAndCraft(ctx, c.input, c.backend, filePath, c.logger) |
| 74 | } |