convex-pbt-cli
Safe HaskellSafe-Inferred
LanguageHaskell2010

PbtCli.Discover

Description

Static, no-compile discovery of a Haskell repository's cabal projects, packages and test suites.

This is a native port of scripts/list-test-suites/list-test-suites.sh. It emits the same JSON document, validating against that tool's list-test-suites.schema.json, so anything already consuming the script's output can consume pbt-cli suites --json unchanged. The port exists because the shipped pbt-cli binary must work on its own: a downloaded binary has no repository checkout to find a bash script in.

Nothing here compiles or even configures anything — it reads *.cabal and cabal.project* as text, which is why it takes milliseconds.

The one deliberate divergence from the shell implementation: a trailing comma on a packages: entry is stripped, because cabal itself accepts comma-separated lists and the shell version would silently drop such a package.

Synopsis

Types

data Discovery Source #

The whole discovery result.

Constructors

Discovery 

Fields

Instances

Instances details
ToJSON Discovery Source # 
Instance details

Defined in PbtCli.Discover

Show Discovery Source # 
Instance details

Defined in PbtCli.Discover

Eq Discovery Source # 
Instance details

Defined in PbtCli.Discover

data Project Source #

One cabal.project* file, or the implicit project when there is none.

Constructors

Project 

Fields

Instances

Instances details
ToJSON Project Source # 
Instance details

Defined in PbtCli.Discover

Show Project Source # 
Instance details

Defined in PbtCli.Discover

Eq Project Source # 
Instance details

Defined in PbtCli.Discover

Methods

(==) :: Project -> Project -> Bool #

(/=) :: Project -> Project -> Bool #

data Package Source #

A package, rendered under exactly one project (see primaryOwner).

Constructors

Package 

Fields

Instances

Instances details
ToJSON Package Source # 
Instance details

Defined in PbtCli.Discover

Show Package Source # 
Instance details

Defined in PbtCli.Discover

Eq Package Source # 
Instance details

Defined in PbtCli.Discover

Methods

(==) :: Package -> Package -> Bool #

(/=) :: Package -> Package -> Bool #

data TestSuite Source #

A single test-suite stanza, with the commands that drive it.

Constructors

TestSuite 

Fields

Instances

Instances details
ToJSON TestSuite Source # 
Instance details

Defined in PbtCli.Discover

Show TestSuite Source # 
Instance details

Defined in PbtCli.Discover

Eq TestSuite Source # 
Instance details

Defined in PbtCli.Discover

data Orphan Source #

A .cabal file no project's packages: field reaches.

Instances

Instances details
ToJSON Orphan Source # 
Instance details

Defined in PbtCli.Discover

Show Orphan Source # 
Instance details

Defined in PbtCli.Discover

Eq Orphan Source # 
Instance details

Defined in PbtCli.Discover

Methods

(==) :: Orphan -> Orphan -> Bool #

(/=) :: Orphan -> Orphan -> Bool #

data EntryPoint Source #

How a test suite's main-is module runs its tests.

Only Streaming suites provide the --streaming-json and --list-tests-json ingredients, because those come from the convex-tasty-streaming library. That makes Streaming the operational definition of "sc-testing-tools compatible".

Constructors

Streaming

defaultMainStreaming and friends: structured discovery and streaming.

Upstream

plain Test.Tasty.defaultMain: runnable, but no structured output.

UnknownEntry

a main-is module with no recognised runner.

MissingEntry

the main-is source file was not found on disk.

entryPointText :: EntryPoint -> Text Source #

The wire name, as it appears in the JSON and in --tsv output.

Discovery

discover :: FilePath -> IO Discovery Source #

Scan root and report every project, package and test suite.

Warnings (orphan .cabal files, packages claimed by several non-default projects) go to stderr, matching the shell tool, so stdout stays a single parseable JSON document.

Compatibility

isCompatible :: TestSuite -> Bool Source #

Is this suite sc-testing-tools compatible — that is, does it support --list-tests-json, --streaming-json and the threat-model options?

compatibleOnly :: Discovery -> Discovery Source #

Drop every non-Streaming suite, and then every package and project left without suites. Used by --compatible-only.

Flattened views

data SuiteRef Source #

A suite together with the context needed to actually run it: which project file owns it and which package it lives in.

The JSON document is intentionally nested (and its schema forbids extra fields), so this flattened view is what the run stream tests commands work with.

Constructors

SuiteRef 

Fields

Instances

Instances details
Show SuiteRef Source # 
Instance details

Defined in PbtCli.Discover

Eq SuiteRef Source # 
Instance details

Defined in PbtCli.Discover

flattenSuites :: Discovery -> [SuiteRef] Source #

Every suite in the discovery, in document order, paired with its project file and package.

srProjectFile is Nothing both for the implicit project and for the default cabal.project, because in either case cabal needs no --project-file flag.

findSuite :: Text -> Discovery -> Maybe SuiteRef Source #

Look a suite up by its cabal test target name.

Reusable pieces

entryPointOfFile :: FilePath -> IO EntryPoint Source #

Classify a main-is source file by the tasty runner it calls.

Streaming is tested first so the *WithIngredients variants are never mistaken for plain upstream defaultMain.

parseTestSuites Source #

Arguments

:: FilePath

absolute root

-> FilePath

package dir, relative to root

-> String

the .cabal contents

-> IO [TestSuite] 

Parse the test-suite stanzas of one .cabal file.

A stanza runs from a test-suite <name> line at column 0 until the next column-0 declaration. main-is is resolved against each of the stanza's hs-source-dirs in order; the first path that exists on disk wins and its source is classified. When none exists the suite is reported as MISSING, which keeps a typo'd (or generated-but-absent) entry point visible instead of silently dropping the suite.

packageNameOf :: String -> Text Source #

The package's name: field, or "" when it has none.

projectFilesIn :: FilePath -> IO [FilePath] Source #

The cabal.project / cabal.project.* files at the top level of root, sorted.

Only the top level is scanned because that is the only place cabal honours them, and .freeze / .local are excluded: they configure a project rather than declaring one.

findCabalFiles :: FilePath -> IO [FilePath] Source #

Every .cabal file under root, relative to it and sorted.

dist-newstyle, tasty-investigate, .git and node_modules are pruned: they hold build artefacts and vendored code whose .cabal files are not part of the repository's own structure. Symlinks are not followed at all -- neither descended into nor reported as .cabal files -- which is what the reference's find does and what keeps a link back to an ancestor from looping.

readFileLenient :: FilePath -> IO String Source #

Read a file without letting a stray non-UTF-8 byte abort discovery.

Vendored .cabal files and generated sources sometimes carry latin-1 bytes. The classifier only looks for ASCII markers, so transliterating one byte is harmless, whereas a decoding exception would lose the entire scan.