summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--app/Main.hs9
-rw-r--r--app/SlackBuilder/CommandLine.hs15
-rw-r--r--app/SlackBuilder/Config.hs16
-rw-r--r--app/SlackBuilder/Updater.hs91
-rw-r--r--config/config.toml.example1
-rw-r--r--lib/up2date.rb14
-rw-r--r--slackbuilder.cabal19
8 files changed, 150 insertions, 17 deletions
diff --git a/.gitignore b/.gitignore
index 2ded37a..088600b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,12 +15,12 @@
*.pk3
*.run
*.deb
-*.jar
*~
.directory
*.phar
/slackbuilds/
+/config/config.toml
/config/config.rb
/vendor/
/.bundle/
diff --git a/app/Main.hs b/app/Main.hs
index ac1aae2..7e821e5 100644
--- a/app/Main.hs
+++ b/app/Main.hs
@@ -6,14 +6,23 @@ import qualified Data.Text.IO as Text.IO
import Data.Maybe (fromMaybe)
import Options.Applicative (execParser)
import SlackBuilder.CommandLine
+import SlackBuilder.Config
import SlackBuilder.Updater
+import qualified Toml
+import qualified Data.Text as Text
main :: IO ()
main = do
programCommand <- execParser slackBuilderParser
+ settings <- Toml.decodeFile settingsCodec "config/config.toml"
latestVersion <- case programCommand of
PackagistCommand packagistArguments ->
latestPackagist packagistArguments
TextCommand textArguments -> latestText textArguments
+ GhCommand ghArguments -> latestGitHub settings ghArguments (stripPrefix "v")
Text.IO.putStrLn $ fromMaybe "" latestVersion
+ where
+ stripPrefix prefix string = Just
+ $ fromMaybe string
+ $ Text.stripPrefix prefix string
diff --git a/app/SlackBuilder/CommandLine.hs b/app/SlackBuilder/CommandLine.hs
index 2459bb5..5680c81 100644
--- a/app/SlackBuilder/CommandLine.hs
+++ b/app/SlackBuilder/CommandLine.hs
@@ -1,5 +1,6 @@
module SlackBuilder.CommandLine
- ( SlackBuilderCommand(..)
+ ( GhArguments(..)
+ , SlackBuilderCommand(..)
, PackagistArguments(..)
, TextArguments(..)
, slackBuilderParser
@@ -21,12 +22,18 @@ import Options.Applicative
data SlackBuilderCommand
= PackagistCommand PackagistArguments
| TextCommand TextArguments
+ | GhCommand GhArguments
data PackagistArguments = PackagistArguments
{ vendor :: Text
, name :: Text
} deriving (Eq, Show)
+data GhArguments = GhArguments
+ { owner :: Text
+ , name :: Text
+ } deriving (Eq, Show)
+
newtype TextArguments = TextArguments Text
packagistArguments :: Parser PackagistArguments
@@ -37,6 +44,11 @@ packagistArguments = PackagistArguments
textArguments :: Parser TextArguments
textArguments = TextArguments <$> argument str (metavar "URL")
+ghArguments :: Parser GhArguments
+ghArguments = GhArguments
+ <$> argument str (metavar "OWNER")
+ <*> argument str (metavar "NAME")
+
slackBuilderParser :: ParserInfo SlackBuilderCommand
slackBuilderParser = info slackBuilderCommand fullDesc
@@ -44,3 +56,4 @@ slackBuilderCommand :: Parser SlackBuilderCommand
slackBuilderCommand = subparser
$ command "packagist" (info (PackagistCommand <$> packagistArguments) mempty)
<> command "text" (info (TextCommand <$> textArguments) mempty)
+ <> command "github" (info (GhCommand <$> ghArguments) mempty)
diff --git a/app/SlackBuilder/Config.hs b/app/SlackBuilder/Config.hs
new file mode 100644
index 0000000..be91ae0
--- /dev/null
+++ b/app/SlackBuilder/Config.hs
@@ -0,0 +1,16 @@
+module SlackBuilder.Config
+ ( Settings(..)
+ , settingsCodec
+ ) where
+
+import Data.Text (Text)
+import Toml ((.=))
+import qualified Toml
+
+newtype Settings = Settings
+ { ghToken :: Text
+ } deriving (Eq, Show)
+
+settingsCodec :: Toml.TomlCodec Settings
+settingsCodec = Settings
+ <$> Toml.text "gh_token" .= ghToken
diff --git a/app/SlackBuilder/Updater.hs b/app/SlackBuilder/Updater.hs
index 5373f7e..0e927e2 100644
--- a/app/SlackBuilder/Updater.hs
+++ b/app/SlackBuilder/Updater.hs
@@ -1,18 +1,23 @@
module SlackBuilder.Updater
- ( latestPackagist
+ ( latestGitHub
+ , latestPackagist
, latestText
) where
+import SlackBuilder.Config
+import qualified Data.Aeson as Aeson
+import Data.Aeson ((.:))
import Data.Aeson.TH (defaultOptions, deriveJSON)
import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as HashMap
import Data.Text (Text)
import qualified Data.Text as Text
import qualified Data.Text.Encoding as Text.Encoding
-import Data.Vector (Vector)
+import Data.Vector (Vector, (!?))
import qualified Data.Vector as Vector
import Network.HTTP.Req
- ( runReq
+ ( header
+ , runReq
, defaultHttpConfig
, req
, GET(..)
@@ -20,10 +25,12 @@ import Network.HTTP.Req
, jsonResponse
, NoReqBody(..)
, (/:)
- , responseBody, useHttpsURI, bsResponse
+ , responseBody, useHttpsURI, bsResponse, POST (POST), ReqBodyJson (ReqBodyJson)
)
import Text.URI (mkURI)
import SlackBuilder.CommandLine
+import qualified Data.Aeson.KeyMap as KeyMap
+import GHC.Records (HasField(..))
newtype PackagistPackage = PackagistPackage
{ version :: Text
@@ -37,6 +44,48 @@ newtype PackagistResponse = PackagistResponse
$(deriveJSON defaultOptions ''PackagistResponse)
+newtype GhRefNode = GhRefNode
+ { name :: Text
+ } deriving (Eq, Show)
+
+$(deriveJSON defaultOptions ''GhRefNode)
+
+newtype GhRef = GhRef
+ { nodes :: Vector GhRefNode
+ } deriving (Eq, Show)
+
+$(deriveJSON defaultOptions ''GhRef)
+
+newtype GhRepository = GhRepository
+ { refs :: GhRef
+ } deriving (Eq, Show)
+
+$(deriveJSON defaultOptions ''GhRepository)
+
+newtype GhData = GhData
+ { repository :: GhRepository
+ } deriving (Eq, Show)
+
+instance Aeson.FromJSON GhData where
+ parseJSON (Aeson.Object keyMap)
+ | Just data' <- KeyMap.lookup "data" keyMap =
+ GhData <$> Aeson.withObject "GhData" (.: "repository") data'
+ parseJSON v = fail "data key not found in the response"
+
+data GhVariables = GhVariables
+ { name :: Text
+ , owner :: Text
+ } deriving (Eq, Show)
+
+$(deriveJSON defaultOptions ''GhVariables)
+
+data GhQuery = GhQuery
+ { query :: Text
+ , variables :: GhVariables
+ } deriving (Eq, Show)
+
+$(deriveJSON defaultOptions ''GhQuery)
+
latestPackagist :: PackagistArguments -> IO (Maybe Text)
latestPackagist PackagistArguments{..} = do
packagistResponse <- runReq defaultHttpConfig $
@@ -59,3 +108,37 @@ latestText (TextArguments textArguments) = do
<$> packagistResponse
where
go uri = req GET uri NoReqBody bsResponse mempty
+
+latestGitHub :: Settings -> GhArguments -> (Text -> Maybe Text) -> IO (Maybe Text)
+latestGitHub Settings{..} GhArguments{..} versionTransform = do
+ ghResponse <- runReq defaultHttpConfig $
+ let uri = https "api.github.com" /: "graphql"
+ query = GhQuery
+ { query = githubQuery
+ , variables = GhVariables
+ { owner = owner
+ , name = name
+ }
+ }
+ authorizationHeader = header "authorization"
+ $ Text.Encoding.encodeUtf8
+ $ "Bearer " <> ghToken
+ in req POST uri (ReqBodyJson query) jsonResponse
+ $ authorizationHeader <> header "User-Agent" "SlackBuilder"
+ let ghNodes = nodes $ refs $ repository $ responseBody ghResponse
+ refs' = Vector.reverse
+ $ Vector.catMaybes
+ $ versionTransform . getField @"name" <$> ghNodes
+ pure $ refs' !? 0
+ where
+ githubQuery =
+ "query ($name: String!, $owner: String!) {\n\
+ \ repository(name: $name, owner: $owner) {\n\
+ \ refs(last: 10, refPrefix: \"refs/tags/\", orderBy: { field: TAG_COMMIT_DATE, direction: ASC }) {\n\
+ \ nodes {\n\
+ \ id,\n\
+ \ name\n\
+ \ }\n\
+ \ }\n\
+ \ }\n\
+ \}"
diff --git a/config/config.toml.example b/config/config.toml.example
new file mode 100644
index 0000000..117472e
--- /dev/null
+++ b/config/config.toml.example
@@ -0,0 +1 @@
+gh_token = ""
diff --git a/lib/up2date.rb b/lib/up2date.rb
index 06e46e3..3ccbbd3 100644
--- a/lib/up2date.rb
+++ b/lib/up2date.rb
@@ -36,7 +36,7 @@ module SlackBuilder
GQL
private_constant :GITHUB_QUERY
- def initialize(owner, name, version_transform = ->(v) { v.delete_prefix 'v' })
+ def initialize(owner, name, version_transform = nil)
super()
@owner = owner
@@ -45,6 +45,16 @@ module SlackBuilder
end
def latest
+ if @version_transform.nil?
+ `./bin/slackbuilder github #{@owner} #{@name}`.strip
+ else
+ latest_with_transform
+ end
+ end
+
+ private
+
+ def latest_with_transform
post_data = {
'query' => GITHUB_QUERY,
'variables' => { 'name' => @name, 'owner' => @owner }
@@ -57,8 +67,6 @@ module SlackBuilder
filter_versions_from_response JSON.parse(response.body)
end
- private
-
def filter_versions_from_response(response)
response['data']['repository']['refs']['nodes']
.map { |node| @version_transform.call node['name'] }
diff --git a/slackbuilder.cabal b/slackbuilder.cabal
index 29c2a9d..58585e2 100644
--- a/slackbuilder.cabal
+++ b/slackbuilder.cabal
@@ -1,13 +1,11 @@
-cabal-version: 2.4
-name: slackbuilder
-version: 0.1.0.0
-
--- A short (one-line) description of the package.
--- synopsis:
+cabal-version: 2.4
+name: slackbuilder
+version: 0.1.0.0
-- A longer description of the package.
-- description:
+synopsis: Slackware build scripts and configuration files.
bug-reports: https://git.caraus.tech/OSS/slackbuilder/issues
license: MPL-2.0
@@ -21,15 +19,19 @@ category: Build
extra-source-files: CHANGELOG.md
executable slackbuilder
- main-is: Main.hs
+ main-is: Main.hs
other-modules:
SlackBuilder.CommandLine
+ SlackBuilder.Config
SlackBuilder.Updater
default-extensions:
+ DataKinds
+ DuplicateRecordFields
OverloadedStrings
RecordWildCards
TemplateHaskell
+ TypeApplications
build-depends:
aeson ^>= 2.2.0,
base ^>= 4.16.4.0,
@@ -38,7 +40,8 @@ executable slackbuilder
optparse-applicative ^>= 0.18.1,
req ^>=3.13,
text ^>= 2.0,
+ tomland ^>= 1.3.3,
unordered-containers ^>= 0.2.19,
vector ^>= 0.13.0
- hs-source-dirs: app
+ hs-source-dirs: app
default-language: Haskell2010