Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
keynmol committed Jul 11, 2024
1 parent 2b2f5c9 commit b78c9a4
Show file tree
Hide file tree
Showing 13 changed files with 290 additions and 39 deletions.
47 changes: 47 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: CI
on:
push:
branches: ["main"]
tags: ["v*"]
pull_request:
branches: ["*"]

jobs:
build:
strategy:
fail-fast: false
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: coursier/cache-action@v6
- uses: VirtusLab/scala-cli-setup@main
with:
power: true

- name: Check formatting
run: make code-check || echo "Run `make pre-ci`"

- name: Test
run: make test

- name: Check documentation compiles and runs
run: make check-docs && make run-example

- name: Publish snapshot
if: github.ref == 'refs/heads/main'
run: make publish-snapshot
env:
SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }}
SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }}

- name: Publish
if: startsWith(github.ref, 'refs/tags/v')
run: make publish
env:
PGP_PASSPHRASE: ${{ secrets.PGP_PASSPHRASE }}
PGP_SECRET: ${{ secrets.PGP_SECRET }}
SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }}
SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }}

5 changes: 5 additions & 0 deletions .github/workflows/import-gpg.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/usr/bin/env bash
set -e
echo "$PGP_SECRET" | base64 -d -i - > /tmp/signing-key.gpg
echo "$PGP_PASSPHRASE" | gpg --pinentry-mode loopback --passphrase-fd 0 --import /tmp/signing-key.gpg
(echo "$PGP_PASSPHRASE"; echo; echo) | gpg --command-fd 0 --pinentry-mode loopback --change-passphrase $(gpg --list-secret-keys --with-colons 2> /dev/null | grep '^sec:' | cut --delimiter ':' --fields 5 | tail -n 1)
2 changes: 1 addition & 1 deletion ArgHint.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ enum ArgHint:
case Short(value: String)
case Help(value: String)
case FlagDefault(value: Boolean)
case Argument(metavar: String | Option[String] = None)
case Positional(metavar: String | Option[String] = None)
end ArgHint
6 changes: 3 additions & 3 deletions ArgHintProvider.scala
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ private[decline_derive] case class ArgHintProvider(e: Expr[Seq[ArgHint]]):

def isArgument(using Quotes) =
getHint:
case ArgHint.Argument(metavar: String) => Some(metavar)
case ArgHint.Argument(None) => None
case ArgHint.Argument(Some(metavar)) => Some(metavar)
case ArgHint.Positional(metavar: String) => Some(metavar)
case ArgHint.Positional(None) => None
case ArgHint.Positional(Some(metavar)) => Some(metavar)

end ArgHintProvider
1 change: 0 additions & 1 deletion CmdHint.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,3 @@ package decline_derive
enum CmdHint:
case Name(value: String)
case Help(value: String)

1 change: 0 additions & 1 deletion CmdHintProvider.scala
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,4 @@ private[decline_derive] case class CmdHintProvider(e: Expr[Seq[CmdHint]]):
getHint:
case CmdHint.Help(value) => value


end CmdHintProvider
29 changes: 29 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
check-docs:
scala-cli compile README.md *.scala

test:
scala-cli test *.scala
scala-cli test --native *.scala
scala-cli test --js *.scala

publish-snapshot:
scala-cli config publish.credentials s01.oss.sonatype.org env:SONATYPE_USERNAME env:SONATYPE_PASSWORD
scala-cli publish *.scala --signer none
scala-cli publish *.scala --native --signer none
scala-cli publish *.scala --js --signer none

publish:
scala-cli config publish.credentials s01.oss.sonatype.org env:SONATYPE_USERNAME env:SONATYPE_PASSWORD
./.github/workflows/import-gpg.sh
scala-cli publish *.scala --signer gpg --gpg-key 15A7215B6CD4016A
scala-cli publish *.scala --js --signer gpg --gpg-key 15A7215B6CD4016A
scala-cli publish *.scala --native --signer gpg --gpg-key 15A7215B6CD4016A

