publiccode

package module
v4.0.0-...-c638004 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 27, 2024 License: EUPL-1.2 Imports: 26 Imported by: 0

README

publiccode.yml parser for Go

Get invited

A Go parser and validator for publiccode.yml files.

publiccode.yml is an international standard for describing public software, which should be placed at the root of Free/Libre and Open Source software repositories.

This parser performs syntactic and semantic validation according to the official spec.

Features

  • Go library and CLI tool (publiccode-parser)
  • Supports the latest version of the publiccode.yml Standard
  • publiccode-parser can output validation errors as JSON or in a errorformat friendly way
  • Verifies the existence of URLs by checking the response for URL fields (can be disabled)

Example

parser, err := NewDefaultParser()
if err != nil {
   // handle errors
}

publicCode, err := parser.Parse("https://foobar.example.org/publiccode.yml")
// OR
// publicCode, err := parser.Parse("file:///path/to/local/dir/publiccode.yml")
if err != nil {
    // handle errors
}

if publicCode != nil {
    switch pc := publicCode.(type) {
    case *publiccode.V0:
        fmt.Println(pc)
    default:
        // handle error
    }
}

Validation from command line

The publiccode-parser binary which be used for validating a publiccode.yml from the command line.

To get the latest development version use:

go install github.com/italia/publiccode-parser-go/v4/publiccode-parser@latest
publiccode-parser mypubliccode.yml

To get the latest stable version go to the release page and grab the one for your arch.

Run publiccode-parser --help for the available command line flags.

The tool returns 0 in case of successful validation, 1 otherwise.

Easy validation with Docker

You can easily validate your files using Docker on your local machine or in your CI pipeline:

docker run -i italia/publiccode-parser-go /dev/stdin < publiccode.yml

The image is available on Dockerhub. You can also build your own running:

docker build -t italia/publiccode-parser-go .
Examples

The examples assume that your publiccode.yml file is on your local machine, at /home/my-user/publiccodes/publiccode.yml

  • Validate and print the canonicalized file

    docker run -i italia/publiccode-parser-go -export /dev/stdout /dev/stdin < publiccode.yml
    
  • Validate a publiccode file named publiccode.yml in /home/user

    docker run -v /home/user:/go/src/files italia/publiccode-parser-go
    
  • Validate a publiccode file named /opt/publiccodes/my-amazing-code.yaml

    docker run -v /opt/publiccodes:/go/src/files italia/publiccode-parser-go my-amazing-code.yaml
    
  • Validate publiccode.yml without using the network (fe. checking URLs are reachable)

    docker run -v /opt/publiccodes/publiccodes:/files italia/publiccode-parser-go -no-network publiccode.yml
    
  • Debugging, access the container interactive shell, overriding the entrypoint

    docker run -it --entrypoint /bin/sh italia/publiccode-parser-go
    

Contributing

Contributing is always appreciated. Feel free to open issues, fork or submit a Pull Request. If you want to know more about how to add new fields, check out CONTRIBUTING.md. In order to support other country-specific extensions in addition to Italy some refactoring might be needed.

See also

Maintainers

This software is maintained by the Developers Italia team.

License

© 2018-present Team per la Trasformazione Digitale - Presidenza del Consiglio dei Minstri

Licensed under the EUPL 1.2. The version control system provides attribution for specific lines of code.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var SupportedVersions = []string{"0.2", "0.2.0", "0.2.1", "0.2.2", "0.3", "0.3.0"}

SupportedVersions contains the publiccode.yml versions this parser supports.

Functions

This section is empty.

Types

type ContactV0

type ContactV0 struct {
	Name        string  `yaml:"name" validate:"required"`
	Email       *string `yaml:"email,omitempty" validate:"omitempty,email"`
	Affiliation *string `yaml:"affiliation,omitempty"`
	Phone       *string `yaml:"phone,omitempty" validate:"omitempty"`
}

Contact is a contact info maintaining the software.

type ContactV1

type ContactV1 struct {
	Name        string  `yaml:"name" validate:"required"`
	Email       *string `yaml:"email,omitempty" validate:"omitempty,email"`
	Affiliation *string `yaml:"affiliation,omitempty"`
	Phone       *string `yaml:"phone,omitempty" validate:"omitempty"`
}

Contact is a contact info maintaining the software.

type ContractorV0

type ContractorV0 struct {
	Name    string  `yaml:"name" validate:"required"`
	Email   *string `yaml:"email,omitempty" validate:"omitempty,email"`
	Website *URL    `yaml:"website,omitempty" validate:"omitnil,url_http_url"`
	Until   string  `yaml:"until" validate:"required,date"`
}

