From 92e42970b00f29c194f25a838b710af6718a935a Mon Sep 17 00:00:00 2001 From: Ajeet D'Souza <98ajeet@gmail.com> Date: Mon, 10 Jun 2019 19:01:18 +0530 Subject: [PATCH 1/7] Initial commit --- .gitignore | 1 + Setup.hs | 3 ++ package.yaml | 29 ++++++++++++ src/CI.hs | 47 +++++++++++++++++++ src/CI/Types.hs | 121 ++++++++++++++++++++++++++++++++++++++++++++++++ stack.yaml | 64 +++++++++++++++++++++++++ 6 files changed, 265 insertions(+) create mode 100644 Setup.hs create mode 100644 package.yaml create mode 100644 src/CI.hs create mode 100644 src/CI/Types.hs create mode 100644 stack.yaml diff --git a/.gitignore b/.gitignore index 82f3a88..55d6fb1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +ci-info.cabal dist dist-* cabal-dev diff --git a/Setup.hs b/Setup.hs new file mode 100644 index 0000000..ebdc00e --- /dev/null +++ b/Setup.hs @@ -0,0 +1,3 @@ +import Distribution.Simple + +main = defaultMain diff --git a/package.yaml b/package.yaml new file mode 100644 index 0000000..6dca4b2 --- /dev/null +++ b/package.yaml @@ -0,0 +1,29 @@ +name: ci-info +version: 0.1.0.0 +github: "hasura/ci-info-hs" +license: MIT +author: "Ajeet D'Souza" +maintainer: "build@hasura.io" +copyright: "2019 Hasura Inc." + +ghc-options: +- -Wall + +extra-source-files: +- README.md + +description: Please see the README on GitHub at + +dependencies: +- base >= 4.7 && < 5 +- aeson +- aeson-casing +- lens +- template-haskell +- th-lift-instances +- text +- unordered-containers +- wreq + +library: + source-dirs: src diff --git a/src/CI.hs b/src/CI.hs new file mode 100644 index 0000000..ab520d0 --- /dev/null +++ b/src/CI.hs @@ -0,0 +1,47 @@ +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE TemplateHaskell #-} + +module CI ( isCI, getCI ) where + +import CI.Types ( CI ) +import qualified CI.Types as CI + +import Control.Arrow ( (***) ) + +import Data.Bool ( bool ) +import Data.Foldable ( find ) +import qualified Data.HashMap.Strict as HashMap +import Data.Maybe ( isJust ) +import qualified Data.Text as T + +import qualified Language.Haskell.TH as TH +import qualified Language.Haskell.TH.Syntax as TH + +import System.Environment ( getEnvironment ) + +vendors :: [CI.Vendor] +vendors = $(TH.runIO CI.getVendors >>= TH.lift) + +getCI :: IO (Maybe CI) +getCI = do + env <- HashMap.fromList . map (T.pack *** T.pack) <$> getEnvironment + let maybeVendor = find (checkVendor env) vendors + return $ case maybeVendor of + Nothing -> bool Nothing (Just CI.UnknownVendor) $ + any (`HashMap.member` env) -- check vendor neutral environment variables + [ "CI" -- Travis CI, CircleCI, Cirrus CI, Gitlab CI, Appveyor, CodeShip, dsari + , "CONTINUOUS_INTEGRATION" -- Travis CI, Cirrus CI + , "BUILD_NUMBER" -- Jenkins, TeamCity + , "RUN_ID" -- TaskCluster, dsari + ] + Just vendor -> Just $ CI.vendorConstant vendor + where + checkVendor env vendor = case CI.vendorEnv vendor of + (CI.VendorEnvString text) -> HashMap.member text env + (CI.VendorEnvList list) -> all (`HashMap.member` env) list + (CI.VendorEnvObject hashMap) -> + all (\(k, v) -> HashMap.lookup k env == Just v) $ + HashMap.toList hashMap + +isCI :: IO Bool +isCI = isJust <$> getCI diff --git a/src/CI/Types.hs b/src/CI/Types.hs new file mode 100644 index 0000000..73b0fb3 --- /dev/null +++ b/src/CI/Types.hs @@ -0,0 +1,121 @@ +{-# LANGUAGE DeriveLift #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE TemplateHaskell #-} + +{-# OPTIONS_GHC -fno-warn-orphans #-} + +module CI.Types where + +import Control.Lens ( (^.) ) + +import qualified Data.Aeson as Aeson +import qualified Data.Aeson.Casing as Aeson +import qualified Data.Aeson.TH as Aeson +import Data.HashMap.Strict ( HashMap ) +import qualified Data.HashMap.Strict as HashMap +import Data.Text ( Text ) +import qualified Data.Text as T + +import Instances.TH.Lift () + +import qualified Language.Haskell.TH.Syntax as TH + +import qualified Network.Wreq as Wreq + +data CI = + AWSCodeBuild -- https://aws.amazon.com/codebuild/ + | AppVeyor -- http://www.appveyor.com/ + | AzurePipelines -- https://azure.microsoft.com/en-us/services/devops/pipelines/ + | Bamboo -- https://www.atlassian.com/software/bamboo/ + | BitbucketPipelines -- https://bitbucket.org/product/features/pipelines/ + | Bitrise -- https://www.bitrise.io/ + | Buddy -- https://buddy.works/ + | Buildkite -- https://buildkite.com/ + | CircleCI -- http://circleci.com/ + | CirrusCI -- https://cirrus-ci.org/ + | Codeship -- https://codeship.com/ + | Drone -- https://drone.io/ + | Dsari -- https://github.com/rfinnie/dsari/ + | GitLabCI -- https://about.gitlab.com/gitlab-ci/ + | GoCD -- https://www.go.cd/ + | Hudson -- http://hudson-ci.org/ + | Jenkins -- https://jenkins-ci.org/ + | MagnumCI -- https://magnum-ci.com/ + | NetlifyCI -- https://www.netlify.com/ + | Nevercode -- http://nevercode.io/ + | SailCI -- https://sail.ci/ + | Semaphore -- https://semaphoreci.com/ + | Shippable -- https://www.shippable.com/ + | SolanoCI -- https://www.solanolabs.com/ + | StriderCD -- https://strider-cd.github.io/ + | TaskCluster -- http://docs.taskcluster.net/ + | TeamCity -- https://www.jetbrains.com/teamcity/ + | TravisCI -- http://travis-ci.org/ + | UnknownVendor + deriving ( Eq, Show, TH.Lift ) + +instance Aeson.FromJSON CI where + parseJSON = Aeson.withText "String" $ \case + "APPVEYOR" -> return AppVeyor + "AZURE_PIPELINES" -> return AzurePipelines + "BAMBOO" -> return Bamboo + "BITBUCKET" -> return BitbucketPipelines + "BITRISE" -> return Bitrise + "BUDDY" -> return Buddy + "BUILDKITE" -> return Buildkite + "CIRCLE" -> return CircleCI + "CIRRUS" -> return CirrusCI + "CODEBUILD" -> return AWSCodeBuild + "CODESHIP" -> return Codeship + "DRONE" -> return Drone + "DSARI" -> return Dsari + "GITLAB" -> return GitLabCI + "GOCD" -> return GoCD + "HUDSON" -> return Hudson + "JENKINS" -> return Jenkins + "MAGNUM" -> return MagnumCI + "NETLIFY" -> return NetlifyCI + "NEVERCODE" -> return Nevercode + "SAIL" -> return SailCI + "SEMAPHORE" -> return Semaphore + "SHIPPABLE" -> return Shippable + "SOLANO" -> return SolanoCI + "STRIDER" -> return StriderCD + "TASKCLUSTER" -> return TaskCluster + "TEAMCITY" -> return TeamCity + "TRAVIS" -> return TravisCI + unknownVendor -> + fail $ "Unknown vendor name: " <> T.unpack unknownVendor + +instance (TH.Lift k, TH.Lift v) => TH.Lift (HashMap k v) where + lift hashMap = [|HashMap.fromList $(TH.lift $ HashMap.toList hashMap)|] + +data VendorEnv = VendorEnvString !Text + | VendorEnvList ![Text] + | VendorEnvObject !(HashMap Text Text) + deriving ( Eq, Show, TH.Lift ) + +instance Aeson.FromJSON VendorEnv where + parseJSON val = case val of + Aeson.String text -> return $ VendorEnvString text + Aeson.Array _ -> VendorEnvList <$> Aeson.parseJSON val + Aeson.Object _ -> VendorEnvObject <$> Aeson.parseJSON val + _ -> fail "expected String, List[String], or Map[String, String] in vendor env" + +data Vendor = + Vendor { vendorName :: Text, vendorConstant :: CI, vendorEnv :: VendorEnv } + deriving ( Eq, Show, TH.Lift ) + +$(Aeson.deriveFromJSON (Aeson.aesonDrop (T.length "vendor") + Aeson.snakeCase) { Aeson.omitNothingFields = True + } + ''Vendor) + +getVendors :: IO [Vendor] +getVendors = do + response <- Wreq.get vendorsUrl + either fail return $ Aeson.eitherDecode $ response ^. Wreq.responseBody + where + vendorsUrl = + "https://raw.githubusercontent.com/watson/ci-info/master/vendors.json" diff --git a/stack.yaml b/stack.yaml new file mode 100644 index 0000000..d56f56d --- /dev/null +++ b/stack.yaml @@ -0,0 +1,64 @@ +# This file was automatically generated by 'stack init' +# +# Some commonly used options have been documented as comments in this file. +# For advanced use and comprehensive documentation of the format, please see: +# https://docs.haskellstack.org/en/stable/yaml_configuration/ + +# Resolver to choose a 'specific' stackage snapshot or a compiler version. +# A snapshot resolver dictates the compiler version and the set of packages +# to be used for project dependencies. For example: +# +# resolver: lts-3.5 +# resolver: nightly-2015-09-21 +# resolver: ghc-7.10.2 +# +# The location of a snapshot can be provided as a file or url. Stack assumes +# a snapshot provided as a file might change, whereas a url resource does not. +# +# resolver: ./custom-snapshot.yaml +# resolver: https://example.com/snapshots/2018-01-01.yaml +resolver: lts-13.25 + +# User packages to be built. +# Various formats can be used as shown in the example below. +# +# packages: +# - some-directory +# - https://example.com/foo/bar/baz-0.0.2.tar.gz +# - location: +# git: https://github.com/commercialhaskell/stack.git +# commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a +# - location: https://github.com/commercialhaskell/stack/commit/e7b331f14bcffb8367cd58fbfc8b40ec7642100a +# subdirs: +# - auto-update +# - wai +packages: +- . +# Dependency packages to be pulled from upstream that are not in the resolver +# using the same syntax as the packages field. +# (e.g., acme-missiles-0.3) +# extra-deps: [] + +# Override default flag values for local packages and extra-deps +# flags: {} + +# Extra package databases containing global packages +# extra-package-dbs: [] + +# Control whether we use the GHC we find on the path +# system-ghc: true +# +# Require a specific version of stack, using version ranges +# require-stack-version: -any # Default +# require-stack-version: ">=1.9" +# +# Override the architecture used by stack, especially useful on Windows +# arch: i386 +# arch: x86_64 +# +# Extra directories used by stack for building +# extra-include-dirs: [/path/to/dir] +# extra-lib-dirs: [/path/to/dir] +# +# Allow a newer minor version of GHC than the snapshot specifies +# compiler-check: newer-minor From a089209f65700dec4e85d21297c459e9e256d7bc Mon Sep 17 00:00:00 2001 From: Ajeet D'Souza <98ajeet@gmail.com> Date: Mon, 10 Jun 2019 20:05:59 +0530 Subject: [PATCH 2/7] Expose only CI module --- package.yaml | 7 ++++--- src/CI.hs | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/package.yaml b/package.yaml index 6dca4b2..b3940b3 100644 --- a/package.yaml +++ b/package.yaml @@ -6,9 +6,6 @@ author: "Ajeet D'Souza" maintainer: "build@hasura.io" copyright: "2019 Hasura Inc." -ghc-options: -- -Wall - extra-source-files: - README.md @@ -25,5 +22,9 @@ dependencies: - unordered-containers - wreq +ghc-options: +- -Wall + library: + exposed-modules: CI source-dirs: src diff --git a/src/CI.hs b/src/CI.hs index ab520d0..0c2fecc 100644 --- a/src/CI.hs +++ b/src/CI.hs @@ -1,7 +1,7 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TemplateHaskell #-} -module CI ( isCI, getCI ) where +module CI ( CI(..), isCI, getCI ) where import CI.Types ( CI ) import qualified CI.Types as CI From 9cab06b9bb7809cd1a74a273df71c66e93857547 Mon Sep 17 00:00:00 2001 From: Ajeet D'Souza <98ajeet@gmail.com> Date: Tue, 11 Jun 2019 13:53:13 +0530 Subject: [PATCH 3/7] Add vendors.json locally --- package.yaml | 3 +- res/vendors.json | 159 +++++++++++++++++++++++++++++++++++++++++++++++ src/CI.hs | 64 ++++++++++--------- src/CI/TH.hs | 20 ++++++ src/CI/Types.hs | 138 +++++++++++++++++----------------------- 5 files changed, 271 insertions(+), 113 deletions(-) create mode 100644 res/vendors.json create mode 100644 src/CI/TH.hs diff --git a/package.yaml b/package.yaml index b3940b3..aa88e86 100644 --- a/package.yaml +++ b/package.yaml @@ -15,12 +15,11 @@ dependencies: - base >= 4.7 && < 5 - aeson - aeson-casing -- lens +- hashable - template-haskell - th-lift-instances - text - unordered-containers -- wreq ghc-options: - -Wall diff --git a/res/vendors.json b/res/vendors.json new file mode 100644 index 0000000..2e691b0 --- /dev/null +++ b/res/vendors.json @@ -0,0 +1,159 @@ +[ + { + "name": "AppVeyor", + "constant": "APPVEYOR", + "env": "APPVEYOR", + "pr": "APPVEYOR_PULL_REQUEST_NUMBER" + }, + { + "name": "Azure Pipelines", + "constant": "AZURE_PIPELINES", + "env": "SYSTEM_TEAMFOUNDATIONCOLLECTIONURI", + "pr": "SYSTEM_PULLREQUEST_PULLREQUESTID" + }, + { + "name": "Bamboo", + "constant": "BAMBOO", + "env": "bamboo_planKey" + }, + { + "name": "Bitbucket Pipelines", + "constant": "BITBUCKET", + "env": "BITBUCKET_COMMIT", + "pr": "BITBUCKET_PR_ID" + }, + { + "name": "Bitrise", + "constant": "BITRISE", + "env": "BITRISE_IO", + "pr": "BITRISE_PULL_REQUEST" + }, + { + "name": "Buddy", + "constant": "BUDDY", + "env": "BUDDY_WORKSPACE_ID", + "pr": "BUDDY_EXECUTION_PULL_REQUEST_ID" + }, + { + "name": "Buildkite", + "constant": "BUILDKITE", + "env": "BUILDKITE", + "pr": { "env": "BUILDKITE_PULL_REQUEST", "ne": "false" } + }, + { + "name": "CircleCI", + "constant": "CIRCLE", + "env": "CIRCLECI", + "pr": "CIRCLE_PULL_REQUEST" + }, + { + "name": "Cirrus CI", + "constant": "CIRRUS", + "env": "CIRRUS_CI", + "pr": "CIRRUS_PR" + }, + { + "name": "AWS CodeBuild", + "constant": "CODEBUILD", + "env": "CODEBUILD_BUILD_ARN" + }, + { + "name": "Codeship", + "constant": "CODESHIP", + "env": { "CI_NAME": "codeship" } + }, + { + "name": "Drone", + "constant": "DRONE", + "env": "DRONE", + "pr": { "DRONE_BUILD_EVENT": "pull_request" } + }, + { + "name": "dsari", + "constant": "DSARI", + "env": "DSARI" + }, + { + "name": "GitLab CI", + "constant": "GITLAB", + "env": "GITLAB_CI" + }, + { + "name": "GoCD", + "constant": "GOCD", + "env": "GO_PIPELINE_LABEL" + }, + { + "name": "Hudson", + "constant": "HUDSON", + "env": "HUDSON_URL" + }, + { + "name": "Jenkins", + "constant": "JENKINS", + "env": ["JENKINS_URL", "BUILD_ID"], + "pr": { "any": ["ghprbPullId", "CHANGE_ID"] } + }, + { + "name": "Magnum CI", + "constant": "MAGNUM", + "env": "MAGNUM" + }, + { + "name": "Netlify CI", + "constant": "NETLIFY", + "env": "NETLIFY_BUILD_BASE", + "pr": { "env": "PULL_REQUEST", "ne": "false" } + }, + { + "name": "Nevercode", + "constant": "NEVERCODE", + "env": "NEVERCODE", + "pr": { "env": "NEVERCODE_PULL_REQUEST", "ne": "false" } + }, + { + "name": "Sail CI", + "constant": "SAIL", + "env": "SAILCI", + "pr": "SAIL_PULL_REQUEST_NUMBER" + }, + { + "name": "Semaphore", + "constant": "SEMAPHORE", + "env": "SEMAPHORE", + "pr": "PULL_REQUEST_NUMBER" + }, + { + "name": "Shippable", + "constant": "SHIPPABLE", + "env": "SHIPPABLE", + "pr": { "IS_PULL_REQUEST": "true" } + }, + { + "name": "Solano CI", + "constant": "SOLANO", + "env": "TDDIUM", + "pr": "TDDIUM_PR_ID" + }, + { + "name": "Strider CD", + "constant": "STRIDER", + "env": "STRIDER" + }, + { + "name": "TaskCluster", + "constant": "TASKCLUSTER", + "env": ["TASK_ID", "RUN_ID"] + }, + { + "name": "TeamCity", + "constant": "TEAMCITY", + "env": "TEAMCITY_VERSION" + }, + { + "name": "Travis CI", + "constant": "TRAVIS", + "env": "TRAVIS", + "pr": { "env": "TRAVIS_PULL_REQUEST", "ne": "false" } + } +] diff --git a/src/CI.hs b/src/CI.hs index 0c2fecc..cff6e5d 100644 --- a/src/CI.hs +++ b/src/CI.hs @@ -1,47 +1,53 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TemplateHaskell #-} -module CI ( CI(..), isCI, getCI ) where +module CI ( Types.CI(..), isCI, getCI ) where -import CI.Types ( CI ) -import qualified CI.Types as CI +import CI.TH ( getVendors ) +import qualified CI.Types as Types -import Control.Arrow ( (***) ) +import Control.Arrow ( (***) ) -import Data.Bool ( bool ) -import Data.Foldable ( find ) -import qualified Data.HashMap.Strict as HashMap -import Data.Maybe ( isJust ) -import qualified Data.Text as T +import Data.Bool ( bool ) +import Data.Foldable ( find ) +import qualified Data.HashMap.Strict as HashMap +import Data.Maybe ( isJust ) +import qualified Data.Text as T -import qualified Language.Haskell.TH as TH -import qualified Language.Haskell.TH.Syntax as TH +import System.Environment ( getEnvironment ) -import System.Environment ( getEnvironment ) +vendors :: [Types.Vendor] +vendors = $(getVendors) -vendors :: [CI.Vendor] -vendors = $(TH.runIO CI.getVendors >>= TH.lift) - -getCI :: IO (Maybe CI) +getCI :: IO (Maybe Types.CI) getCI = do - env <- HashMap.fromList . map (T.pack *** T.pack) <$> getEnvironment + env <- mkEnvMap <$> getEnvironment let maybeVendor = find (checkVendor env) vendors return $ case maybeVendor of - Nothing -> bool Nothing (Just CI.UnknownVendor) $ - any (`HashMap.member` env) -- check vendor neutral environment variables - [ "CI" -- Travis CI, CircleCI, Cirrus CI, Gitlab CI, Appveyor, CodeShip, dsari - , "CONTINUOUS_INTEGRATION" -- Travis CI, Cirrus CI - , "BUILD_NUMBER" -- Jenkins, TeamCity - , "RUN_ID" -- TaskCluster, dsari - ] - Just vendor -> Just $ CI.vendorConstant vendor + Nothing -> bool Nothing (Just Types.CI_UNKNOWN_VENDOR) $ + checkUnknownVendor env + Just vendor -> Just $ Types.vendorConstant vendor where - checkVendor env vendor = case CI.vendorEnv vendor of - (CI.VendorEnvString text) -> HashMap.member text env - (CI.VendorEnvList list) -> all (`HashMap.member` env) list - (CI.VendorEnvObject hashMap) -> + checkVendor env vendor = case Types.vendorEnv vendor of + (Types.VendorEnvString text) -> HashMap.member text env + (Types.VendorEnvList list) -> all (`HashMap.member` env) list + (Types.VendorEnvObject hashMap) -> all (\(k, v) -> HashMap.lookup k env == Just v) $ HashMap.toList hashMap + -- check vendor neutral environment variables + checkUnknownVendor env = any (`HashMap.member` env) unknownVendorEnvVars + + unknownVendorEnvVars = + map Types.EnvVarName + [ "CI" -- Travis CI, CircleCI, Cirrus CI, Gitlab CI, Appveyor, CodeShip, dsari + , "CONTINUOUS_INTEGRATION" -- Travis CI, Cirrus CI + , "BUILD_NUMBER" -- Jenkins, TeamCity + , "RUN_ID" -- TaskCluster, dsari + ] + + mkEnvMap = HashMap.fromList + . map (Types.EnvVarName . T.pack *** Types.EnvVarValue . T.pack) + isCI :: IO Bool isCI = isJust <$> getCI diff --git a/src/CI/TH.hs b/src/CI/TH.hs new file mode 100644 index 0000000..06d32f8 --- /dev/null +++ b/src/CI/TH.hs @@ -0,0 +1,20 @@ +module CI.TH ( getVendors ) where + +import qualified CI.Types as Types + +import qualified Data.Aeson as Aeson + +import qualified Language.Haskell.TH as TH +import qualified Language.Haskell.TH.Syntax as TH + +getVendors :: TH.Q TH.Exp +getVendors = TH.runIO readVendors >>= TH.lift + where + vendorsPath = "res/vendors.json" + + readVendors :: IO [Types.Vendor] + readVendors = do + vendors <- Aeson.eitherDecodeFileStrict' vendorsPath + case vendors of + Left e -> fail $ "parsing vendors.json failed: " <> e + Right v -> return v diff --git a/src/CI/Types.hs b/src/CI/Types.hs index 73b0fb3..8120abf 100644 --- a/src/CI/Types.hs +++ b/src/CI/Types.hs @@ -1,4 +1,5 @@ {-# LANGUAGE DeriveLift #-} +{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TemplateHaskell #-} @@ -7,13 +8,12 @@ module CI.Types where -import Control.Lens ( (^.) ) - import qualified Data.Aeson as Aeson import qualified Data.Aeson.Casing as Aeson import qualified Data.Aeson.TH as Aeson import Data.HashMap.Strict ( HashMap ) import qualified Data.HashMap.Strict as HashMap +import Data.Hashable ( Hashable ) import Data.Text ( Text ) import qualified Data.Text as T @@ -21,101 +21,75 @@ import Instances.TH.Lift () import qualified Language.Haskell.TH.Syntax as TH -import qualified Network.Wreq as Wreq - data CI = - AWSCodeBuild -- https://aws.amazon.com/codebuild/ - | AppVeyor -- http://www.appveyor.com/ - | AzurePipelines -- https://azure.microsoft.com/en-us/services/devops/pipelines/ - | Bamboo -- https://www.atlassian.com/software/bamboo/ - | BitbucketPipelines -- https://bitbucket.org/product/features/pipelines/ - | Bitrise -- https://www.bitrise.io/ - | Buddy -- https://buddy.works/ - | Buildkite -- https://buildkite.com/ - | CircleCI -- http://circleci.com/ - | CirrusCI -- https://cirrus-ci.org/ - | Codeship -- https://codeship.com/ - | Drone -- https://drone.io/ - | Dsari -- https://github.com/rfinnie/dsari/ - | GitLabCI -- https://about.gitlab.com/gitlab-ci/ - | GoCD -- https://www.go.cd/ - | Hudson -- http://hudson-ci.org/ - | Jenkins -- https://jenkins-ci.org/ - | MagnumCI -- https://magnum-ci.com/ - | NetlifyCI -- https://www.netlify.com/ - | Nevercode -- http://nevercode.io/ - | SailCI -- https://sail.ci/ - | Semaphore -- https://semaphoreci.com/ - | Shippable -- https://www.shippable.com/ - | SolanoCI -- https://www.solanolabs.com/ - | StriderCD -- https://strider-cd.github.io/ - | TaskCluster -- http://docs.taskcluster.net/ - | TeamCity -- https://www.jetbrains.com/teamcity/ - | TravisCI -- http://travis-ci.org/ - | UnknownVendor + CI_APPVEYOR -- http://www.appveyor.com/ + | CI_AZURE_PIPELINES -- https://azure.microsoft.com/en-us/services/devops/pipelines/ + | CI_BAMBOO -- https://www.atlassian.com/software/bamboo/ + | CI_BITBUCKET -- https://bitbucket.org/product/features/pipelines/ + | CI_BITRISE -- https://www.bitrise.io/ + | CI_BUDDY -- https://buddy.works/ + | CI_BUILDKITE -- https://buildkite.com/ + | CI_CIRCLE -- http://circleci.com/ + | CI_CIRRUS -- https://cirrus-ci.org/ + | CI_CODEBUILD -- https://aws.amazon.com/codebuild/ + | CI_CODESHIP -- https://codeship.com/ + | CI_DRONE -- https://drone.io/ + | CI_DSARI -- https://github.com/rfinnie/dsari/ + | CI_GITLAB -- https://about.gitlab.com/gitlab-ci/ + | CI_GOCD -- https://www.go.cd/ + | CI_HUDSON -- http://hudson-ci.org/ + | CI_JENKINS -- https://jenkins-ci.org/ + | CI_MAGNUM -- https://magnum-ci.com/ + | CI_NETLIFY -- https://www.netlify.com/ + | CI_NEVERCODE -- http://nevercode.io/ + | CI_SAIL -- https://sail.ci/ + | CI_SEMAPHORE -- https://semaphoreci.com/ + | CI_SHIPPABLE -- https://www.shippable.com/ + | CI_SOLANO -- https://www.solanolabs.com/ + | CI_STRIDER -- https://strider-cd.github.io/ + | CI_TASKCLUSTER -- http://docs.taskcluster.net/ + | CI_TEAMCITY -- https://www.jetbrains.com/teamcity/ + | CI_TRAVIS -- http://travis-ci.org/ + | CI_UNKNOWN_VENDOR deriving ( Eq, Show, TH.Lift ) -instance Aeson.FromJSON CI where - parseJSON = Aeson.withText "String" $ \case - "APPVEYOR" -> return AppVeyor - "AZURE_PIPELINES" -> return AzurePipelines - "BAMBOO" -> return Bamboo - "BITBUCKET" -> return BitbucketPipelines - "BITRISE" -> return Bitrise - "BUDDY" -> return Buddy - "BUILDKITE" -> return Buildkite - "CIRCLE" -> return CircleCI - "CIRRUS" -> return CirrusCI - "CODEBUILD" -> return AWSCodeBuild - "CODESHIP" -> return Codeship - "DRONE" -> return Drone - "DSARI" -> return Dsari - "GITLAB" -> return GitLabCI - "GOCD" -> return GoCD - "HUDSON" -> return Hudson - "JENKINS" -> return Jenkins - "MAGNUM" -> return MagnumCI - "NETLIFY" -> return NetlifyCI - "NEVERCODE" -> return Nevercode - "SAIL" -> return SailCI - "SEMAPHORE" -> return Semaphore - "SHIPPABLE" -> return Shippable - "SOLANO" -> return SolanoCI - "STRIDER" -> return StriderCD - "TASKCLUSTER" -> return TaskCluster - "TEAMCITY" -> return TeamCity - "TRAVIS" -> return TravisCI - unknownVendor -> - fail $ "Unknown vendor name: " <> T.unpack unknownVendor +$(Aeson.deriveJSON Aeson.defaultOptions { Aeson.constructorTagModifier = + drop $ T.length "CI_" + } + ''CI) instance (TH.Lift k, TH.Lift v) => TH.Lift (HashMap k v) where lift hashMap = [|HashMap.fromList $(TH.lift $ HashMap.toList hashMap)|] -data VendorEnv = VendorEnvString !Text - | VendorEnvList ![Text] - | VendorEnvObject !(HashMap Text Text) +newtype EnvVarName = EnvVarName { unEnvVarName :: Text } + deriving ( Eq, Hashable, Show, Aeson.FromJSON, Aeson.FromJSONKey + , Aeson.ToJSON, Aeson.ToJSONKey, TH.Lift ) + +newtype EnvVarValue = EnvVarValue { unEnvVarValue :: Text } + deriving ( Eq, Show, Aeson.FromJSON, Aeson.ToJSON, TH.Lift ) + +data VendorEnv = VendorEnvString !EnvVarName + | VendorEnvList ![EnvVarName] + | VendorEnvObject !(HashMap EnvVarName EnvVarValue) deriving ( Eq, Show, TH.Lift ) instance Aeson.FromJSON VendorEnv where parseJSON val = case val of - Aeson.String text -> return $ VendorEnvString text + Aeson.String _ -> VendorEnvString <$> Aeson.parseJSON val Aeson.Array _ -> VendorEnvList <$> Aeson.parseJSON val Aeson.Object _ -> VendorEnvObject <$> Aeson.parseJSON val _ -> fail "expected String, List[String], or Map[String, String] in vendor env" +instance Aeson.ToJSON VendorEnv where + toJSON val = case val of + VendorEnvString key -> Aeson.toJSON key + VendorEnvList list -> Aeson.toJSON list + VendorEnvObject object -> Aeson.toJSON object + +newtype VendorName = VendorName {unVendorName :: Text} deriving (Eq, Show, Aeson.FromJSON, Aeson.ToJSON, TH.Lift) + data Vendor = - Vendor { vendorName :: Text, vendorConstant :: CI, vendorEnv :: VendorEnv } + Vendor { vendorName :: !VendorName, vendorConstant :: !CI, vendorEnv :: !VendorEnv } deriving ( Eq, Show, TH.Lift ) -$(Aeson.deriveFromJSON (Aeson.aesonDrop (T.length "vendor") - Aeson.snakeCase) { Aeson.omitNothingFields = True - } - ''Vendor) - -getVendors :: IO [Vendor] -getVendors = do - response <- Wreq.get vendorsUrl - either fail return $ Aeson.eitherDecode $ response ^. Wreq.responseBody - where - vendorsUrl = - "https://raw.githubusercontent.com/watson/ci-info/master/vendors.json" +$(Aeson.deriveJSON (Aeson.aesonPrefix Aeson.snakeCase) ''Vendor) From fbccd98f07e7ee079816f1a49e57004d94c3ba06 Mon Sep 17 00:00:00 2001 From: Ajeet D'Souza <98ajeet@gmail.com> Date: Tue, 11 Jun 2019 15:13:14 +0530 Subject: [PATCH 4/7] Update README --- README.md | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 50dcd44..521937e 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,19 @@ # ci-info-hs - Get details about the current Continuous Integration environment - Haskell port of https://github.com/watson/ci-info + +Checks if the current environment is a Continuous Integration server. + +This is a Haskell port of [watson/ci-info](https://github.com/watson/ci-info). + +## Usage + +Check if the current environment is a CI server: + +```haskell +isCI :: IO Bool +``` + +Get the name of the CI vendor. Returns `Nothing` if no CI could be detected. Returns `Just CI_UNKNOWN_VENDOR` if a CI was detected, but the vendor name could not be determined: + +```haskell +getCI :: IO (Maybe CI) +``` From f8b1da317ee520a60fe446bada8c1998141fffd9 Mon Sep 17 00:00:00 2001 From: Ajeet D'Souza <98ajeet@gmail.com> Date: Tue, 11 Jun 2019 15:56:43 +0530 Subject: [PATCH 5/7] Add ghc-options --- package.yaml | 7 +++++++ src/CI/Types.hs | 17 +++++++++++++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/package.yaml b/package.yaml index aa88e86..7ec4e93 100644 --- a/package.yaml +++ b/package.yaml @@ -23,6 +23,13 @@ dependencies: ghc-options: - -Wall +- -Wincomplete-uni-patterns +- -Wincomplete-record-updates +- -Wcompat +- -Widentities +- -Wredundant-constraints +- -Wmissing-export-lists +- -Wpartial-fields library: exposed-modules: CI diff --git a/src/CI/Types.hs b/src/CI/Types.hs index 8120abf..e7779e5 100644 --- a/src/CI/Types.hs +++ b/src/CI/Types.hs @@ -6,7 +6,13 @@ {-# OPTIONS_GHC -fno-warn-orphans #-} -module CI.Types where +module CI.Types + ( CI(..) + , Vendor(..) + , VendorEnv(..) + , EnvVarName(..) + , EnvVarValue(..) + ) where import qualified Data.Aeson as Aeson import qualified Data.Aeson.Casing as Aeson @@ -86,10 +92,13 @@ instance Aeson.ToJSON VendorEnv where VendorEnvList list -> Aeson.toJSON list VendorEnvObject object -> Aeson.toJSON object -newtype VendorName = VendorName {unVendorName :: Text} deriving (Eq, Show, Aeson.FromJSON, Aeson.ToJSON, TH.Lift) +newtype VendorName = VendorName { unVendorName :: Text } + deriving ( Eq, Show, Aeson.FromJSON, Aeson.ToJSON, TH.Lift ) -data Vendor = - Vendor { vendorName :: !VendorName, vendorConstant :: !CI, vendorEnv :: !VendorEnv } +data Vendor = Vendor { vendorName :: !VendorName + , vendorConstant :: !CI + , vendorEnv :: !VendorEnv + } deriving ( Eq, Show, TH.Lift ) $(Aeson.deriveJSON (Aeson.aesonPrefix Aeson.snakeCase) ''Vendor) From d593f919be8d27677181903d39091d74489466e3 Mon Sep 17 00:00:00 2001 From: Ajeet D'Souza <98ajeet@gmail.com> Date: Thu, 13 Jun 2019 13:09:53 +0530 Subject: [PATCH 6/7] Format with stylish-haskell --- src/CI.hs | 58 +++++++++++------------ src/CI/TH.hs | 12 ++--- src/CI/Types.hs | 121 +++++++++++++++++++++++------------------------- 3 files changed, 92 insertions(+), 99 deletions(-) diff --git a/src/CI.hs b/src/CI.hs index cff6e5d..bf2e926 100644 --- a/src/CI.hs +++ b/src/CI.hs @@ -1,53 +1,51 @@ {-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE TemplateHaskell #-} -module CI ( Types.CI(..), isCI, getCI ) where +module CI (Types.CI(..), isCI, getCI) where -import CI.TH ( getVendors ) +import CI.TH (getVendors) import qualified CI.Types as Types - -import Control.Arrow ( (***) ) - -import Data.Bool ( bool ) -import Data.Foldable ( find ) +import Control.Arrow ((***)) +import Data.Bool (bool) +import Data.Foldable (find) import qualified Data.HashMap.Strict as HashMap -import Data.Maybe ( isJust ) +import Data.Maybe (isJust) import qualified Data.Text as T - -import System.Environment ( getEnvironment ) +import System.Environment (getEnvironment) vendors :: [Types.Vendor] vendors = $(getVendors) getCI :: IO (Maybe Types.CI) getCI = do - env <- mkEnvMap <$> getEnvironment - let maybeVendor = find (checkVendor env) vendors - return $ case maybeVendor of - Nothing -> bool Nothing (Just Types.CI_UNKNOWN_VENDOR) $ - checkUnknownVendor env - Just vendor -> Just $ Types.vendorConstant vendor + env <- mkEnvMap <$> getEnvironment + let maybeVendor = find (checkVendor env) vendors + return + $ case maybeVendor of + Nothing -> bool Nothing (Just Types.CI_UNKNOWN_VENDOR) + $ checkUnknownVendor env + Just vendor -> Just $ Types.vendorConstant vendor where checkVendor env vendor = case Types.vendorEnv vendor of - (Types.VendorEnvString text) -> HashMap.member text env - (Types.VendorEnvList list) -> all (`HashMap.member` env) list - (Types.VendorEnvObject hashMap) -> - all (\(k, v) -> HashMap.lookup k env == Just v) $ - HashMap.toList hashMap + (Types.VendorEnvString text) -> HashMap.member text env + (Types.VendorEnvList list) -> all (`HashMap.member` env) list + (Types.VendorEnvObject hashMap) -> all + (\(k, v) -> HashMap.lookup k env == Just v) + $ HashMap.toList hashMap -- check vendor neutral environment variables checkUnknownVendor env = any (`HashMap.member` env) unknownVendorEnvVars - unknownVendorEnvVars = - map Types.EnvVarName - [ "CI" -- Travis CI, CircleCI, Cirrus CI, Gitlab CI, Appveyor, CodeShip, dsari - , "CONTINUOUS_INTEGRATION" -- Travis CI, Cirrus CI - , "BUILD_NUMBER" -- Jenkins, TeamCity - , "RUN_ID" -- TaskCluster, dsari - ] + unknownVendorEnvVars = map + Types.EnvVarName + [ "CI" -- Travis CI, CircleCI, Cirrus CI, Gitlab CI, Appveyor, CodeShip, dsari + , "CONTINUOUS_INTEGRATION" -- Travis CI, Cirrus CI + , "BUILD_NUMBER" -- Jenkins, TeamCity + , "RUN_ID" -- TaskCluster, dsari + ] mkEnvMap = HashMap.fromList - . map (Types.EnvVarName . T.pack *** Types.EnvVarValue . T.pack) + . map (Types.EnvVarName . T.pack *** Types.EnvVarValue . T.pack) isCI :: IO Bool isCI = isJust <$> getCI diff --git a/src/CI/TH.hs b/src/CI/TH.hs index 06d32f8..578d1b9 100644 --- a/src/CI/TH.hs +++ b/src/CI/TH.hs @@ -1,9 +1,7 @@ -module CI.TH ( getVendors ) where +module CI.TH (getVendors) where import qualified CI.Types as Types - import qualified Data.Aeson as Aeson - import qualified Language.Haskell.TH as TH import qualified Language.Haskell.TH.Syntax as TH @@ -14,7 +12,7 @@ getVendors = TH.runIO readVendors >>= TH.lift readVendors :: IO [Types.Vendor] readVendors = do - vendors <- Aeson.eitherDecodeFileStrict' vendorsPath - case vendors of - Left e -> fail $ "parsing vendors.json failed: " <> e - Right v -> return v + vendors <- Aeson.eitherDecodeFileStrict' vendorsPath + case vendors of + Left e -> fail $ "parsing vendors.json failed: " <> e + Right v -> return v diff --git a/src/CI/Types.hs b/src/CI/Types.hs index e7779e5..1082cd0 100644 --- a/src/CI/Types.hs +++ b/src/CI/Types.hs @@ -1,8 +1,8 @@ -{-# LANGUAGE DeriveLift #-} +{-# LANGUAGE DeriveLift #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} -{-# LANGUAGE LambdaCase #-} -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE TemplateHaskell #-} {-# OPTIONS_GHC -fno-warn-orphans #-} @@ -11,94 +11,91 @@ module CI.Types , Vendor(..) , VendorEnv(..) , EnvVarName(..) - , EnvVarValue(..) - ) where + , EnvVarValue(..)) where import qualified Data.Aeson as Aeson import qualified Data.Aeson.Casing as Aeson import qualified Data.Aeson.TH as Aeson -import Data.HashMap.Strict ( HashMap ) +import Data.Hashable (Hashable) +import Data.HashMap.Strict (HashMap) import qualified Data.HashMap.Strict as HashMap -import Data.Hashable ( Hashable ) -import Data.Text ( Text ) +import Data.Text (Text) import qualified Data.Text as T - import Instances.TH.Lift () - import qualified Language.Haskell.TH.Syntax as TH data CI = - CI_APPVEYOR -- http://www.appveyor.com/ - | CI_AZURE_PIPELINES -- https://azure.microsoft.com/en-us/services/devops/pipelines/ - | CI_BAMBOO -- https://www.atlassian.com/software/bamboo/ - | CI_BITBUCKET -- https://bitbucket.org/product/features/pipelines/ - | CI_BITRISE -- https://www.bitrise.io/ - | CI_BUDDY -- https://buddy.works/ - | CI_BUILDKITE -- https://buildkite.com/ - | CI_CIRCLE -- http://circleci.com/ - | CI_CIRRUS -- https://cirrus-ci.org/ - | CI_CODEBUILD -- https://aws.amazon.com/codebuild/ - | CI_CODESHIP -- https://codeship.com/ - | CI_DRONE -- https://drone.io/ - | CI_DSARI -- https://github.com/rfinnie/dsari/ - | CI_GITLAB -- https://about.gitlab.com/gitlab-ci/ - | CI_GOCD -- https://www.go.cd/ - | CI_HUDSON -- http://hudson-ci.org/ - | CI_JENKINS -- https://jenkins-ci.org/ - | CI_MAGNUM -- https://magnum-ci.com/ - | CI_NETLIFY -- https://www.netlify.com/ - | CI_NEVERCODE -- http://nevercode.io/ - | CI_SAIL -- https://sail.ci/ - | CI_SEMAPHORE -- https://semaphoreci.com/ - | CI_SHIPPABLE -- https://www.shippable.com/ - | CI_SOLANO -- https://www.solanolabs.com/ - | CI_STRIDER -- https://strider-cd.github.io/ - | CI_TASKCLUSTER -- http://docs.taskcluster.net/ - | CI_TEAMCITY -- https://www.jetbrains.com/teamcity/ - | CI_TRAVIS -- http://travis-ci.org/ - | CI_UNKNOWN_VENDOR - deriving ( Eq, Show, TH.Lift ) - -$(Aeson.deriveJSON Aeson.defaultOptions { Aeson.constructorTagModifier = - drop $ T.length "CI_" - } - ''CI) + CI_APPVEYOR -- http://www.appveyor.com/ + | CI_AZURE_PIPELINES -- https://azure.microsoft.com/en-us/services/devops/pipelines/ + | CI_BAMBOO -- https://www.atlassian.com/software/bamboo/ + | CI_BITBUCKET -- https://bitbucket.org/product/features/pipelines/ + | CI_BITRISE -- https://www.bitrise.io/ + | CI_BUDDY -- https://buddy.works/ + | CI_BUILDKITE -- https://buildkite.com/ + | CI_CIRCLE -- http://circleci.com/ + | CI_CIRRUS -- https://cirrus-ci.org/ + | CI_CODEBUILD -- https://aws.amazon.com/codebuild/ + | CI_CODESHIP -- https://codeship.com/ + | CI_DRONE -- https://drone.io/ + | CI_DSARI -- https://github.com/rfinnie/dsari/ + | CI_GITLAB -- https://about.gitlab.com/gitlab-ci/ + | CI_GOCD -- https://www.go.cd/ + | CI_HUDSON -- http://hudson-ci.org/ + | CI_JENKINS -- https://jenkins-ci.org/ + | CI_MAGNUM -- https://magnum-ci.com/ + | CI_NETLIFY -- https://www.netlify.com/ + | CI_NEVERCODE -- http://nevercode.io/ + | CI_SAIL -- https://sail.ci/ + | CI_SEMAPHORE -- https://semaphoreci.com/ + | CI_SHIPPABLE -- https://www.shippable.com/ + | CI_SOLANO -- https://www.solanolabs.com/ + | CI_STRIDER -- https://strider-cd.github.io/ + | CI_TASKCLUSTER -- http://docs.taskcluster.net/ + | CI_TEAMCITY -- https://www.jetbrains.com/teamcity/ + | CI_TRAVIS -- http://travis-ci.org/ + | CI_UNKNOWN_VENDOR + deriving (Eq, Show, TH.Lift) + +$(Aeson.deriveJSON + Aeson.defaultOptions { Aeson.constructorTagModifier = drop $ T.length "CI_" } + ''CI) instance (TH.Lift k, TH.Lift v) => TH.Lift (HashMap k v) where - lift hashMap = [|HashMap.fromList $(TH.lift $ HashMap.toList hashMap)|] + lift hashMap = [|HashMap.fromList $(TH.lift $ HashMap.toList hashMap)|] newtype EnvVarName = EnvVarName { unEnvVarName :: Text } - deriving ( Eq, Hashable, Show, Aeson.FromJSON, Aeson.FromJSONKey - , Aeson.ToJSON, Aeson.ToJSONKey, TH.Lift ) + deriving (Eq, Hashable, Show, Aeson.FromJSON, Aeson.FromJSONKey, Aeson.ToJSON + , Aeson.ToJSONKey, TH.Lift) newtype EnvVarValue = EnvVarValue { unEnvVarValue :: Text } - deriving ( Eq, Show, Aeson.FromJSON, Aeson.ToJSON, TH.Lift ) + deriving (Eq, Show, Aeson.FromJSON, Aeson.ToJSON, TH.Lift) data VendorEnv = VendorEnvString !EnvVarName | VendorEnvList ![EnvVarName] | VendorEnvObject !(HashMap EnvVarName EnvVarValue) - deriving ( Eq, Show, TH.Lift ) + deriving (Eq, Show, TH.Lift) instance Aeson.FromJSON VendorEnv where - parseJSON val = case val of - Aeson.String _ -> VendorEnvString <$> Aeson.parseJSON val - Aeson.Array _ -> VendorEnvList <$> Aeson.parseJSON val - Aeson.Object _ -> VendorEnvObject <$> Aeson.parseJSON val - _ -> fail "expected String, List[String], or Map[String, String] in vendor env" + parseJSON val = case val of + Aeson.String _ -> VendorEnvString <$> Aeson.parseJSON val + Aeson.Array _ -> VendorEnvList <$> Aeson.parseJSON val + Aeson.Object _ -> VendorEnvObject <$> Aeson.parseJSON val + _ -> fail + "expected String, List[String], or Map[String, String] in vendor env" instance Aeson.ToJSON VendorEnv where - toJSON val = case val of - VendorEnvString key -> Aeson.toJSON key - VendorEnvList list -> Aeson.toJSON list - VendorEnvObject object -> Aeson.toJSON object + toJSON val = case val of + VendorEnvString key -> Aeson.toJSON key + VendorEnvList list -> Aeson.toJSON list + VendorEnvObject object -> Aeson.toJSON object newtype VendorName = VendorName { unVendorName :: Text } - deriving ( Eq, Show, Aeson.FromJSON, Aeson.ToJSON, TH.Lift ) + deriving (Eq, Show, Aeson.FromJSON, Aeson.ToJSON, TH.Lift) data Vendor = Vendor { vendorName :: !VendorName , vendorConstant :: !CI , vendorEnv :: !VendorEnv } - deriving ( Eq, Show, TH.Lift ) + deriving (Eq, Show, TH.Lift) $(Aeson.deriveJSON (Aeson.aesonPrefix Aeson.snakeCase) ''Vendor) From 09eee7716433253f2877380a09b6366fe030ee6e Mon Sep 17 00:00:00 2001 From: Ajeet D'Souza <98ajeet@gmail.com> Date: Thu, 13 Jun 2019 13:18:17 +0530 Subject: [PATCH 7/7] Reorder imports --- src/CI.hs | 18 +++++++++++++----- src/CI/TH.hs | 8 ++++++-- src/CI/Types.hs | 22 ++++++++++++---------- 3 files changed, 31 insertions(+), 17 deletions(-) diff --git a/src/CI.hs b/src/CI.hs index bf2e926..1d203a5 100644 --- a/src/CI.hs +++ b/src/CI.hs @@ -1,18 +1,26 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TemplateHaskell #-} -module CI (Types.CI(..), isCI, getCI) where +module CI + ( Types.CI(..) + , isCI + , getCI + ) where -import CI.TH (getVendors) -import qualified CI.Types as Types import Control.Arrow ((***)) import Data.Bool (bool) import Data.Foldable (find) -import qualified Data.HashMap.Strict as HashMap import Data.Maybe (isJust) -import qualified Data.Text as T import System.Environment (getEnvironment) +import CI.TH (getVendors) + +import qualified Data.HashMap.Strict as HashMap +import qualified Data.Text as T + +import qualified CI.Types as Types + + vendors :: [Types.Vendor] vendors = $(getVendors) diff --git a/src/CI/TH.hs b/src/CI/TH.hs index 578d1b9..2a615d2 100644 --- a/src/CI/TH.hs +++ b/src/CI/TH.hs @@ -1,10 +1,14 @@ -module CI.TH (getVendors) where +module CI.TH + ( getVendors + ) where -import qualified CI.Types as Types import qualified Data.Aeson as Aeson import qualified Language.Haskell.TH as TH import qualified Language.Haskell.TH.Syntax as TH +import qualified CI.Types as Types + + getVendors :: TH.Q TH.Exp getVendors = TH.runIO readVendors >>= TH.lift where diff --git a/src/CI/Types.hs b/src/CI/Types.hs index 1082cd0..02eec7c 100644 --- a/src/CI/Types.hs +++ b/src/CI/Types.hs @@ -7,23 +7,25 @@ {-# OPTIONS_GHC -fno-warn-orphans #-} module CI.Types - ( CI(..) - , Vendor(..) - , VendorEnv(..) - , EnvVarName(..) - , EnvVarValue(..)) where + ( CI(..) + , Vendor(..) + , VendorEnv(..) + , EnvVarName(..) + , EnvVarValue(..)) where + +import Data.Hashable (Hashable) +import Data.HashMap.Strict (HashMap) +import Data.Text (Text) +import Instances.TH.Lift () import qualified Data.Aeson as Aeson import qualified Data.Aeson.Casing as Aeson import qualified Data.Aeson.TH as Aeson -import Data.Hashable (Hashable) -import Data.HashMap.Strict (HashMap) import qualified Data.HashMap.Strict as HashMap -import Data.Text (Text) import qualified Data.Text as T -import Instances.TH.Lift () import qualified Language.Haskell.TH.Syntax as TH + data CI = CI_APPVEYOR -- http://www.appveyor.com/ | CI_AZURE_PIPELINES -- https://azure.microsoft.com/en-us/services/devops/pipelines/ @@ -85,7 +87,7 @@ instance Aeson.FromJSON VendorEnv where instance Aeson.ToJSON VendorEnv where toJSON val = case val of - VendorEnvString key -> Aeson.toJSON key + VendorEnvString name -> Aeson.toJSON name VendorEnvList list -> Aeson.toJSON list VendorEnvObject object -> Aeson.toJSON object