code-check:
scala-cli fmt . --check

run-example:
scala-cli run README.md *.scala -M helloDecline -- --help

pre-ci:
scala-cli fmt *.scala
50 changes: 50 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# decline-derive

<!--toc:start-->
- [decline-derive](#decline-derive)
- [Installation](#installation)
- [Getting started](#getting-started)
- [Contributing](#contributing)
<!--toc:end-->

An _experimental_ [Smithy4s](https://disneystreaming.github.io/smithy4s/) client backend for [Scala.js](https://www.scala-js.org/), utilising [Fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch) directly, without introducing a http4s/cats dependency.

The purpose of this library is to provide users of Smithy4s backend services a more lightweight client for the frontend – if your Scala.js frontend is not using Cats/Cats-Effect based libraries, you can communicate with your Smithy4s backend directly using Fetch, **reducing bundle size by as much as 50% in some instances**.

The library is currently only available for Scala 3, but we will welcome contributions cross-compiling it to 2.13 – it should be very easy. API surface is very minimal and designed for binary compatible evolution, so after initial round of testing and gathering community feedback, we plan to release 1.0.0 and start checking binary/Tasty compatibility for each release.

## Installation

Latest version: [![decline-derive Scala version support](https://index.scala-lang.org/neandertech/decline-derive/decline-derive/latest.svg)](https://index.scala-lang.org/neandertech/decline-derive/decline-derive)

- **SBT**: `libraryDependencies += "com.indoorvivants" %%% "decline-derive" % "<latest version>"`
- **Scala CLI**: `//> using dep com.indoorvivants::decline-derive::<latest version>`
- **Mill**: `ivy"com.indoorvivants::decline-derive::<latest version>"`

## Getting started

```scala
import decline_derive.*

enum CLI derives CommandApplication:
case Index(location: String, @arg(_.Name("lit")) isLit: Boolean)
case Run(@arg(_.Positional()) files: List[String])

@main def helloDecline(args: String*) =
println(CommandApplication.parse[CLI](args))
```

## Contributing

If you see something that can be improved in this library – please contribute!

This is a relatively standard Scala CLI project, even though the tests run a
Scala version newer than the library itself (library is published for 3.3, tests are
in 3.4, to make use of smithy4s-deriving).

Here are some useful commands:

- `make test` – run tests
- `make check-docs` – verify that snippets in `README.md` (this file) compile
- `make pre-ci` – format the code so that it passes CI check
- `make run-example` – run example from README against real https://httpbin.org
1 change: 0 additions & 1 deletion annotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,3 @@ class arg(val hints: (ArgHint.type => ArgHint)*)
class cmd(val hints: (CmdHint.type => CmdHint)*)
extends annotation.StaticAnnotation:
private[decline_derive] def getHints = hints.map(_(CmdHint))

140 changes: 140 additions & 0 deletions library.test.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import munit.FunSuite

import decline_derive.*

class Tests extends FunSuite:
test("simple parameters"):
case class Cmd(location: String, test: Boolean, y: Int)
derives CommandApplication

assertArgs[Cmd](Cmd("howdy", true, 25))(
"--location",
"howdy",
"--test",
"--y",
"25"
)

assertArgs[Cmd](Cmd("yass", false, -150))(
"--location",
"yass",
"--y",
"-150"
)

test("optional parameters"):
case class Cmd(location: Option[String], y: Option[Int])
derives CommandApplication

assertArgs[Cmd](Cmd(None, None))()

assertArgs[Cmd](Cmd(Some("yess"), Some(150)))(
"--location",
"yess",
"--y",
"150"
)

test("repeated parameters"):
case class Cmd(locations: List[String]) derives CommandApplication

assertArgs[Cmd](Cmd(List("yess", "yo")))(
"--locations",
"yess",
"--locations",
"yo"
)

test("optional repeated parameters"):
case class Cmd(locations: Option[List[String]]) derives CommandApplication

assertArgs[Cmd](Cmd(Some(List("yess", "yo"))))(
"--locations",
"yess",
"--locations",
"yo"
)

assertArgs[Cmd](Cmd(None))()

test("argument hints: name"):
case class Cmd(@arg(_.Name("yepp")) location: Option[String])
derives CommandApplication

assertArgs[Cmd](Cmd(Some("shroom")))("--yepp", "shroom")

test("argument hints: short"):
case class Cmd(@arg(_.Short("y")) location: Option[String])
derives CommandApplication

assertArgs[Cmd](Cmd(Some("shroom")))("-y", "shroom")

test("argument hints: flag default"):
case class Cmd(@arg(_.FlagDefault(true)) isLit: Boolean)
derives CommandApplication

assertArgs[Cmd](Cmd(false))("--isLit")

test("argument hints: positional"):
case class Cmd(
location: String,
@arg(_.Positional("metavar")) isLit: String
) derives CommandApplication

assertArgs[Cmd](Cmd("hello", "yes"))("--location", "hello", "yes")

test("argument hints: positional (repeated)"):
case class Cmd(
location: String,
@arg(_.Positional("metavar"))
isLit: List[String]
) derives CommandApplication

assertArgs[Cmd](Cmd("hello", List("yes", "bla", "test")))(
"--location",
"hello",
"yes",
"bla",
"test"
)

test("subcommands: basic"):
enum Cmd derives CommandApplication:
case Index(location: String)
case Evaluate(file: String, strict: Boolean)

assertArgs(Cmd.Index("hello.trig"))("index", "--location", "hello.trig")
assertArgs(Cmd.Evaluate("hello.trig", true))(
"evaluate",
"--file",
"hello.trig",
"--strict"
)

assertErr[Cmd]("unknown")
assertErr[Cmd]()

test("subcommands: name hints"):
enum Cmd derives CommandApplication:
@cmd(_.Name("index-file")) case Index(location: String)
@cmd(_.Name("evaluate-all")) case Evaluate(file: String, strict: Boolean)

assertArgs(Cmd.Index("hello.trig"))(
"index-file",
"--location",
"hello.trig"
)
assertArgs(Cmd.Evaluate("hello.trig", true))(
"evaluate-all",
"--file",
"hello.trig",
"--strict"
)

private def assertArgs[T: CommandApplication](res: T)(args: String*) =
assertEquals(CommandApplication.parse[T](args), Right(res))

private def assertErr[T: CommandApplication](args: String*) =
val newValue = CommandApplication.parse[T](args)
assert(newValue.isLeft, newValue)
end Tests
2 changes: 1 addition & 1 deletion macros.scala
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ private[decline_derive] object Macros:
'{
given ClassTag[e] = $ct
${ constructOption[List[e]](name, hints) }
.map(_.asInstanceOf[List[e]].toArray())
.map(_.asInstanceOf[List[e]].toArray)
}

case '[e] =>
Expand Down
14 changes: 14 additions & 0 deletions project.scala
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
//> using dep com.monovore::decline::2.4.1
//> using option -Wunused:all
//> using test.dep org.scalameta::munit::1.0.0

//> using publish.computeVersion git:tag
//> using publish.name decline-derive
//> using publish.organization com.indoorvivants
//> using publish.repository "central-s01"
//> using publish.secretKey env:PGP_SECRET
//> using publish.secretKeyPassword env:PGP_PASSPHRASE
//> using publish.license Apache-2.0
//> using publish.developer "velvetbaldmime|Anton Sviridov|https://indoorvivants.com"
//> using publish.vcs github:indoorivants/decline-derive
//> using publish.url https://github.com/indoorivants/decline-derive
//> using scala 3.3.3
//> using nativeVersion 0.4.17
//> using jsVersion 1.16.0
31 changes: 0 additions & 31 deletions test.scala

This file was deleted.

0 comments on commit b78c9a4

Please sign in to comment.