Skip to content

Commit

Permalink
feat: jsonschema (#350)
Browse files Browse the repository at this point in the history
* feat: jsonschema

Signed-off-by: Carlos A Becker <caarlos0@gmail.com>

* fix: gitattr

Signed-off-by: Carlos A Becker <caarlos0@gmail.com>

* docs: schema

Signed-off-by: Carlos A Becker <caarlos0@gmail.com>

* docs: schema

Signed-off-by: Carlos A Becker <caarlos0@gmail.com>

* docs: improvements

Signed-off-by: Carlos A Becker <caarlos0@gmail.com>
  • Loading branch information
caarlos0 authored Jul 7, 2021
1 parent a582b89 commit 5c895f6
Show file tree
Hide file tree
Showing 11 changed files with 769 additions and 66 deletions.
3 changes: 2 additions & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
# Denote all files that are truly binary and should not be modified.
*.png binary
*.jpg binary
*.ico binary
*.ico binary
www/docs/static/schema.json linguist-generated=true
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ require (
github.com/Masterminds/semver/v3 v3.1.1
github.com/ProtonMail/go-crypto v0.0.0-20210512092938-c05353c2d58c
github.com/ProtonMail/gopenpgp/v2 v2.2.0
github.com/alecthomas/jsonschema v0.0.0-20210526225647-edb03dcab7bc
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb
github.com/go-git/go-git/v5 v5.3.0 // indirect
github.com/google/rpmpack v0.0.0-20210410105602-e20c988a6f5a
Expand Down
5 changes: 5 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ github.com/ProtonMail/gopenpgp/v2 v2.2.0 h1:XLsUEY/dQhQcOg8r0ijNvMTJIKM4EBkf3K7z
github.com/ProtonMail/gopenpgp/v2 v2.2.0/go.mod h1:ajUlBGvxMH1UBZnaYO3d1FSVzjiC6kK9XlZYGiDCvpM=
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs=
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
github.com/alecthomas/jsonschema v0.0.0-20210526225647-edb03dcab7bc h1:mT8qSzuyEAkxbv4GBln7yeuQZpBnfikr3PTuiPs6Z3k=
github.com/alecthomas/jsonschema v0.0.0-20210526225647-edb03dcab7bc/go.mod h1:/n6+1/DWPltRLWL/VKyUxg6tzsl5kHUCcraimt4vr60=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
Expand Down Expand Up @@ -246,6 +248,8 @@ github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2p
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw=
github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0 h1:i462o439ZjprVSFSZLZxcsoAe592sZB1rci2Z8j4wdk=
github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36vB07FNRdD2geA=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
Expand Down Expand Up @@ -380,6 +384,7 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.3.1-0.20190311161405-34c6fa2dc709/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
Expand Down
1 change: 1 addition & 0 deletions internal/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ func newRootCmd(version string, exit func(int)) *rootCmd {
newInitCmd().cmd,
newPackageCmd().cmd,
newDocsCmd().cmd,
newSchemaCmd().cmd,
)

root.cmd = cmd
Expand Down
53 changes: 53 additions & 0 deletions internal/cmd/schema.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package cmd

import (
"encoding/json"
"fmt"
"os"
"path/filepath"

"github.com/alecthomas/jsonschema"
"github.com/goreleaser/nfpm/v2"
"github.com/spf13/cobra"
)

type schemaCmd struct {
cmd *cobra.Command
output string
}

func newSchemaCmd() *schemaCmd {
root := &schemaCmd{}
cmd := &cobra.Command{
Use: "jsonschema",
Aliases: []string{"schema"},
Short: "outputs nFPM's JSON schema",
SilenceUsage: true,
SilenceErrors: true,
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
schema := jsonschema.Reflect(&nfpm.Config{})
schema.Description = "nFPM configuration definition file"
bts, err := json.MarshalIndent(schema, " ", " ")
if err != nil {
return fmt.Errorf("failed to create jsonschema: %w", err)
}
if root.output == "-" {
fmt.Println(string(bts))
return nil
}
if err := os.MkdirAll(filepath.Dir(root.output), 0o755); err != nil {
return fmt.Errorf("failed to write jsonschema file: %w", err)
}
if err := os.WriteFile(root.output, bts, 0o666); err != nil {
return fmt.Errorf("failed to write jsonschema file: %w", err)
}
return nil
},
}

cmd.Flags().StringVarP(&root.output, "output", "o", "-", "where to save the json schema")

root.cmd = cmd
return root
}
126 changes: 63 additions & 63 deletions nfpm.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ type Packager interface {
// Config contains the top level configuration for packages.
type Config struct {
Info `yaml:",inline"`
Overrides map[string]Overridables `yaml:"overrides,omitempty"`
Overrides map[string]Overridables `yaml:"overrides,omitempty" jsonschema:"title=overrides,description=override some fields when packaging with a specific packager,enum=apk,enum=deb,enum=rpm"`
envMappingFunc func(string) string
}

Expand Down Expand Up @@ -187,24 +187,24 @@ func (c *Config) expandEnvVars() {
// Info contains information about a single package.
type Info struct {
Overridables `yaml:",inline"`
Name string `yaml:"name,omitempty"`
Arch string `yaml:"arch,omitempty"`
Platform string `yaml:"platform,omitempty"`
Epoch string `yaml:"epoch,omitempty"`
Version string `yaml:"version,omitempty"`
VersionSchema string `yaml:"version_schema,omitempty"`
Release string `yaml:"release,omitempty"`
Prerelease string `yaml:"prerelease,omitempty"`
VersionMetadata string `yaml:"version_metadata,omitempty"`
Section string `yaml:"section,omitempty"`
Priority string `yaml:"priority,omitempty"`
Maintainer string `yaml:"maintainer,omitempty"`
Description string `yaml:"description,omitempty"`
Vendor string `yaml:"vendor,omitempty"`
Homepage string `yaml:"homepage,omitempty"`
License string `yaml:"license,omitempty"`
Changelog string `yaml:"changelog,omitempty"`
DisableGlobbing bool `yaml:"disable_globbing"`
Name string `yaml:"name" jsonschema:"title=package name"`
Arch string `yaml:"arch" jsonschema:"title=target architecture,example=amd64"`
Platform string `yaml:"platform,omitempty" jsonschema:"title=target platform,example=linux,default=linux"`
Epoch string `yaml:"epoch,omitempty" jsonschema:"title=version epoch,example=2,default=extracted from version"`
Version string `yaml:"version" jsonschema:"title=version,example=v1.0.2,example=2.0.1"`
VersionSchema string `yaml:"version_schema,omitempty" jsonschema:"title=version schema,enum=semver,enum=none,default=semver"`
Release string `yaml:"release,omitempty" jsonschema:"title=version release,example=1"`
Prerelease string `yaml:"prerelease,omitempty" jsonschema:"title=version prerelease,default=extracted from version"`
VersionMetadata string `yaml:"version_metadata,omitempty" jsonschema:"title=version metadata,example=git"`
Section string `yaml:"section,omitempty" jsonschema:"title=package section,example=default"`
Priority string `yaml:"priority,omitempty" jsonschema:"title=package priority,example=extra"`
Maintainer string `yaml:"maintainer,omitempty" jsonschema:"title=package maintainer,example=me@example.com"`
Description string `yaml:"description,omitempty" jsonschema:"title=package description"`
Vendor string `yaml:"vendor,omitempty" jsonschema:"title=package vendor,example=MyCorp"`
Homepage string `yaml:"homepage,omitempty" jsonschema:"title=package homepage,example=https://example.com"`
License string `yaml:"license,omitempty" jsonschema:"title=package license,example=MIT"`
Changelog string `yaml:"changelog,omitempty" jsonschema:"title=package changelog,example=changelog.yaml,description=see https://github.com/goreleaser/chglog for more details"`
DisableGlobbing bool `yaml:"disable_globbing,omitempty" jsonschema:"title=wether to disable file globbing,default=false"`
Target string `yaml:"-"`
}

Expand Down Expand Up @@ -248,39 +248,39 @@ func (i *Info) parseSemver() {

// Overridables contain the field which are overridable in a package.
type Overridables struct {
Replaces []string `yaml:"replaces,omitempty"`
Provides []string `yaml:"provides,omitempty"`
Depends []string `yaml:"depends,omitempty"`
Recommends []string `yaml:"recommends,omitempty"`
Suggests []string `yaml:"suggests,omitempty"`
Conflicts []string `yaml:"conflicts,omitempty"`
Contents files.Contents `yaml:"contents,omitempty"`
EmptyFolders []string `yaml:"empty_folders,omitempty"`
Scripts Scripts `yaml:"scripts,omitempty"`
RPM RPM `yaml:"rpm,omitempty"`
Deb Deb `yaml:"deb,omitempty"`
APK APK `yaml:"apk,omitempty"`
Replaces []string `yaml:"replaces,omitempty" jsonschema:"title=replaces directive,example=nfpm"`
Provides []string `yaml:"provides,omitempty" jsonschema:"title=provides directive,example=nfpm"`
Depends []string `yaml:"depends,omitempty" jsonschema:"title=depends directive,example=nfpm"`
Recommends []string `yaml:"recommends,omitempty" jsonschema:"title=recommends directive,example=nfpm"`
Suggests []string `yaml:"suggests,omitempty" jsonschema:"title=suggests directive,example=nfpm"`
Conflicts []string `yaml:"conflicts,omitempty" jsonschema:"title=conflicts directive,example=nfpm"`
Contents files.Contents `yaml:"contents,omitempty" jsonschema:"title=files to add to the package"`
EmptyFolders []string `yaml:"empty_folders,omitempty" jsonschema:"title=empty folders to be created when installing the package,example=/var/log/nfpm"`
Scripts Scripts `yaml:"scripts,omitempty" jsonschema:"title=scripts to execute"`
RPM RPM `yaml:"rpm,omitempty" jsonschema:"title=rpm-specific settings"`
Deb Deb `yaml:"deb,omitempty" jsonschema:"title=deb-specific settings"`
APK APK `yaml:"apk,omitempty" jsonschema:"title=apk-specific settings"`
}

// RPM is custom configs that are only available on RPM packages.
type RPM struct {
Scripts RPMScripts `yaml:"scripts,omitempty"`
Group string `yaml:"group,omitempty"`
Summary string `yaml:"summary,omitempty"`
Compression string `yaml:"compression,omitempty"`
Signature RPMSignature `yaml:"signature,omitempty"`
Scripts RPMScripts `yaml:"scripts,omitempty" jsonschema:"title=rpm-specific scripts"`
Group string `yaml:"group,omitempty" jsonschema:"title=package group,example=Unspecified"`
Summary string `yaml:"summary,omitempty" jsonschema:"title=package summary"`
Compression string `yaml:"compression,omitempty" jsonschema:"title=compression algorithm to be used,enum=gzip,enum=lzma,enum=xz,default=gzip"`
Signature RPMSignature `yaml:"signature,omitempty" jsonschema:"title=rpm signature"`
}

// RPMScripts represents scripts only available on RPM packages.
type RPMScripts struct {
PreTrans string `yaml:"pretrans,omitempty"`
PostTrans string `yaml:"posttrans,omitempty"`
PreTrans string `yaml:"pretrans,omitempty" jsonschema:"title=pretrans script"`
PostTrans string `yaml:"posttrans,omitempty" jsonschema:"title=posttrans script"`
}

type PackageSignature struct {
// PGP secret key, can be ASCII-armored
KeyFile string `yaml:"key_file,omitempty"`
KeyID *string `yaml:"key_id,omitempty"`
KeyFile string `yaml:"key_file,omitempty" jsonschema:"title=key file,example=key.gpg"`
KeyID *string `yaml:"key_id,omitempty" jsonschema:"title=key id,example=bc8acdd415bd80b3"`
KeyPassphrase string `yaml:"-"` // populated from environment variable
}

Expand All @@ -289,60 +289,60 @@ type RPMSignature struct {
}

type APK struct {
Signature APKSignature `yaml:"signature,omitempty"`
Scripts APKScripts `yaml:"scripts,omitempty"`
Signature APKSignature `yaml:"signature,omitempty" jsonschema:"title=apk signature"`
Scripts APKScripts `yaml:"scripts,omitempty" jsonschema:"title=apk scripts"`
}

type APKSignature struct {
PackageSignature `yaml:",inline"`
// defaults to <maintainer email>.rsa.pub
KeyName string `yaml:"key_name,omitempty"`
KeyName string `yaml:"key_name,omitempty" jsonschema:"title=key name,example=origin,default=maintainer_email.rsa.pub"`
}

type APKScripts struct {
PreUpgrade string `yaml:"preupgrade,omitempty"`
PostUpgrade string `yaml:"postupgrade,omitempty"`
PreUpgrade string `yaml:"preupgrade,omitempty" jsonschema:"title=pre upgrade script"`
PostUpgrade string `yaml:"postupgrade,omitempty" jsonschema:"title=post upgrade script"`
}

// Deb is custom configs that are only available on deb packages.
type Deb struct {
Scripts DebScripts `yaml:"scripts,omitempty"`
Triggers DebTriggers `yaml:"triggers,omitempty"`
Breaks []string `yaml:"breaks,omitempty"`
Signature DebSignature `yaml:"signature,omitempty"`
Scripts DebScripts `yaml:"scripts,omitempty" jsonschema:"title=scripts"`
Triggers DebTriggers `yaml:"triggers,omitempty" jsonschema:"title=triggers"`
Breaks []string `yaml:"breaks,omitempty" jsonschema:"title=breaks"`
Signature DebSignature `yaml:"signature,omitempty" jsonschema:"title=signature"`
}

type DebSignature struct {
PackageSignature `yaml:",inline"`
// origin, maint or archive (defaults to origin)
Type string `yaml:"type,omitempty"`
Type string `yaml:"type,omitempty" jsonschema:"title=signer role,enum=origin,enum=maint,enum=archive,default=origin"`
}

// DebTriggers contains triggers only available for deb packages.
// https://wiki.debian.org/DpkgTriggers
// https://man7.org/linux/man-pages/man5/deb-triggers.5.html
type DebTriggers struct {
Interest []string `yaml:"interest,omitempty"`
InterestAwait []string `yaml:"interest_await,omitempty"`
InterestNoAwait []string `yaml:"interest_noawait,omitempty"`
Activate []string `yaml:"activate,omitempty"`
ActivateAwait []string `yaml:"activate_await,omitempty"`
ActivateNoAwait []string `yaml:"activate_noawait,omitempty"`
Interest []string `yaml:"interest,omitempty" jsonschema:"title=interest"`
InterestAwait []string `yaml:"interest_await,omitempty" jsonschema:"title=interest await"`
InterestNoAwait []string `yaml:"interest_noawait,omitempty" jsonschema:"title=interest noawait"`
Activate []string `yaml:"activate,omitempty" jsonschema:"title=activate"`
ActivateAwait []string `yaml:"activate_await,omitempty" jsonschema:"title=activate await"`
ActivateNoAwait []string `yaml:"activate_noawait,omitempty" jsonschema:"title=activate noawait"`
}

// DebScripts is scripts only available on deb packages.
type DebScripts struct {
Rules string `yaml:"rules,omitempty"`
Templates string `yaml:"templates,omitempty"`
Config string `yaml:"config,omitempty"`
Rules string `yaml:"rules,omitempty" jsonschema:"title=rules"`
Templates string `yaml:"templates,omitempty" jsonschema:"title=templates"`
Config string `yaml:"config,omitempty" jsonschema:"title=config"`
}

// Scripts contains information about maintainer scripts for packages.
type Scripts struct {
PreInstall string `yaml:"preinstall,omitempty"`
PostInstall string `yaml:"postinstall,omitempty"`
PreRemove string `yaml:"preremove,omitempty"`
PostRemove string `yaml:"postremove,omitempty"`
PreInstall string `yaml:"preinstall,omitempty" jsonschema:"title=pre install"`
PostInstall string `yaml:"postinstall,omitempty" jsonschema:"title=post install"`
PreRemove string `yaml:"preremove,omitempty" jsonschema:"title=pre remove"`
PostRemove string `yaml:"postremove,omitempty" jsonschema:"title=post remove"`
}

// ErrFieldEmpty happens when some required field is empty.
Expand Down
1 change: 1 addition & 0 deletions scripts/cmd_docs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ git checkout -- go.*
go mod edit -replace github.com/spf13/cobra=github.com/caarlos0/cobra@completions-md
go mod tidy
go run ./cmd/nfpm docs
go run ./cmd/nfpm schema -o ./www/docs/static/schema.json

"$SED" \
-i'' \
Expand Down
2 changes: 1 addition & 1 deletion www/docs/cmd/nfpm.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@ nFPM is a simple, 0-dependencies, deb, rpm and apk packager.

* [nfpm completion](/cmd/nfpm_completion/) - generate the autocompletion script for the specified shell
* [nfpm init](/cmd/nfpm_init/) - creates a sample nfpm.yaml config file
* [nfpm jsonschema](/cmd/nfpm_jsonschema/) - creates a JSON schema file
* [nfpm jsonschema](/cmd/nfpm_jsonschema/) - outputs nFPM's JSON schema
* [nfpm package](/cmd/nfpm_package/) - creates a package based on the given the given config file and flags

2 changes: 1 addition & 1 deletion www/docs/cmd/nfpm_jsonschema.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# nfpm jsonschema

creates a JSON schema file
outputs nFPM's JSON schema

```
nfpm jsonschema [flags]
Expand Down
17 changes: 17 additions & 0 deletions www/docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -292,3 +292,20 @@ Templating is not and will not be supported.
If you really need it, you can build on top of nFPM, use `envsubst`, `jsonnet`
or apply some other templating on top of it.


## JSON Schema

nFPM also has a [jsonschema][] file which you can use to have better editor support:

```
https://nfpm.goreleaser.com/schema.json
```

You can also generate it for your specific version using the [`nfpm jsonschema`][schema] command.

Note that it is in early stages.
Any help and/or feedback is greatly appreciated!

[jsonschema]: http://json-schema.org/draft/2020-12/json-schema-validation.html
[schema]: /cmd/nfpm_jsonschema/
Loading

1 comment on commit 5c895f6

@vercel
Copy link

@vercel vercel bot commented on 5c895f6 Jul 7, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.