[Bash] Bash client script generator (#4541)

* Initial commit

* Remormatted petstore tests

* Added Bash codegen to main README.md

* Added bash to integration tests

* Fixed stdin detection in generated script

* Added back ruby module
This commit is contained in:
Bartek Kryza 2017-01-12 09:48:25 +01:00 committed by wing328
parent 2e4de0ca1e
commit 0fb154e9a2
24 changed files with 8338 additions and 1 deletions

View File

@ -24,6 +24,12 @@ before_install:
- docker pull swaggerapi/petstore
- docker run -d -e SWAGGER_HOST=http://petstore.swagger.io -e SWAGGER_BASE_PATH=/v2 -p 80:8080 swaggerapi/petstore
- docker ps -a
# Add bats test framework and cURL for Bash script integration tests
- sudo add-apt-repository ppa:duggan/bats --yes
- sudo apt-get update -qq
- sudo apt-get install -qq bats
- sudo apt-get install -qq curl
# show host table to confirm petstore.swagger.io is mapped to localhost
- cat /etc/hosts

View File

@ -30,6 +30,7 @@ For a list of variables available in the template, please refer to this [page](h
### Style guide
Code change should conform to the programming style guide of the respective languages:
- Android: https://source.android.com/source/code-style.html
- Bash: https://github.com/bahamas10/bash-style-guide
- C#: https://msdn.microsoft.com/en-us/library/vstudio/ff926074.aspx
- C++: https://google.github.io/styleguide/cppguide.html
- Clojure: https://github.com/bbatsov/clojure-style-guide

View File

@ -15,7 +15,7 @@
## Overview
This is the swagger codegen project, which allows generation of API client libraries (SDK generation), server stubs and documentation automatically given an [OpenAPI Spec](https://github.com/OAI/OpenAPI-Specification). Currently, the following languages/frameworks are supported:
- **API clients**: **ActionScript**, **C#** (.net 2.0, 4.0 or later), **C++** (cpprest, Qt5, Tizen), **Clojure**, **Dart**, **Go**, **Groovy**, **Haskell**, **Java** (Jersey1.x, Jersey2.x, OkHttp, Retrofit1.x, Retrofit2.x, Feign), **Node.js** (ES5, ES6, AngularJS with Google Closure Compiler annotations) **Objective-C**, **Perl**, **PHP**, **Python**, **Ruby**, **Scala**, **Swift** (2.x, 3.x), **Typescript** (Angular1.x, Angular2.x, Fetch, Node)
- **API clients**: **ActionScript**, **Bash**,**C#** (.net 2.0, 4.0 or later), **C++** (cpprest, Qt5, Tizen), **Clojure**, **Dart**, **Go**, **Groovy**, **Haskell**, **Java** (Jersey1.x, Jersey2.x, OkHttp, Retrofit1.x, Retrofit2.x, Feign), **Node.js** (ES5, ES6, AngularJS with Google Closure Compiler annotations) **Objective-C**, **Perl**, **PHP**, **Python**, **Ruby**, **Scala**, **Swift** (2.x, 3.x), **Typescript** (Angular1.x, Angular2.x, Fetch, Node)
- **Server stubs**: **C#** (ASP.NET Core, NancyFx), **Erlang**, **Go**, **Haskell**, **Java** (MSF4J, Spring, Undertow, JAX-RS: CDI, CXF, Inflector, RestEasy), **PHP** (Lumen, Slim, Silex), **Python** (Flask), **NodeJS**, **Ruby** (Sinatra, Rails5), **Scala** (Scalatra)
- **API documentation generators**: **HTML**, **Confluence Wiki**
- **Others**: **JMeter**
@ -463,6 +463,7 @@ AndroidClientCodegen.java
AspNet5ServerCodegen.java
AspNetCoreServerCodegen.java
AsyncScalaClientCodegen.java
BashClientCodegen.java
CSharpClientCodegen.java
ClojureClientCodegen.java
CsharpDotNet2ClientCodegen.java
@ -891,6 +892,7 @@ Swagger Codegen core team members are contributors who have been making signific
Here is a list of template creators:
* API Clients:
* Akka-Scala: @cchafer
* Bash: @bkryza
* C++ REST: @Danielku15
* C# (.NET 2.0): @who
* Clojure: @xhh

31
bin/bash-petstore.sh Executable file
View File

@ -0,0 +1,31 @@
#!/bin/sh
SCRIPT="$0"
while [ -h "$SCRIPT" ] ; do
ls=`ls -ld "$SCRIPT"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
SCRIPT="$link"
else
SCRIPT=`dirname "$SCRIPT"`/"$link"
fi
done
if [ ! -d "${APP_DIR}" ]; then
APP_DIR=`dirname "$SCRIPT"`/..
APP_DIR=`cd "${APP_DIR}"; pwd`
fi
executable="./modules/swagger-codegen-cli/target/swagger-codegen-cli.jar"
if [ ! -f "$executable" ]
then
mvn clean package
fi
# if you've executed sbt assembly previously it will use that instead.
export JAVA_OPTS="${JAVA_OPTS} -XX:MaxPermSize=256M -Xmx1024M -DloggerPath=conf/log4j.properties"
args="$@ generate -t modules/swagger-codegen/src/main/resources/bash -i modules/swagger-codegen/src/test/resources/2_0/petstore-with-fake-endpoints-models-for-testing.yaml -l bash -o samples/client/petstore/bash -c modules/swagger-codegen/src/test/resources/2_0/bash-config.json"
java $JAVA_OPTS -jar $executable $args

View File

@ -0,0 +1,655 @@
package io.swagger.codegen.languages;
import io.swagger.codegen.*;
import io.swagger.models.properties.*;
import io.swagger.models.parameters.*;
import io.swagger.models.Model;
import io.swagger.models.Operation;
import io.swagger.models.Swagger;
import io.swagger.models.properties.ArrayProperty;
import io.swagger.models.properties.MapProperty;
import io.swagger.models.properties.Property;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.io.File;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.node.ObjectNode;
public class BashClientCodegen extends DefaultCodegen implements CodegenConfig {
protected String apiVersion = "1.0.0";
protected String curlOptions;
protected boolean processMarkdown = false;
protected String scriptName = "client.sh";
protected boolean generateBashCompletion = false;
protected boolean generateZshCompletion = false;
protected String hostEnvironmentVariable;
protected String basicAuthEnvironmentVariable;
protected String apiKeyAuthEnvironmentVariable;
public static final String CURL_OPTIONS = "curlOptions";
public static final String PROCESS_MARKDOWN = "processMarkdown";
public static final String SCRIPT_NAME = "scriptName";
public static final String
GENERATE_BASH_COMPLETION = "generateBashCompletion";
public static final String
GENERATE_ZSH_COMPLETION = "generateZshCompletion";
public static final String
HOST_ENVIRONMENT_VARIABLE_NAME = "hostEnvironmentVariable";
public static final String
BASIC_AUTH_ENVIRONMENT_VARIABLE_NAME = "basicAuthEnvironmentVariable";
public static final String
APIKEY_AUTH_ENVIRONMENT_VARIABLE_NAME = "apiKeyAuthEnvironmentVariable";
/**
* Configures the type of generator.
*
* @return the CodegenType for this generator
* @see io.swagger.codegen.CodegenType
*/
public CodegenType getTag() {
return CodegenType.CLIENT;
}
/**
* Configures a friendly name for the generator. This will be used by
* the generator to select the library with the -l flag.
*
* @return the friendly name for the generator
*/
public String getName() {
return "bash";
}
/**
* Returns human-friendly help for the generator. Provide the consumer with
* help tips, parameters here
*
* @return A string value for the help message
*/
public String getHelp() {
return "Generates a Bash client script based on cURL.";
}
public BashClientCodegen() {
super();
/**
* Set the output folder here
*/
outputFolder = "generated-code/bash";
/**
* No model files.
*/
modelTemplateFiles.clear();
/**
* No API files.
*/
apiTemplateFiles.clear();
/**
* Templates location for client script and bash completion template.
*/
templateDir = "bash";
/**
* Allow the user to force the script to always include certain cURL
* comamnds
*/
cliOptions.add(CliOption.newString(CURL_OPTIONS, "Default cURL options"));
cliOptions.add(CliOption.newBoolean(PROCESS_MARKDOWN,
"Convert all Markdown Markup into terminal formatting"));
cliOptions.add(CliOption.newString(SCRIPT_NAME,
"The name of the script that will be generated "+
"(e.g. petstore-cli)"));
cliOptions.add(CliOption.newBoolean(GENERATE_BASH_COMPLETION,
"Whether to generate the Bash completion script"));
cliOptions.add(CliOption.newBoolean(GENERATE_ZSH_COMPLETION,
"Whether to generate the Zsh completion script"));
cliOptions.add(CliOption.newString(HOST_ENVIRONMENT_VARIABLE_NAME,
"Name of environment variable where host can be defined "+
"(e.g. PETSTORE_HOST='http://petstore.swagger.io:8080')"));
cliOptions.add(CliOption.newString(BASIC_AUTH_ENVIRONMENT_VARIABLE_NAME,
"Name of environment variable where username and password "
+
"can be defined (e.g. PETSTORE_CREDS='username:password')"));
cliOptions.add(CliOption.newBoolean(APIKEY_AUTH_ENVIRONMENT_VARIABLE_NAME,
"Name of environment variable where API key "
+
"can be defined (e.g. PETSTORE_APIKEY='kjhasdGASDa5asdASD')"));
/**
* Bash reserved words.
*/
reservedWords = new HashSet<String> (
Arrays.asList(
"case",
"do",
"done",
"elif",
"else",
"esac",
"fi",
"for",
"function",
"if",
"in",
"select",
"then",
"time",
"until",
"while")
);
typeMapping.clear();
typeMapping.put("array", "array");
typeMapping.put("map", "map");
typeMapping.put("List", "array");
typeMapping.put("boolean", "boolean");
typeMapping.put("string", "string");
typeMapping.put("int", "integer");
typeMapping.put("float", "float");
typeMapping.put("number", "integer");
typeMapping.put("DateTime", "string");
typeMapping.put("long", "integer");
typeMapping.put("short", "integer");
typeMapping.put("char", "string");
typeMapping.put("double", "float");
typeMapping.put("object", "map");
typeMapping.put("integer", "integer");
typeMapping.put("ByteArray", "string");
typeMapping.put("binary", "binary");
/**
* Additional Properties. These values can be passed to the templates and
* are available in models, apis, and supporting files.
*/
additionalProperties.put("apiVersion", apiVersion);
/**
* Language Specific Primitives. These types will not trigger imports by
* the client generator
*/
languageSpecificPrimitives = new HashSet<String>();
}
@Override
public void processOpts() {
super.processOpts();
String curlopts = "";
if (additionalProperties.containsKey(CURL_OPTIONS)) {
setCurlOptions(additionalProperties.get(CURL_OPTIONS).toString());
additionalProperties.put("x-codegen-curl-options", curlopts);
}
if (additionalProperties.containsKey(PROCESS_MARKDOWN)) {
setProcessMarkdown(
Boolean.parseBoolean(
additionalProperties.get(PROCESS_MARKDOWN).toString()));
}
if (additionalProperties.containsKey(GENERATE_BASH_COMPLETION)) {
setGenerateBashCompletion(
Boolean.parseBoolean(
additionalProperties.get(GENERATE_BASH_COMPLETION).toString()));
}
if (additionalProperties.containsKey(GENERATE_ZSH_COMPLETION)) {
setGenerateZshCompletion(
Boolean.parseBoolean(
additionalProperties.get(GENERATE_ZSH_COMPLETION).toString()));
}
if (additionalProperties.containsKey(SCRIPT_NAME)) {
setScriptName(additionalProperties.get(SCRIPT_NAME).toString());
}
additionalProperties.put("x-codegen-script-name", scriptName);
if (additionalProperties.containsKey(HOST_ENVIRONMENT_VARIABLE_NAME)) {
setHostEnvironmentVariable(
additionalProperties.get(HOST_ENVIRONMENT_VARIABLE_NAME).toString());
additionalProperties.put("x-codegen-host-env", hostEnvironmentVariable);
}
if (additionalProperties.containsKey(BASIC_AUTH_ENVIRONMENT_VARIABLE_NAME)) {
setBasicAuthEnvironmentVariable(
additionalProperties.get(BASIC_AUTH_ENVIRONMENT_VARIABLE_NAME).toString());
additionalProperties.put("x-codegen-basicauth-env", basicAuthEnvironmentVariable);
}
if (additionalProperties.containsKey(APIKEY_AUTH_ENVIRONMENT_VARIABLE_NAME)) {
setApiKeyAuthEnvironmentVariable(
additionalProperties.get(APIKEY_AUTH_ENVIRONMENT_VARIABLE_NAME).toString());
additionalProperties.put("x-codegen-apikey-env", apiKeyAuthEnvironmentVariable);
}
supportingFiles.add(new SupportingFile(
"client.mustache", "", scriptName));
supportingFiles.add(new SupportingFile(
"bash-completion.mustache", "", scriptName+".bash-completion"));
supportingFiles.add(new SupportingFile(
"zsh-completion.mustache", "", "_"+scriptName));
supportingFiles.add(new SupportingFile(
"README.mustache", "", "README.md"));
}
public void setCurlOptions(String curlOptions) {
this.curlOptions = curlOptions;
}
public void setProcessMarkdown(boolean processMarkdown) {
this.processMarkdown = processMarkdown;
}
public void setScriptName(String scriptName) {
this.scriptName = scriptName;
}
public void setGenerateBashCompletion(boolean generateBashCompletion) {
this.generateBashCompletion = generateBashCompletion;
}
public void setGenerateZshCompletion(boolean generateZshCompletion) {
this.generateZshCompletion = generateZshCompletion;
}
public void setHostEnvironmentVariable(String hostEnvironmentVariable) {
this.hostEnvironmentVariable = hostEnvironmentVariable;
}
public void setBasicAuthEnvironmentVariable(String
basicAuthEnvironmentVariable) {
this.basicAuthEnvironmentVariable = basicAuthEnvironmentVariable;
}
public void setApiKeyAuthEnvironmentVariable(String
apiKeyAuthEnvironmentVariable) {
this.apiKeyAuthEnvironmentVariable = apiKeyAuthEnvironmentVariable;
}
/**
* Escapes a reserved word as defined in the `reservedWords` array. Handle
* escaping those terms here. This logic is only called if a variable
* matches the reseved words.
*
* @return the escaped term
*/
@Override
public String escapeReservedWord(String name) {
return "_" + name; // add an underscore to the name
}
/**
* Location to write model files. You can use the modelPackage() as defined
* when the class is instantiated.
*/
public String modelFileFolder() {
return outputFolder;
}
/**
* Location to write api files. You can use the apiPackage() as defined when
* the class is instantiated.
*/
@Override
public String apiFileFolder() {
return outputFolder;
}
/**
* Optional - type declaration. This is a String which is used by the
* templates to instantiate your types. There is typically special handling
* for different property types
*
* @return a string value used as the `dataType` field for model templates,
* `returnType` for api templates
*/
@Override
public String getTypeDeclaration(Property p) {
if(p instanceof ArrayProperty) {
ArrayProperty ap = (ArrayProperty) p;
Property inner = ap.getItems();
return getSwaggerType(p) + "[" + getTypeDeclaration(inner) + "]";
}
else if (p instanceof MapProperty) {
MapProperty mp = (MapProperty) p;
Property inner = mp.getAdditionalProperties();
return getSwaggerType(p) + "[String, " + getTypeDeclaration(inner) + "]";
}
return super.getTypeDeclaration(p);
}
/**
* Optional - swagger type conversion. This is used to map swagger types in
* a `Property` into either language specific types via `typeMapping` or into
* complex models if there is not a mapping.
*
* @return a string value of the type or complex model for this property
* @see io.swagger.models.properties.Property
*/
@Override
public String getSwaggerType(Property p) {
String swaggerType = super.getSwaggerType(p);
String type = null;
if(typeMapping.containsKey(swaggerType)) {
type = typeMapping.get(swaggerType);
if(languageSpecificPrimitives.contains(type))
return type;
}
else
type = swaggerType;
return toModelName(type);
}
/**
* Convert Swagger Parameter object to Codegen Parameter object
*
* @param param Swagger parameter object
* @param imports set of imports for library/package/module
* @return Codegen Parameter object
*/
@Override
public CodegenParameter fromParameter(Parameter param, Set<String> imports) {
CodegenParameter p = super.fromParameter(param, imports);
if(param instanceof BodyParameter) {
Model model = ((BodyParameter)param).getSchema();
}
else if(param instanceof SerializableParameter) {
/**
* Currently it's not possible to specify in the codegen other collection
* formats than 'multi'
*/
SerializableParameter sparam = (SerializableParameter)param;
if( sparam.getCollectionFormat() != null
&& !sparam.getCollectionFormat().isEmpty()) {
String collectionFormat = sparam.getCollectionFormat();
if(sparam.isExclusiveMaximum()!=null && sparam.isExclusiveMaximum()) {
p.vendorExtensions.put("x-codegen-collection-max-items",
sparam.getMaxItems());
}
if(sparam.isExclusiveMinimum()!=null && sparam.isExclusiveMinimum()) {
p.vendorExtensions.put("x-codegen-collection-min-items",
sparam.getMinItems());
}
if( (collectionFormat.equals("multi"))
&& (param.getIn().equals("query")) ) {
/**
* 'multi' is only supported for query parameters
*/
p.vendorExtensions.put("x-codegen-collection-multi", true);
}
else if(collectionFormat.equals("csv")) {
p.vendorExtensions.put("x-codegen-collection-csv", true);
}
else if(collectionFormat.equals("ssv")) {
p.vendorExtensions.put("x-codegen-collection-ssv", true);
}
else if(collectionFormat.equals("tsv")) {
p.vendorExtensions.put("x-codegen-collection-tsv", true);
}
else if(collectionFormat.equals("pipes")) {
p.vendorExtensions.put("x-codegen-collection-pipes", true);
}
else {
/** Unsupported collection format */
}
}
}
return p;
}
/**
* Override with any special text escaping logic
*/
@SuppressWarnings("static-method")
public String escapeText(String input) {
if (input == null) {
return input;
}
/**
* remove standalone '\'
*
* replace " with \"
* outter unescape to retain the original multi-byte characters
*/
String result = escapeUnsafeCharacters(
StringEscapeUtils.unescapeJava(
StringEscapeUtils.escapeJava(input).replace("\\/", "/"))
.replace("\\", "\\\\")
.replace("\"", "\\\""));
if(this.processMarkdown) {
/**
* Convert markdown strong **Bold text** and __Bold text__
* to bash bold control sequences (tput bold)
*/
result = result.replaceAll("(?m)(^|\\s)\\*{2}([\\w\\d ]+)\\*{2}($|\\s)",
"\\$\\(tput bold\\) $2 \\$\\(tput sgr0\\)");
result = result.replaceAll("(?m)(^|\\s)_{2}([\\w\\d ]+)_{2}($|\\s)",
"\\$\\(tput bold\\) $2 \\$\\(tput sgr0\\)");
/**
* Convert markdown *Italics text* and _Italics text_ to bash dim
* control sequences (tput dim)
*/
result = result.replaceAll("(?m)(^|\\s)\\*{1}([\\w\\d ]+)\\*{1}($|\\s)",
"\\$\\(tput dim\\) $2 \\$\\(tput sgr0\\)");
result = result.replaceAll("(?m)(^|\\s)_{1}([\\w\\d ]+)_{1}($|\\s)",
"\\$\\(tput dim\\) $2 \\$\\(tput sgr0\\)");
/**
* Convert all markdown section 1 level headers with bold
*/
result = result.replaceAll("(?m)^\\#\\s+(.+)$",
"\n\\$\\(tput bold\\)\\$\\(tput setaf 7\\)"
+"$1\\$\\(tput sgr0\\)");
/**
* Convert all markdown section 2 level headers with bold
*/
result = result.replaceAll("(?m)^\\#\\#\\s+(.+)$",
"\n\\$\\(tput bold\\)\\$\\(tput setaf 7\\)"
+"$1\\$\\(tput sgr0\\)");
/**
* Convert all markdown section 3 level headers with bold
*/
result = result.replaceAll("(?m)^\\#\\#\\#\\s+(.+)$",
"\n\\$\\(tput bold\\)\\$\\(tput setaf 7\\)"
+"$1\\$\\(tput sgr0\\)");
/**
* Convert all markdown code blocks into --- delimited sections
*/
result = result.replaceAll("(?m)\\s*```.*$",
"\n---");
result = result.replaceAll("(?m)\\s*\\'\\'\\'.*$",
"\n---");
/**
* Remove any trailing new line at the end of the string
*/
result = result.replaceAll("\\s+$", "");
}
return result;
}
@Override
public String escapeQuotationMark(String input) {
return input;
}
/**
* Override with any special text escaping logic to handle unsafe
* characters so as to avoid code injection.
*
* @param input String to be cleaned up
* @return string with unsafe characters removed or escaped
*/
public String escapeUnsafeCharacters(String input) {
/**
* Replace backticks with normal single quotes.
*/
String result = input.replaceAll("`", "'");
return result;
}
@Override
public CodegenOperation fromOperation(String path, String httpMethod,
Operation operation,
Map<String, Model> definitions,
Swagger swagger) {
CodegenOperation op = super.fromOperation(path, httpMethod, operation,
definitions, swagger);
/**
* Check if the operation has a Bash codegen specific description
* for help
*/
if(op.vendorExtensions.containsKey("x-bash-codegen-description")) {
String bash_description
= (String)op.vendorExtensions.get("x-bash-codegen-description");
op.vendorExtensions.put("x-bash-codegen-description",
escapeText(bash_description));
}
/**
* Check if operation has an 'x-code-samples' vendor extension with
* Shell example
*/
if(op.vendorExtensions.containsKey("x-code-samples")) {
List codesamples = (List)op.vendorExtensions.get("x-code-samples");
for (Object codesample : codesamples) {
ObjectNode codesample_object = (ObjectNode)codesample;
if((codesample_object.get("lang").asText()).equals("Shell")) {
op.vendorExtensions.put("x-bash-codegen-sample",
escapeUnsafeCharacters(
codesample_object.get("source").asText()));
}
}
}
for (CodegenParameter p : op.bodyParams) {
if(p.dataType != null && definitions.get(p.dataType) != null) {
/**
* If the operation produces Json and has nonempty example
* try to reformat it.
*/
if(operation.getConsumes() != null
&& operation.getConsumes().contains("application/json")
&& definitions.get(p.dataType).getExample() != null) {
ObjectMapper mapper = new ObjectMapper();
try {
p.vendorExtensions.put(
"x-codegen-body-example",
mapper.writerWithDefaultPrettyPrinter().writeValueAsString(
definitions.get(p.dataType).getExample()));
}
catch(JsonProcessingException e) {
e.printStackTrace();
}
}
else {
/**
* Otherwise present whatever is provided as example
*/
p.vendorExtensions.put(
"x-codegen-body-example",
definitions.get(p.dataType).getExample());
}
}
}
return op;
}
/**
* Preprocess original properties from the Swagger definition where necessary.
*
* @param swagger [description]
*/
@Override
public void preprocessSwagger(Swagger swagger) {
super.preprocessSwagger(swagger);
if ("/".equals(swagger.getBasePath())) {
swagger.setBasePath("");
}
if(swagger.getInfo() != null
&& swagger.getInfo().getVendorExtensions()!=null) {
String bash_codegen_app_description
= (String)swagger.getInfo().getVendorExtensions()
.get("x-bash-codegen-description");
if(bash_codegen_app_description != null) {
bash_codegen_app_description
= escapeText(bash_codegen_app_description);
additionalProperties.put("x-bash-codegen-app-description",
bash_codegen_app_description);
}
}
}
}

