github-release (empty) → 0.1.0
raw patch · 9 files changed
+283/−0 lines, 9 filesdep +aesondep +basedep +bytestringsetup-changed
Dependencies added: aeson, base, bytestring, github-release, http-client, http-client-tls, http-types, mime-types, optparse-generic, text, unordered-containers, uri-templater
Files
- CHANGELOG.markdown +7/−0
- LICENSE.markdown +23/−0
- README.markdown +25/−0
- Setup.hs +4/−0
- executable/Main.hs +3/−0
- github-release.cabal +53/−0
- library/GitHubRelease.hs +123/−0
- package.yaml +42/−0
- stack.yaml +3/−0
+ CHANGELOG.markdown view
@@ -0,0 +1,7 @@+# Change log++GitHub Release uses [Semantic Versioning][].+The change log is available through the [releases on GitHub][].++[Semantic Versioning]: http://semver.org/spec/v2.0.0.html+[releases on GitHub]: https://github.com/tfausak/github-release/releases
+ LICENSE.markdown view
@@ -0,0 +1,23 @@+# [The MIT License (MIT)][]++Copyright (c) 2016 Taylor Fausak++Permission is hereby granted, free of charge, to any person obtaining a copy of+this software and associated documentation files (the "Software"), to deal in+the Software without restriction, including without limitation the rights to+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies+of the Software, and to permit persons to whom the Software is furnished to do+so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in all+copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+SOFTWARE.++[The MIT License (MIT)]: http://opensource.org/licenses/MIT
+ README.markdown view
@@ -0,0 +1,25 @@+# [GitHub Release][]++[![Version badge][]][version]+[![Build badge][]][build]++GitHub Release is a command-line utility for uploading files to GitHub+releases.++``` sh+github-release upload \+ --token '...' \+ --owner 'someone' \+ --repo 'something' \+ --tag '1.2.3' \+ --file 'path/to/example.tgz' \+ --name 'example-1.2.3.tgz'+```++Inspired by <https://github.com/aktau/github-release>.++[GitHub Release]: https://github.com/tfausak/github-release+[Version badge]: https://www.stackage.org/package/github-release/badge/nightly?label=version+[version]: https://www.stackage.org/package/github-release+[Build badge]: https://travis-ci.org/tfausak/github-release.svg+[build]: https://travis-ci.org/tfausak/github-release
+ Setup.hs view
@@ -0,0 +1,4 @@+import qualified Distribution.Simple++main :: IO ()+main = Distribution.Simple.defaultMain
+ executable/Main.hs view
@@ -0,0 +1,3 @@+module Main (module GitHubRelease) where++import GitHubRelease (main)
+ github-release.cabal view
@@ -0,0 +1,53 @@+name: github-release+version: 0.1.0+cabal-version: >=1.10+build-type: Simple+license: MIT+license-file: LICENSE.markdown+maintainer: Taylor Fausak+homepage: https://github.com/tfausak/github-release#readme+bug-reports: https://github.com/tfausak/github-release/issues+synopsis: Upload files to GitHub releases.+description:+ GitHub Release is a command-line utility for uploading files to GitHub releases.+category: Utility+extra-source-files:+ CHANGELOG.markdown+ package.yaml+ README.markdown+ stack.yaml++source-repository head+ type: git+ location: https://github.com/tfausak/github-release++library+ exposed-modules:+ GitHubRelease+ build-depends:+ aeson >=0.9.0.1 && <0.10,+ base >=4.8.2.0 && <4.9,+ bytestring >=0.10.6.0 && <0.11,+ http-client >=0.4.28 && <0.5,+ http-client-tls >=0.2.4 && <0.3,+ http-types ==0.9.*,+ mime-types >=0.1.0.7 && <0.2,+ optparse-generic >=1.1.0 && <1.2,+ text >=1.2.2.1 && <1.3,+ unordered-containers >=0.2.5.1 && <0.3,+ uri-templater >=0.2.0.0 && <0.3+ default-language: Haskell2010+ hs-source-dirs: library+ other-modules:+ Paths_github_release+ ghc-options: -Wall++executable github-release+ main-is: Main.hs+ build-depends:+ base >=4.8.2.0 && <4.9,+ github-release >=0.1.0 && <0.2+ default-language: Haskell2010+ hs-source-dirs: executable+ ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-N+
+ library/GitHubRelease.hs view
@@ -0,0 +1,123 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeOperators #-}++module GitHubRelease where++import qualified Data.Aeson as Aeson+import qualified Data.ByteString.Char8 as BS8+import qualified Data.ByteString.Lazy as BSL+import qualified Data.HashMap.Strict as HashMap+import qualified Data.Text as Text+import qualified Data.Version as Version+import qualified GHC.Generics as Generics+import qualified Network.HTTP.Client as Client+import qualified Network.HTTP.Client.TLS as TLS+import qualified Network.HTTP.Types as HTTP+import qualified Network.Mime as MIME+import qualified Network.URI.Template as Template+import qualified Network.URI.Template.Types as Template+import qualified Options.Generic as Options+import qualified Paths_github_release as This+import qualified System.IO as IO+import qualified Text.Printf as Printf++data Command+ = Upload+ { file :: FilePath Options.<?>+ "The path to the local file to upload."+ , name :: String Options.<?>+ "The name to give the file on the release."+ , owner :: String Options.<?>+ "The GitHub owner, either a user or organization."+ , repo :: String Options.<?>+ "The GitHub repository name."+ , tag :: String Options.<?>+ "The tag name."+ , token :: String Options.<?>+ "Your OAuth2 token."+ }+ | Version+ deriving (Generics.Generic, Show)++instance Options.ParseRecord Command++main :: IO ()+main = do+ command <- Options.getRecord (Text.pack "Upload a file to a GitHub release.")+ runCommand command++runCommand :: Command -> IO ()+runCommand command = case command of+ Upload aName anOwner aFile aRepo aTag aToken -> upload+ (Options.unHelpful aToken)+ (Options.unHelpful anOwner)+ (Options.unHelpful aRepo)+ (Options.unHelpful aTag)+ (Options.unHelpful aFile)+ (Options.unHelpful aName)+ Version -> putStrLn versionString++upload :: String -> String -> String -> String -> FilePath -> String -> IO ()+upload aToken anOwner aRepo aTag aFile aName = do+ manager <- Client.newManager TLS.tlsManagerSettings+ uploadUrl <- getUploadUrl manager anOwner aRepo aTag+ response <- uploadFile manager uploadUrl aToken aFile aName+ case HTTP.statusCode (Client.responseStatus response) of+ 201 -> pure ()+ _ -> do+ IO.hPrint IO.stderr response+ BSL.hPutStr IO.stderr (Client.responseBody response)+ fail "Failed to upload file to release!"++getUploadUrl :: Client.Manager -> String -> String -> String -> IO Template.UriTemplate+getUploadUrl manager anOwner aRepo aTag = do+ (Right json) <- getTag manager anOwner aRepo aTag+ let (Just (Aeson.String text)) = HashMap.lookup (Text.pack "upload_url") json+ let uploadUrl = Text.unpack text+ let (Right template) = Template.parseTemplate uploadUrl+ pure template++getTag :: Client.Manager -> String -> String -> String -> IO (Either String Aeson.Object)+getTag manager anOwner aRepo aTag = do+ let format = "https://api.github.com/repos/%s/%s/releases/tags/%s"+ let url = Printf.printf format anOwner aRepo aTag+ initialRequest <- Client.parseUrl url+ let request = initialRequest { Client.requestHeaders = [userAgentHeader] }+ response <- Client.httpLbs request manager+ let body = Client.responseBody response+ let json = Aeson.eitherDecode body+ return json++userAgentHeader :: HTTP.Header+userAgentHeader = (HTTP.hUserAgent, BS8.pack userAgent)++userAgent :: String+userAgent = Printf.printf "%s/%s-%s" "tfausak" "github-release" versionString++versionString :: String+versionString = Version.showVersion This.version++uploadFile :: Client.Manager -> Template.UriTemplate -> String -> FilePath -> String -> IO (Client.Response BSL.ByteString)+uploadFile manager template aToken aFile aName = do+ contents <- BSL.readFile aFile+ let body = Client.RequestBodyLBS contents+ uploadBody manager template aToken body aName++uploadBody :: Client.Manager -> Template.UriTemplate -> String -> Client.RequestBody -> String -> IO (Client.Response BSL.ByteString)+uploadBody manager template aToken body aName = do+ let url = Template.render template+ [ ("name", Template.WrappedValue (Template.Single aName))+ ]+ initialRequest <- Client.parseUrl url+ let request = initialRequest+ { Client.method = BS8.pack "POST"+ , Client.requestBody = body+ , Client.requestHeaders =+ [ (HTTP.hAuthorization, BS8.pack (Printf.printf "token %s" aToken))+ , (HTTP.hContentType, MIME.defaultMimeLookup (Text.pack aName))+ , userAgentHeader+ ]+ }+ Client.httpLbs request manager
+ package.yaml view
@@ -0,0 +1,42 @@+category: Utility+description: GitHub Release is a command-line utility for uploading files to GitHub+ releases.+executables:+ github-release:+ dependencies:+ - base+ - github-release+ ghc-options:+ - -threaded+ - -rtsopts+ - -with-rtsopts=-N+ main: Main.hs+ source-dirs: executable+extra-source-files:+- CHANGELOG.markdown+- package.yaml+- README.markdown+- stack.yaml+ghc-options: -Wall+github: tfausak/github-release+library:+ dependencies:+ - aeson+ - base+ - bytestring+ - http-client+ - http-client-tls+ - http-types+ - mime-types+ - optparse-generic+ - text+ - unordered-containers+ - uri-templater+ other-modules: Paths_github_release+ source-dirs: library+license: MIT+license-file: LICENSE.markdown+maintainer: Taylor Fausak+name: github-release+synopsis: Upload files to GitHub releases.+version: '0.1.0'
+ stack.yaml view
@@ -0,0 +1,3 @@+extra-deps:+- optparse-generic-1.1.0+resolver: lts-5.15