packages feed

hspec-formatter-github (empty) → 0.1.0.0

raw patch · 8 files changed

+371/−0 lines, 8 filesdep +basedep +hspecdep +hspec-apisetup-changed

Dependencies added: base, hspec, hspec-api, hspec-core, hspec-formatter-github

Files

+ CHANGELOG.md view
@@ -0,0 +1,11 @@+# Changelog for `hspec-formatter-github`++All notable changes to this project will be documented in this file.++The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),+and this project adheres to the+[Haskell Package Versioning Policy](https://pvp.haskell.org/).++## Unreleased++## 0.1.0.0 - 2023-12-07
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Author name here (c) 2023++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Author name here nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,4 @@+# `hspec-formatter-github`++This package provides an `hspec` `Formatter` that emits Github Actions Annotations.+This highlights test failures directly in the PR view.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ hspec-formatter-github.cabal view
@@ -0,0 +1,131 @@+cabal-version: 2.2++-- This file has been generated from package.yaml by hpack version 0.35.2.+--+-- see: https://github.com/sol/hpack++name:           hspec-formatter-github+version:        0.1.0.0+synopsis:       A Formatter for hspec that provides Github Actions Annotations+description:    Please see the README on GitHub at <https://github.com/MercuryTechnologies/hspec-formatter-github#readme>+category:       Testing+homepage:       https://github.com/MercuryTechnologies/hspec-formatter-github#readme+bug-reports:    https://github.com/MercuryTechnologies/hspec-formatter-github/issues+author:         Alex Vieth, Matt von Hagen+maintainer:     mattp@mercury.com+copyright:      2023 Mercury Technologies+license:        BSD-3-Clause+license-file:   LICENSE+build-type:     Simple+extra-source-files:+    README.md+    CHANGELOG.md++source-repository head+  type: git+  location: https://github.com/MercuryTechnologies/hspec-formatter-github++library+  exposed-modules:+      Test.Hspec.Formatters.GithubAction+      Test.Hspec.Formatters.GithubAction.Internal+  other-modules:+      Paths_hspec_formatter_github+  autogen-modules:+      Paths_hspec_formatter_github+  hs-source-dirs:+      src+  default-extensions:+      BlockArguments+      DataKinds+      DefaultSignatures+      DeriveFunctor+      DeriveGeneric+      DeriveLift+      DerivingStrategies+      DerivingVia+      FlexibleContexts+      FlexibleInstances+      GADTs+      GeneralizedNewtypeDeriving+      ImportQualifiedPost+      InstanceSigs+      LambdaCase+      MultiParamTypeClasses+      MultiWayIf+      NamedFieldPuns+      NegativeLiterals+      NumericUnderscores+      OverloadedLabels+      OverloadedStrings+      PartialTypeSignatures+      PatternSynonyms+      RankNTypes+      RecordWildCards+      ScopedTypeVariables+      StandaloneDeriving+      TypeApplications+      TypeFamilies+      UndecidableInstances+      ViewPatterns+      TypeOperators+      NoForeignFunctionInterface+  ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints+  build-depends:+      base >=4.14 && <5+    , hspec-api+    , hspec-core+  default-language: Haskell2010++test-suite test+  type: exitcode-stdio-1.0+  main-is: Main.hs+  other-modules:+      Paths_hspec_formatter_github+  autogen-modules:+      Paths_hspec_formatter_github+  hs-source-dirs:+      test+  default-extensions:+      BlockArguments+      DataKinds+      DefaultSignatures+      DeriveFunctor+      DeriveGeneric+      DeriveLift+      DerivingStrategies+      DerivingVia+      FlexibleContexts+      FlexibleInstances+      GADTs+      GeneralizedNewtypeDeriving+      ImportQualifiedPost+      InstanceSigs+      LambdaCase+      MultiParamTypeClasses+      MultiWayIf+      NamedFieldPuns+      NegativeLiterals+      NumericUnderscores+      OverloadedLabels+      OverloadedStrings+      PartialTypeSignatures+      PatternSynonyms+      RankNTypes+      RecordWildCards+      ScopedTypeVariables+      StandaloneDeriving+      TypeApplications+      TypeFamilies+      UndecidableInstances+      ViewPatterns+      TypeOperators+      NoForeignFunctionInterface+  ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints -threaded -rtsopts -with-rtsopts=-N -O0+  build-depends:+      base >=4.14 && <5+    , hspec+    , hspec-api+    , hspec-core+    , hspec-formatter-github+  default-language: Haskell2010
+ src/Test/Hspec/Formatters/GithubAction.hs view
@@ -0,0 +1,52 @@+{-# LANGUAGE StrictData #-}+{-# LANGUAGE OverloadedStrings #-}++-- | This module provides a utility to allow you to have annotations on+-- test failures in GitHub Actions.+--+-- To use this, you'll call 'registerGithubActionsAnnotations' with+-- a 'Formatter' of your choice.+--+-- @+-- main :: IO ()+-- main = do+--     let hspecConfig =+--             'registerGithubActionsAnnotations' 'checks' 'defaultConfig'+--     'hspecWith' hspecConfig spec+-- @+--+-- This will make the @github@ formatter available.+--+-- Then, to actually use the formatter, you can provide the argument+-- @--format=github@ on the command line or in a @.hspec@ file, or the+-- @HSPEC_FORMAT=github@ environment variable.+--+-- To do this locally with @cabal@, you must use @cabal run@, as @cabal+-- test@ evidently does not allow you to pass @--test-arguments@ anymore?+--+-- > $ cabal run $(test-target-name) -- --format=github+--+-- The environment variable is easier to set in CI, probably.+--+-- > $ HSPEC_FORMAT=github cabal test+--+-- And you can use a file, if you really want to, for some reason.+--+-- > $ echo "--format=github" >> .hspec+-- > $ cabal test+module Test.Hspec.Formatters.GithubAction+    ( registerGithubActionsAnnotations+    , withGithubActionFormatter+    -- * Re-exported 'Formatter'+    , silent+    , checks+    ) where++import Test.Hspec.Formatters.GithubAction.Internal+import Test.Hspec.Api.Formatters.V2++-- | This function adds the GitHub Annotations to the underlying+-- 'Formatter'+registerGithubActionsAnnotations :: Formatter -> Config -> Config+registerGithubActionsAnnotations format =+    registerFormatter ("github", withGithubActionFormatter format)
+ src/Test/Hspec/Formatters/GithubAction/Internal.hs view
@@ -0,0 +1,126 @@+{-# LANGUAGE StrictData #-}+{-# LANGUAGE OverloadedStrings #-}++-- | This module is internal! Use at your own risk. Breaking changes to+-- this module will not necessarily be reflected in PVP versions.+module Test.Hspec.Formatters.GithubAction.Internal where++import Prelude+import Control.Applicative+import Test.Hspec.Core.Util (joinPath)+import Test.Hspec.Api.Formatters.V2++-- | This option enhances a given 'Formatter' with annotations that will+-- show up on the correct test item failure. This allows you to use the+-- test output you want, and additionally get Github Action annotations.+withGithubActionFormatter :: Formatter -> Formatter+withGithubActionFormatter fmtr = fmtr+  { formatterItemDone = \path item -> do+      formatterItemDone fmtr path item+      emitGithubActionAnnotation path item+  }++-- | A representation of the Github Actions error format.+data ErrorCommand = ErrorCommand+    { title   :: Maybe String+    , file    :: Maybe String+    , line    :: Maybe Int+    , col     :: Maybe Int+    , message :: String+    }++-- | Make a suitable error annotation from an hspec failure.+--+-- Not clear what to do with the Maybe Location here: do we use the one from+-- the Item, or this one? What if both or neither are available?+-- Also not clear whether to use itemInfo.+errorCommandFor :: Path -> Item -> Maybe Location -> FailureReason -> ErrorCommand+errorCommandFor specPath@(_nesting, requirement) item mFailureLocation reason = ErrorCommand+    { -- requirement is used because it should always be non-empty and meaningful+      title = Just requirement+    , file = locationFile   <$> mloc+    , line = locationLine   <$> mloc+    , col  = locationColumn <$> mloc+    , message = unlines (messageHeaderLines ++ messageBodyLines)+    }+  where+    -- prefer the location of the actual failure. if that is not present,+    -- fall  back to the test definition location+    mloc = mFailureLocation <|> itemLocation item+    -- Use the path to give a message header, so that the message is never empty.+    -- Empty messages seem to cause github actions to ignore the annotation.+    messageHeaderLines :: [String]+    messageHeaderLines = joinPath specPath : if itemInfo item == "" then [] else [itemInfo item]++    messageBodyLines :: [String]+    messageBodyLines = case reason of+        NoReason -> []+        Reason str -> [str]+        ExpectedButGot preface expected actual ->+            let bodyLines =+                    [ mconcat ["expected: ", expected]+                    , mconcat ["     got: ", actual  ]+                    ]+                headerLines = maybe [] (\x -> [x]) preface+            in  headerLines ++ bodyLines+        Error preface err ->+            let bodyLines = [show err]+                headerLines = maybe [] (\x -> [x]) preface+            in  headerLines ++ bodyLines++-- | The github actions command format.+formatErrorCommand :: ErrorCommand -> String+formatErrorCommand ec = mconcat+    [ "\n::error "+    , "title=", maybe "" escapeProperty (title ec), ","+    , "file=", maybe "" escapeProperty (file ec), ","+    , "line=", maybe "" show (line ec), ","+    , "col=", maybe "" show (col ec)+    , "::"+    , escapeData (message ec)+    -- FIXME should check if on windows and use \r\n, as this is what the+    -- github library does.+    , "\n"+    ]++{-+function escapeData(s: any): string {+  return toCommandValue(s)+    .replace(/%/g, '%25')+    .replace(/\r/g, '%0D')+    .replace(/\n/g, '%0A')+}+function escapeProperty(s: any): string {+  return toCommandValue(s)+    .replace(/%/g, '%25')+    .replace(/\r/g, '%0D')+    .replace(/\n/g, '%0A')+    .replace(/:/g, '%3A')+    .replace(/,/g, '%2C')+}+-}++escapeData :: String -> String+escapeData = (>>= replace)+  where+    replace '%'  = "%25"+    replace '\r' = "%0D"+    replace '\n' = "%0A"+    replace c    = [c]++escapeProperty :: String -> String+escapeProperty = (>>= replace)+  where+    replace '%'  = "%25"+    replace '\r' = "%0D"+    replace '\n' = "%0A"+    replace ':'  = "%3A"+    replace ','  = "%2C"+    replace c    = [c]++-- | If you want to extend+emitGithubActionAnnotation :: Path -> Item -> FormatM ()+emitGithubActionAnnotation path item = case itemResult item of+    Success -> pure ()+    Pending _ _ -> pure ()+    Failure mLoc reason -> write . formatErrorCommand $ errorCommandFor path item mLoc reason
+ test/Main.hs view
@@ -0,0 +1,15 @@+module Main where++import Test.Hspec+import Test.Hspec.Core.Runner+import Test.Hspec.Formatters.GithubAction++main :: IO ()+main = do+    hspecWith (registerGithubActionsAnnotations checks defaultConfig) $ do+        describe "it works" $ do+            it "unmark pending to test" $ do+                pendingWith "test is pending by default"+                expectationFailure "oh no"++