From a1e9a077c05877298090778b392abaf888f204a9 Mon Sep 17 00:00:00 2001 From: "Sven A. Schmidt" Date: Thu, 4 Apr 2019 16:42:50 +0200 Subject: [PATCH 01/13] Add coverage to test-macos-spm --- Makefile | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 14198d1..0421674 100644 --- a/Makefile +++ b/Makefile @@ -16,19 +16,22 @@ build-docker-app: build-docker-base docker tag rester-base finestructure/rester:base-$(VERSION) docker build --tag rester:$(VERSION) -f Dockerfile.app --build-arg VERSION=$(VERSION) . -test-linux: build-docker-base +test-linux-spm: build-docker-base docker run --rm rester-base swift test -test-macos: xcodeproj +test-macos-xcode: xcodeproj set -o pipefail && \ xcodebuild test \ -scheme Rester \ -destination platform="macOS" \ + -enableCodeCoverage YES -test-swift: - swift test +test-macos-spm: BUILD_DIR=$(shell swift build --show-bin-path) +test-macos-spm: + swift test --enable-code-coverage + xcrun llvm-cov report -ignore-filename-regex=".build/*" -instr-profile $(BUILD_DIR)/codecov/default.profdata $(BUILD_DIR)/rester -test-all: test-linux test-macos +test-all: test-linux-spm test-macos-spm test-macos-xcode magic: sourcery --templates ./.sourcery --sources Tests --args testimports='@testable import '"ResterTests" --output Tests/LinuxMain.swift From b8295f8d4365a4394d1ba5b52692ec2c0b39d274 Mon Sep 17 00:00:00 2001 From: "Sven A. Schmidt" Date: Thu, 4 Apr 2019 18:15:50 +0200 Subject: [PATCH 02/13] Try codecov --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 8f57808..0df2b70 100644 --- a/.travis.yml +++ b/.travis.yml @@ -67,7 +67,9 @@ jobs: - stage: test name: swift test - script: swift test + script: swift test --enable-code-coverage + after_success: + - bash <(curl -s https://codecov.io/bash) -X xcodellvm - stage: test name: docker swift test From db3796e152ceeda1ad8c1df27b08a6c9ea5e4b60 Mon Sep 17 00:00:00 2001 From: "Sven A. Schmidt" Date: Thu, 4 Apr 2019 18:31:20 +0200 Subject: [PATCH 03/13] Set derived data dir --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 0df2b70..543b93f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -69,7 +69,7 @@ jobs: name: swift test script: swift test --enable-code-coverage after_success: - - bash <(curl -s https://codecov.io/bash) -X xcodellvm + - bash <(curl -s https://codecov.io/bash) -X xcodellvm -D $(swift build --show-bin-path) - stage: test name: docker swift test From 92c5403c284c66dfc606e5fadcb7049c5803bb39 Mon Sep 17 00:00:00 2001 From: "Sven A. Schmidt" Date: Thu, 4 Apr 2019 18:45:31 +0200 Subject: [PATCH 04/13] Teak build --- .travis.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 543b93f..bb01489 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,10 +13,10 @@ stages: - test -install: -- if [[ $TRAVIS_OS_NAME == "linux" ]]; then - eval "$(curl -sL https://gist.githubusercontent.com/kylef/5c0475ff02b7c7671d2a/raw/9f442512a46d7a2af7b850d65a7e9bd31edfb09b/swiftenv-install.sh)"; - fi +# install: +# - if [[ $TRAVIS_OS_NAME == "linux" ]]; then +# eval "$(curl -sL https://swiftenv.fuller.li/install.sh)" +# fi jobs: @@ -67,6 +67,7 @@ jobs: - stage: test name: swift test + os: osx script: swift test --enable-code-coverage after_success: - bash <(curl -s https://codecov.io/bash) -X xcodellvm -D $(swift build --show-bin-path) From 10c2c089e96ad8359eada5d780b62da6179d20de Mon Sep 17 00:00:00 2001 From: "Sven A. Schmidt" Date: Thu, 4 Apr 2019 18:52:04 +0200 Subject: [PATCH 05/13] Try -J --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index bb01489..c5f9d57 100644 --- a/.travis.yml +++ b/.travis.yml @@ -70,7 +70,7 @@ jobs: os: osx script: swift test --enable-code-coverage after_success: - - bash <(curl -s https://codecov.io/bash) -X xcodellvm -D $(swift build --show-bin-path) + - bash <(curl -s https://codecov.io/bash) -J '^Rester$' -J '^ResterCore$' -D $(swift build --show-bin-path) - stage: test name: docker swift test From 4cd293f240b5a3e1349c106bfc1f7fc8c3b2ff14 Mon Sep 17 00:00:00 2001 From: "Sven A. Schmidt" Date: Thu, 4 Apr 2019 18:55:34 +0200 Subject: [PATCH 06/13] Cleanup --- .travis.yml | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index c5f9d57..673655b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,13 +21,13 @@ stages: jobs: include: - - os: linux - dist: trusty - - os: osx - osx_image: xcode10.2 - - stage: build base image + - &linux os: linux + dist: trusty + + - <<: *linux + stage: build base image script: | set -e @@ -42,8 +42,8 @@ jobs: # push docker push $IMG - - stage: build app image - os: linux + - <<: *linux + stage: build app image script: | set -e @@ -65,16 +65,19 @@ jobs: docker tag $IMG finestructure/rester:latest docker push finestructure/rester:latest - - stage: test - name: swift test + - name: swift test + stage: test os: osx + osx_image: xcode10.2 script: swift test --enable-code-coverage after_success: - bash <(curl -s https://codecov.io/bash) -J '^Rester$' -J '^ResterCore$' -D $(swift build --show-bin-path) - - stage: test + - <<: *linux name: docker swift test + stage: test os: linux + dist: trusty script: | set -e echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin From 025221411f23c95371e22d3028e56cf809a12fe5 Mon Sep 17 00:00:00 2001 From: "Sven A. Schmidt" Date: Thu, 4 Apr 2019 19:09:46 +0200 Subject: [PATCH 07/13] Fix -D path --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 673655b..f2ac362 100644 --- a/.travis.yml +++ b/.travis.yml @@ -71,7 +71,7 @@ jobs: osx_image: xcode10.2 script: swift test --enable-code-coverage after_success: - - bash <(curl -s https://codecov.io/bash) -J '^Rester$' -J '^ResterCore$' -D $(swift build --show-bin-path) + - bash <(curl -s https://codecov.io/bash) -J '^Rester$' -J '^ResterCore$' -D .build - <<: *linux name: docker swift test From 6ffa98d7608576186aabffca79fd3e512eefd6ac Mon Sep 17 00:00:00 2001 From: "Sven A. Schmidt" Date: Fri, 5 Apr 2019 07:43:06 +0200 Subject: [PATCH 08/13] Move code to ResterCode to fix coverage reporting --- .travis.yml | 2 +- Sources/Rester/main.swift | 106 --------------------------------- Sources/ResterCore/Main.swift | 108 ++++++++++++++++++++++++++++++++++ 3 files changed, 109 insertions(+), 107 deletions(-) create mode 100644 Sources/ResterCore/Main.swift diff --git a/.travis.yml b/.travis.yml index f2ac362..4edee7b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -71,7 +71,7 @@ jobs: osx_image: xcode10.2 script: swift test --enable-code-coverage after_success: - - bash <(curl -s https://codecov.io/bash) -J '^Rester$' -J '^ResterCore$' -D .build + - bash <(curl -s https://codecov.io/bash) -J '^ResterCore$' -D .build - <<: *linux name: docker swift test diff --git a/Sources/Rester/main.swift b/Sources/Rester/main.swift index 06958b6..c9bb4c7 100644 --- a/Sources/Rester/main.swift +++ b/Sources/Rester/main.swift @@ -1,109 +1,3 @@ -import Commander -import Foundation -import LegibleError -import Path -import PromiseKit -import Rainbow import ResterCore -import Yams - - -extension Console { - func display(variables: [Key: Value]) { - guard variables.count > 0 else { return } - Current.console.display(verbose: "Defined variables:") - for v in variables.keys { - Current.console.display(verbose: " - \(v)") - } - Current.console.display(verbose: "") - } -} - - -func before(name: Request.Name) { - Current.console.display("🎬 \(name.blue) started ...\n") -} - - -func after(name: Request.Name, response: Response, result: ValidationResult) -> Bool { - switch result { - case .valid: - let duration = format(response.elapsed).map { " (\($0)s)" } ?? "" - Current.console.display("✅ \(name.blue) \("PASSED".green.bold)\(duration)\n") - return true - case let .invalid(message): - Current.console.display(verbose: "Response:".bold) - Current.console.display(verbose: "\(response)\n") - Current.console.display("❌ \(name.blue) \("FAILED".red.bold) : \(message.red)\n") - return false - } -} - - -let main = command( - Flag("verbose", flag: "v", description: "Verbose output"), - Option("workdir", default: "", flag: "w", description: "Working directory (for the purpose of resolving relative paths in Restfiles)"), - Option("timeout", default: 10, flag: "t", description: "Request timeout"), - Flag("insecure", default: false, description: "do not validate SSL certificate (macOS only)"), - Argument("filename", description: "A Restfile") -) { verbose, wdir, timeout, insecure, filename in - - #if !os(macOS) - if insecure { - Current.console.display("--insecure flag currently only supported on macOS") - exit(1) - } - #endif - - Current.console.display("🚀 Resting \(filename.bold) ...\n") - - let restfilePath = Path(filename) ?? Path.cwd/filename - Current.workDir = getWorkDir(input: wdir) ?? (restfilePath).parent - - if verbose { - Current.console.display(verbose: "Restfile path: \(restfilePath)") - Current.console.display(verbose: "Working directory: \(Current.workDir)\n") - } - - if timeout != Request.defaultTimeout { - Current.console.display(verbose: "Request timeout: \(timeout)s\n") - } - - let rester: Rester - do { - rester = try Rester(path: restfilePath, workDir: Current.workDir) - } catch { - Current.console.display(error) - exit(1) - } - - if verbose { - Current.console.display(variables: rester.allVariables) - } - - guard rester.requestCount > 0 else { - Current.console.display("⚠️ no requests defined in \(filename.bold)!") - exit(0) - } - - rester.test(before: before, after: after, timeout: timeout, validateCertificate: !insecure) - .done { results in - let failureCount = results.filter { !$0 }.count - let failureMsg = failureCount == 0 ? "0".green.bold : failureCount.description.red.bold - Current.console.display("Executed \(results.count.description.bold) tests, with \(failureMsg) failures") - if failureCount > 0 { - exit(1) - } else { - exit(0) - } - }.catch { error in - Current.console.display(error) - exit(1) - } - - RunLoop.main.run() - -} - main.run(ResterVersion) diff --git a/Sources/ResterCore/Main.swift b/Sources/ResterCore/Main.swift new file mode 100644 index 0000000..91d2a74 --- /dev/null +++ b/Sources/ResterCore/Main.swift @@ -0,0 +1,108 @@ +// +// Main.swift +// ResterCore +// +// Created by Sven A. Schmidt on 05/04/2019. +// + +import Commander +import Foundation +import Path + + +extension Console { + func display(variables: [Key: Value]) { + guard variables.count > 0 else { return } + Current.console.display(verbose: "Defined variables:") + for v in variables.keys { + Current.console.display(verbose: " - \(v)") + } + Current.console.display(verbose: "") + } +} + + +func before(name: Request.Name) { + Current.console.display("🎬 \(name.blue) started ...\n") +} + + +func after(name: Request.Name, response: Response, result: ValidationResult) -> Bool { + switch result { + case .valid: + let duration = format(response.elapsed).map { " (\($0)s)" } ?? "" + Current.console.display("✅ \(name.blue) \("PASSED".green.bold)\(duration)\n") + return true + case let .invalid(message): + Current.console.display(verbose: "Response:".bold) + Current.console.display(verbose: "\(response)\n") + Current.console.display("❌ \(name.blue) \("FAILED".red.bold) : \(message.red)\n") + return false + } +} + + +public let main = command( + Flag("verbose", flag: "v", description: "Verbose output"), + Option("workdir", default: "", flag: "w", description: "Working directory (for the purpose of resolving relative paths in Restfiles)"), + Option("timeout", default: 10, flag: "t", description: "Request timeout"), + Flag("insecure", default: false, description: "do not validate SSL certificate (macOS only)"), + Argument("filename", description: "A Restfile") +) { verbose, wdir, timeout, insecure, filename in + + #if !os(macOS) + if insecure { + Current.console.display("--insecure flag currently only supported on macOS") + exit(1) + } + #endif + + Current.console.display("🚀 Resting \(filename.bold) ...\n") + + let restfilePath = Path(filename) ?? Path.cwd/filename + Current.workDir = getWorkDir(input: wdir) ?? (restfilePath).parent + + if verbose { + Current.console.display(verbose: "Restfile path: \(restfilePath)") + Current.console.display(verbose: "Working directory: \(Current.workDir)\n") + } + + if timeout != Request.defaultTimeout { + Current.console.display(verbose: "Request timeout: \(timeout)s\n") + } + + let rester: Rester + do { + rester = try Rester(path: restfilePath, workDir: Current.workDir) + } catch { + Current.console.display(error) + exit(1) + } + + if verbose { + Current.console.display(variables: rester.allVariables) + } + + guard rester.requestCount > 0 else { + Current.console.display("⚠️ no requests defined in \(filename.bold)!") + exit(0) + } + + rester.test(before: before, after: after, timeout: timeout, validateCertificate: !insecure) + .done { results in + let failureCount = results.filter { !$0 }.count + let failureMsg = failureCount == 0 ? "0".green.bold : failureCount.description.red.bold + Current.console.display("Executed \(results.count.description.bold) tests, with \(failureMsg) failures") + if failureCount > 0 { + exit(1) + } else { + exit(0) + } + }.catch { error in + Current.console.display(error) + exit(1) + } + + RunLoop.main.run() + +} From a31fa3fcc35948a82a986cb4ff582a768fcde95a Mon Sep 17 00:00:00 2001 From: "Sven A. Schmidt" Date: Fri, 5 Apr 2019 08:20:15 +0200 Subject: [PATCH 09/13] Fix build --- Package.swift | 4 ++-- Sources/ResterCore/{Main.swift => Run.swift} | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename Sources/ResterCore/{Main.swift => Run.swift} (100%) diff --git a/Package.swift b/Package.swift index 47f0d16..f979343 100644 --- a/Package.swift +++ b/Package.swift @@ -23,10 +23,10 @@ let package = Package( targets: [ .target( name: "Rester", - dependencies: ["Commander", "Rainbow", "ResterCore"]), + dependencies: ["ResterCore"]), .target( name: "ResterCore", - dependencies: ["LegibleError", "PMKFoundation", "Path", "PromiseKit", "Rainbow", "Regex", "ValueCodable", "Yams"]), + dependencies: ["Commander", "LegibleError", "PMKFoundation", "Path", "PromiseKit", "Rainbow", "Regex", "ValueCodable", "Yams"]), .testTarget( name: "ResterTests", dependencies: ["ResterCore", "SnapshotTesting"]), diff --git a/Sources/ResterCore/Main.swift b/Sources/ResterCore/Run.swift similarity index 100% rename from Sources/ResterCore/Main.swift rename to Sources/ResterCore/Run.swift From 848e0a3eb72c0eccc746e9e6730a8a33db8edd5e Mon Sep 17 00:00:00 2001 From: "Sven A. Schmidt" Date: Fri, 5 Apr 2019 08:49:21 +0200 Subject: [PATCH 10/13] Reorg build steps, add Xcode build for coverage --- .travis.yml | 67 +++++++++++++++++++---------------------------------- Makefile | 3 ++- 2 files changed, 26 insertions(+), 44 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4edee7b..3eec842 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,42 +8,43 @@ env: - secure: "j39yC3GJMPK1/s/Q3VLT7fLuwhkN9lmo9OcRVb5iP8OW7HPrxb4b/e7Yp5Gia2KBjHVai/1zH0YA8UFzQju4VjvZdgLc1F+I7FK4NCXG2Vib3fy76A2wOvNl29qrTMgjYjA6dsfdUigLtZf0EE0yLV8MeVGVzsOa4w2iiJhZtWoNbBY7Xo/cAm9csZvvMJ7W+03tmsWo0VLwV9b1F8gW+WXWNLjg84tOj4KsGPDd+1dniK5xb2OxmmzygcxULm5Sbw/Dityz963LFGHIXlVxPzlQxFnio7iOQn60SA12+dwmRfRWHdUTWp7/pQgvK69kdTCJ2D8K5/QTNuxEJQ+dAT8OEoGISYUa9wS88bHM4NqK+uA9t5XsLkrpSyHMCvWadeacwMyIqxGcc9IwHVJYpMwFX2+ufu3g3JwXV54w+jjj72N/shMvhKQVfMM1V+zUGKyblPMYfbFizywa96/R4UTQFjvBknC95SnsQPOqCEEaiBKYVGtHWiFxXIsiX07lEsbsrbdzczFxBJCgYLPSpkVuydWkXxjpXZ3mo47lZomJy354RW3nRs4pfmz99o5IVjeLPqUiElXA9tkFu4yzRB5L1K+LUxwnLy1SX79BvA06rQBkqXRt5TBidtow3LcxpfrqwP0Eoop6GnoiPhbez3ZUnp3hgskAZovqCKaPzsc=" stages: - - build base image - - build app image - test - - -# install: -# - if [[ $TRAVIS_OS_NAME == "linux" ]]; then -# eval "$(curl -sL https://swiftenv.fuller.li/install.sh)" -# fi + - push app image jobs: include: - - &linux + - name: macos spm test + stage: test + os: osx + osx_image: xcode10.2 + script: make test-macos-spm + + - name: macos xcode test + stage: test + os: osx + osx_image: xcode10.2 + script: make test-macos-xcode + after_success: + # upload coverage data + - bash <(curl -s https://codecov.io/bash) -J '^ResterCore$' -D .build/derivedData + + - name: docker spm test + stage: test os: linux dist: trusty - - - <<: *linux - stage: build base image script: | set -e - - # login echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin - - # build VERSION=${TRAVIS_TAG:-$TRAVIS_COMMIT} - IMG=finestructure/rester:base-$VERSION - docker build --pull -t $IMG -f Dockerfile.base . - - # push - docker push $IMG + IMAGE=finestructure/rester:base-$VERSION + docker build --pull -t $IMAGE -f Dockerfile.base . + docker run --rm -e GITHUB_TOKEN=$GITHUB_TOKEN $IMAGE swift test - - <<: *linux - stage: build app image + - stage: push app image + os: linux + dist: trusty script: | set -e @@ -64,23 +65,3 @@ jobs: # tag and push latest docker tag $IMG finestructure/rester:latest docker push finestructure/rester:latest - - - name: swift test - stage: test - os: osx - osx_image: xcode10.2 - script: swift test --enable-code-coverage - after_success: - - bash <(curl -s https://codecov.io/bash) -J '^ResterCore$' -D .build - - - <<: *linux - name: docker swift test - stage: test - os: linux - dist: trusty - script: | - set -e - echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin - VERSION=${TRAVIS_TAG:-$TRAVIS_COMMIT} - IMAGE=finestructure/rester:base-$VERSION - docker run --rm -e GITHUB_TOKEN=$GITHUB_TOKEN $IMAGE swift test diff --git a/Makefile b/Makefile index 0421674..071ea89 100644 --- a/Makefile +++ b/Makefile @@ -24,7 +24,8 @@ test-macos-xcode: xcodeproj xcodebuild test \ -scheme Rester \ -destination platform="macOS" \ - -enableCodeCoverage YES + -enableCodeCoverage YES \ + -derivedDataPath .build/derivedData test-macos-spm: BUILD_DIR=$(shell swift build --show-bin-path) test-macos-spm: From c13d70f5ec13cb8c465d58d7ef812f43f0a9c1fe Mon Sep 17 00:00:00 2001 From: "Sven A. Schmidt" Date: Fri, 5 Apr 2019 08:58:49 +0200 Subject: [PATCH 11/13] Fix deploy step --- .travis.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3eec842..03c8bfb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,7 @@ env: stages: - test - - push app image + - deploy jobs: @@ -41,8 +41,10 @@ jobs: IMAGE=finestructure/rester:base-$VERSION docker build --pull -t $IMAGE -f Dockerfile.base . docker run --rm -e GITHUB_TOKEN=$GITHUB_TOKEN $IMAGE swift test + docker push $IMAGE - - stage: push app image + - name: push app image + stage: deploy os: linux dist: trusty script: | From d056cfc42687414de3ae80f82beec65cef23baec Mon Sep 17 00:00:00 2001 From: "Sven A. Schmidt" Date: Fri, 5 Apr 2019 08:59:56 +0200 Subject: [PATCH 12/13] Add badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b37e14e..75a143d 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Rester -![](https://img.shields.io/badge/Swift-5-blue.svg) [![Build Status](https://travis-ci.org/finestructure/Rester.svg?branch=develop)](https://travis-ci.org/finestructure/Rester) +![](https://img.shields.io/badge/Swift-5-blue.svg) [![Build Status](https://travis-ci.org/finestructure/Rester.svg?branch=develop)](https://travis-ci.org/finestructure/Rester) [![codecov](https://codecov.io/gh/finestructure/Rester/branch/develop/graph/badge.svg)](https://codecov.io/gh/finestructure/Rester) Rester is a command line tool to test HTTP APIs. It takes a request description like the following: From e3482626c2ddcdfdff7429b7a60af80fa6aba8ef Mon Sep 17 00:00:00 2001 From: "Sven A. Schmidt" Date: Fri, 5 Apr 2019 09:15:50 +0200 Subject: [PATCH 13/13] Rename files --- Sources/Rester/main.swift | 2 +- Sources/ResterCore/{Run.swift => App.swift} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename Sources/ResterCore/{Run.swift => App.swift} (99%) diff --git a/Sources/Rester/main.swift b/Sources/Rester/main.swift index c9bb4c7..f40215b 100644 --- a/Sources/Rester/main.swift +++ b/Sources/Rester/main.swift @@ -1,3 +1,3 @@ import ResterCore -main.run(ResterVersion) +app.run(ResterVersion) diff --git a/Sources/ResterCore/Run.swift b/Sources/ResterCore/App.swift similarity index 99% rename from Sources/ResterCore/Run.swift rename to Sources/ResterCore/App.swift index 91d2a74..4ca19a7 100644 --- a/Sources/ResterCore/Run.swift +++ b/Sources/ResterCore/App.swift @@ -42,7 +42,7 @@ func after(name: Request.Name, response: Response, result: ValidationResult) -> } -public let main = command( +public let app = command( Flag("verbose", flag: "v", description: "Verbose output"), Option("workdir", default: "", flag: "w", description: "Working directory (for the purpose of resolving relative paths in Restfiles)"), Option("timeout", default: 10, flag: "t", description: "Request timeout"),