Contractor is an entity or entities, if any, that are currently contracted for maintaining the software.

type ContractorV1

type ContractorV1 struct {
	Name    string  `yaml:"name" validate:"required"`
	Email   *string `yaml:"email,omitempty" validate:"omitempty,email"`
	Website *URL    `yaml:"website,omitempty" validate:"omitnil,url_http_url"`
	Until   string  `yaml:"until" validate:"required,date"`
}

Contractor is an entity or entities, if any, that are currently contracted for maintaining the software.

type DependencyV0

type DependencyV0 struct {
	Name       string  `yaml:"name" validate:"required,gt=0"`
	VersionMin *string `yaml:"versionMin,omitempty"`
	VersionMax *string `yaml:"versionMax,omitempty"`
	Optional   *bool   `yaml:"optional,omitempty"`
	Version    *string `yaml:"version,omitempty"`
}

Dependency describe system-level dependencies required to install and use this software.

type DependencyV1

type DependencyV1 struct {
	Name       string  `yaml:"name" validate:"required,gt=0"`
	VersionMin *string `yaml:"versionMin,omitempty"`
	VersionMax *string `yaml:"versionMax,omitempty"`
	Optional   *bool   `yaml:"optional,omitempty"`
	Version    *string `yaml:"version,omitempty"`
}

Dependency describe system-level dependencies required to install and use this software.

type DescV0

type DescV0 struct {
	LocalisedName    *string   `yaml:"localisedName,omitempty"`
	GenericName      string    `yaml:"genericName" validate:"umax=35"`
	ShortDescription string    `yaml:"shortDescription" validate:"required,umax=150"`
	LongDescription  string    `yaml:"longDescription,omitempty" validate:"required,umin=150,umax=10000"`
	Documentation    *URL      `yaml:"documentation,omitempty" validate:"omitnil,url_http_url"`
	APIDocumentation *URL      `yaml:"apiDocumentation,omitempty" validate:"omitnil,url_http_url"`
	Features         *[]string `yaml:"features,omitempty" validate:"gt=0,dive"`
	Screenshots      []string  `yaml:"screenshots,omitempty"`
	Videos           []*URL    `yaml:"videos,omitempty" validate:"dive,omitnil,url_http_url"`
	Awards           []string  `yaml:"awards,omitempty"`
}

Desc is a general description of the software.

type DescV1

type DescV1 struct {
	LocalisedName    *string   `yaml:"localisedName,omitempty"`
	GenericName      string    `yaml:"genericName" validate:"umax=35"`
	ShortDescription string    `yaml:"shortDescription" validate:"required,umax=150"`
	LongDescription  string    `yaml:"longDescription,omitempty" validate:"required,umin=150,umax=10000"`
	Documentation    *URL      `yaml:"documentation,omitempty" validate:"omitnil,url_http_url"`
	APIDocumentation *URL      `yaml:"apiDocumentation,omitempty" validate:"omitnil,url_http_url"`
	Features         *[]string `yaml:"features,omitempty" validate:"gt=0,dive"`
	Screenshots      []string  `yaml:"screenshots,omitempty"`
	Videos           []*URL    `yaml:"videos,omitempty" validate:"dive,omitnil,url_http_url"`
	Awards           []string  `yaml:"awards,omitempty"`
}

Desc is a general description of the software.

type ITSectionV0

type ITSectionV0 struct {
	CountryExtensionVersion string `yaml:"countryExtensionVersion"`

	Conforme struct {
		LineeGuidaDesign        bool `yaml:"lineeGuidaDesign,omitempty"`
		ModelloInteroperabilita bool `yaml:"modelloInteroperabilita"`
		MisureMinimeSicurezza   bool `yaml:"misureMinimeSicurezza"`
		GDPR                    bool `yaml:"gdpr"`
	} `yaml:"conforme"`

	Riuso struct {
		CodiceIPA string `yaml:"codiceIPA,omitempty" validate:"omitempty,is_italian_ipa_code"`
	} `yaml:"riuso,omitempty"`

	Piattaforme struct {
		SPID   bool `yaml:"spid"`
		PagoPa bool `yaml:"pagopa"`
		CIE    bool `yaml:"cie"`
		ANPR   bool `yaml:"anpr"`
		Io     bool `yaml:"io"`
	} `yaml:"piattaforme"`
}

type ITSectionV1