View File

@ -2,6 +2,7 @@ io.swagger.codegen.languages.AndroidClientCodegen
io.swagger.codegen.languages.AspNet5ServerCodegen
io.swagger.codegen.languages.AspNetCoreServerCodegen
io.swagger.codegen.languages.AsyncScalaClientCodegen
io.swagger.codegen.languages.BashClientCodegen
io.swagger.codegen.languages.ConfluenceWikiGenerator
io.swagger.codegen.languages.CSharpClientCodegen
io.swagger.codegen.languages.CppRestClientCodegen

View File

@ -0,0 +1,220 @@
# Bash script generator for Swagger Codegen
## Overview
This is a Bash client script codegen.
The codegen creates a standalone, single-file Bash script client to quickly test and access Swagger annotated REST services. The generated script uses underneath [cURL](https://curl.haxx.se) to make actual REST calls.
The generated Bash script has only 2 dependencies:
- Bash (>= 4.3)
- cURL
## Features
- Fully automatic generation of a client Bash script to access any Swagger-defined REST service
- Generation of Bash and Zsh completion scripts
- All valid cURL options can be passed directly
- Preview of cURL commands to execute each operation using `--dry-run` option
- Complete help for entire service as well as for each operation
- No external dependencies besides Bash and cURL
## Usage
### Generating Bash client for REST service
Get the sources:
```shell
$ git clone https://github.com/swagger-api/swagger-codegen
```
Build the codegen:
```shell
$ mvn assembly:assembly -DdescriptorId=jar-with-dependencies
```
Define custom codegen properties in a Json file, e.g.:
```shell
{
"processMarkdown": true,
"curlOptions": "-sS --tlsv1.2",
"scriptName": "petstore-cli",
"generateBashCompletion": true,
"generateZshCompletion": true,
"hostEnvironmentVariable": "PETSTORE_HOST",
"basicAuthEnvironmentVariable": "PETSTORE_BASIC_AUTH",
"apiKeyAuthEnvironmentVariable": "PETSTORE_API_KEY"
}
```
Generate the client:
```shell
$ java -cp target/bash-swagger-codegen-1.0.0.jar io.swagger.codegen.SwaggerCodegen generate -l bash -i http://petstore.swagger.io/v2/swagger.json -o output -c resources/example-config.json
$ chmod +x output/petstore-cli
```
Enjoy:
```shell
$ output/petstore-cli -h
Swagger Petstore command line client (API version 1.0.0)
Usage
petstore-cli [-h|--help] [-V|--version] [--about] [<curl-options>]
[-ac|--accept <mime-type>] [-ct,--content-type <mime-type>]
[--host <url>] [--dry-run] <operation> [-h|--help] [<headers>]
[<parameters>] [<body-parameters>]
- <url> - endpoint of the REST service without basepath
Can also be specified in PETSTORE_HOST environment variable.
- <curl-options> - any valid cURL options can be passed before <operation>
- <mime-type> - either full mime-type or one of supported abbreviations:
(text, html, md, csv, css, rtf, json, xml, yaml, js, bin,
rdf, jpg, png, gif, bmp, tiff)
- <headers> - HTTP headers can be passed in the form HEADER:VALUE
- <parameters> - REST operation parameters can be passed in the following
forms:
* KEY=VALUE - path or query parameters
- <body-parameters> - simple JSON body content (first level only) can be build
using the following arguments:
* KEY==VALUE - body parameters which will be added to body
JSON as '{ ..., "KEY": "VALUE", ... }'
* KEY:=VALUE - body parameters which will be added to body
JSON as '{ ..., "KEY": VALUE, ... }'
Authentication methods
- Api-key - add 'api_key:<api-key>' after <operation>
or export PETSTORE_API_KEY='<api-key>'
- OAuth2 (flow: implicit)
Authorization URL:
* http://petstore.swagger.io/oauth/dialog
Scopes:
* write:pets - modify pets in your account
* read:pets - read your pets
Operations (grouped by tags)
[pet]
addPet Add a new pet to the store
deletePet Deletes a pet
findPetsByStatus Finds Pets by status
findPetsByTags Finds Pets by tags
getPetById Find pet by ID
updatePet Update an existing pet
updatePetWithForm Updates a pet in the store with form data
uploadFile uploads an image
[store]
deleteOrder Delete purchase order by ID
getInventory Returns pet inventories by status
getOrderById Find purchase order by ID
placeOrder Place an order for a pet
[user]
createUser Create user
createUsersWithArrayInput Creates list of users with given input array
createUsersWithListInput Creates list of users with given input array
deleteUser Delete user
getUserByName Get user by user name
loginUser Logs user into the system
logoutUser Logs out current logged in user session
updateUser Updated user
Options
-h,--help Print this help
-V,--version Print API version
--about Print the information about service
--host <url> Specify the host URL
(e.g. 'https://petstore.swagger.io')
--force Force command invocation in spite of missing
required parameters or wrong content type
--dry-run Print out the cURL command without
executing it
-ac,--accept <mime-type> Set the 'Accept' header in the request
-ct,--content-type <mime-type> Set the 'Content-type' header in
the request
```
Client generator takes several specific configuration options:
* *processMarkdown* - [boolean] if set to `true`, all text (descriptions) in the Swagger specification will be treated as Markdown and converted to terminal formatting commands,
* *curlOptions* - [string] a list of default cURL options that will be added to each command
* *scriptName* - [string] the name of the target script, necessary when building Bash completion script
* *generateBashCompletion* - [boolean] if set to `true` the Bash completion script will be generated
* *generateZshCompletion* - [boolean] if set to `true` the Bash completion script will be generated
* *hostEnvironmentVariable* - [string] the name of environment variable to search for default host
* *basicAuthEnvironmentVariable* - [string] the name of environment variable to search for default basic auth credentials
* *apiKeyAuthEnvironmentVariable* - [string] the name of environment variable to search for default api key
These options can be specified in a Json file used when running the codegen using option `-c` (see [example](resources/example-config.json)).
### Using the generated Bash script
```shell
# Print the list of operations available on the service
$ petstore-cli --help
# Print the service description
$ petstore-cli --about
# Print detailed information about specific operation
$ petstore-cli addPet --help
# Call REST API operation
$ echo '{"id":891,"name":"lucky","status":"available"}' | petstore-cli --host http://petstore.swagger.io --content-type json addPet -
{"id":891,"name":"lucky","photoUrls":[],"tags":[],"status":"available"}
# The above is equivalent to
$ petstore-cli --host http://petstore.swagger.io --content-type json --accept xml addPet id:=891 name==lucky status==available
<xml version="1.0" encoding="UTF-8" standalone="yes"?><Pet><id>891</id><name>lucky</name><photoUrls/><status>available</status><tags/></Pet>
# Preview the cURL command without actually executing it
# The above is equivalent to
$ petstore-cli --host http://petstore.swagger.io --content-type json --dry-run addPet id:=891 name==lucky status==available
curl -sS --tlsv1.2 -H 'Content-type: application/json' -X POST -d '{"name": "lucky", "status": "available", "id": 891}' "http://petstore.swagger.io/v2/pet"
```
## Shell completion
### Bash
The generated bash-completion script can be either directly loaded to the current Bash session using:
```shell
source output/petstore-cli.bash-completion
```
Alternatively, the script can be copied to the `/etc/bash-completion.d` (or on OSX with Homebrew to `/usr/local/etc/bash-completion.d`):
```shell
sudo cp output/petstore-cli.bash-completion /etc/bash-completion.d/petstore-cli
```
#### OS X
On OSX you might need to install bash-completion using Homebrew:
```shell
brew install bash-completion
```
and add the following to the `~/.bashrc`:
```shell
if [ -f $(brew --prefix)/etc/bash_completion ]; then
. $(brew --prefix)/etc/bash_completion
fi
```
### Zsh
In Zsh, the generated `_{{scriptName}}` file (e.g. _petstore-cli) must be copied to one of the folders under `$fpath` variable.
## TODO
- [ ] Add enum values for parameters shell completion
- [ ] Wrap handling of errors returned by the service, using comments defined in the Swagger specification
- [ ] Improve `--help` and `--about` formatting
- [ ] Add support to bash 4.0-4.2 (currently must be >= 4.3)
- [ ] Add manpage generation
- [ ] Add support for form data
- [ ] Move todos to Github issues

View File

@ -0,0 +1,75 @@
# {{appName}} Bash client
## Overview
This is a Bash client script for accessing {{appName}} service.
The script uses cURL underneath for making all REST calls.
## Usage
```shell
# Make sure the script has executable rights
$ chmod u+x {{scriptName}}
# Print the list of operations available on the service
$ ./{{scriptName}} -h
# Print the service description
$ ./{{scriptName}} --about
# Print detailed information about specific operation
$ ./{{scriptName}} <operationId> -h
# Make GET request
./{{scriptName}} --host http://<hostname>:<port> --accept xml <operationId> <queryParam1>=<value1> <header_key1>:<header_value2>
# Make GET request using arbitrary curl options (must be passed before <operationId>) to an SSL service using username:password
{{scriptName}} -k -sS --tlsv1.2 --host https://<hostname> -u <user>:<password> --accept xml <operationId> <queryParam1>=<value1> <header_key1>:<header_value2>
# Make POST request
$ echo '<body_content>' | {{scriptName}} --host <hostname> --content-type json <operationId> -
# Make POST request with simple JSON content, e.g.:
# {
# "key1": "value1",
# "key2": "value2",
# "key3": 23
# }
$ echo '<body_content>' | {{scriptName}} --host <hostname> --content-type json <operationId> key1==value1 key2=value2 key3:=23 -
# Preview the cURL command without actually executing it
$ {{scriptName}} --host http://<hostname>:<port> --dry-run <operationid>
```
## Shell completion
### Bash
The generated bash-completion script can be either directly loaded to the current Bash session using:
```shell
source {{scriptName}}.bash-completion
```
Alternatively, the script can be copied to the `/etc/bash-completion.d` (or on OSX with Homebrew to `/usr/local/etc/bash-completion.d`):
```shell
sudo cp {{scriptName}}.bash-completion /etc/bash-completion.d/{{scriptName}}
```
#### OS X
On OSX you might need to install bash-completion using Homebrew:
```shell
brew install bash-completion
```
and add the following to the `~/.bashrc`:
```shell
if [ -f $(brew --prefix)/etc/bash_completion ]; then
. $(brew --prefix)/etc/bash_completion
fi
```
### Zsh
In Zsh, the generated `_{{scriptName}}` Zsh completion file must be copied to one of the folders under `$FPATH` variable.

View File

@ -0,0 +1,286 @@
# {{scriptName}} completion -*- shell-script -*-
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# !
# ! Note:
# !
# ! THIS SCRIPT HAS BEEN AUTOMATICALLY GENERATED USING
# ! swagger-codegen (https://github.com/swagger-api/swagger-codegen)
# ! FROM SWAGGER SPECIFICATION IN JSON.
# !
# ! Generated on: {{generatedDate}}
# !
# !
# ! System wide installation:
# !
# ! $ sudo cp {{scriptName}}.bash-completion /etc/bash-completion.d/{{scriptName}}
# !
# !
# ! User home installation (add this line to .bash_profile):
# !
# ! [ -r ~/{{scriptName}}.bash-completion ] && source ~/{{scriptName}}.bash-completion
# !
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
declare -A mime_type_abbreviations
# text/*
mime_type_abbreviations["text"]="text/plain"
mime_type_abbreviations["html"]="text/html"
mime_type_abbreviations["md"]="text/x-markdown"
mime_type_abbreviations["csv"]="text/csv"
mime_type_abbreviations["css"]="text/css"
mime_type_abbreviations["rtf"]="text/rtf"
# application/*
mime_type_abbreviations["json"]="application/json"
mime_type_abbreviations["xml"]="application/xml"
mime_type_abbreviations["yaml"]="application/yaml"
mime_type_abbreviations["js"]="application/javascript"
mime_type_abbreviations["bin"]="application/octet-stream"
mime_type_abbreviations["rdf"]="application/rdf+xml"
# image/*
mime_type_abbreviations["jpg"]="image/jpeg"
mime_type_abbreviations["png"]="image/png"
mime_type_abbreviations["gif"]="image/gif"
mime_type_abbreviations["bmp"]="image/bmp"
mime_type_abbreviations["tiff"]="image/tiff"
__osx_init_completion()
{
COMPREPLY=()
_get_comp_words_by_ref cur prev words cword
}
_{{scriptName}}()
{
local cur
local prev
local words
local cword
#words="${COMP_WORDS}"
#cword="${COMP_CWORD}"
#prev="${COMP_WORDS[COMP_CWORD-1]}"
#cur="${COMP_WORDS[COMP_CWORD]}"
# The reference of currently selected REST operation
local operation=""
# The list of available operation in the REST service
# It's modelled as an associative array for efficient key lookup
declare -A operations
{{#apiInfo}}
{{#apis}}
{{#operations}}
{{#operation}}
operations["{{operationId}}"]=1
{{/operation}}
{{/operations}}
{{/apis}}
{{/apiInfo}}
# An associative array of operations to their parameters
# Only include path, query and header parameters
declare -A operation_parameters
{{#apiInfo}}
{{#apis}}
{{#operations}}
{{#operation}}
operation_parameters["{{operationId}}"]="{{#pathParams}}{{baseName}}= {{/pathParams}}{{#queryParams}}{{baseName}}= {{/queryParams}}{{#headerParams}}{{baseName}}: {{/headerParams}}"
{{/operation}}
{{/operations}}
{{/apis}}
{{/apiInfo}}
# An associative array of possible values for enum parameters
declare -A operation_parameters_enum_values
{{#apiInfo}}
{{#apis}}
{{#operations}}
{{#operation}}
{{#allParams}}
{{#pathParams}}
{{#isBoolean}}
operation_parameters_enum_values["{{operationId}}::{{baseName}}"]="true false"
{{/isBoolean}}
{{#isEnum}}
operation_parameters_enum_values["{{operationId}}::{{baseName}}"]=""
{{/isEnum}}
{{/pathParams}}
{{#queryParams}}
{{#isBoolean}}
operation_parameters_enum_values["{{operationId}}::{{baseName}}"]="true false"
{{/isBoolean}}
{{/queryParams}}
{{#headerParams}}
{{#isBoolean}}
operation_parameters_enum_values["{{operationId}}::{{baseName}}"]="true false"
{{/isBoolean}}
{{/headerParams}}
{{/allParams}}
{{/operation}}
{{/operations}}
{{/apis}}
{{/apiInfo}}
#
# Check if the _init_completion function is available, which is
# available since bash-completion 1.4
#
if declare -F _init_completions >/dev/null 2>&1; then
_init_completion -s || return
else
__osx_init_completion || return
fi
# Check if operation is already in the command line provided
for word in "${words[@]}"; do
if [[ -n $word && ${operations[$word]} ]]; then
operation="${word}"
fi
done
if [[ -z $operation ]]; then
case $prev in
--ciphers|--connect-timeout|-C|--continue-at|-F|--form|--form-string|\
--ftp-account|--ftp-alternative-to-user|-P|--ftp-port|-H|--header|-h|\
--help|--hostpubmd5|--keepalive-time|--krb|--limit-rate|--local-port|\
--mail-from|--mail-rcpt|--max-filesize|--max-redirs|-m|--max-time|\
--pass|--proto|--proto-redir|--proxy-user|--proxy1.0|-Q|--quote|-r|\
--range|-X|--request|--retry|--retry-delay|--retry-max-time|\
--socks5-gssapi-service|-t|--telnet-option|--tftp-blksize|-z|\
--time-cond|--url|-u|--user|-A|--user-agent|-V|--version|-w|\
--write-out|--resolve|--tlsuser|--tlspassword|--about)
return
;;
-K|--config|-b|--cookie|-c|--cookie-jar|-D|--dump-header|--egd-file|\
--key|--libcurl|-o|--output|--random-file|-T|--upload-file|--trace|\
--trace-ascii|--netrc-file)
_filedir
return
;;
--cacert|-E|--cert)
_filedir '@(c?(e)rt|cer|pem|der)'
return
;;
--capath)
_filedir -d
return
;;
--cert-type|--key-type)
COMPREPLY=( $( compgen -W 'DER PEM ENG' -- "$cur" ) )
return
;;
--crlfile)
_filedir crl
return
;;
-d|--data|--data-ascii|--data-binary|--data-urlencode)
if [[ $cur == \@* ]]; then
cur=${cur:1}
_filedir
COMPREPLY=( "${COMPREPLY[@]/#/@}" )
fi
return
;;
--delegation)
COMPREPLY=( $( compgen -W 'none policy always' -- "$cur" ) )
return
;;
--engine)
COMPREPLY=( $( compgen -W 'list' -- "$cur" ) )
return
;;
--ftp-method)
COMPREPLY=( $( compgen -W 'multicwd nocwd singlecwd' -- "$cur" ) )
return
;;
--ftp-ssl-ccc-mode)
COMPREPLY=( $( compgen -W 'active passive' -- "$cur" ) )
return
;;
--interface)
_available_interfaces -a
return
;;
-x|--proxy|--socks4|--socks4a|--socks5|--socks5-hostname)
_known_hosts_real
return
;;
--pubkey)
_filedir pub
return
;;
--stderr)
COMPREPLY=( $( compgen -W '-' -- "$cur" ) )
_filedir
return
;;
--tlsauthtype)
COMPREPLY=( $( compgen -W 'SRP' -- "$cur" ) )
return
;;
--host)
COMPREPLY=( $( compgen -W 'http:// https://' -- "$cur" ) )
return
;;
-ct|--content-type|-ac|--accept)
COMPREPLY=( $( compgen -W '${!mime_type_abbreviations[*]}' -- "$cur" ) )
return
;;
esac
fi
#
# Complete the server address based on ~/.ssh/known_hosts
# and ~/.ssh/config
#
# \todo Fix - cur matches only '//' when $prev is ':'
#
if [[ "$cur" == "http://" || "$cur" == "https://" ]]; then
COMPREPLY=()
local comp_ssh_hosts=`cat ~/.ssh/known_hosts | \
cut -f 1 -d ' ' | \
sed -e s/,.*//g | \
grep -v ^# | \
uniq | \
grep -v "\[" ;
cat ~/.ssh/config | \
grep "^Host " | \
awk '{print $2}'`
COMPREPLY=( $(compgen -W "${comp_ssh_hosts}" -- $cur))
return
fi
#
# Complete the {{scriptName}} and cURL's arguments
#
if [[ $cur == -* ]]; then
COMPREPLY=( $( compgen -W '$(_parse_help curl) $(_parse_help $1)' -- "$cur" ) )
return
fi
#
# If the argument starts with a letter this could be either an operation
# or an operation parameter
# When $cur is empty, suggest the list of operations by default
#
if [[ $cur =~ ^[A-Za-z_0-9]* ]]; then
# If operation has not been yet selected, suggest the list of operations
# otherwise suggest arguments of this operation as declared in the
# Swagger specification
if [[ -z $operation ]]; then
COMPREPLY=( $(compgen -W '${!operations[*]}' -- ${cur}) )
else
COMPREPLY=( $(compgen -W '${operation_parameters[$operation]}' -- ${cur}) )
fi
return
fi
} &&
complete -F _{{scriptName}} {{scriptName}}
# ex: ts=4 sw=4 et filetype=sh

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,301 @@
#compdef {{scriptName}}
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# !
# ! Note:
# !
# ! THIS SCRIPT HAS BEEN AUTOMATICALLY GENERATED USING
# ! swagger-codegen (https://github.com/swagger-api/swagger-codegen)
# ! FROM SWAGGER SPECIFICATION IN JSON.
# !
# ! Based on: https://github.com/Valodim/zsh-curl-completion/blob/master/_curl
# !
# ! Generated on: {{generatedDate}}
# !
# !
# ! Installation:
# !
# ! Copy the _{{scriptName}} file to any directory under FPATH
# ! environment variable (echo $FPATH)
# !
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
local curcontext="$curcontext" state line ret=1
typeset -A opt_args
#
# cURL crypto engines completion function
#
_curl_crypto_engine() {
local vals
vals=( ${${(f)"$(curl --engine list)":gs/ /}[2,$]} )
_describe -t outputs 'engines' vals && return 0
}
#
# cURL post data completion functions=
#
_curl_post_data() {
# don't do anything further if this is raw content
compset -P '=' && _message 'raw content' && return 0
# complete filename or stdin for @ syntax
compset -P '*@' && {
local expl
_description files expl stdin
compadd "$expl[@]" - "-"
_files
return 0
}
# got a name already? expecting data.
compset -P '*=' && _message 'data value' && return 0
# otherwise, name (or @ or =) should be specified
_message 'data name' && return 0
}
local arg_http arg_ftp arg_other arg_proxy arg_crypto arg_connection arg_auth arg_input arg_output
# HTTP Arguments
arg_http=(''\
{-0,--http1.0}'[force use of use http 1.0 instead of 1.1]' \
{-b,--cookie}'[pass data to http server as cookie]:data or file' \
{-c,--cookie-jar}'[specify cookie file]:file name:_files' \
{-d,--data}'[send specified data as HTTP POST data]:data:{_curl_post_data}' \
'--data-binary[post HTTP POST data without any processing]:data:{_curl_post_data}' \
'--data-urlencode[post HTTP POST data, with url encoding]:data:{_curl_post_data}' \
{-f,--fail}'[enable failfast behavior for server errors]' \
'*'{-F,--form}'[add POST form data]:name=content' \
{-G,--get}'[use HTTP GET even with data (-d, --data, --data-binary)]' \
'*'{-H,--header}'[specify an extra header]:header' \
'--ignore-content-length[ignore Content-Length header]' \
{-i,--include}'[include HTTP header in the output]' \
{-j,--junk-session-cookies}'[discard all session cookies]' \
{-e,--referer}'[send url as referer]:referer url:_urls' \
{-L,--location}'[follow Location headers on http 3XX response]' \
'--location-trusted[like --location, but allows sending of auth data to redirected hosts]' \
'--max-redirs[set maximum number of redirection followings allowed]:number' \
{-J,--remote-header-name}'[use Content-Disposition for output file name]' \
{-O,--remote-name}'[write to filename parsed from url instead of stdout]' \
'--post301[do not convert POST to GET after following 301 Location response (follow RFC 2616/10.3.2)]' \
'--post302[do not convert POST to GET after following 302 Location response (follow RFC 2616/10.3.2)]' \
)
# FTP arguments
arg_ftp=(\
{-a,--append}'[append to target file instead of overwriting (FTP/SFTP)]' \
'--crlf[convert LF to CRLF in upload]' \
'--disable-eprt[disable use of EPRT and LPRT for active FTP transfers]' \
'--disable-epsv[disable use of EPSV for passive FTP transfers]' \
'--ftp-account[account data (FTP)]:data' \
'--ftp-alternative-to-user[command to send when USER and PASS commands fail (FTP)]:command' \
'--ftp-create-dirs[create paths remotely if it does not exist]' \
'--ftp-method[ftp method to use to reach a file (FTP)]:method:(multicwd ocwd singlecwd)' \
'--ftp-pasv[use passive mode for the data connection (FTP)]' \
'--ftp-skip-pasv-ip[do not use the ip the server suggests for PASV]' \
'--form-string[like --form, but do not parse content]:name=string' \
'--ftp-pret[send PRET before PASV]' \
'--ftp-ssl-ccc[use clear command channel (CCC) after authentication (FTP)]' \
'--ftp-ssl-ccc-mode[sets the CCC mode (FTP)]:mode:(active passive)' \
'--ftp-ssl-control[require SSL/TLS for FTP login, clear for transfer]' \
{-l,--list-only}'[list names only when listing directories (FTP)]' \
{-P,--ftp-port}'[use active mode, tell server to connect to specified address or interface (FTP]:address' \
'*'{-Q,--quote}'[send arbitrary command to the remote server before transfer (FTP/SFTP)]:command' \
)
# Other Protocol arguments
arg_other=(\
'--mail-from[specify From: address]:address' \
'--mail-rcpt[specify email recipient for SMTP, may be given multiple times]:address' \
{-t,--telnet-option}'[pass options to telnet protocol]:opt=val' \
'--tftp-blksize[set tftp BLKSIZE option]:value' \
)
# Proxy arguments
arg_proxy=(\
'--noproxy[list of hosts to connect directly to instead of through proxy]:no-proxy-list' \
{-p,--proxytunnel}'[tunnel non-http protocols through http proxy]' \
{-U,--proxy-user}'[specify the user name and password to use for proxy authentication]:user:password' \
'--proxy-anyauth[use any authentication method for proxy, default to most secure]' \
'--proxy-basic[use HTTP Basic authentication for proxy]' \
'--proxy-digest[use http digest authentication for proxy]' \
'--proxy-negotiate[enable GSS-Negotiate authentication for proxy]' \
'--proxy-ntlm[enable ntlm authentication for proxy]' \
'--proxy1.0[use http 1.0 proxy]:proxy url' \
{-x,--proxy}'[use specified proxy]:proxy url' \
'--socks5-gssapi-service[change service name for socks server]:servicename' \
'--socks5-gssapi-nec[allow unprotected exchange of protection mode negotiation]' \
)
# Crypto arguments
arg_crypto=(\
{-1,--tlsv1}'[Forces curl to use TLS version 1 when negotiating with a remote TLS server.]' \
{-2,--sslv2}'[Forces curl to use SSL version 2 when negotiating with a remote SSL server.]' \
{-3,--sslv3}'[Forces curl to use SSL version 3 when negotiating with a remote SSL server.]' \
'--ciphers[specifies which cipher to use for the ssl connection]:list of ciphers' \
'--crlfile[specify file with revoked certificates]:file' \
'--delegation[set delegation policy to use with GSS/kerberos]:delegation policy:(none policy always)' \
{-E,--cert}'[use specified client certificate]:certificate file:_files' \
'--engine[use selected OpenSSL crypto engine]:ssl crypto engine:{_curl_crypto_engine}' \
'--egd-file[set ssl entropy gathering daemon socket]:entropy socket:_files' \
'--cert-type[specify certificate type (PEM, DER, ENG)]:certificate type:(PEM DER ENG)' \
'--cacert[specify certificate file to verify the peer with]:CA certificate:_files' \
'--capath[specify a search path for certificate files]:CA certificate directory:_directories' \
'--hostpubmd5[check remote hosts public key]:md5 hash' \
{-k,--insecure}'[allow ssl to perform insecure ssl connections (ie, ignore certificate)]' \
'--key[ssl/ssh private key file name]:key file:_files' \
'--key-type[ssl/ssh private key file type]:file type:(PEM DER ENG)' \
'--pubkey[ssh public key file]:pubkey file:_files' \
'--random-file[set source of random data for ssl]:random source:_files' \
'--no-sessionid[disable caching of ssl session ids]' \
'--pass:phrase[passphrase for ssl/ssh private key]' \
'--ssl[try to use ssl/tls for connection, if available]' \
'--ssl-reqd[try to use ssl/tls for connection, fail if unavailable]' \
'--tlsauthtype[set TLS authentication type (only SRP supported!)]:authtype' \
'--tlsuser[set username for TLS authentication]:user' \
'--tlspassword[set password for TLS authentication]:password' \
)
# Connection arguments
arg_connection=(\
{-4,--ipv4}'[prefer ipv4]' \
{-6,--ipv6}'[prefer ipv6, if available]' \
{-B,--use-ascii}'[use ascii mode]' \
'--compressed[request a compressed transfer]' \
'--connect-timeout[timeout for connection phase]:seconds' \
{-I,--head}'[fetch http HEAD only (HTTP/FTP/FILE]' \
'--interface[work on a specific interface]:name' \
'--keepalive-time[set time to wait before sending keepalive probes]:seconds' \
'--limit-rate[specify maximum transfer rate]:speed' \
'--local-port[set preferred number or range of local ports to use]:num' \
{-N,--no-buffer}'[disable buffering of the output stream]' \
'--no-keepalive[disable use of keepalive messages in TCP connections]' \
'--raw[disable all http decoding and pass raw data]' \
'--resolve[provide a custom address for a specific host and port pair]:host\:port\:address' \
'--retry[specify maximum number of retries for transient errors]:num' \
'--retry-delay[specify delay between retries]:seconds' \
'--retry-max-time[maximum time to spend on retries]:seconds' \
'--tcp-nodelay[turn on TCP_NODELAY option]' \
{-y,--speed-time}'[specify time to abort after if download is slower than speed-limit]:time' \
{-Y,--speed-limit}'[specify minimum speed for --speed-time]:speed' \
)
# Authentication arguments
arg_auth=(\
'--anyauth[use any authentication method, default to most secure]' \
'--basic[use HTTP Basic authentication]' \
'--ntlm[enable ntlm authentication]' \
'--digest[use http digest authentication]' \
'--krb[use kerberos authentication]:auth:(clear safe confidential private)' \
'--negotiate[enable GSS-Negotiate authentication]' \
{-n,--netrc}'[scan ~/.netrc for login data]' \
'--netrc-optional[like --netrc, but does not make .netrc usage mandatory]' \
'--netrc-file[like --netrc, but specify file to use]:netrc file:_files' \
'--tr-encoding[request compressed transfer-encoding]' \
{-u,--user}'[specify user name and password for server authentication]:user\:password' \
)
# Input arguments
arg_input=(\
{-C,--continue-at}'[resume at offset ]:offset' \
{-g,--globoff}'[do not glob {}\[\] letters]' \
'--max-filesize[maximum filesize to download, fail for bigger files]:bytes' \
'--proto[specify allowed protocols for transfer]:protocols' \
'--proto-redir[specify allowed protocols for transfer after a redirect]:protocols' \
{-r,--range}'[set range of bytes to request (HTTP/FTP/SFTP/FILE)]:range' \
{-R,--remote-time}'[use timestamp of remote file for local file]' \
{-T,--upload-file}'[transfer file to remote url (using PUT for HTTP)]:file to upload:_files' \
'--url[specify a URL to fetch (multi)]:url:_urls' \
{-z,--time-cond}'[request downloaded file to be newer than date or given reference file]:date expression' \
)
# Output arguments
arg_output=(\
'--create-dirs[create local directory hierarchy as needed]' \
{-D,--dump-header}'[write protocol headers to file]:dump file:_files' \
{-o,--output}'[write to specified file instead of stdout]:output file:_files' \
{--progress-bar,-\#}'[display progress as a simple progress bar]' \
{-\#,--progress-bar}'[Make curl display progress as a simple progress bar instead of the standard, more informational, meter.]' \
{-R,--remote-time}'[use timestamp of remote file for local file]' \
'--raw[disable all http decoding and pass raw data]' \
{-s,--silent}'[silent mode, do not show progress meter or error messages]' \
{-S,--show-error}'[show errors in silent mode]' \
'--stderr[redirect stderr to specified file]:output file:_files' \
'--trace[enable full trace dump of all incoming and outgoing data]:trace file:_files' \
'--trace-ascii[enable full trace dump of all incoming and outgoing data, without hex data]:trace file:_files' \
'--trace-time[prepends a time stamp to each trace or verbose line that curl displays]' \
{-v,--verbose}'[output debug info]' \
{-w,--write-out}'[specify message to output on successful operation]:format string' \
'--xattr[store some file metadata in extended file attributes]' \
{-X,--request}'[specifies request method for HTTP server]:method:(GET POST PUT DELETE HEAD OPTIONS TRACE CONNECT PATCH LINK UNLINK)' \
)
_arguments -C -s $arg_http $arg_ftp $arg_other $arg_crypto $arg_connection $arg_auth $arg_input $arg_output \
{-M,--manual}'[print manual]' \
'*'{-K,--config}'[use other config file to read arguments from]:config file:_files' \
'--libcurl[output libcurl code for the operation to file]:output file:_files' \
{-m,--max-time}'[limit total time of operation]:seconds' \
{-s,--silent}'[silent mode, do not show progress meter or error messages]' \
{-S,--show-error}'[show errors in silent mode]' \
'--stderr[redirect stderr to specified file]:output file:_files' \
'-q[do not read settings from .curlrc (must be first option)]' \
{-h,--help}'[Print help and list of operations]' \
{-V,--version}'[Print service API version]' \
'--about[Print the information about service]' \
'--host[Specify the host URL]':URL:_urls \
'--dry-run[Print out the cURL command without executing it]' \
{-ac,--accept}'[Set the 'Accept' header in the request]' \
{-ct,--content-type}'[Set the 'Content-type' header in request]' \
'1: :->ops' \
'*:: :->args' \
&& ret=0
case $state in
ops)
# Operations
_values "Operations" \
{{#apiInfo}}
{{#apis}}
{{#operations}}
{{#operation}}
"{{operationId}}[{{{summary}}}]" {{#hasMore}}\
{{/hasMore}}{{/operation}}{{/operations}}{{/apis}}{{#hasMore}}\
{{/hasMore}}
{{/apiInfo}}
_arguments "(--help)--help[Print information about operation]"
ret=0
;;
args)
case $line[1] in
{{#apiInfo}}
{{#apis}}
{{#operations}}
{{#operation}}
{{operationId}})
local -a _op_arguments
_op_arguments=(
{{#pathParams}}"{{baseName}}=:{{{description}}}"
{{/pathParams}} {{#queryParams}}{{#isBoolean}}"{{baseName}}=true:{{description}}"
"{{baseName}}=false:{{description}}"{{/isBoolean}}{{^isBoolean}}"{{baseName}}=:{{description}}"{{/isBoolean}}
{{/queryParams}} {{#headerParams}}"{{baseName}}\::{{{description}}}"
{{/headerParams}})
_describe -t actions 'operations' _op_arguments && ret=0
;;
{{/operation}}
{{/operations}}
{{/apis}}
{{/apiInfo}}
esac
;;
esac
return ret

View File

@ -0,0 +1,56 @@
package io.swagger.codegen.bash;
import io.swagger.codegen.AbstractOptionsTest;
import io.swagger.codegen.CodegenConfig;
import io.swagger.codegen.languages.BashClientCodegen;
import io.swagger.codegen.options.BashClientOptionsProvider;
import mockit.Expectations;
import mockit.Tested;
public class BashClientOptionsTest extends AbstractOptionsTest {
@Tested
private BashClientCodegen clientCodegen;
public BashClientOptionsTest() {
super(new BashClientOptionsProvider());
}
@Override
protected CodegenConfig getCodegenConfig() {
return clientCodegen;
}
@SuppressWarnings("unused")
@Override
protected void setExpectations() {
new Expectations(clientCodegen) {{
clientCodegen.setCurlOptions(
BashClientOptionsProvider.CURL_OPTIONS);
times = 1;
clientCodegen.setProcessMarkdown(
Boolean.parseBoolean(
BashClientOptionsProvider.PROCESS_MARKDOWN));
times = 1;
clientCodegen.setScriptName(
BashClientOptionsProvider.SCRIPT_NAME);
times = 1;
clientCodegen.setGenerateBashCompletion(
Boolean.parseBoolean(
BashClientOptionsProvider.GENERATE_BASH_COMPLETION));
times = 1;
clientCodegen.setGenerateZshCompletion(
Boolean.parseBoolean(
BashClientOptionsProvider.GENERATE_ZSH_COMPLETION));
times = 1;
clientCodegen.setHostEnvironmentVariable(
BashClientOptionsProvider.HOST_ENVIRONMENT_VARIABLE_NAME);
times = 1;
clientCodegen.setApiKeyAuthEnvironmentVariable(
BashClientOptionsProvider.APIKEY_AUTH_ENVIRONMENT_VARIABLE_NAME);
times = 1;
}};
}
}

View File

@ -0,0 +1,158 @@
package io.swagger.codegen.python;
import io.swagger.codegen.CodegenModel;
import io.swagger.codegen.CodegenOperation;
import io.swagger.codegen.CodegenProperty;
import io.swagger.codegen.CodegenParameter;
import io.swagger.codegen.DefaultCodegen;
import io.swagger.codegen.languages.BashClientCodegen;
import io.swagger.models.ArrayModel;
import io.swagger.models.Model;
import io.swagger.models.ModelImpl;
import io.swagger.models.Operation;
import io.swagger.models.Swagger;
import io.swagger.models.properties.ArrayProperty;
import io.swagger.models.properties.DateTimeProperty;
import io.swagger.models.properties.LongProperty;
import io.swagger.models.properties.MapProperty;
import io.swagger.models.properties.RefProperty;
import io.swagger.models.properties.StringProperty;
import io.swagger.parser.SwaggerParser;
import org.testng.Assert;
import org.testng.annotations.Test;
import org.testng.annotations.ITestAnnotation;
import com.google.common.collect.Sets;
import java.util.Map;
@SuppressWarnings("static-method")
public class BashTest {
@Test(description = "test basic petstore operation with Bash extensions")
public void petstoreOperationTest() {
final Swagger swagger
= new SwaggerParser()
.read("src/test/resources/2_0/petstore-bash.json");
final DefaultCodegen codegen = new BashClientCodegen();
final Operation findPetsByStatusOperation
= swagger.getPath("/pet/findByStatus").getGet();
final CodegenOperation op
= codegen.fromOperation(
"/pet/findByStatus",
"GET",
findPetsByStatusOperation,
swagger.getDefinitions(),
swagger);
Assert.assertTrue(
op.vendorExtensions.containsKey("x-bash-codegen-sample"));
Assert.assertEquals(
op.vendorExtensions.get("x-bash-codegen-description"),
"Multiple status 'values' can be provided with comma separated strings");
}
@Test(description = "test basic petstore operation with example body")
public void petstoreParameterExampleTest() {
final Swagger swagger
= new SwaggerParser()
.read("src/test/resources/2_0/petstore-bash.json");
final DefaultCodegen codegen = new BashClientCodegen();
final Operation addPetOperation
= swagger.getPath("/pet").getPost();
final CodegenOperation op
= codegen.fromOperation(
"/pet",
"POST",
addPetOperation,
swagger.getDefinitions(),
swagger);
Assert.assertEquals(op.bodyParams.size(), 1);
CodegenParameter pet = op.bodyParams.get(0);
Assert.assertTrue(pet.vendorExtensions
.containsKey("x-codegen-body-example"));
}
@Test(description = "test Bash client codegen escapeText method")
public void escapeTextTest() {
final DefaultCodegen codegen = new BashClientCodegen();
Assert.assertEquals(codegen.escapeText("\\/"), "/");
Assert.assertEquals(codegen.escapeText("\\"), "\\\\");
((BashClientCodegen)codegen).setProcessMarkdown(false);
Assert.assertEquals(codegen.escapeText("__Bold text__"),
"__Bold text__");
Assert.assertEquals(codegen.escapeText("**Bold text**"),
"**Bold text**");
Assert.assertEquals(codegen.escapeText("*Italic text*"),
"*Italic text*");
Assert.assertEquals(codegen.escapeText("_Italic text_"),
"_Italic text_");
((BashClientCodegen)codegen).setProcessMarkdown(true);
Assert.assertEquals(codegen.escapeText("__Bold text__"),
"$(tput bold) Bold text $(tput sgr0)");
Assert.assertEquals(codegen.escapeText("**Bold text**"),
"$(tput bold) Bold text $(tput sgr0)");
Assert.assertEquals(codegen.escapeText("*Italic text*"),
"$(tput dim) Italic text $(tput sgr0)");
Assert.assertEquals(codegen.escapeText("_Italic text_"),
"$(tput dim) Italic text $(tput sgr0)");
Assert.assertEquals(codegen.escapeText("# SECTION NAME"),
"\n$(tput bold)$(tput setaf 7)SECTION NAME$(tput sgr0)");
Assert.assertEquals(codegen.escapeText("## SECTION NAME"),
"\n$(tput bold)$(tput setaf 7)SECTION NAME$(tput sgr0)");
Assert.assertEquals(codegen.escapeText("### SECTION NAME"),
"\n$(tput bold)$(tput setaf 7)SECTION NAME$(tput sgr0)");
Assert.assertEquals(codegen.escapeText(
"```\nnice -n 100 mvn test\n```"),
"\n---\nnice -n 100 mvn test\n---");
}
@Test(description = "test Bash client codegen escapeUnsafeCharacters method")
public void escapeUnsafeCharactersTest() {
final DefaultCodegen codegen = new BashClientCodegen();
Assert.assertEquals(codegen.escapeUnsafeCharacters("`no backticks`"),
"'no backticks'");
}
@Test(description = "test Bash client codegen escapeReservedWord method")
public void escapeReservedWordTest() {
final DefaultCodegen codegen = new BashClientCodegen();
Assert.assertEquals(codegen.escapeReservedWord("case"), "_case");
}
}

View File

@ -0,0 +1,61 @@
package io.swagger.codegen.options;
import io.swagger.codegen.CodegenConstants;
import io.swagger.codegen.languages.BashClientCodegen;
import com.google.common.collect.ImmutableMap;
import java.util.Map;
public class BashClientOptionsProvider implements OptionsProvider {
public static final String CURL_OPTIONS = "-k --tlsv1.2";
public static final String PROCESS_MARKDOWN = "true";
public static final String SCRIPT_NAME = "petstore-cli";
public static final String GENERATE_BASH_COMPLETION = "true";
public static final String GENERATE_ZSH_COMPLETION = "false";
public static final String HOST_ENVIRONMENT_VARIABLE_NAME
= "PETSTORE_HOSTNAME";
public static final String BASIC_AUTH_ENVIRONMENT_VARIABLE_NAME
= "PETSTORE_BASIC_AUTH";
public static final String APIKEY_AUTH_ENVIRONMENT_VARIABLE_NAME
= "PETSTORE_APIKEY";
@Override
public String getLanguage() {
return "bash";
}
@Override
public Map<String, String> createOptions() {
ImmutableMap.Builder<String, String> builder
= new ImmutableMap.Builder<String, String>();
return builder
.put(BashClientCodegen.CURL_OPTIONS, CURL_OPTIONS)
.put(BashClientCodegen.SCRIPT_NAME, SCRIPT_NAME)
.put(BashClientCodegen.PROCESS_MARKDOWN, PROCESS_MARKDOWN)
.put(BashClientCodegen.GENERATE_BASH_COMPLETION,
GENERATE_BASH_COMPLETION)
.put(BashClientCodegen.GENERATE_ZSH_COMPLETION,
GENERATE_ZSH_COMPLETION)
.put(BashClientCodegen.HOST_ENVIRONMENT_VARIABLE_NAME,
HOST_ENVIRONMENT_VARIABLE_NAME)
.put(BashClientCodegen.BASIC_AUTH_ENVIRONMENT_VARIABLE_NAME,
BASIC_AUTH_ENVIRONMENT_VARIABLE_NAME)
.put(BashClientCodegen.APIKEY_AUTH_ENVIRONMENT_VARIABLE_NAME,
APIKEY_AUTH_ENVIRONMENT_VARIABLE_NAME)
.put(CodegenConstants.SORT_PARAMS_BY_REQUIRED_FLAG, "false")
.put(CodegenConstants.ENSURE_UNIQUE_PARAMS, "false")
.build();
}
@Override
public boolean isServer() {
return false;
}
}

View File

@ -0,0 +1,10 @@
{
"processMarkdown": true,
"curlOptions": "-sS --tlsv1.2",
"scriptName": "petstore-cli",
"generateBashCompletion": true,
"generateZshCompletion": true,
"hostEnvironmentVariable": "PETSTORE_HOST",
"basicAuthEnvironmentVariable": "PETSTORE_BASIC_AUTH",
"apiKeyAuthEnvironmentVariable": "PETSTORE_API_KEY"
}

File diff suppressed because it is too large Load Diff

13
pom.xml
View File

@ -314,6 +314,18 @@
<module>samples/client/petstore/android/volley</module>
</modules>
</profile>
<profile>
<id>bash-client</id>
<activation>
<property>
<name>env</name>
<value>java</value>
</property>
</activation>
<modules>
<module>samples/client/petstore/bash</module>
</modules>
</profile>
<profile>
<id>clojure-client</id>
<activation>
@ -748,6 +760,7 @@
<!-- clients -->
<module>samples/client/petstore/ruby</module>
<module>samples/client/petstore/android/volley</module>
<module>samples/client/petstore/bash</module>
<module>samples/client/petstore/clojure</module>
<module>samples/client/petstore/go</module>
<module>samples/client/petstore/java/feign</module>

View File

@ -0,0 +1,23 @@
# Swagger Codegen Ignore
# Generated by swagger-codegen https://github.com/swagger-api/swagger-codegen
# Use this file to prevent files from being overwritten by the generator.
# The patterns follow closely to .gitignore or .dockerignore.
# As an example, the C# client generator defines ApiClient.cs.
# You can make changes and tell Swagger Codgen to ignore just this file by uncommenting the following line:
#ApiClient.cs
# You can match any string of characters against a directory, file or extension with a single asterisk (*):
#foo/*/qux
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
#foo/**/qux
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
# You can also negate patterns with an exclamation (!).
# For example, you can ignore all files in a docs folder with the file extension .md:
#docs/*.md
# Then explicitly reverse the ignore rule for a single file:
#!docs/README.md

View File

@ -0,0 +1,75 @@
# Swagger Petstore Bash client
## Overview
This is a Bash client script for accessing Swagger Petstore service.
The script uses cURL underneath for making all REST calls.
## Usage
```shell
# Make sure the script has executable rights
$ chmod u+x petstore-cli
# Print the list of operations available on the service
$ ./petstore-cli -h
# Print the service description
$ ./petstore-cli --about
# Print detailed information about specific operation
$ ./petstore-cli <operationId> -h
# Make GET request
./petstore-cli --host http://<hostname>:<port> --accept xml <operationId> <queryParam1>=<value1> <header_key1>:<header_value2>
# Make GET request using arbitrary curl options (must be passed before <operationId>) to an SSL service using username:password
petstore-cli -k -sS --tlsv1.2 --host https://<hostname> -u <user>:<password> --accept xml <operationId> <queryParam1>=<value1> <header_key1>:<header_value2>
# Make POST request
$ echo '<body_content>' | petstore-cli --host <hostname> --content-type json <operationId> -
# Make POST request with simple JSON content, e.g.:
# {
# "key1": "value1",
# "key2": "value2",
# "key3": 23
# }
$ echo '<body_content>' | petstore-cli --host <hostname> --content-type json <operationId> key1==value1 key2=value2 key3:=23 -
# Preview the cURL command without actually executing it
$ petstore-cli --host http://<hostname>:<port> --dry-run <operationid>
```
## Shell completion
### Bash
The generated bash-completion script can be either directly loaded to the current Bash session using:
```shell
source petstore-cli.bash-completion
```
Alternatively, the script can be copied to the `/etc/bash-completion.d` (or on OSX with Homebrew to `/usr/local/etc/bash-completion.d`):
```shell
sudo cp petstore-cli.bash-completion /etc/bash-completion.d/petstore-cli
```
#### OS X
On OSX you might need to install bash-completion using Homebrew:
```shell
brew install bash-completion
```
and add the following to the `~/.bashrc`:
```shell
if [ -f $(brew --prefix)/etc/bash_completion ]; then
. $(brew --prefix)/etc/bash_completion
fi
```
### Zsh
In Zsh, the generated `_petstore-cli` Zsh completion file must be copied to one of the folders under `$FPATH` variable.

View File

@ -0,0 +1,454 @@
#compdef petstore-cli
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# !
# ! Note:
# !
# ! THIS SCRIPT HAS BEEN AUTOMATICALLY GENERATED USING
# ! swagger-codegen (https://github.com/swagger-api/swagger-codegen)
# ! FROM SWAGGER SPECIFICATION IN JSON.
# !
# ! Based on: https://github.com/Valodim/zsh-curl-completion/blob/master/_curl
# !
# ! Generated on: 2017-01-12T00:07:27.471+01:00
# !
# !
# ! Installation:
# !
# ! Copy the _petstore-cli file to any directory under FPATH
# ! environment variable (echo $FPATH)
# !
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
local curcontext="$curcontext" state line ret=1
typeset -A opt_args
#
# cURL crypto engines completion function
#
_curl_crypto_engine() {
local vals
vals=( ${${(f)"$(curl --engine list)":gs/ /}[2,$]} )
_describe -t outputs 'engines' vals && return 0
}
#
# cURL post data completion functions=
#
_curl_post_data() {
# don't do anything further if this is raw content
compset -P '=' && _message 'raw content' && return 0
# complete filename or stdin for @ syntax
compset -P '*@' && {
local expl
_description files expl stdin
compadd "$expl[@]" - "-"
_files
return 0
}
# got a name already? expecting data.
compset -P '*=' && _message 'data value' && return 0
# otherwise, name (or @ or =) should be specified
_message 'data name' && return 0
}
local arg_http arg_ftp arg_other arg_proxy arg_crypto arg_connection arg_auth arg_input arg_output
# HTTP Arguments
arg_http=(''\
{-0,--http1.0}'[force use of use http 1.0 instead of 1.1]' \
{-b,--cookie}'[pass data to http server as cookie]:data or file' \
{-c,--cookie-jar}'[specify cookie file]:file name:_files' \
{-d,--data}'[send specified data as HTTP POST data]:data:{_curl_post_data}' \
'--data-binary[post HTTP POST data without any processing]:data:{_curl_post_data}' \
'--data-urlencode[post HTTP POST data, with url encoding]:data:{_curl_post_data}' \
{-f,--fail}'[enable failfast behavior for server errors]' \
'*'{-F,--form}'[add POST form data]:name=content' \
{-G,--get}'[use HTTP GET even with data (-d, --data, --data-binary)]' \
'*'{-H,--header}'[specify an extra header]:header' \
'--ignore-content-length[ignore Content-Length header]' \
{-i,--include}'[include HTTP header in the output]' \
{-j,--junk-session-cookies}'[discard all session cookies]' \
{-e,--referer}'[send url as referer]:referer url:_urls' \
{-L,--location}'[follow Location headers on http 3XX response]' \
'--location-trusted[like --location, but allows sending of auth data to redirected hosts]' \
'--max-redirs[set maximum number of redirection followings allowed]:number' \
{-J,--remote-header-name}'[use Content-Disposition for output file name]' \
{-O,--remote-name}'[write to filename parsed from url instead of stdout]' \
'--post301[do not convert POST to GET after following 301 Location response (follow RFC 2616/10.3.2)]' \
'--post302[do not convert POST to GET after following 302 Location response (follow RFC 2616/10.3.2)]' \
)
# FTP arguments
arg_ftp=(\
{-a,--append}'[append to target file instead of overwriting (FTP/SFTP)]' \
'--crlf[convert LF to CRLF in upload]' \
'--disable-eprt[disable use of EPRT and LPRT for active FTP transfers]' \
'--disable-epsv[disable use of EPSV for passive FTP transfers]' \
'--ftp-account[account data (FTP)]:data' \
'--ftp-alternative-to-user[command to send when USER and PASS commands fail (FTP)]:command' \
'--ftp-create-dirs[create paths remotely if it does not exist]' \
'--ftp-method[ftp method to use to reach a file (FTP)]:method:(multicwd ocwd singlecwd)' \
'--ftp-pasv[use passive mode for the data connection (FTP)]' \
'--ftp-skip-pasv-ip[do not use the ip the server suggests for PASV]' \
'--form-string[like --form, but do not parse content]:name=string' \
'--ftp-pret[send PRET before PASV]' \
'--ftp-ssl-ccc[use clear command channel (CCC) after authentication (FTP)]' \
'--ftp-ssl-ccc-mode[sets the CCC mode (FTP)]:mode:(active passive)' \
'--ftp-ssl-control[require SSL/TLS for FTP login, clear for transfer]' \
{-l,--list-only}'[list names only when listing directories (FTP)]' \
{-P,--ftp-port}'[use active mode, tell server to connect to specified address or interface (FTP]:address' \
'*'{-Q,--quote}'[send arbitrary command to the remote server before transfer (FTP/SFTP)]:command' \
)
# Other Protocol arguments
arg_other=(\
'--mail-from[specify From: address]:address' \
'--mail-rcpt[specify email recipient for SMTP, may be given multiple times]:address' \
{-t,--telnet-option}'[pass options to telnet protocol]:opt=val' \
'--tftp-blksize[set tftp BLKSIZE option]:value' \
)
# Proxy arguments
arg_proxy=(\
'--noproxy[list of hosts to connect directly to instead of through proxy]:no-proxy-list' \
{-p,--proxytunnel}'[tunnel non-http protocols through http proxy]' \
{-U,--proxy-user}'[specify the user name and password to use for proxy authentication]:user:password' \
'--proxy-anyauth[use any authentication method for proxy, default to most secure]' \
'--proxy-basic[use HTTP Basic authentication for proxy]' \
'--proxy-digest[use http digest authentication for proxy]' \
'--proxy-negotiate[enable GSS-Negotiate authentication for proxy]' \
'--proxy-ntlm[enable ntlm authentication for proxy]' \
'--proxy1.0[use http 1.0 proxy]:proxy url' \
{-x,--proxy}'[use specified proxy]:proxy url' \
'--socks5-gssapi-service[change service name for socks server]:servicename' \
'--socks5-gssapi-nec[allow unprotected exchange of protection mode negotiation]' \
)
# Crypto arguments
arg_crypto=(\
{-1,--tlsv1}'[Forces curl to use TLS version 1 when negotiating with a remote TLS server.]' \
{-2,--sslv2}'[Forces curl to use SSL version 2 when negotiating with a remote SSL server.]' \
{-3,--sslv3}'[Forces curl to use SSL version 3 when negotiating with a remote SSL server.]' \
'--ciphers[specifies which cipher to use for the ssl connection]:list of ciphers' \
'--crlfile[specify file with revoked certificates]:file' \
'--delegation[set delegation policy to use with GSS/kerberos]:delegation policy:(none policy always)' \
{-E,--cert}'[use specified client certificate]:certificate file:_files' \
'--engine[use selected OpenSSL crypto engine]:ssl crypto engine:{_curl_crypto_engine}' \
'--egd-file[set ssl entropy gathering daemon socket]:entropy socket:_files' \
'--cert-type[specify certificate type (PEM, DER, ENG)]:certificate type:(PEM DER ENG)' \
'--cacert[specify certificate file to verify the peer with]:CA certificate:_files' \
'--capath[specify a search path for certificate files]:CA certificate directory:_directories' \
'--hostpubmd5[check remote hosts public key]:md5 hash' \
{-k,--insecure}'[allow ssl to perform insecure ssl connections (ie, ignore certificate)]' \
'--key[ssl/ssh private key file name]:key file:_files' \
'--key-type[ssl/ssh private key file type]:file type:(PEM DER ENG)' \
'--pubkey[ssh public key file]:pubkey file:_files' \
'--random-file[set source of random data for ssl]:random source:_files' \
'--no-sessionid[disable caching of ssl session ids]' \
'--pass:phrase[passphrase for ssl/ssh private key]' \
'--ssl[try to use ssl/tls for connection, if available]' \
'--ssl-reqd[try to use ssl/tls for connection, fail if unavailable]' \
'--tlsauthtype[set TLS authentication type (only SRP supported!)]:authtype' \
'--tlsuser[set username for TLS authentication]:user' \
'--tlspassword[set password for TLS authentication]:password' \
)
# Connection arguments
arg_connection=(\
{-4,--ipv4}'[prefer ipv4]' \
{-6,--ipv6}'[prefer ipv6, if available]' \
{-B,--use-ascii}'[use ascii mode]' \
'--compressed[request a compressed transfer]' \
'--connect-timeout[timeout for connection phase]:seconds' \
{-I,--head}'[fetch http HEAD only (HTTP/FTP/FILE]' \
'--interface[work on a specific interface]:name' \
'--keepalive-time[set time to wait before sending keepalive probes]:seconds' \
'--limit-rate[specify maximum transfer rate]:speed' \
'--local-port[set preferred number or range of local ports to use]:num' \
{-N,--no-buffer}'[disable buffering of the output stream]' \
'--no-keepalive[disable use of keepalive messages in TCP connections]' \
'--raw[disable all http decoding and pass raw data]' \
'--resolve[provide a custom address for a specific host and port pair]:host\:port\:address' \
'--retry[specify maximum number of retries for transient errors]:num' \
'--retry-delay[specify delay between retries]:seconds' \
'--retry-max-time[maximum time to spend on retries]:seconds' \
'--tcp-nodelay[turn on TCP_NODELAY option]' \
{-y,--speed-time}'[specify time to abort after if download is slower than speed-limit]:time' \
{-Y,--speed-limit}'[specify minimum speed for --speed-time]:speed' \
)
# Authentication arguments
arg_auth=(\
'--anyauth[use any authentication method, default to most secure]' \
'--basic[use HTTP Basic authentication]' \
'--ntlm[enable ntlm authentication]' \
'--digest[use http digest authentication]' \
'--krb[use kerberos authentication]:auth:(clear safe confidential private)' \
'--negotiate[enable GSS-Negotiate authentication]' \
{-n,--netrc}'[scan ~/.netrc for login data]' \
'--netrc-optional[like --netrc, but does not make .netrc usage mandatory]' \
'--netrc-file[like --netrc, but specify file to use]:netrc file:_files' \
'--tr-encoding[request compressed transfer-encoding]' \
{-u,--user}'[specify user name and password for server authentication]:user\:password' \
)
# Input arguments
arg_input=(\
{-C,--continue-at}'[resume at offset ]:offset' \
{-g,--globoff}'[do not glob {}\[\] letters]' \
'--max-filesize[maximum filesize to download, fail for bigger files]:bytes' \
'--proto[specify allowed protocols for transfer]:protocols' \
'--proto-redir[specify allowed protocols for transfer after a redirect]:protocols' \
{-r,--range}'[set range of bytes to request (HTTP/FTP/SFTP/FILE)]:range' \
{-R,--remote-time}'[use timestamp of remote file for local file]' \
{-T,--upload-file}'[transfer file to remote url (using PUT for HTTP)]:file to upload:_files' \
'--url[specify a URL to fetch (multi)]:url:_urls' \
{-z,--time-cond}'[request downloaded file to be newer than date or given reference file]:date expression' \
)
# Output arguments
arg_output=(\
'--create-dirs[create local directory hierarchy as needed]' \
{-D,--dump-header}'[write protocol headers to file]:dump file:_files' \
{-o,--output}'[write to specified file instead of stdout]:output file:_files' \
{--progress-bar,-\#}'[display progress as a simple progress bar]' \
{-\#,--progress-bar}'[Make curl display progress as a simple progress bar instead of the standard, more informational, meter.]' \
{-R,--remote-time}'[use timestamp of remote file for local file]' \
'--raw[disable all http decoding and pass raw data]' \
{-s,--silent}'[silent mode, do not show progress meter or error messages]' \
{-S,--show-error}'[show errors in silent mode]' \
'--stderr[redirect stderr to specified file]:output file:_files' \
'--trace[enable full trace dump of all incoming and outgoing data]:trace file:_files' \
'--trace-ascii[enable full trace dump of all incoming and outgoing data, without hex data]:trace file:_files' \
'--trace-time[prepends a time stamp to each trace or verbose line that curl displays]' \
{-v,--verbose}'[output debug info]' \
{-w,--write-out}'[specify message to output on successful operation]:format string' \
'--xattr[store some file metadata in extended file attributes]' \
{-X,--request}'[specifies request method for HTTP server]:method:(GET POST PUT DELETE HEAD OPTIONS TRACE CONNECT PATCH LINK UNLINK)' \
)
_arguments -C -s $arg_http $arg_ftp $arg_other $arg_crypto $arg_connection $arg_auth $arg_input $arg_output \
{-M,--manual}'[print manual]' \
'*'{-K,--config}'[use other config file to read arguments from]:config file:_files' \
'--libcurl[output libcurl code for the operation to file]:output file:_files' \
{-m,--max-time}'[limit total time of operation]:seconds' \
{-s,--silent}'[silent mode, do not show progress meter or error messages]' \
{-S,--show-error}'[show errors in silent mode]' \
'--stderr[redirect stderr to specified file]:output file:_files' \
'-q[do not read settings from .curlrc (must be first option)]' \
{-h,--help}'[Print help and list of operations]' \
{-V,--version}'[Print service API version]' \
'--about[Print the information about service]' \
'--host[Specify the host URL]':URL:_urls \
'--dry-run[Print out the cURL command without executing it]' \
{-ac,--accept}'[Set the 'Accept' header in the request]' \
{-ct,--content-type}'[Set the 'Content-type' header in request]' \
'1: :->ops' \
'*:: :->args' \
&& ret=0
case $state in
ops)
# Operations
_values "Operations" \
"testClientModel[To test \"client\" model]" \
"testEndpointParameters[Fake endpoint for testing various parameters
假端點
偽のエンドポイント
가짜 엔드 포인트]" \
"testEnumParameters[To test enum parameters]" "addPet[Add a new pet to the store]" \
"deletePet[Deletes a pet]" \
"findPetsByStatus[Finds Pets by status]" \
"findPetsByTags[Finds Pets by tags]" \
"getPetById[Find pet by ID]" \
"updatePet[Update an existing pet]" \
"updatePetWithForm[Updates a pet in the store with form data]" \
"uploadFile[uploads an image]" "deleteOrder[Delete purchase order by ID]" \
"getInventory[Returns pet inventories by status]" \
"getOrderById[Find purchase order by ID]" \
"placeOrder[Place an order for a pet]" "createUser[Create user]" \
"createUsersWithArrayInput[Creates list of users with given input array]" \
"createUsersWithListInput[Creates list of users with given input array]" \
"deleteUser[Delete user]" \
"getUserByName[Get user by user name]" \
"loginUser[Logs user into the system]" \
"logoutUser[Logs out current logged in user session]" \
"updateUser[Updated user]"
_arguments "(--help)--help[Print information about operation]"
ret=0
;;
args)
case $line[1] in
testClientModel)
local -a _op_arguments
_op_arguments=(
)
_describe -t actions 'operations' _op_arguments && ret=0
;;
testEndpointParameters)
local -a _op_arguments
_op_arguments=(
)
_describe -t actions 'operations' _op_arguments && ret=0
;;
testEnumParameters)
local -a _op_arguments
_op_arguments=(
"enum_query_string_array=:Query parameter enum test (string array)"
"enum_query_string=:Query parameter enum test (string)"
"enum_query_integer=:Query parameter enum test (double)"
"enum_header_string_array\::Header parameter enum test (string array)"
"enum_header_string\::Header parameter enum test (string)"
)
_describe -t actions 'operations' _op_arguments && ret=0
;;
addPet)
local -a _op_arguments
_op_arguments=(
)
_describe -t actions 'operations' _op_arguments && ret=0
;;
deletePet)
local -a _op_arguments
_op_arguments=(
"petId=:Pet id to delete"
"api_key\::"
)
_describe -t actions 'operations' _op_arguments && ret=0
;;
findPetsByStatus)
local -a _op_arguments
_op_arguments=(
"status=:Status values that need to be considered for filter"
)
_describe -t actions 'operations' _op_arguments && ret=0
;;
findPetsByTags)
local -a _op_arguments
_op_arguments=(
"tags=:Tags to filter by"
)
_describe -t actions 'operations' _op_arguments && ret=0
;;
getPetById)
local -a _op_arguments
_op_arguments=(
"petId=:ID of pet to return"
)
_describe -t actions 'operations' _op_arguments && ret=0
;;
updatePet)
local -a _op_arguments
_op_arguments=(
)
_describe -t actions 'operations' _op_arguments && ret=0
;;
updatePetWithForm)
local -a _op_arguments
_op_arguments=(
"petId=:ID of pet that needs to be updated"
)
_describe -t actions 'operations' _op_arguments && ret=0
;;
uploadFile)
local -a _op_arguments
_op_arguments=(
"petId=:ID of pet to update"
)
_describe -t actions 'operations' _op_arguments && ret=0
;;
deleteOrder)
local -a _op_arguments
_op_arguments=(
"orderId=:ID of the order that needs to be deleted"
)
_describe -t actions 'operations' _op_arguments && ret=0
;;
getInventory)
local -a _op_arguments
_op_arguments=(
)
_describe -t actions 'operations' _op_arguments && ret=0
;;
getOrderById)
local -a _op_arguments
_op_arguments=(
"orderId=:ID of pet that needs to be fetched"
)
_describe -t actions 'operations' _op_arguments && ret=0
;;
placeOrder)
local -a _op_arguments
_op_arguments=(
)
_describe -t actions 'operations' _op_arguments && ret=0
;;
createUser)
local -a _op_arguments
_op_arguments=(
)
_describe -t actions 'operations' _op_arguments && ret=0
;;
createUsersWithArrayInput)
local -a _op_arguments
_op_arguments=(
)
_describe -t actions 'operations' _op_arguments && ret=0
;;
createUsersWithListInput)
local -a _op_arguments
_op_arguments=(
)
_describe -t actions 'operations' _op_arguments && ret=0
;;
deleteUser)
local -a _op_arguments
_op_arguments=(
"username=:The name that needs to be deleted"
)
_describe -t actions 'operations' _op_arguments && ret=0
;;
getUserByName)
local -a _op_arguments
_op_arguments=(
"username=:The name that needs to be fetched. Use user1 for testing."
)
_describe -t actions 'operations' _op_arguments && ret=0
;;
loginUser)
local -a _op_arguments
_op_arguments=(
"username=:The user name for login"
"password=:The password for login in clear text"
)
_describe -t actions 'operations' _op_arguments && ret=0
;;
logoutUser)
local -a _op_arguments
_op_arguments=(
)
_describe -t actions 'operations' _op_arguments && ret=0
;;
updateUser)
local -a _op_arguments
_op_arguments=(
"username=:name that need to be deleted"
)
_describe -t actions 'operations' _op_arguments && ret=0
;;
esac
;;
esac
return ret

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,286 @@
# petstore-cli completion -*- shell-script -*-
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# !
# ! Note:
# !
# ! THIS SCRIPT HAS BEEN AUTOMATICALLY GENERATED USING
# ! swagger-codegen (https://github.com/swagger-api/swagger-codegen)
# ! FROM SWAGGER SPECIFICATION IN JSON.
# !
# ! Generated on: 2017-01-12T00:07:27.471+01:00
# !
# !
# ! System wide installation:
# !
# ! $ sudo cp petstore-cli.bash-completion /etc/bash-completion.d/petstore-cli
# !
# !
# ! User home installation (add this line to .bash_profile):
# !
# ! [ -r ~/petstore-cli.bash-completion ] && source ~/petstore-cli.bash-completion
# !
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
declare -A mime_type_abbreviations
# text/*
mime_type_abbreviations["text"]="text/plain"
mime_type_abbreviations["html"]="text/html"
mime_type_abbreviations["md"]="text/x-markdown"
mime_type_abbreviations["csv"]="text/csv"
mime_type_abbreviations["css"]="text/css"
mime_type_abbreviations["rtf"]="text/rtf"
# application/*
mime_type_abbreviations["json"]="application/json"
mime_type_abbreviations["xml"]="application/xml"
mime_type_abbreviations["yaml"]="application/yaml"
mime_type_abbreviations["js"]="application/javascript"
mime_type_abbreviations["bin"]="application/octet-stream"
mime_type_abbreviations["rdf"]="application/rdf+xml"
# image/*
mime_type_abbreviations["jpg"]="image/jpeg"
mime_type_abbreviations["png"]="image/png"
mime_type_abbreviations["gif"]="image/gif"
mime_type_abbreviations["bmp"]="image/bmp"
mime_type_abbreviations["tiff"]="image/tiff"
__osx_init_completion()
{
COMPREPLY=()
_get_comp_words_by_ref cur prev words cword
}
_petstore-cli()
{
local cur
local prev
local words
local cword
#words="${COMP_WORDS}"
#cword="${COMP_CWORD}"
#prev="${COMP_WORDS[COMP_CWORD-1]}"
#cur="${COMP_WORDS[COMP_CWORD]}"
# The reference of currently selected REST operation
local operation=""
# The list of available operation in the REST service
# It's modelled as an associative array for efficient key lookup
declare -A operations
operations["testClientModel"]=1
operations["testEndpointParameters"]=1
operations["testEnumParameters"]=1
operations["addPet"]=1
operations["deletePet"]=1
operations["findPetsByStatus"]=1
operations["findPetsByTags"]=1
operations["getPetById"]=1
operations["updatePet"]=1
operations["updatePetWithForm"]=1
operations["uploadFile"]=1
operations["deleteOrder"]=1
operations["getInventory"]=1
operations["getOrderById"]=1
operations["placeOrder"]=1
operations["createUser"]=1
operations["createUsersWithArrayInput"]=1
operations["createUsersWithListInput"]=1
operations["deleteUser"]=1
operations["getUserByName"]=1
operations["loginUser"]=1
operations["logoutUser"]=1
operations["updateUser"]=1
# An associative array of operations to their parameters
# Only include path, query and header parameters
declare -A operation_parameters
operation_parameters["testClientModel"]=""
operation_parameters["testEndpointParameters"]=""
operation_parameters["testEnumParameters"]="enum_query_string_array= enum_query_string= enum_query_integer= enum_header_string_array: enum_header_string: "
operation_parameters["addPet"]=""
operation_parameters["deletePet"]="petId= api_key: "
operation_parameters["findPetsByStatus"]="status= "
operation_parameters["findPetsByTags"]="tags= "
operation_parameters["getPetById"]="petId= "
operation_parameters["updatePet"]=""
operation_parameters["updatePetWithForm"]="petId= "
operation_parameters["uploadFile"]="petId= "
operation_parameters["deleteOrder"]="orderId= "
operation_parameters["getInventory"]=""
operation_parameters["getOrderById"]="orderId= "
operation_parameters["placeOrder"]=""
operation_parameters["createUser"]=""
operation_parameters["createUsersWithArrayInput"]=""
operation_parameters["createUsersWithListInput"]=""
operation_parameters["deleteUser"]="username= "
operation_parameters["getUserByName"]="username= "
operation_parameters["loginUser"]="username= password= "
operation_parameters["logoutUser"]=""
operation_parameters["updateUser"]="username= "
# An associative array of possible values for enum parameters
declare -A operation_parameters_enum_values
#
# Check if the _init_completion function is available, which is
# available since bash-completion 1.4
#
if declare -F _init_completions >/dev/null 2>&1; then
_init_completion -s || return
else
__osx_init_completion || return
fi
# Check if operation is already in the command line provided
for word in "${words[@]}"; do
if [[ -n $word && ${operations[$word]} ]]; then
operation="${word}"
fi
done
if [[ -z $operation ]]; then
case $prev in
--ciphers|--connect-timeout|-C|--continue-at|-F|--form|--form-string|\
--ftp-account|--ftp-alternative-to-user|-P|--ftp-port|-H|--header|-h|\
--help|--hostpubmd5|--keepalive-time|--krb|--limit-rate|--local-port|\
--mail-from|--mail-rcpt|--max-filesize|--max-redirs|-m|--max-time|\
--pass|--proto|--proto-redir|--proxy-user|--proxy1.0|-Q|--quote|-r|\
--range|-X|--request|--retry|--retry-delay|--retry-max-time|\
--socks5-gssapi-service|-t|--telnet-option|--tftp-blksize|-z|\
--time-cond|--url|-u|--user|-A|--user-agent|-V|--version|-w|\
--write-out|--resolve|--tlsuser|--tlspassword|--about)
return
;;
-K|--config|-b|--cookie|-c|--cookie-jar|-D|--dump-header|--egd-file|\
--key|--libcurl|-o|--output|--random-file|-T|--upload-file|--trace|\
--trace-ascii|--netrc-file)
_filedir
return
;;
--cacert|-E|--cert)
_filedir '@(c?(e)rt|cer|pem|der)'
return
;;
--capath)
_filedir -d
return
;;
--cert-type|--key-type)
COMPREPLY=( $( compgen -W 'DER PEM ENG' -- "$cur" ) )
return
;;
--crlfile)
_filedir crl
return
;;
-d|--data|--data-ascii|--data-binary|--data-urlencode)
if [[ $cur == \@* ]]; then
cur=${cur:1}
_filedir
COMPREPLY=( "${COMPREPLY[@]/#/@}" )
fi
return
;;
--delegation)
COMPREPLY=( $( compgen -W 'none policy always' -- "$cur" ) )
return
;;
--engine)
COMPREPLY=( $( compgen -W 'list' -- "$cur" ) )
return
;;
--ftp-method)
COMPREPLY=( $( compgen -W 'multicwd nocwd singlecwd' -- "$cur" ) )
return
;;
--ftp-ssl-ccc-mode)
COMPREPLY=( $( compgen -W 'active passive' -- "$cur" ) )
return
;;
--interface)
_available_interfaces -a
return
;;
-x|--proxy|--socks4|--socks4a|--socks5|--socks5-hostname)
_known_hosts_real
return
;;
--pubkey)
_filedir pub
return
;;
--stderr)
COMPREPLY=( $( compgen -W '-' -- "$cur" ) )
_filedir
return
;;
--tlsauthtype)
COMPREPLY=( $( compgen -W 'SRP' -- "$cur" ) )
return
;;
--host)
COMPREPLY=( $( compgen -W 'http:// https://' -- "$cur" ) )
return
;;
-ct|--content-type|-ac|--accept)
COMPREPLY=( $( compgen -W '${!mime_type_abbreviations[*]}' -- "$cur" ) )
return
;;
esac
fi
#
# Complete the server address based on ~/.ssh/known_hosts
# and ~/.ssh/config
#
# \todo Fix - cur matches only '//' when $prev is ':'
#
if [[ "$cur" == "http://" || "$cur" == "https://" ]]; then
COMPREPLY=()
local comp_ssh_hosts=`cat ~/.ssh/known_hosts | \
cut -f 1 -d ' ' | \
sed -e s/,.*//g | \
grep -v ^# | \
uniq | \
grep -v "\[" ;
cat ~/.ssh/config | \
grep "^Host " | \
awk '{print $2}'`
COMPREPLY=( $(compgen -W "${comp_ssh_hosts}" -- $cur))
return
fi
#
# Complete the petstore-cli and cURL's arguments
#
if [[ $cur == -* ]]; then
COMPREPLY=( $( compgen -W '$(_parse_help curl) $(_parse_help $1)' -- "$cur" ) )
return
fi
#
# If the argument starts with a letter this could be either an operation
# or an operation parameter
# When $cur is empty, suggest the list of operations by default
#
if [[ $cur =~ ^[A-Za-z_0-9]* ]]; then
# If operation has not been yet selected, suggest the list of operations
# otherwise suggest arguments of this operation as declared in the
# Swagger specification
if [[ -z $operation ]]; then
COMPREPLY=( $(compgen -W '${!operations[*]}' -- ${cur}) )
else
COMPREPLY=( $(compgen -W '${operation_parameters[$operation]}' -- ${cur}) )
fi
return
fi
} &&
complete -F _petstore-cli petstore-cli
# ex: ts=4 sw=4 et filetype=sh

View File

@ -0,0 +1,47 @@
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>io.swagger</groupId>
<artifactId>BashPetstoreClientTests</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<name>Bash Swagger Petstore Client</name>
<build>
<plugins>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<executions>
<execution>
<id>bats-test</id>
<phase>integration-test</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>bats</executable>
<arguments>
<argument>--tap</argument>
<argument>tests/petstore_test.sh</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,102 @@
#!/usr/bin/env bats
export PETSTORE_CLI="petstore-cli"
export PETSTORE_HOST="http://petstore.swagger.io"
#
# Tests for parameter handling and validation
#
@test "addPet without host" {
unset PETSTORE_HOST
run bash $PETSTORE_CLI -ac xml -ct json \
addPet id:=123321 name==lucky status==available
[[ "$output" =~ "Error: No hostname provided!!!" ]]
}
@test "addPet without content type" {
run bash $PETSTORE_CLI -ac xml --host $PETSTORE_HOST \
addPet id:=123321 name==lucky status==available
[[ "$output" =~ "Error: Request's content-type not specified!" ]]
}
@test "fakeOperation invalid operation name" {
run bash \
-c "bash $PETSTORE_CLI --host http://petstore.swagger.io fakeOperation"
[[ "$output" =~ "Error: No operation specified!" ]]
}
@test "findPetsByStatus basic auth" {
run bash \
-c "bash $PETSTORE_CLI -u alice:secret --host http://petstore.swagger.io findPetsByStatus status=s1 --dry-run"
[[ "$output" =~ "-u alice:secret" ]]
}
@test "findPetsByStatus api key" {
run bash \
-c "bash $PETSTORE_CLI --host http://petstore.swagger.io findPetsByStatus status=s1 api_key:1234 --dry-run"
[[ "$output" =~ "-H \"api_key: 1234\"" ]]
}
@test "findPetsByStatus empty api key" {
run bash \
-c "bash $PETSTORE_CLI --host http://petstore.swagger.io findPetsByStatus status=s1 --dry-run"
[[ ! "$output" =~ "-H \"api_key:" ]]
}
@test "findPetsByStatus too few values" {
run bash \
-c "bash $PETSTORE_CLI --host http://petstore.swagger.io findPetsByStatus"
[[ "$output" =~ "Error: Too few values" ]]
}
@test "findPetsByTags too few values" {
run bash \
-c "bash $PETSTORE_CLI --host http://petstore.swagger.io findPetsByTags"
[[ "$output" =~ "Error: Too few values" ]]
}
@test "findPetsByStatus status with space" {
run bash \
-c "bash $PETSTORE_CLI --host http://petstore.swagger.io findPetsByStatus \
status=available status=\"gone test\" --dry-run"
[[ "$output" =~ "status=available,gone%20test" ]]
}
@test "findPetsByStatus collection csv" {
run bash \
-c "bash $PETSTORE_CLI --host http://petstore.swagger.io findPetsByTags \
tags=TAG1 tags=TAG2 --dry-run"
[[ "$output" =~ "tags=TAG1,TAG2" ]]
}
@test "findPetsByStatus collection csv with space and question mark" {
run bash \
-c "bash $PETSTORE_CLI --host http://petstore.swagger.io findPetsByTags \
tags=TAG1 tags=\"TAG2 TEST\" tags=TAG3?TEST --dry-run"
[[ "$output" =~ "tags=TAG1,TAG2%20TEST,TAG3%3FTEST" ]]
}
#
# Operations calling the service and checking result
#
@test "addPet from parameters" {
run bash $PETSTORE_CLI -ct json -ac xml \
addPet id:=123321 name==lucky status==available
[[ "$output" =~ "<id>123321</id>" ]]
}
@test "addPet from pipe" {
run bash \
-c "echo '{\"id\": 37567, \"name\": \"lucky\", \"status\": \"available\"}' | \
bash $PETSTORE_CLI -ct json -ac xml addPet -"
[[ "$output" =~ "<id>37567</id>" ]]
}