diff --git a/linting.go b/linting.go index a05035b..0ae918e 100644 --- a/linting.go +++ b/linting.go @@ -18,6 +18,42 @@ const ( WarningSeverity LinterResultSeverity = "warning" ) +type LintingProcessor struct { + linters []SpecificationLinter +} + +func NewLintingProcessor(linters ...SpecificationLinter) *LintingProcessor { + return &LintingProcessor{linters: linters} +} + +func (l LintingProcessor) Name() string { + return "linting_processor" +} + +func (l LintingProcessor) Process(ctx ProcessingContext) ([]ProcessingOutput, error) { + linter := CompositeSpecificationLinter(l.linters...) + ctx.Logger.Info("\nLinting specifications ...") + lr := linter.Lint(SpecificationGroup(ctx.DependencyGraph)) + if lr.HasWarnings() { + for _, w := range lr.Warnings() { + ctx.Logger.Warning(fmt.Sprintf("Warning: %s\n", w.Message)) + } + } + + if lr.HasErrors() { + for _, e := range lr.Errors().Errors { + ctx.Logger.Error(fmt.Sprintf("Error: %s\n", e.Error())) + } + } + + if !lr.HasWarnings() && !lr.HasErrors() { + ctx.Logger.Success("Specifications linted successfully.") + } + + return nil, nil + +} + type LinterResult struct { Severity LinterResultSeverity Message string @@ -97,7 +133,7 @@ func SpecificationMustNotHaveUndefinedNames() SpecificationLinterFunc { if s.Name() == UndefinedSpecificationName { result = append(result, LinterResult{ Severity: ErrorSeverity, - Message: fmt.Sprintf("specification at \"%s\" has an undefined type FilePath", s.Source().Location), + Message: fmt.Sprintf("specification at %q has an undefined type FilePath", s.Source().Location), }) } } @@ -138,7 +174,7 @@ func SpecificationsMustHaveUniqueNames() SpecificationLinterFunc { result = append(result, LinterResult{ Severity: ErrorSeverity, Message: fmt.Sprintf( - "duplicate specification name detected for \"%s\" in the following file(s): %s", + "duplicate specification name detected for %q in the following file(s): %s", name, strings.Join(fileNames, ", "), ), @@ -158,7 +194,7 @@ func SpecificationsMustHaveDescriptionAttribute() SpecificationLinterFunc { if s.Description() == "" { result = append(result, LinterResult{ Severity: ErrorSeverity, - Message: fmt.Sprintf("specification at location \"%s\" does not have a description.", s.Source().Location), + Message: fmt.Sprintf("specification at location %q does not have a description.", s.Source().Location), }) } } @@ -175,7 +211,7 @@ func SpecificationsMustHaveLowerCaseNames() SpecificationLinterFunc { result = append(result, LinterResult{ Severity: ErrorSeverity, Message: fmt.Sprintf( - fmt.Sprintf("specification names must be lowercase got \"%s\" at location \"%s\"", + fmt.Sprintf("specification names must be lowercase got %q at location %q", s.Name(), s.Source().Location, ), diff --git a/specter.go b/specter.go index 607d9a2..5fdd428 100644 --- a/specter.go +++ b/specter.go @@ -23,7 +23,6 @@ type Specter struct { SourceLoaders []SourceLoader Loaders []SpecificationLoader Processors []SpecificationProcessor - Linters []SpecificationLinter OutputProcessors []OutputProcessor Logger Logger ExecutionMode ExecutionMode @@ -39,7 +38,7 @@ type Stats struct { } func (s Stats) ExecutionTime() time.Duration { - return s.EndedAt.Sub(s.EndedAt) + return s.EndedAt.Sub(s.StartedAt) } // Run the pipeline from start to finish. @@ -47,13 +46,19 @@ func (s Specter) Run(sourceLocations []string) error { stats := Stats{} defer func() { - s.Logger.Info(fmt.Sprintf("\nStarted At: %s, ended at: %s, execution time: %s", stats.StartedAt, stats.EndedAt, stats.ExecutionTime())) + stats.EndedAt = time.Now() + + s.Logger.Info(fmt.Sprintf("\nStarted At: %s", stats.StartedAt)) + s.Logger.Info(fmt.Sprintf("Ended at: %s", stats.EndedAt)) + s.Logger.Info(fmt.Sprintf("Execution time: %s", stats.ExecutionTime())) s.Logger.Info(fmt.Sprintf("Number of source locations: %d", stats.NbSourceLocations)) s.Logger.Info(fmt.Sprintf("Number of sources: %d", stats.NbSources)) s.Logger.Info(fmt.Sprintf("Number of specifications: %d", stats.NbSpecifications)) s.Logger.Info(fmt.Sprintf("Number of outputs: %d", stats.NbOutputs)) }() + stats.StartedAt = time.Now() + // Load sources stats.NbSourceLocations = len(sourceLocations) sources, err := s.LoadSources(sourceLocations) @@ -83,20 +88,6 @@ func (s Specter) Run(sourceLocations []string) error { return e } - // Lint Specifications - lr := s.LintSpecifications(deps) - if lr.HasErrors() { - errs := errors.NewGroup(errors.InternalErrorCode) - for _, e := range lr.Errors().Errors { - errs = errs.Append(e) - } - return errors.WrapWithMessage(errs, errors.InternalErrorCode, "linting errors encountered") - } - // stop here - if s.ExecutionMode == LintMode { - return nil - } - // Process Specifications var outputs []ProcessingOutput outputs, err = s.ProcessSpecifications(deps) @@ -209,30 +200,6 @@ func (s Specter) ResolveDependencies(specifications []Specification) (ResolvedDe return deps, nil } -// LintSpecifications runes all Linters against a list of Specifications. -func (s Specter) LintSpecifications(specifications []Specification) LinterResultSet { - linter := CompositeSpecificationLinter(s.Linters...) - s.Logger.Info("\nLinting specifications ...") - lr := linter.Lint(specifications) - if lr.HasWarnings() { - for _, w := range lr.Warnings() { - s.Logger.Warning(fmt.Sprintf("Warning: %s\n", w.Message)) - } - } - - if lr.HasErrors() { - for _, e := range lr.Errors().Errors { - s.Logger.Error(fmt.Sprintf("Error: %s\n", e.Error())) - } - } - - if !lr.HasWarnings() && !lr.HasErrors() { - s.Logger.Success("Specifications linted successfully.") - } - - return lr -} - // ProcessSpecifications sends the specifications to processors. func (s Specter) ProcessSpecifications(specifications ResolvedDependencies) ([]ProcessingOutput, error) { ctx := ProcessingContext{ @@ -315,13 +282,6 @@ func WithLoaders(loaders ...SpecificationLoader) Option { } } -// WithLinters configures the SpecificationLinter of a Specter instance. -func WithLinters(linters ...SpecificationLinter) Option { - return func(s *Specter) { - s.Linters = append(s.Linters, linters...) - } -} - // WithProcessors configures the SpecProcess of a Specter instance. func WithProcessors(processors ...SpecificationProcessor) Option { return func(s *Specter) {