type ITSectionV1 struct {
	CountryExtensionVersion string `yaml:"countryExtensionVersion"`

	Conforme struct {
		LineeGuidaDesign        bool `yaml:"lineeGuidaDesign,omitempty"`
		ModelloInteroperabilita bool `yaml:"modelloInteroperabilita"`
		MisureMinimeSicurezza   bool `yaml:"misureMinimeSicurezza"`
		GDPR                    bool `yaml:"gdpr"`
	} `yaml:"conforme"`

	Riuso struct {
		CodiceIPA string `yaml:"codiceIPA,omitempty" validate:"omitempty,is_italian_ipa_code"`
	} `yaml:"riuso,omitempty"`

	Piattaforme struct {
		SPID   bool `yaml:"spid"`
		PagoPa bool `yaml:"pagopa"`
		CIE    bool `yaml:"cie"`
		ANPR   bool `yaml:"anpr"`
		Io     bool `yaml:"io"`
	} `yaml:"piattaforme"`
}

type ParseError

type ParseError struct {
	Reason string
}

A generic parse error.

func (ParseError) Error

func (e ParseError) Error() string

type Parser

type Parser struct {
	// contains filtered or unexported fields
}

Parser is a helper class for parsing publiccode.yml files.

func NewDefaultParser

func NewDefaultParser() (*Parser, error)

NewDefaultParser creates and returns a new Parser instance, using the default config.

It returns a pointer to the newly created Parser, if successful, and an error. The error is non-nil if there was an issue initializing the Parser.

The default config is ParserConfig's fields zero values.

Example usage:

parser, err := NewDefaultParser()
if err != nil {
    log.Fatalf("Failed to create parser: %v", err)
}
// Use parser...

func NewParser

func NewParser(config ParserConfig) (*Parser, error)

NewParser creates and returns a new Parser instance based on the provided ParserConfig.

It returns a pointer to the newly created Parser, if successful, and an error. The error is non-nil if there was an issue initializing the Parser.

Example usage:

config := ParserConfig{
    DisableNetwork: true
}
parser, err := NewParser(config)
if err != nil {
    log.Fatalf("Failed to create parser: %v", err)
}
// Use parser...

func (*Parser) Parse

func (p *Parser) Parse(uri string) (PublicCode, error)

Parse reads from the provided uri and attempts to parse it into a PublicCode object.

Returns a non-nil error if there is an issue with the parsing process and a a struct implementing the Publiccode interface, depending on the version of the publiccode.yml file parsed.

The only possible type returned is V0, representing v0.* files.

PublicCode can be nil when there are major parsing issues. It can also be non-nil even in presence of errors: in that case the returned struct is filled as much as possible, based on what is successful parsed.

Example usage:

// publicCode, err := parser.Parse("file:///app/publiccode.yml")
publicCode, err := parser.Parse("https://foobar.example.org/publiccode.yml")
if err != nil {
    log.Printf("Parsing errors: %v", err)
}
if publicCode != nil {
    switch pc := publicCode.(type) {
    case *publiccode.V0:
        fmt.Println(pc)
    default:
        log.Println("PublicCode parsed, but unexpected type found.")
    }
}

func (*Parser) ParseStream

func (p *Parser) ParseStream(in io.Reader) (PublicCode, error)

ParseStream reads from the provided io.Reader and attempts to parse the input stream into a PublicCode object.

Returns a non-nil error if there is an issue with the parsing process and a a struct implementing the Publiccode interface, depending on the version of the publiccode.yml file parsed.

The only possible type returned is V0, representing v0.* files.

PublicCode can be nil when there are major parsing issues. It can also be non-nil even in presence of errors: in that case the returned struct is filled as much as possible, based on what is successful parsed.

Example usage:

file, err := os.Open("publiccode.yml")
if err != nil {
    log.Fatalf("Failed to open file: %v", err)
}
defer file.Close()

publicCode, err := parser.ParseStream(file)
if err != nil {
    log.Printf("Parsing errors: %v", err)
}
if publicCode != nil {
    switch pc := publicCode.(type) {
    case *publiccode.V0:
        fmt.Println(pc)
    default:
        log.Println("PublicCode parsed, but unexpected type found.")
    }
}

type ParserConfig

type ParserConfig struct {
	// DisableNetwork disables all network tests (fe. URL existence and Oembed). This
	// results in much faster parsing.
	DisableNetwork bool

	// The name of the branch used to check for existence of the files referenced
	// in the publiccode.yml
	Branch string

	// The path or URL used as base of relative files in publiccode.yml (eg. logo). If
	// given, it will be used for existence checks and such, instead of the `url` key
	// in the publiccode.yml file
	BaseURL string
}

