mirror of
https://github.com/aelve/guide.git
synced 2024-11-22 03:12:58 +03:00
Generate swagger.json for branches (#380)
* Generate swagger.json for branches * Fix * Fix again * Fix once more * [skip ci] Regenerate swagger.json * Don't log debug info to stdout * Push even if the branch is ahead * Fix * Empty * [skip ci] Regenerate swagger.json * Don't use "skip ci"
This commit is contained in:
parent
a100905cbf
commit
ce62066598
27
.travis.yml
27
.travis.yml
@ -47,10 +47,31 @@ jobs:
|
|||||||
- curl -sSL https://get.haskellstack.org/ | sh
|
- curl -sSL https://get.haskellstack.org/ | sh
|
||||||
# travis_retry works around https://github.com/commercialhaskell/stack/issues/4888
|
# travis_retry works around https://github.com/commercialhaskell/stack/issues/4888
|
||||||
- travis_retry stack setup
|
- travis_retry stack setup
|
||||||
|
# Decrypt the GitHub deploy key (travis_key.enc)
|
||||||
|
- openssl aes-256-cbc -k "$travis_key_password" -d -md sha256 -a -in travis_key.enc -out travis_key
|
||||||
|
- echo "Host github.com" > ~/.ssh/config
|
||||||
|
- echo " IdentityFile $(pwd)/travis_key" >> ~/.ssh/config
|
||||||
|
- chmod 400 travis_key
|
||||||
|
- git remote set-url origin git@github.com:aelve/guide.git
|
||||||
script:
|
script:
|
||||||
# Build
|
# Build
|
||||||
- stack --no-terminal build --test --no-run-tests --dependencies-only
|
- stack --no-terminal build --test --no-run-tests --dependencies-only
|
||||||
- stack --no-terminal build --test --no-run-tests
|
- stack --no-terminal build --test --no-run-tests
|
||||||
|
# Regenerate Swagger and push to the same branch, even if the branch
|
||||||
|
# is already ahead (which may happen if the previous build in the
|
||||||
|
# pipeline also pushed to it)
|
||||||
|
- |
|
||||||
|
if [ "$TRAVIS_EVENT_TYPE" = "push" ]; then
|
||||||
|
git checkout "$TRAVIS_BRANCH" && git pull
|
||||||
|
stack exec -- guide api-docs > back/swagger.json
|
||||||
|
git add back/swagger.json
|
||||||
|
# Will only push if the commit was created successfully. Note
|
||||||
|
# that we don't use "[skip ci]" in the commit message here
|
||||||
|
# because then Mergify goes "oh, but Travis hasn't passed, so I
|
||||||
|
# shouldn't merge this".
|
||||||
|
(git commit -m "Regenerate swagger.json" && git push) || true
|
||||||
|
git checkout "$TRAVIS_COMMIT"
|
||||||
|
fi
|
||||||
# Upload the Docker image
|
# Upload the Docker image
|
||||||
- |
|
- |
|
||||||
if [ "$TRAVIS_EVENT_TYPE" = "push" ]; then
|
if [ "$TRAVIS_EVENT_TYPE" = "push" ]; then
|
||||||
@ -113,3 +134,9 @@ jobs:
|
|||||||
notifications:
|
notifications:
|
||||||
slack:
|
slack:
|
||||||
secure: BgQpUYFmvXrf7HVBP/fefS/8UVwES800+fT+ufgJX8b2HMx2FvaWVsdv3ErKAryLE0B3fwmvforWugTdgLO3kq66YUgSt51SNQOBLkMVGubIoQsgvr3Ernu+Wpw1DyoMkXQH9q9O9rfCIc4IwkQCEHqu5SVRqdOd5px/CHFl/ktTI22JkT8ap/Be53qjlB2U2sWUf4GxYXq0V/gGF6fDwsUwTVKFb14RfSDrOgK5Vlce2GRf3gNr1C/j7A7EHIR/Z+rNd2hvv69cFw6TRc3s39QmP8XPe3SLZPIHTZ8vRveX1SZioMeEy747r5rHd9vylEjxWtVHhvP9fOt693+woXa8ZAl5uVRgB6S4mTWLZ+LAbqhaCmDGJYr9GrrBMoqWvJiMuBX3ZvHptsAc6O2l/fxZQU3otTE++SmHkhbyoDQkcPCjXPDUi/ZlnoLc5zfMAfApcsZZ8b9t47z12H0O4uDZd2YiNPiQJ1iUA6R879LH3pcxPB3RaoWsfXzv/klkKrU/V2K4SXD9j4/bmAFArlig+dar+Dm44L/a3/G7vbU1lQIa1bG0EqB36qgUS3UCkuy2ppti/JTHpkYx7HVF2BipoCjOVvfBl9G8RkvcQIhyuCfOGm7WL1TjrKVMccIEGJKhm7OO6wOZYCBfAI5zILxi8XEJAIvBm9NywhQlwxI=
|
secure: BgQpUYFmvXrf7HVBP/fefS/8UVwES800+fT+ufgJX8b2HMx2FvaWVsdv3ErKAryLE0B3fwmvforWugTdgLO3kq66YUgSt51SNQOBLkMVGubIoQsgvr3Ernu+Wpw1DyoMkXQH9q9O9rfCIc4IwkQCEHqu5SVRqdOd5px/CHFl/ktTI22JkT8ap/Be53qjlB2U2sWUf4GxYXq0V/gGF6fDwsUwTVKFb14RfSDrOgK5Vlce2GRf3gNr1C/j7A7EHIR/Z+rNd2hvv69cFw6TRc3s39QmP8XPe3SLZPIHTZ8vRveX1SZioMeEy747r5rHd9vylEjxWtVHhvP9fOt693+woXa8ZAl5uVRgB6S4mTWLZ+LAbqhaCmDGJYr9GrrBMoqWvJiMuBX3ZvHptsAc6O2l/fxZQU3otTE++SmHkhbyoDQkcPCjXPDUi/ZlnoLc5zfMAfApcsZZ8b9t47z12H0O4uDZd2YiNPiQJ1iUA6R879LH3pcxPB3RaoWsfXzv/klkKrU/V2K4SXD9j4/bmAFArlig+dar+Dm44L/a3/G7vbU1lQIa1bG0EqB36qgUS3UCkuy2ppti/JTHpkYx7HVF2BipoCjOVvfBl9G8RkvcQIhyuCfOGm7WL1TjrKVMccIEGJKhm7OO6wOZYCBfAI5zILxi8XEJAIvBm9NywhQlwxI=
|
||||||
|
|
||||||
|
# travis_key.enc decryption password, see:
|
||||||
|
# http://markbucciarelli.com/posts/2019-01-26_how-to-push-to-github-from-travis-ci.html
|
||||||
|
env:
|
||||||
|
matrix:
|
||||||
|
secure: RqWbR4JjNKL5+KS6um6R2xKRGMxYO4qxRdI/RFi5oHsjRwKAQPGATb00Zmd84V/jaVb+NOccG1qp0/SNVwAaFf6Yr1MO9aV3GKC0fDFwSffKLdtVO2yx/JHrRYZ2ymrjEkBGug1FMrHFGZsSLaZYsYKx974tBs04xwAmPv6Yby8bZTGJyknbuyIMeSe6XZIkinyKaw/Zay6QC2CtSLoX50gqY2/HX0fVBgWKDNStigH0UEEynSetRYm/PFRcoBwu3XmHW89Y9B0E/zgvnvFuAgMVmZSUZnD9wBRlnFvfC1pUaFZP8Tz2VZhcJ4xTRTq+r3t2IRTNQBIhlQseobQMxoTrv1Y/ZiEmO14CLSwy3yeX5vCiGmCaA3957FqnjTP07svbru/A0qWMyEtuBtpheCVbQSVvMUBnrl0txTMFiBb4dsJ7zWrp3f7RQ8SFB11FwpGv89d+FifOpXN42DWRXjU0fLCPs8S5iKODWkTSQ41vpGXXUoZdaUOUg1y6tZSoc8gs61KlhcDTrBI2ZCJMNY6c6JVE/BOnJrp6zqyKhY2znyJUodEvjPsy9iccmrt0bEZTVshzbW4Q9okQ26usNtwIJoHNDUdifpmMcobb/ATYEr+C7n9ztxRy9AnZLzp6SsCDlfSDDp32fr7762PMk+2jR9w7fMrR/PBMtDXNsYQ=
|
||||||
|
@ -3,9 +3,11 @@ module Guide.Api
|
|||||||
module Guide.Api.Methods,
|
module Guide.Api.Methods,
|
||||||
module Guide.Api.Server,
|
module Guide.Api.Server,
|
||||||
module Guide.Api.Types,
|
module Guide.Api.Types,
|
||||||
|
module Guide.Api.Docs,
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
import Guide.Api.Methods
|
import Guide.Api.Methods
|
||||||
import Guide.Api.Server
|
import Guide.Api.Server
|
||||||
import Guide.Api.Types
|
import Guide.Api.Types
|
||||||
|
import Guide.Api.Docs
|
||||||
|
32
back/src/Guide/Api/Docs.hs
Normal file
32
back/src/Guide/Api/Docs.hs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
|
||||||
|
-- | Rendered documentation for the API.
|
||||||
|
module Guide.Api.Docs
|
||||||
|
(
|
||||||
|
apiSwaggerDoc,
|
||||||
|
apiSwaggerRendered,
|
||||||
|
)
|
||||||
|
where
|
||||||
|
|
||||||
|
import Imports
|
||||||
|
|
||||||
|
import Servant.Swagger (toSwagger)
|
||||||
|
import Data.Swagger
|
||||||
|
import qualified Data.Aeson.Encode.Pretty as AesonPretty
|
||||||
|
|
||||||
|
import Guide.Api.Types
|
||||||
|
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
-- Swagger
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- | Swagger docs for the 'Api'.
|
||||||
|
apiSwaggerDoc :: Swagger
|
||||||
|
apiSwaggerDoc =
|
||||||
|
toSwagger (Proxy @Api)
|
||||||
|
& info.title .~ "Aelve Guide API"
|
||||||
|
& info.version .~ "alpha"
|
||||||
|
|
||||||
|
-- | Pretty-printed @swagger.json@ for the 'Api'.
|
||||||
|
apiSwaggerRendered :: Text
|
||||||
|
apiSwaggerRendered = utf8ToText $ AesonPretty.encodePretty apiSwaggerDoc
|
@ -13,19 +13,18 @@ where
|
|||||||
|
|
||||||
import Imports
|
import Imports
|
||||||
|
|
||||||
import Data.Swagger.Lens hiding (format)
|
|
||||||
import Network.Wai (Middleware, Request)
|
import Network.Wai (Middleware, Request)
|
||||||
import Network.Wai.Middleware.Cors (CorsResourcePolicy (..), corsOrigins,
|
import Network.Wai.Middleware.Cors (CorsResourcePolicy (..), corsOrigins,
|
||||||
simpleCorsResourcePolicy)
|
simpleCorsResourcePolicy)
|
||||||
import Servant
|
import Servant
|
||||||
import Servant.API.Generic
|
import Servant.API.Generic
|
||||||
import Servant.Server.Generic
|
import Servant.Server.Generic
|
||||||
import Servant.Swagger
|
|
||||||
import Servant.Swagger.UI
|
import Servant.Swagger.UI
|
||||||
|
|
||||||
import Guide.Api.Guider
|
import Guide.Api.Guider
|
||||||
import Guide.Api.Methods
|
import Guide.Api.Methods
|
||||||
import Guide.Api.Types
|
import Guide.Api.Types
|
||||||
|
import Guide.Api.Docs
|
||||||
import Guide.Logger
|
import Guide.Logger
|
||||||
import Guide.Config
|
import Guide.Config
|
||||||
import Guide.State
|
import Guide.State
|
||||||
@ -76,11 +75,13 @@ logException logger mbReq ex =
|
|||||||
-- Servant servers
|
-- Servant servers
|
||||||
----------------------------------------------------------------------------
|
----------------------------------------------------------------------------
|
||||||
|
|
||||||
-- Collect API and Swagger server to united 'FullApi'. First takes precedence in case of overlap.
|
-- | Collect API and Swagger server to united 'FullApi'. First takes
|
||||||
|
-- precedence in case of overlap.
|
||||||
fullServer :: DB -> Logger -> Config -> Server FullApi
|
fullServer :: DB -> Logger -> Config -> Server FullApi
|
||||||
fullServer db di config = apiServer db di config :<|> docServer
|
fullServer db di config = apiServer db di config :<|> docServer
|
||||||
|
|
||||||
-- Collect api out of guiders and convert them to handlers. Type 'type Server api = ServerT api Handler' needed it.
|
-- | Collect api out of guiders and convert them to handlers. Type 'type
|
||||||
|
-- Server api = ServerT api Handler' needed it.
|
||||||
apiServer :: DB -> Logger -> Config -> Server Api
|
apiServer :: DB -> Logger -> Config -> Server Api
|
||||||
apiServer db di config = do
|
apiServer db di config = do
|
||||||
requestDetails <- ask
|
requestDetails <- ask
|
||||||
@ -89,11 +90,7 @@ apiServer db di config = do
|
|||||||
|
|
||||||
-- | A 'Server' for Swagger docs.
|
-- | A 'Server' for Swagger docs.
|
||||||
docServer :: Server (SwaggerSchemaUI "api" "swagger.json")
|
docServer :: Server (SwaggerSchemaUI "api" "swagger.json")
|
||||||
docServer = swaggerSchemaUIServer doc
|
docServer = swaggerSchemaUIServer apiSwaggerDoc
|
||||||
where
|
|
||||||
doc = toSwagger (Proxy @Api)
|
|
||||||
& info.title .~ "Aelve Guide API"
|
|
||||||
& info.version .~ "alpha"
|
|
||||||
|
|
||||||
----------------------------------------------------------------------------
|
----------------------------------------------------------------------------
|
||||||
-- API handlers put together ('Site')
|
-- API handlers put together ('Site')
|
||||||
|
@ -24,42 +24,10 @@ import qualified Options.Applicative as Opt
|
|||||||
|
|
||||||
-- | All available commands
|
-- | All available commands
|
||||||
data Command
|
data Command
|
||||||
= RunServer -- ^ run server
|
= RunServer -- ^ Run server
|
||||||
| DryRun -- ^ load database and exit
|
| DryRun -- ^ Load database and exit
|
||||||
| LoadPublic FilePath -- ^ load PublicDB, create base on it and exit
|
| LoadPublic FilePath -- ^ Load PublicDB, create base on it and exit
|
||||||
|
| ApiDocs -- ^ Show docs for the backend API
|
||||||
----------------------------------------------------------------------------
|
|
||||||
-- Parsers
|
|
||||||
----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
{-
|
|
||||||
To see help run command:
|
|
||||||
$ guide --help
|
|
||||||
Usage: guide [-v|--version] [COMMAND]
|
|
||||||
|
|
||||||
Available options:
|
|
||||||
-h,--help Show this help text
|
|
||||||
-v,--version Show Guide version
|
|
||||||
|
|
||||||
Available commands:
|
|
||||||
run Run server
|
|
||||||
dry-run Load database and exit
|
|
||||||
load-public Load PublicDB, create base on it and exit
|
|
||||||
|
|
||||||
NOTE:
|
|
||||||
Command 'guide' is the same as 'guide run'
|
|
||||||
|
|
||||||
----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
$ guide load-public --help
|
|
||||||
Usage: guide load-public (-p|--path FILEPATH)
|
|
||||||
Load PublicDB, create base on it and exit
|
|
||||||
|
|
||||||
Available options:
|
|
||||||
-h,--help Show this help text
|
|
||||||
-p,--path FILEPATH Public DB file name
|
|
||||||
|
|
||||||
-}
|
|
||||||
|
|
||||||
-- | Parse the command line of the application.
|
-- | Parse the command line of the application.
|
||||||
--
|
--
|
||||||
@ -72,10 +40,14 @@ parseCommandLine = Opt.execParser
|
|||||||
-- | All possible commands.
|
-- | All possible commands.
|
||||||
commandsParser :: Parser Command
|
commandsParser :: Parser Command
|
||||||
commandsParser = Opt.subparser
|
commandsParser = Opt.subparser
|
||||||
$ Opt.command "run" (infoP (pure RunServer) "Start server")
|
$ Opt.command "run"
|
||||||
<> Opt.command "dry-run" (infoP (pure DryRun) "Load database and exit")
|
(infoP (pure RunServer) "Start server")
|
||||||
|
<> Opt.command "dry-run"
|
||||||
|
(infoP (pure DryRun) "Load database and exit")
|
||||||
<> Opt.command "load-public"
|
<> Opt.command "load-public"
|
||||||
(infoP loadPublicParser "Load PublicDB, create base on it and exit")
|
(infoP loadPublicParser "Load PublicDB, create base on it and exit")
|
||||||
|
<> Opt.command "api-docs"
|
||||||
|
(infoP (pure ApiDocs) "Show swagger.json for the backend API")
|
||||||
where
|
where
|
||||||
infoP parser desc = Opt.info (Opt.helper <*> parser) $ Opt.progDesc desc
|
infoP parser desc = Opt.info (Opt.helper <*> parser) $ Opt.progDesc desc
|
||||||
|
|
||||||
|
@ -16,11 +16,10 @@ where
|
|||||||
|
|
||||||
import Imports hiding ((.=))
|
import Imports hiding ((.=))
|
||||||
|
|
||||||
-- JSON
|
|
||||||
import Data.Aeson as Aeson
|
import Data.Aeson as Aeson
|
||||||
import Data.Aeson.Encode.Pretty as Aeson hiding (Config)
|
import Data.Aeson.Encode.Pretty as Aeson hiding (Config)
|
||||||
-- Default
|
|
||||||
import Data.Default
|
import Data.Default
|
||||||
|
import Say (sayErr)
|
||||||
|
|
||||||
import Guide.Utils
|
import Guide.Utils
|
||||||
|
|
||||||
@ -125,7 +124,7 @@ readConfig = do
|
|||||||
let filename = "config.json"
|
let filename = "config.json"
|
||||||
exists <- doesFileExist filename
|
exists <- doesFileExist filename
|
||||||
unless exists $ do
|
unless exists $ do
|
||||||
putStrLn "config.json doesn't exist, creating it"
|
sayErr "config.json doesn't exist, creating it"
|
||||||
BSL.writeFile filename (Aeson.encodePretty (def :: Config))
|
BSL.writeFile filename (Aeson.encodePretty (def :: Config))
|
||||||
contents <- toLazyByteString <$> BS.readFile filename
|
contents <- toLazyByteString <$> BS.readFile filename
|
||||||
case Aeson.eitherDecode' contents of
|
case Aeson.eitherDecode' contents of
|
||||||
|
@ -15,6 +15,7 @@ module Guide.Main
|
|||||||
runServer,
|
runServer,
|
||||||
dryRun,
|
dryRun,
|
||||||
loadPublic,
|
loadPublic,
|
||||||
|
apiDocs,
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
@ -47,7 +48,7 @@ import System.Signal
|
|||||||
-- HVect
|
-- HVect
|
||||||
import Data.HVect hiding (length)
|
import Data.HVect hiding (length)
|
||||||
|
|
||||||
import Guide.Api (runApiServer)
|
import Guide.Api (runApiServer, apiSwaggerRendered)
|
||||||
import Guide.App
|
import Guide.App
|
||||||
import Guide.Cli
|
import Guide.Cli
|
||||||
import Guide.Config
|
import Guide.Config
|
||||||
@ -124,6 +125,7 @@ runCommand config = \case
|
|||||||
RunServer -> runServer config
|
RunServer -> runServer config
|
||||||
DryRun -> dryRun config
|
DryRun -> dryRun config
|
||||||
LoadPublic path -> loadPublic config path
|
LoadPublic path -> loadPublic config path
|
||||||
|
ApiDocs -> apiDocs config
|
||||||
|
|
||||||
----------------------------------------------------------------------------
|
----------------------------------------------------------------------------
|
||||||
-- Commands
|
-- Commands
|
||||||
@ -167,6 +169,11 @@ loadPublic config path = withLogger config $ \logger ->
|
|||||||
logDebugIO logger "PublicDB imported to GlobalState"
|
logDebugIO logger "PublicDB imported to GlobalState"
|
||||||
exitSuccess
|
exitSuccess
|
||||||
|
|
||||||
|
-- | Dump API docs to the output.
|
||||||
|
apiDocs :: Config -> IO ()
|
||||||
|
apiDocs config = withLogger config $ \_logger ->
|
||||||
|
T.putStrLn apiSwaggerRendered
|
||||||
|
|
||||||
----------------------------------------------------------------------------
|
----------------------------------------------------------------------------
|
||||||
-- Helpers
|
-- Helpers
|
||||||
----------------------------------------------------------------------------
|
----------------------------------------------------------------------------
|
||||||
|
1211
back/swagger.json
Normal file
1211
back/swagger.json
Normal file
File diff suppressed because it is too large
Load Diff
71
travis_key.enc
Normal file
71
travis_key.enc
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
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
|
Loading…
Reference in New Issue
Block a user