docs: add generated CLI help output to repo (#46)

Generate the help pages using `cobras` builtin functionality and commit
them to the repository. This gives users to ability to review the
options of `hcloud-upload-image` without having to install it first.
This commit is contained in:
Julian Tölle 2024-11-02 21:57:53 +01:00 committed by GitHub
parent b181eebd38
commit 4e24d83c7a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 188 additions and 18 deletions

View file

@ -30,7 +30,6 @@ jobs:
args: --timeout 5m args: --timeout 5m
working-directory: hcloudimages working-directory: hcloudimages
test: test:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@ -45,7 +44,6 @@ jobs:
- name: Run tests - name: Run tests
run: go test -v -race -coverpkg=./...,./hcloudimages/... ./... ./hcloudimages/... run: go test -v -race -coverpkg=./...,./hcloudimages/... ./... ./hcloudimages/...
go-mod-tidy: go-mod-tidy:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@ -65,3 +63,23 @@ jobs:
- if: failure() - if: failure()
run: echo "::error::Check failed, please run 'go mod tidy' and commit the changes." run: echo "::error::Check failed, please run 'go mod tidy' and commit the changes."
cli-help-pages:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
- name: Generate CLI help pages
run: go run ./scripts/cli-help-pages.go
- name: Check uncommitted changes
run: git diff --exit-code
- if: failure()
run: echo "::error::Check failed, please run 'go run ./scripts/cli-help-pages.go' and commit the changes."

View file

@ -63,7 +63,7 @@ hcloud-upload-image upload \
--compression bz2 --compression bz2
``` ```
To learn more, you can use the embedded help output: To learn more, you can use the embedded help output or check out the [CLI help pages in this repository](docs/cli/hcloud-upload-image.md).:
```shell ```shell
hcloud-upload-image --help hcloud-upload-image --help

View file

@ -23,6 +23,7 @@ $ hcloud ssh-key list -l apricote.de/created-by=hcloud-upload-image
This command does not handle any parallel executions of hcloud-upload-image This command does not handle any parallel executions of hcloud-upload-image
and will remove in-use resources if called at the same time.`, and will remove in-use resources if called at the same time.`,
DisableAutoGenTag: true,
GroupID: "primary", GroupID: "primary",
@ -44,5 +45,5 @@ and will remove in-use resources if called at the same time.`,
} }
func init() { func init() {
rootCmd.AddCommand(cleanupCmd) RootCmd.AddCommand(cleanupCmd)
} }

View file

@ -28,11 +28,13 @@ var (
// The pre-authenticated client. Set in the root command PersistentPreRun // The pre-authenticated client. Set in the root command PersistentPreRun
var client *hcloudimages.Client var client *hcloudimages.Client
// rootCmd represents the base command when called without any subcommands // RootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{ var RootCmd = &cobra.Command{
Use: "hcloud-upload-image", Use: "hcloud-upload-image",
Short: `Manage custom OS images on Hetzner Cloud.`,
Long: `Manage custom OS images on Hetzner Cloud.`, Long: `Manage custom OS images on Hetzner Cloud.`,
SilenceUsage: true, SilenceUsage: true,
DisableAutoGenTag: true,
Version: version.Version, Version: version.Version,
@ -98,18 +100,18 @@ func initClient(cmd *cobra.Command, _ []string) {
} }
func Execute() { func Execute() {
err := rootCmd.Execute() err := RootCmd.Execute()
if err != nil { if err != nil {
os.Exit(1) os.Exit(1)
} }
} }
func init() { func init() {
rootCmd.SetErrPrefix("\033[1;31mError:") RootCmd.SetErrPrefix("\033[1;31mError:")
rootCmd.PersistentFlags().CountVarP(&verbose, flagVerbose, "v", "verbose debug output, can be specified up to 2 times") RootCmd.PersistentFlags().CountVarP(&verbose, flagVerbose, "v", "verbose debug output, can be specified up to 2 times")
rootCmd.AddGroup(&cobra.Group{ RootCmd.AddGroup(&cobra.Group{
ID: "primary", ID: "primary",
Title: "Primary Commands:", Title: "Primary Commands:",
}) })

View file

@ -29,8 +29,8 @@ var uploadCmd = &cobra.Command{
Long: `This command implements a fake "upload", by going through a real server and snapshots. Long: `This command implements a fake "upload", by going through a real server and snapshots.
This does cost a bit of money for the server.`, This does cost a bit of money for the server.`,
Example: ` hcloud-upload-image upload --image-path /home/you/images/custom-linux-image-x86.bz2 --architecture x86 --compression bz2 --description "My super duper custom linux" Example: ` hcloud-upload-image upload --image-path /home/you/images/custom-linux-image-x86.bz2 --architecture x86 --compression bz2 --description "My super duper custom linux"
hcloud-upload-image upload --image-url https://examples.com/image-arm.raw --architecture arm --labels foo=bar,version=latest hcloud-upload-image upload --image-url https://examples.com/image-arm.raw --architecture arm --labels foo=bar,version=latest`,
`, DisableAutoGenTag: true,
GroupID: "primary", GroupID: "primary",
@ -88,7 +88,7 @@ This does cost a bit of money for the server.`,
} }
func init() { func init() {
rootCmd.AddCommand(uploadCmd) RootCmd.AddCommand(uploadCmd)
uploadCmd.Flags().String(uploadFlagImageURL, "", "Remote URL of the disk image that should be uploaded") uploadCmd.Flags().String(uploadFlagImageURL, "", "Remote URL of the disk image that should be uploaded")
uploadCmd.Flags().String(uploadFlagImagePath, "", "Local path to the disk image that should be uploaded") uploadCmd.Flags().String(uploadFlagImagePath, "", "Local path to the disk image that should be uploaded")

View file

@ -0,0 +1,20 @@
## hcloud-upload-image
Manage custom OS images on Hetzner Cloud.
### Synopsis
Manage custom OS images on Hetzner Cloud.
### Options
```
-h, --help help for hcloud-upload-image
-v, --verbose count verbose debug output, can be specified up to 2 times
```
### SEE ALSO
* [hcloud-upload-image cleanup](hcloud-upload-image_cleanup.md) - Remove any temporary resources that were left over
* [hcloud-upload-image upload](hcloud-upload-image_upload.md) - Upload the specified disk image into your Hetzner Cloud project.

View file

@ -0,0 +1,38 @@
## hcloud-upload-image cleanup
Remove any temporary resources that were left over
### Synopsis
If the upload fails at any point, there might still exist a server or
ssh key in your Hetzner Cloud project. This command cleans up any resources
that match the label "apricote.de/created-by=hcloud-upload-image".
If you want to see a preview of what would be removed, you can use the official hcloud CLI and run:
$ hcloud server list -l apricote.de/created-by=hcloud-upload-image
$ hcloud ssh-key list -l apricote.de/created-by=hcloud-upload-image
This command does not handle any parallel executions of hcloud-upload-image
and will remove in-use resources if called at the same time.
```
hcloud-upload-image cleanup [flags]
```
### Options
```
-h, --help help for cleanup
```
### Options inherited from parent commands
```
-v, --verbose count verbose debug output, can be specified up to 2 times
```
### SEE ALSO
* [hcloud-upload-image](hcloud-upload-image.md) - Manage custom OS images on Hetzner Cloud.

View file

@ -0,0 +1,43 @@
## hcloud-upload-image upload
Upload the specified disk image into your Hetzner Cloud project.
### Synopsis
This command implements a fake "upload", by going through a real server and snapshots.
This does cost a bit of money for the server.
```
hcloud-upload-image upload (--image-path=<local-path> | --image-url=<url>) --architecture=<x86|arm> [flags]
```
### Examples
```
hcloud-upload-image upload --image-path /home/you/images/custom-linux-image-x86.bz2 --architecture x86 --compression bz2 --description "My super duper custom linux"
hcloud-upload-image upload --image-url https://examples.com/image-arm.raw --architecture arm --labels foo=bar,version=latest
```
### Options
```
--architecture string CPU architecture of the disk image [choices: x86, arm]
--compression string Type of compression that was used on the disk image [choices: bz2, xz]
--description string Description for the resulting image
-h, --help help for upload
--image-path string Local path to the disk image that should be uploaded
--image-url string Remote URL of the disk image that should be uploaded
--labels stringToString Labels for the resulting image (default [])
--server-type string Explicitly use this server type to generate the image. Mutually exclusive with --architecture.
```
### Options inherited from parent commands
```
-v, --verbose count verbose debug output, can be specified up to 2 times
```
### SEE ALSO
* [hcloud-upload-image](hcloud-upload-image.md) - Manage custom OS images on Hetzner Cloud.

3
go.mod
View file

@ -11,17 +11,20 @@ require (
require ( require (
github.com/beorn7/perks v1.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/prometheus/client_golang v1.19.1 // indirect github.com/prometheus/client_golang v1.19.1 // indirect
github.com/prometheus/client_model v0.5.0 // indirect github.com/prometheus/client_model v0.5.0 // indirect
github.com/prometheus/common v0.48.0 // indirect github.com/prometheus/common v0.48.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/pflag v1.0.5 // indirect
golang.org/x/crypto v0.24.0 // indirect golang.org/x/crypto v0.24.0 // indirect
golang.org/x/net v0.25.0 // indirect golang.org/x/net v0.25.0 // indirect
golang.org/x/sys v0.21.0 // indirect golang.org/x/sys v0.21.0 // indirect
golang.org/x/text v0.16.0 // indirect golang.org/x/text v0.16.0 // indirect
google.golang.org/protobuf v1.33.0 // indirect google.golang.org/protobuf v1.33.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
) )
replace github.com/apricote/hcloud-upload-image/hcloudimages => ./hcloudimages replace github.com/apricote/hcloud-upload-image/hcloudimages => ./hcloudimages

10
go.sum
View file

@ -2,6 +2,7 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@ -11,6 +12,10 @@ github.com/hetznercloud/hcloud-go/v2 v2.9.0 h1:s0N6R7Zoi2DPfMtUF5o9VeUBzTtHVY6MI
github.com/hetznercloud/hcloud-go/v2 v2.9.0/go.mod h1:qtW/TuU7Bs16ibXl/ktJarWqU2LwHr7eGlwoilHxtgg= github.com/hetznercloud/hcloud-go/v2 v2.9.0/go.mod h1:qtW/TuU7Bs16ibXl/ktJarWqU2LwHr7eGlwoilHxtgg=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
@ -21,6 +26,9 @@ github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSz
github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc=
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
@ -41,5 +49,7 @@ golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

35
scripts/cli-help-pages.go Normal file
View file

@ -0,0 +1,35 @@
package main
import (
"fmt"
"os"
"github.com/spf13/cobra/doc"
"github.com/apricote/hcloud-upload-image/cmd"
)
func run() error {
// Define the directory where the docs will be generated
dir := "docs/cli"
// Ensure the directory exists
if err := os.MkdirAll(dir, 0755); err != nil {
return fmt.Errorf("error creating docs directory: %v", err)
}
// Generate the docs
if err := doc.GenMarkdownTree(cmd.RootCmd, dir); err != nil {
return fmt.Errorf("error generating docs: %v", err)
}
fmt.Println("Docs generated successfully in", dir)
return nil
}
func main() {
if err := run(); err != nil {
fmt.Printf("Error: %v\n", err)
os.Exit(1)
}
}