ParserConfig defines the configuration options for the Parser

type PublicCode

type PublicCode interface {
	Version() uint
	Url() *URL
	ToYAML() ([]byte, error)
}

type URL

type URL url.URL

func (*URL) MarshalYAML

func (u *URL) MarshalYAML() (interface{}, error)

func (URL) String

func (u URL) String() string

func (*URL) UnmarshalYAML

func (u *URL) UnmarshalYAML(unmarshal func(interface{}) error) error

UnmarshalYAML implements the yaml.Unmarshaler interface for URLs.

type UrlOrUrlArray

type UrlOrUrlArray []*URL

func (*UrlOrUrlArray) UnmarshalYAML

func (a *UrlOrUrlArray) UnmarshalYAML(unmarshal func(interface{}) error) error

type V0

type V0 struct {
	PubliccodeYamlVersion string `yaml:"publiccodeYmlVersion" validate:"required,oneof=0.2 0.2.0 0.2.1 0.2.2 0.3 0.3.0"`

	Name             string `yaml:"name" validate:"required"`
	ApplicationSuite string `yaml:"applicationSuite,omitempty"`
	URL              *URL   `yaml:"url" validate:"required,url_url"`
	LandingURL       *URL   `yaml:"landingURL,omitempty" validate:"omitnil,url_http_url"`

	IsBasedOn       UrlOrUrlArray `yaml:"isBasedOn,omitempty"`
	SoftwareVersion string        `yaml:"softwareVersion,omitempty"`
	ReleaseDate     string        `yaml:"releaseDate" validate:"required,date"`

	InputTypes  []string `yaml:"inputTypes,omitempty"`
	OutputTypes []string `yaml:"outputTypes,omitempty"`

	Platforms []string `yaml:"platforms" validate:"gt=0"`

	Categories []string `yaml:"categories" validate:"required,gt=0,dive,is_category_v0_2"`

	UsedBy *[]string `yaml:"usedBy,omitempty"`

	Roadmap *URL `yaml:"roadmap,omitempty" validate:"omitnil,url_http_url"`

	DevelopmentStatus string `yaml:"developmentStatus" validate:"required,oneof=concept development beta stable obsolete"`

	SoftwareType string `` /* 181-byte string literal not displayed */

	IntendedAudience *struct {
		Scope                *[]string `yaml:"scope,omitempty" validate:"omitempty,dive,is_scope_v0_2"`
		Countries            *[]string `yaml:"countries,omitempty" validate:"omitempty,dive,iso3166_1_alpha2_lowercase"`
		UnsupportedCountries *[]string `yaml:"unsupportedCountries,omitempty" validate:"omitempty,dive,iso3166_1_alpha2_lowercase"`
	} `yaml:"intendedAudience,omitempty"`

	Description map[string]DescV0 `yaml:"description" validate:"gt=0,dive,keys,bcp47_language_tag,endkeys,required"`

	Legal struct {
		License            string  `yaml:"license" validate:"required"`
		MainCopyrightOwner *string `yaml:"mainCopyrightOwner,omitempty"`
		RepoOwner          *string `yaml:"repoOwner,omitempty"`
		AuthorsFile        *string `yaml:"authorsFile,omitempty"`
	} `yaml:"legal" validate:"required"`

	Maintenance struct {
		Type        string         `yaml:"type" validate:"required,oneof=internal contract community none"`
		Contractors []ContractorV0 `yaml:"contractors,omitempty" validate:"required_if=Type contract,dive"`
		Contacts    []ContactV0    `yaml:"contacts,omitempty" validate:"required_if=Type community,required_if=Type internal,dive"`
	} `yaml:"maintenance"`

	Localisation struct {
		LocalisationReady  *bool    `yaml:"localisationReady" validate:"required"`
		AvailableLanguages []string `yaml:"availableLanguages" validate:"required,gt=0,dive,bcp47_language_tag"`
	} `yaml:"localisation" validate:"required"`

	DependsOn *struct {
		Open        *[]DependencyV0 `yaml:"open,omitempty" validate:"omitempty,dive"`
		Proprietary *[]DependencyV0 `yaml:"proprietary,omitempty" validate:"omitempty,dive"`
		Hardware    *[]DependencyV0 `yaml:"hardware,omitempty" validate:"omitempty,dive"`
	} `yaml:"dependsOn,omitempty"`

	It ITSectionV0 `yaml:"it"`
}

