API Documentation

How to help improve the Jenkins X API documentation

Jenkins X has two types of API documentation: Kubernetes Custom Resource Documentation and Godoc. Both types are generated from the codegen binary which is part of the jx repository.

Setup your development environment

It’s best to make changes to the Jenkins X code on your local machine. Follow the development guide to get set up.

Writing custom resource documentation

The custom resource documentation is mostly generated from the comments on the go structs that define the custom resources, with the introductory content and structure injected.

Toolchain

The custom resource documentation is generated using the same toolchain as Kubernetes, but wrapped up in a series of codegen commands so that you don’t have to download and setup the different tools yourself.

The HTML docs are generated via an OpenAPI specification which in turn is generated from Go Structs which are generated from the code comments. To generate the structs and the OpenAPI specification run:

make generate-openapi

and to generate the HTML run:

make generate-docs

You should run make generate-openapi whenever you change the custom resources, and check the generated changes into source control. This means that there is always a tagged version of the OpenAPI spec available for others to use.

make generate-docs is run by the release build, and the changes are automatically uploaded to the Jenkins X website on every release. They’ll be available a few minutes after the release build completes.

Making changes to the documentation

Each file for which you want to generate docs must be located in the jenkins.io/v1 directory, and must have a the

// +k8s:openapi-gen=true

comment at the top of the file.

To exclude a type or member, add

// +k8s:openapi-gen=false

to it.

Comments on types are ignored. Comments on struct fields are used as the description for each field.

The left hand menu is generated from the resource_categories in config.yaml. The introductory text for each category is authored as html.

The styles can also be customized.

OpenAPI

The OpenAPI spec is generated from the code. The structure is generated from the structs and fields. The json tags are used to provide additional information including:

  • name is generated from the key
  • if omitempty is not set, the property will be required
  • if the key is - the field will be skipped
  • if inline is set, the properties will be inlined into the parent object

Additionally the

// +optional

comment can be used to prevent a property being required. For example:

  metav1.TypeMeta `json:",inline"
    // +optional
    metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
  Spec BuildPackSpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"`

OpenAPI Extensions

OpenAPI spec can have extensions on types. To define one or more extensions on a type or its member add +k8s:openapi-gen=x-kubernetes-$NAME:$VALUE to the comment lines before type/member. A type/member can have multiple extensions. The rest of the line in the comment will be used as $VALUE so there is no need to escape or quote the value string. Extensions can be used to pass more information to client generators or documentation generators. For example a type might have a friendly name to be displayed in documentation or being used in a client’s fluent interface.

Custom OpenAPI type definitions

Custom types which otherwise don’t map directly to OpenAPI can override their OpenAPI definition by implementing a function named “OpenAPIDefinition” with the following signature:

    import openapi "k8s.io/kube-openapi/pkg/common"

    // ...

    type Time struct {
        time.Time
    }

    func (_ Time) OpenAPIDefinition() openapi.OpenAPIDefinition {
        return openapi.OpenAPIDefinition{
            Schema: spec.Schema{
                SchemaProps: spec.SchemaProps{
                   Type:   []string{"string"},
                   Format: "date-time",
                },
            },
        }
    }

Alternatively, the type can avoid the “openapi” import by defining the following methods. The following example produces the same OpenAPI definition as the example above:

    func (_ Time) OpenAPISchemaType() []string { return []string{"string"} }
    func (_ Time) OpenAPISchemaFormat() string { return "date-time" }

Write Godoc

Jenkins X uses the standard approach to Godoc, and it is automatically generated by godoc.org. This blog provides a good introduction to writing Godoc.