github.com/jenkins-x/jx/v2@v2.1.155/cmd/codegen/app/generate_openapi.go (about)

     1  package app
     2  
     3  import (
     4  	"go/build"
     5  	"os"
     6  	"path/filepath"
     7  	"strings"
     8  
     9  	"github.com/jenkins-x/jx/v2/cmd/codegen/generator"
    10  	"github.com/jenkins-x/jx/v2/cmd/codegen/util"
    11  
    12  	"github.com/pkg/errors"
    13  
    14  	"github.com/spf13/cobra"
    15  )
    16  
    17  // CreateClientOpenAPIOptions the options for the create client openapi command
    18  type CreateClientOpenAPIOptions struct {
    19  	GenerateOptions
    20  	Title                string
    21  	Version              string
    22  	ReferenceDocsVersion string
    23  	OpenAPIDependencies  []string
    24  	OpenAPIOutputDir     string
    25  	ModuleName           string
    26  }
    27  
    28  var (
    29  	createClientOpenAPILong = `This command code generates OpenAPI specs for
    30  the specified custom resources.
    31  `
    32  
    33  	createClientOpenAPIExample = `
    34  # lets generate client docs
    35  codegen openapi
    36  	--output-package=github.com/jenkins-x/jx/v2/pkg/client \
    37  	--input-package=github.com/jenkins-x/pkg-apis \
    38  	--group-with-version=jenkins.io:v1
    39  	--version=1.2.3
    40  	--title=Jenkins X
    41  
    42  # You will normally want to add a target to your Makefile that looks like
    43  generate-openapi:
    44  	codegen openapi
    45  		--output-package=github.com/jenkins-x/jx/v2/pkg/client \
    46  		--input-package=github.com/jenkins-x/jx/v2/pkg/apis \
    47  		--group-with-version=jenkins.io:v1
    48  		--version=${VERSION}
    49  		--title=${TITLE}
    50  
    51  # and then call
    52  make generate-openapi
    53  `
    54  )
    55  
    56  // NewCmdCreateClientOpenAPI creates the command
    57  func NewCmdCreateClientOpenAPI(genOpts GenerateOptions) *cobra.Command {
    58  	o := &CreateClientOpenAPIOptions{
    59  		GenerateOptions: genOpts,
    60  	}
    61  
    62  	cobraCmd := &cobra.Command{
    63  		Use:     "openapi",
    64  		Short:   "Creates OpenAPI specs for Custom Resources",
    65  		Long:    createClientOpenAPILong,
    66  		Example: createClientOpenAPIExample,
    67  
    68  		Run: func(c *cobra.Command, args []string) {
    69  			o.Cmd = c
    70  			o.Args = args
    71  			err := o.Run()
    72  			util.CheckErr(err)
    73  		},
    74  	}
    75  
    76  	wd, err := os.Getwd()
    77  	if err != nil {
    78  		util.AppLogger().Warnf("Error getting working directory for %v\n", err)
    79  	}
    80  
    81  	openAPIDependencies := []string{
    82  		"k8s.io/apimachinery?modules:pkg/apis:meta:v1",
    83  		"k8s.io/apimachinery?modules:pkg/api:resource:",
    84  		"k8s.io/apimachinery?modules:pkg/util:intstr:",
    85  		"k8s.io/api?modules::batch:v1",
    86  		"k8s.io/api?modules::core:v1",
    87  		"k8s.io/api?modules::rbac:v1",
    88  	}
    89  
    90  	moduleName := strings.TrimPrefix(strings.TrimPrefix(wd, filepath.Join(build.Default.GOPATH, "src")), "/")
    91  
    92  	cobraCmd.Flags().StringVarP(&o.OutputBase, "output-base", "", wd,
    93  		"Output base directory, by default the current working directory")
    94  	cobraCmd.Flags().StringVarP(&o.BoilerplateFile, optionBoilerplateFile, "", "custom-boilerplate.go.txt",
    95  		"Custom boilerplate to add to all files if the file is missing it will be ignored")
    96  	cobraCmd.Flags().StringVarP(&o.InputBase, optionInputBase, "", wd,
    97  		"Input base (the root of module the OpenAPI is being generated for), by default the current working directory")
    98  	cobraCmd.Flags().StringVarP(&o.InputPackage, optionInputPackage, "i", "", "Input package (relative to input base), "+
    99  		"must specify")
   100  	cobraCmd.Flags().StringVarP(&o.OutputPackage, optionOutputPackage, "o", "", "Output package, must specify")
   101  	cobraCmd.Flags().StringVarP(&o.Title, "title", "", "Jenkins X", "Title for OpenAPI, JSON Schema and HTML docs")
   102  	cobraCmd.Flags().StringVarP(&o.Version, "version", "", "", "Version for OpenAPI, JSON Schema and HTML docs")
   103  	cobraCmd.Flags().StringArrayVarP(&o.OpenAPIDependencies, "open-api-dependency", "", openAPIDependencies,
   104  		"Add <path?modules:package:group:apiVersion> dependencies for OpenAPI generation")
   105  	cobraCmd.Flags().StringVarP(&o.OpenAPIOutputDir, "openapi-output-directory", "",
   106  		"docs/apidocs", "Output directory for the OpenAPI specs, "+
   107  			"relative to the output-base unless absolute. "+
   108  			"OpenAPI spec JSON and YAML files are placed in openapi-spec sub directory.")
   109  	cobraCmd.Flags().StringArrayVarP(&o.GroupsWithVersions, optionGroupWithVersion, "g", make([]string, 0),
   110  		"group name:version (e.g. jenkins.io:v1) to generate, must specify at least once")
   111  	cobraCmd.Flags().StringVarP(&o.ModuleName, optionModuleName, "", moduleName,
   112  		"module name (e.g. github.com/jenkins-x/jx)")
   113  	cobraCmd.Flags().BoolVarP(&o.Global, global, "", false, "use the users GOPATH")
   114  	cobraCmd.Flags().StringVarP(&o.SemVer, optionSemVer, "", "", "semantic version to use in packages")
   115  	return cobraCmd
   116  }
   117  
   118  // Run implements this command
   119  func (o *CreateClientOpenAPIOptions) Run() error {
   120  	var err error
   121  	o.BoilerplateFile, err = generator.GetBoilerplateFile(o.BoilerplateFile)
   122  	if err != nil {
   123  		return errors.Wrapf(err, "reading file %s specified by %s", o.BoilerplateFile, optionBoilerplateFile)
   124  	}
   125  	if o.InputPackage == "" {
   126  		return util.MissingOption(optionInputPackage)
   127  	}
   128  	if o.OutputPackage == "" {
   129  		return util.MissingOption(optionOutputPackage)
   130  	}
   131  
   132  	err = o.configure()
   133  	if err != nil {
   134  		return errors.Wrapf(err, "ensuring GOPATH is set correctly")
   135  	}
   136  
   137  	if len(o.GroupsWithVersions) < 1 {
   138  		return util.InvalidOptionf(optionGroupWithVersion, o.GroupsWithVersions, "must specify at least once")
   139  	}
   140  
   141  	cleanupFunc := func() {}
   142  
   143  	gopath := util.GoPath()
   144  	if !o.Global {
   145  		gopath, err = util.IsolatedGoPath()
   146  		if err != nil {
   147  			return errors.Wrapf(err, "getting isolated gopath")
   148  		}
   149  		cleanupFunc, err = util.BackupGoModAndGoSum()
   150  		if err != nil {
   151  			return errors.Wrapf(err, "backing up go.mod and go.sum")
   152  		}
   153  	}
   154  
   155  	err = generator.InstallOpenApiGen(o.GeneratorVersion, gopath)
   156  	// Reset the go.mod and go.sum after installing openapi-gen
   157  	cleanupFunc()
   158  	if err != nil {
   159  		return errors.Wrapf(err, "error installing kubernetes openapi tools")
   160  	}
   161  
   162  	cleanupFunc, err = util.BackupGoModAndGoSum()
   163  	if err != nil {
   164  		return errors.Wrapf(err, "backing up go.mod and go.sum")
   165  	}
   166  	// Reset again after we've completed generation.
   167  	defer cleanupFunc()
   168  
   169  	if !filepath.IsAbs(o.OpenAPIOutputDir) {
   170  		o.OpenAPIOutputDir = filepath.Join(o.OutputBase, o.OpenAPIOutputDir)
   171  	}
   172  
   173  	util.AppLogger().Infof("generating Go code to %s in package %s from package %s\n", o.OutputBase, o.GoPathOutputPackage, o.InputPackage)
   174  	err = generator.GenerateOpenApi(o.GroupsWithVersions, o.InputPackage, o.GoPathOutputPackage, o.OutputPackage,
   175  		filepath.Join(build.Default.GOPATH, "src"), o.OpenAPIDependencies, o.InputBase, o.ModuleName, o.BoilerplateFile, gopath, o.SemVer)
   176  	if err != nil {
   177  		return errors.Wrapf(err, "generating openapi structs to %s", o.GoPathOutputPackage)
   178  	}
   179  
   180  	util.AppLogger().Infof("generating OpenAPI spec files to %s from package %s\n", o.OpenAPIOutputDir, filepath.Join(o.InputBase,
   181  		o.InputPackage))
   182  	err = generator.GenerateSchema(o.OpenAPIOutputDir, o.OutputPackage, o.InputBase, o.Title, o.Version, gopath)
   183  	if err != nil {
   184  		return errors.Wrapf(err, "generating schema to %s", o.OpenAPIOutputDir)
   185  	}
   186  
   187  	return nil
   188  }