V0 represents a publiccode.yml v0.*

func (V0) ToYAML

func (p V0) ToYAML() ([]byte, error)

func (V0) Url

func (p V0) Url() *URL

func (V0) Version

func (p V0) Version() uint

type V1

type V1 struct {
	PubliccodeYamlVersion string `yaml:"publiccodeYmlVersion" validate:"required,oneof=1.0 1.0.0"`

	Name             string `yaml:"name" validate:"required"`
	ApplicationSuite string `yaml:"applicationSuite,omitempty"`
	URL              *URL   `yaml:"url" validate:"required,url_url"`
	LandingURL       *URL   `yaml:"landingURL,omitempty" validate:"omitnil,url_http_url"`

	IsBasedOn       *[]URL `yaml:"isBasedOn,omitempty"`
	SoftwareVersion string `yaml:"softwareVersion,omitempty"`
	ReleaseDate     string `yaml:"releaseDate" validate:"required,date"`

	Platforms []string `yaml:"platforms" validate:"gt=0"`

	Categories []string `yaml:"categories" validate:"required,gt=0,dive,is_category_v0_2"`

	UsedBy *[]string `yaml:"usedBy,omitempty"`

	Roadmap *URL `yaml:"roadmap,omitempty" validate:"omitnil,url_http_url"`

	DevelopmentStatus string `yaml:"developmentStatus" validate:"required,oneof=concept development beta stable obsolete"`

	SoftwareType string `` /* 181-byte string literal not displayed */

	IntendedAudience *struct {
		Scope                *[]string `yaml:"scope,omitempty" validate:"omitempty,dive,is_scope_v0_2"`
		Countries            *[]string `yaml:"countries,omitempty" validate:"omitempty,dive,iso3166_1_alpha2_lowercase"`
		UnsupportedCountries *[]string `yaml:"unsupportedCountries,omitempty" validate:"omitempty,dive,iso3166_1_alpha2_lowercase"`
	} `yaml:"intendedAudience,omitempty"`

	Description map[string]DescV1 `yaml:"description" validate:"gt=0,dive,keys,bcp47_language_tag,endkeys,required"`

	Legal struct {
		License            string  `yaml:"license" validate:"required"`
		MainCopyrightOwner *string `yaml:"mainCopyrightOwner,omitempty"`
		RepoOwner          *string `yaml:"repoOwner,omitempty"`
		AuthorsFile        *string `yaml:"authorsFile,omitempty"`
	} `yaml:"legal" validate:"required"`

	Maintenance struct {
		Type        string         `yaml:"type" validate:"required,oneof=internal contract community none"`
		Contractors []ContractorV1 `yaml:"contractors,omitempty" validate:"required_if=Type contract,dive"`
		Contacts    []ContactV1    `yaml:"contacts,omitempty" validate:"required_if=Type community,required_if=Type internal,dive"`
	} `yaml:"maintenance"`

	Localisation struct {
		LocalisationReady  *bool    `yaml:"localisationReady" validate:"required"`
		AvailableLanguages []string `yaml:"availableLanguages" validate:"required,gt=0,dive,bcp47_language_tag"`
	} `yaml:"localisation" validate:"required"`

	DependsOn *struct {
		Open        *[]DependencyV1 `yaml:"open,omitempty" validate:"omitempty,dive"`
		Proprietary *[]DependencyV1 `yaml:"proprietary,omitempty" validate:"omitempty,dive"`
		Hardware    *[]DependencyV1 `yaml:"hardware,omitempty" validate:"omitempty,dive"`
	} `yaml:"dependsOn,omitempty"`

	It ITSectionV1 `yaml:"it"`
}

func (V1) ToYAML

func (p V1) ToYAML() ([]byte, error)

func (V1) Url

func (p V1) Url() *URL

func (V1) Version

func (p V1) Version() uint

type ValidationError

type ValidationError struct {
	Key         string `json:"key"`
	Description string `json:"description"`
	Line        int    `json:"line"`
	Column      int    `json:"column"`
}

func (ValidationError) Error

func (e ValidationError) Error() string

func (ValidationError) MarshalJSON

func (e ValidationError) MarshalJSON() ([]byte, error)

type ValidationResults

type ValidationResults []error

func (ValidationResults) Error

func (vr ValidationResults) Error() string

type ValidationWarning

type ValidationWarning ValidationError

func (ValidationWarning) Error

func (e ValidationWarning) Error() string

func (ValidationWarning) MarshalJSON

func (e ValidationWarning) MarshalJSON() ([]byte, error)

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL