From 8f99e9435350b16a804a79f879a7708126954d9a Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Sun, 18 Oct 2026 21:38:35 +0200 Subject: [PATCH 1/8] feat: accept JPEG, WebP and AVIF images for the logo and screenshots See publiccodeyml/publiccode.yml#350. --- testdata/v0/valid/assets/img/logo.webp | 0 testdata/v0/valid/assets/img/sshot.avif | 0 testdata/v0/valid/assets/img/sshot.jpeg | 0 testdata/v0/valid/assets/img/sshot.jpg | 0 testdata/v0/valid/assets/img/sshot.webp | 0 testdata/v0/valid/image_formats.yml | 57 +++++++++++++++++++++++++ validations.go | 4 +- 7 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 testdata/v0/valid/assets/img/logo.webp create mode 100644 testdata/v0/valid/assets/img/sshot.avif create mode 100644 testdata/v0/valid/assets/img/sshot.jpeg create mode 100644 testdata/v0/valid/assets/img/sshot.jpg create mode 100644 testdata/v0/valid/assets/img/sshot.webp create mode 100644 testdata/v0/valid/image_formats.yml diff --git a/testdata/v0/valid/assets/img/logo.webp b/testdata/v0/valid/assets/img/logo.webp new file mode 100644 index 0000000..e69de29 diff --git a/testdata/v0/valid/assets/img/sshot.avif b/testdata/v0/valid/assets/img/sshot.avif new file mode 100644 index 0000000..e69de29 diff --git a/testdata/v0/valid/assets/img/sshot.jpeg b/testdata/v0/valid/assets/img/sshot.jpeg new file mode 100644 index 0000000..e69de29 diff --git a/testdata/v0/valid/assets/img/sshot.jpg b/testdata/v0/valid/assets/img/sshot.jpg new file mode 100644 index 0000000..e69de29 diff --git a/testdata/v0/valid/assets/img/sshot.webp b/testdata/v0/valid/assets/img/sshot.webp new file mode 100644 index 0000000..e69de29 diff --git a/testdata/v0/valid/image_formats.yml b/testdata/v0/valid/image_formats.yml new file mode 100644 index 0000000..9bbfc65 --- /dev/null +++ b/testdata/v0/valid/image_formats.yml @@ -0,0 +1,57 @@ +publiccodeYmlVersion: "0" + +name: Medusa +url: "https://github.com/italia/developers.italia.it.git" + +logo: assets/img/logo.webp + +platforms: + - web + +categories: + - cloud-management + +developmentStatus: development + +softwareType: "standalone/other" + +description: + en-GB: + localisedName: Medusa + shortDescription: > + A rather short description which + is probably useless + longDescription: > + Very long description of this software, also split + on multiple rows. You should note what the software + is and why one should need it. This is 158 characters. + Very long description of this software, also split + on multiple rows. You should note what the software + is and why one should need it. This is 316 characters. + Very long description of this software, also split + on multiple rows. You should note what the software + is and why one should need it. This is 474 characters. + Very long description of this software, also split + on multiple rows. You should note what the software + is and why one should need it. This is 632 characters. + screenshots: + - assets/img/sshot.avif + - assets/img/sshot.jpg + - assets/img/sshot.jpeg + - assets/img/sshot.webp + features: + - Just one feature + +legal: + license: AGPL-3.0-or-later + +maintenance: + type: "community" + + contacts: + - name: Francesco Rossi + +localisation: + localisationReady: true + availableLanguages: + - en diff --git a/validations.go b/validations.go index 2648863..7b085f9 100644 --- a/validations.go +++ b/validations.go @@ -158,7 +158,7 @@ func (p *Parser) fileExists(u url.URL, network bool) (bool, error) { // isImageFile check whether the string is a valid image. It also checks if the file exists. // It returns true if it is an image or false if it's not and an error, if any. func (p *Parser) isImageFile(u url.URL, network bool) (bool, error) { - validExt := []string{".jpg", ".png"} + validExt := []string{".png", ".jpg", ".jpeg", ".webp", ".avif"} ext := strings.ToLower(filepath.Ext(u.Path)) if !slices.Contains(validExt, ext) { @@ -171,7 +171,7 @@ func (p *Parser) isImageFile(u url.URL, network bool) (bool, error) { // validLogo returns true if the file path in value is a valid logo. // It also checks if the file exists. func (p *Parser) validLogo(u url.URL, network bool) (bool, error) { - validExt := []string{".svg", ".svgz", ".png"} + validExt := []string{".svg", ".svgz", ".png", ".jpg", ".jpeg", ".webp", ".avif"} ext := strings.ToLower(filepath.Ext(u.Path)) // Check for valid extension. From 321de4c1f0af55dd3e27f480214e0f427cbfd1b9 Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Sun, 18 Oct 2026 21:30:47 +0200 Subject: [PATCH 2/8] feat: add deprecation warning for the government scope See publiccodeyml/publiccode.yml#353. --- fields.go | 11 ++++ .../valid_with_government_scope.yml | 55 +++++++++++++++++++ v0_test.go | 3 + 3 files changed, 69 insertions(+) create mode 100644 testdata/v0/valid_with_warnings/valid_with_government_scope.yml diff --git a/fields.go b/fields.go index c875bcc..1563fc5 100644 --- a/fields.go +++ b/fields.go @@ -100,6 +100,17 @@ func validateFieldsV0(publiccode PublicCode, parser *Parser, network bool, baseU } } + if publiccodev0.IntendedAudience.Scope != nil { + for i, scope := range *publiccodev0.IntendedAudience.Scope { + if scope == "government" { + vr = append(vr, newValidationWarning( + fmt.Sprintf("intendedAudience.scope[%d]", i), + "The 'government' scope is DEPRECATED and will be removed in the future. It's safe to drop it", + )) + } + } + } + if publiccodev0.IntendedAudience.UnsupportedCountries != nil { for i, c := range *publiccodev0.IntendedAudience.UnsupportedCountries { if sharedValidate.Var(c, "iso3166_1_alpha2_lower_or_upper") == nil && c == strings.ToLower(c) { diff --git a/testdata/v0/valid_with_warnings/valid_with_government_scope.yml b/testdata/v0/valid_with_warnings/valid_with_government_scope.yml new file mode 100644 index 0000000..2a1afac --- /dev/null +++ b/testdata/v0/valid_with_warnings/valid_with_government_scope.yml @@ -0,0 +1,55 @@ +publiccodeYmlVersion: "0" + +name: Medusa +url: "https://github.com/italia/developers.italia.it.git" + +platforms: + - web + +categories: + - cloud-management + +developmentStatus: development + +softwareType: "standalone/other" + +intendedAudience: + scope: + - science-and-technology + - government + +description: + en-GB: + localisedName: Medusa + shortDescription: > + A rather short description which + is probably useless + longDescription: > + Very long description of this software, also split + on multiple rows. You should note what the software + is and why one should need it. This is 158 characters. + Very long description of this software, also split + on multiple rows. You should note what the software + is and why one should need it. This is 316 characters. + Very long description of this software, also split + on multiple rows. You should note what the software + is and why one should need it. This is 474 characters. + Very long description of this software, also split + on multiple rows. You should note what the software + is and why one should need it. This is 632 characters. + features: + - Just one feature + +legal: + license: AGPL-3.0-or-later + +maintenance: + type: "community" + + contacts: + - name: Francesco Rossi + +localisation: + localisationReady: true + availableLanguages: + - en diff --git a/v0_test.go b/v0_test.go index b415f20..a0c6d77 100644 --- a/v0_test.go +++ b/v0_test.go @@ -641,6 +641,9 @@ func TestValidWithWarningsTestcasesV0(t *testing.T) { ValidationWarning{"", "intendedAudience.countries[1]", "Lowercase country codes are DEPRECATED. Use uppercase instead ('DE')", 32, 7}, ValidationWarning{"", "intendedAudience.unsupportedCountries[0]", "Lowercase country codes are DEPRECATED. Use uppercase instead ('US')", 34, 7}, }, + "valid_with_government_scope.yml": ValidationResults{ + ValidationWarning{"", "intendedAudience.scope[1]", "The 'government' scope is DEPRECATED and will be removed in the future. It's safe to drop it", 19, 7}, + }, "valid_with_legal_repoOwner.yml": ValidationResults{ ValidationWarning{"", "legal.repoOwner", "This key is DEPRECATED and will be removed in the future. Use 'organisation.name' instead", 70, 3}, }, From 3ddfc9614a3f8863c8584fe87f3cf724329540c3 Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Sun, 18 Oct 2026 21:39:07 +0200 Subject: [PATCH 3/8] feat: add deprecation warning for dependsOn.open See publiccodeyml/publiccode.yml#358. --- fields.go | 7 +++ .../v0/valid/countryExtensionVersion_1.0.yml | 8 --- testdata/v0/valid/dependsOn.yml | 8 --- testdata/v0/valid/no-network/valid.yml | 8 --- testdata/v0/valid/valid.yml | 8 --- testdata/v0/valid/valid_no_it_conforme.yml | 8 --- ...ith_country_specific_section_uppercase.yml | 8 --- .../no-network/authorsFile.yml | 8 --- .../valid_with_IT_riuso_codiceIPA.yml | 8 --- ...with_country_specific_section_downcase.yml | 8 --- .../valid_with_dependsOn_open.yml | 59 +++++++++++++++++++ .../valid_with_it_conforme.yml | 8 --- .../valid_with_legal_repoOwner.yml | 8 --- .../valid_with_lowercase_countries.yml | 8 --- v0_test.go | 15 ++++- 15 files changed, 78 insertions(+), 99 deletions(-) create mode 100644 testdata/v0/valid_with_warnings/valid_with_dependsOn_open.yml diff --git a/fields.go b/fields.go index 1563fc5..e8a4e7f 100644 --- a/fields.go +++ b/fields.go @@ -158,6 +158,13 @@ func validateFieldsV0(publiccode PublicCode, parser *Parser, network bool, baseU )) } + if publiccodev0.DependsOn != nil && publiccodev0.DependsOn.Open != nil { + vr = append(vr, newValidationWarning( + "dependsOn.open", + "This key is DEPRECATED and will be removed in the future. It's safe to drop it", + )) + } + if publiccodev0.OutputTypes != nil { vr = append(vr, newValidationWarning( "outputTypes", diff --git a/testdata/v0/valid/countryExtensionVersion_1.0.yml b/testdata/v0/valid/countryExtensionVersion_1.0.yml index 280fd1e..99e7280 100644 --- a/testdata/v0/valid/countryExtensionVersion_1.0.yml +++ b/testdata/v0/valid/countryExtensionVersion_1.0.yml @@ -84,14 +84,6 @@ localisation: - de dependsOn: - open: - - name: MySQL - versionMin: "1.1" - versionMax: "1.3" - optional: true - - name: PostgreSQL - version: "3.2" - optional: true proprietary: - name: Oracle versionMin: "11.4" diff --git a/testdata/v0/valid/dependsOn.yml b/testdata/v0/valid/dependsOn.yml index 26fa26b..0c6cda1 100644 --- a/testdata/v0/valid/dependsOn.yml +++ b/testdata/v0/valid/dependsOn.yml @@ -87,14 +87,6 @@ localisation: - de dependsOn: # List of dependencies. The only mandatory list is the proprietary one - open: # List of open dependencies. Optional - - name: MySQL - versionMin: "1.1" - versionMax: "1.3" - optional: true - - name: PostgreSQL - version: "3.2" - optional: true # List of proprietary software which is a dependency for using this product. This includes runtime dependencies proprietary: - name: Oracle diff --git a/testdata/v0/valid/no-network/valid.yml b/testdata/v0/valid/no-network/valid.yml index 240fc05..38852fd 100644 --- a/testdata/v0/valid/no-network/valid.yml +++ b/testdata/v0/valid/no-network/valid.yml @@ -209,14 +209,6 @@ localisation: - sl-IT-nedis dependsOn: - open: - - name: MySQL - versionMin: "1.1" - versionMax: "1.3" - optional: true - - name: PostgreSQL - version: "3.2" - optional: true proprietary: - name: Oracle versionMin: "11.4" diff --git a/testdata/v0/valid/valid.yml b/testdata/v0/valid/valid.yml index d74a567..a0c84cb 100644 --- a/testdata/v0/valid/valid.yml +++ b/testdata/v0/valid/valid.yml @@ -212,14 +212,6 @@ localisation: - sl-IT-nedis dependsOn: - open: - - name: MySQL - versionMin: "1.1" - versionMax: "1.3" - optional: true - - name: PostgreSQL - version: "3.2" - optional: true proprietary: - name: Oracle versionMin: "11.4" diff --git a/testdata/v0/valid/valid_no_it_conforme.yml b/testdata/v0/valid/valid_no_it_conforme.yml index 71638ed..b7cfe9e 100644 --- a/testdata/v0/valid/valid_no_it_conforme.yml +++ b/testdata/v0/valid/valid_no_it_conforme.yml @@ -84,14 +84,6 @@ localisation: - de dependsOn: - open: - - name: MySQL - versionMin: "1.1" - versionMax: "1.3" - optional: true - - name: PostgreSQL - version: "3.2" - optional: true proprietary: - name: Oracle versionMin: "11.4" diff --git a/testdata/v0/valid/valid_with_country_specific_section_uppercase.yml b/testdata/v0/valid/valid_with_country_specific_section_uppercase.yml index 892d818..f09cb87 100644 --- a/testdata/v0/valid/valid_with_country_specific_section_uppercase.yml +++ b/testdata/v0/valid/valid_with_country_specific_section_uppercase.yml @@ -84,14 +84,6 @@ localisation: - de dependsOn: - open: - - name: MySQL - versionMin: "1.1" - versionMax: "1.3" - optional: true - - name: PostgreSQL - version: "3.2" - optional: true proprietary: - name: Oracle versionMin: "11.4" diff --git a/testdata/v0/valid_with_warnings/no-network/authorsFile.yml b/testdata/v0/valid_with_warnings/no-network/authorsFile.yml index 20b9ddd..3c9000e 100644 --- a/testdata/v0/valid_with_warnings/no-network/authorsFile.yml +++ b/testdata/v0/valid_with_warnings/no-network/authorsFile.yml @@ -88,14 +88,6 @@ localisation: - de dependsOn: # List of dependencies. The only mandatory list is the proprietary one - open: # List of open dependencies. Optional - - name: MySQL - versionMin: "1.1" - versionMax: "1.3" - optional: true - - name: PostgreSQL - version: "3.2" - optional: true # List of proprietary software which is a dependency for using this product. This includes runtime dependencies proprietary: - name: Oracle diff --git a/testdata/v0/valid_with_warnings/valid_with_IT_riuso_codiceIPA.yml b/testdata/v0/valid_with_warnings/valid_with_IT_riuso_codiceIPA.yml index 567b0c1..d0d1571 100644 --- a/testdata/v0/valid_with_warnings/valid_with_IT_riuso_codiceIPA.yml +++ b/testdata/v0/valid_with_warnings/valid_with_IT_riuso_codiceIPA.yml @@ -98,14 +98,6 @@ localisation: - de dependsOn: - open: - - name: MySQL - versionMin: "1.1" - versionMax: "1.3" - optional: true - - name: PostgreSQL - version: "3.2" - optional: true proprietary: - name: Oracle versionMin: "11.4" diff --git a/testdata/v0/valid_with_warnings/valid_with_country_specific_section_downcase.yml b/testdata/v0/valid_with_warnings/valid_with_country_specific_section_downcase.yml index b43ea66..807d6c7 100644 --- a/testdata/v0/valid_with_warnings/valid_with_country_specific_section_downcase.yml +++ b/testdata/v0/valid_with_warnings/valid_with_country_specific_section_downcase.yml @@ -84,14 +84,6 @@ localisation: - de dependsOn: - open: - - name: MySQL - versionMin: "1.1" - versionMax: "1.3" - optional: true - - name: PostgreSQL - version: "3.2" - optional: true proprietary: - name: Oracle versionMin: "11.4" diff --git a/testdata/v0/valid_with_warnings/valid_with_dependsOn_open.yml b/testdata/v0/valid_with_warnings/valid_with_dependsOn_open.yml new file mode 100644 index 0000000..d82a530 --- /dev/null +++ b/testdata/v0/valid_with_warnings/valid_with_dependsOn_open.yml @@ -0,0 +1,59 @@ +publiccodeYmlVersion: "0" + +name: Medusa +url: "https://github.com/italia/developers.italia.it.git" + +platforms: + - web + +categories: + - cloud-management + +developmentStatus: development + +softwareType: "standalone/other" + +description: + en-GB: + localisedName: Medusa + shortDescription: > + A rather short description which + is probably useless + longDescription: > + Very long description of this software, also split + on multiple rows. You should note what the software + is and why one should need it. This is 158 characters. + Very long description of this software, also split + on multiple rows. You should note what the software + is and why one should need it. This is 316 characters. + Very long description of this software, also split + on multiple rows. You should note what the software + is and why one should need it. This is 474 characters. + Very long description of this software, also split + on multiple rows. You should note what the software + is and why one should need it. This is 632 characters. + features: + - Just one feature + +legal: + license: AGPL-3.0-or-later + +maintenance: + type: "community" + + contacts: + - name: Francesco Rossi + +localisation: + localisationReady: true + availableLanguages: + - en + +dependsOn: + open: + - name: MySQL + versionMin: "1.1" + versionMax: "1.3" + optional: true + - name: PostgreSQL + version: "3.2" diff --git a/testdata/v0/valid_with_warnings/valid_with_it_conforme.yml b/testdata/v0/valid_with_warnings/valid_with_it_conforme.yml index 2edfd08..0879ffc 100644 --- a/testdata/v0/valid_with_warnings/valid_with_it_conforme.yml +++ b/testdata/v0/valid_with_warnings/valid_with_it_conforme.yml @@ -98,14 +98,6 @@ localisation: - de dependsOn: - open: - - name: MySQL - versionMin: "1.1" - versionMax: "1.3" - optional: true - - name: PostgreSQL - version: "3.2" - optional: true proprietary: - name: Oracle versionMin: "11.4" diff --git a/testdata/v0/valid_with_warnings/valid_with_legal_repoOwner.yml b/testdata/v0/valid_with_warnings/valid_with_legal_repoOwner.yml index 6dd031c..653d2da 100644 --- a/testdata/v0/valid_with_warnings/valid_with_legal_repoOwner.yml +++ b/testdata/v0/valid_with_warnings/valid_with_legal_repoOwner.yml @@ -100,14 +100,6 @@ localisation: - de dependsOn: - open: - - name: MySQL - versionMin: "1.1" - versionMax: "1.3" - optional: true - - name: PostgreSQL - version: "3.2" - optional: true proprietary: - name: Oracle versionMin: "11.4" diff --git a/testdata/v0/valid_with_warnings/valid_with_lowercase_countries.yml b/testdata/v0/valid_with_warnings/valid_with_lowercase_countries.yml index 21e9ca7..68aab88 100644 --- a/testdata/v0/valid_with_warnings/valid_with_lowercase_countries.yml +++ b/testdata/v0/valid_with_warnings/valid_with_lowercase_countries.yml @@ -99,14 +99,6 @@ localisation: - de dependsOn: - open: - - name: MySQL - versionMin: "1.1" - versionMax: "1.3" - optional: true - - name: PostgreSQL - version: "3.2" - optional: true proprietary: - name: Oracle versionMin: "11.4" diff --git a/v0_test.go b/v0_test.go index a0c6d77..a93e8e1 100644 --- a/v0_test.go +++ b/v0_test.go @@ -52,6 +52,7 @@ func TestInvalidTestcasesV0_NoNetwork(t *testing.T) { "landingURL_invalid.yml": ValidationResults{ // Just a syntax check here, no check for reachability as network is disabled ValidationError{"", "landingURL", "landingURL must be an HTTP URL", 8, 1}, + ValidationWarning{"", "dependsOn.open", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 104, 3}, }, // monochromeLogo @@ -151,10 +152,12 @@ func TestInvalidTestcasesV0(t *testing.T) { // landingURL "landingURL_wrong_type.yml": ValidationResults{ ValidationError{"", "landingURL", "wrong type for this field", 8, 1}, + ValidationWarning{"", "dependsOn.open", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 100, 3}, }, "landingURL_invalid.yml": ValidationResults{ ValidationError{"", "landingURL", "landingURL must be an HTTP URL", 8, 1}, ValidationError{"", "landingURL", "'???' not reachable: missing URL scheme", 8, 1}, + ValidationWarning{"", "dependsOn.open", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 104, 3}, }, // isBasedOn @@ -549,11 +552,13 @@ func TestInvalidTestcasesV0(t *testing.T) { ValidationError{"", "IT.riuso.codiceIPA", "codiceIPA must be a valid Italian Public Administration Code (iPA) (see https://github.com/publiccodeyml/italian-organizations-ipa-vocabulary)", 55, 5}, }, "it_IT_duplicated.yml": ValidationResults{ + ValidationWarning{"", "dependsOn.open", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 87, 3}, ValidationWarning{"", "it", "Lowercase country codes are DEPRECATED and will be removed in the future. Use 'IT' instead", 116, 1}, ValidationError{"", "it", "'IT' key already present. Remove this key", 116, 1}, }, "it_wrong_case.yml": ValidationResults{ ValidationError{"", "It", "unknown field \"It\"", 107, 1}, + ValidationWarning{"", "dependsOn.open", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 87, 3}, }, "description_en_gb_invalid_bcp47.yml": ValidationResults{ ValidationError{"", "description", "description must be a valid BCP 47 language", 18, 1}, @@ -631,10 +636,10 @@ func TestValidWithWarningsTestcasesV0(t *testing.T) { ValidationWarning{"", "outputTypes", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 50, 1}, }, "valid_with_it_conforme.yml": ValidationResults{ - ValidationWarning{"", "IT.conforme", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 119, 3}, + ValidationWarning{"", "IT.conforme", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 111, 3}, }, "valid_with_country_specific_section_downcase.yml": ValidationResults{ - ValidationWarning{"", "it", "Lowercase country codes are DEPRECATED and will be removed in the future. Use 'IT' instead", 107, 1}, + ValidationWarning{"", "it", "Lowercase country codes are DEPRECATED and will be removed in the future. Use 'IT' instead", 99, 1}, }, "valid_with_lowercase_countries.yml": ValidationResults{ ValidationWarning{"", "intendedAudience.countries[0]", "Lowercase country codes are DEPRECATED. Use uppercase instead ('IT')", 31, 7}, @@ -647,8 +652,11 @@ func TestValidWithWarningsTestcasesV0(t *testing.T) { "valid_with_legal_repoOwner.yml": ValidationResults{ ValidationWarning{"", "legal.repoOwner", "This key is DEPRECATED and will be removed in the future. Use 'organisation.name' instead", 70, 3}, }, + "valid_with_dependsOn_open.yml": ValidationResults{ + ValidationWarning{"", "dependsOn.open", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 53, 3}, + }, "valid_with_IT_riuso_codiceIPA.yml": ValidationResults{ - ValidationWarning{"", "IT.riuso.codiceIPA", "This key is DEPRECATED and will be removed in the future. Use 'organisation.uri' and set it to 'urn:x-italian-pa:pcm' instead", 119, 5}, + ValidationWarning{"", "IT.riuso.codiceIPA", "This key is DEPRECATED and will be removed in the future. Use 'organisation.uri' and set it to 'urn:x-italian-pa:pcm' instead", 111, 5}, }, } @@ -680,6 +688,7 @@ func TestDecodeValueErrorsRemote(t *testing.T) { ValidationWarning{"", "intendedAudience.countries[0]", "Lowercase country codes are DEPRECATED. Use uppercase instead ('IT')", 31, 7}, ValidationWarning{"", "intendedAudience.countries[1]", "Lowercase country codes are DEPRECATED. Use uppercase instead ('DE')", 32, 7}, ValidationWarning{"", "intendedAudience.unsupportedCountries[0]", "Lowercase country codes are DEPRECATED. Use uppercase instead ('US')", 34, 7}, + ValidationWarning{"", "dependsOn.open", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 102, 3}, }}, } From 2485a329dc03576ca662496dd98f8d5a46fe4ad2 Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Sun, 18 Oct 2026 21:39:07 +0200 Subject: [PATCH 4/8] feat: add deprecation warning for usedBy See publiccodeyml/publiccode.yml#187. --- fields.go | 7 +++ .../v0/valid/countryExtensionVersion_1.0.yml | 4 -- testdata/v0/valid/dependsOn.yml | 4 -- testdata/v0/valid/no-network/valid.yml | 4 -- testdata/v0/valid/valid.yml | 4 -- testdata/v0/valid/valid_no_it_conforme.yml | 4 -- ...ith_country_specific_section_uppercase.yml | 4 -- .../no-network/authorsFile.yml | 4 -- .../valid_with_IT_riuso_codiceIPA.yml | 4 -- ...with_country_specific_section_downcase.yml | 4 -- .../valid_with_it_conforme.yml | 4 -- .../valid_with_legal_repoOwner.yml | 4 -- .../valid_with_lowercase_countries.yml | 4 -- .../valid_with_warnings/valid_with_usedBy.yml | 54 +++++++++++++++++++ v0_test.go | 25 ++++++--- 15 files changed, 78 insertions(+), 56 deletions(-) create mode 100644 testdata/v0/valid_with_warnings/valid_with_usedBy.yml diff --git a/fields.go b/fields.go index e8a4e7f..fdaaaf9 100644 --- a/fields.go +++ b/fields.go @@ -165,6 +165,13 @@ func validateFieldsV0(publiccode PublicCode, parser *Parser, network bool, baseU )) } + if publiccodev0.UsedBy != nil { + vr = append(vr, newValidationWarning( + "usedBy", + "This key is DEPRECATED and will be removed in the future. It's safe to drop it", + )) + } + if publiccodev0.OutputTypes != nil { vr = append(vr, newValidationWarning( "outputTypes", diff --git a/testdata/v0/valid/countryExtensionVersion_1.0.yml b/testdata/v0/valid/countryExtensionVersion_1.0.yml index 99e7280..96e0d24 100644 --- a/testdata/v0/valid/countryExtensionVersion_1.0.yml +++ b/testdata/v0/valid/countryExtensionVersion_1.0.yml @@ -16,10 +16,6 @@ platforms: categories: - cloud-management -usedBy: - - Comune di Firenze - - Comune di Roma - roadmap: "https://designers.italia.it/roadmap/" developmentStatus: development diff --git a/testdata/v0/valid/dependsOn.yml b/testdata/v0/valid/dependsOn.yml index 0c6cda1..64d4160 100644 --- a/testdata/v0/valid/dependsOn.yml +++ b/testdata/v0/valid/dependsOn.yml @@ -17,10 +17,6 @@ platforms: # or Windows, Mac, Linux, etc. categories: - cloud-management -usedBy: - - Comune di Firenze - - Comune di Roma - roadmap: "https://designers.italia.it/roadmap/" developmentStatus: development diff --git a/testdata/v0/valid/no-network/valid.yml b/testdata/v0/valid/no-network/valid.yml index 38852fd..bfd65cb 100644 --- a/testdata/v0/valid/no-network/valid.yml +++ b/testdata/v0/valid/no-network/valid.yml @@ -121,10 +121,6 @@ categories: - website-builder - workflow-management -usedBy: - - Comune di Firenze - - Comune di Roma - roadmap: "https://designers.italia.it/roadmap/" developmentStatus: development diff --git a/testdata/v0/valid/valid.yml b/testdata/v0/valid/valid.yml index a0c84cb..43dddba 100644 --- a/testdata/v0/valid/valid.yml +++ b/testdata/v0/valid/valid.yml @@ -124,10 +124,6 @@ categories: - website-builder - workflow-management -usedBy: - - Comune di Firenze - - Comune di Roma - roadmap: "https://designers.italia.it/roadmap/" developmentStatus: development diff --git a/testdata/v0/valid/valid_no_it_conforme.yml b/testdata/v0/valid/valid_no_it_conforme.yml index b7cfe9e..54086b9 100644 --- a/testdata/v0/valid/valid_no_it_conforme.yml +++ b/testdata/v0/valid/valid_no_it_conforme.yml @@ -16,10 +16,6 @@ platforms: categories: - cloud-management -usedBy: - - Comune di Firenze - - Comune di Roma - roadmap: "https://designers.italia.it/roadmap/" developmentStatus: development diff --git a/testdata/v0/valid/valid_with_country_specific_section_uppercase.yml b/testdata/v0/valid/valid_with_country_specific_section_uppercase.yml index f09cb87..4776f34 100644 --- a/testdata/v0/valid/valid_with_country_specific_section_uppercase.yml +++ b/testdata/v0/valid/valid_with_country_specific_section_uppercase.yml @@ -16,10 +16,6 @@ platforms: categories: - cloud-management -usedBy: - - Comune di Firenze - - Comune di Roma - roadmap: "https://designers.italia.it/roadmap/" developmentStatus: development diff --git a/testdata/v0/valid_with_warnings/no-network/authorsFile.yml b/testdata/v0/valid_with_warnings/no-network/authorsFile.yml index 3c9000e..b860825 100644 --- a/testdata/v0/valid_with_warnings/no-network/authorsFile.yml +++ b/testdata/v0/valid_with_warnings/no-network/authorsFile.yml @@ -17,10 +17,6 @@ platforms: # or Windows, Mac, Linux, etc. categories: - cloud-management -usedBy: - - Comune di Firenze - - Comune di Roma - roadmap: "https://designers.italia.it/roadmap/" developmentStatus: development diff --git a/testdata/v0/valid_with_warnings/valid_with_IT_riuso_codiceIPA.yml b/testdata/v0/valid_with_warnings/valid_with_IT_riuso_codiceIPA.yml index d0d1571..04c5f08 100644 --- a/testdata/v0/valid_with_warnings/valid_with_IT_riuso_codiceIPA.yml +++ b/testdata/v0/valid_with_warnings/valid_with_IT_riuso_codiceIPA.yml @@ -15,10 +15,6 @@ platforms: categories: - cloud-management -usedBy: - - Comune di Firenze - - Comune di Roma - roadmap: "https://designers.italia.it/roadmap/" developmentStatus: development diff --git a/testdata/v0/valid_with_warnings/valid_with_country_specific_section_downcase.yml b/testdata/v0/valid_with_warnings/valid_with_country_specific_section_downcase.yml index 807d6c7..1c0241c 100644 --- a/testdata/v0/valid_with_warnings/valid_with_country_specific_section_downcase.yml +++ b/testdata/v0/valid_with_warnings/valid_with_country_specific_section_downcase.yml @@ -16,10 +16,6 @@ platforms: categories: - cloud-management -usedBy: - - Comune di Firenze - - Comune di Roma - roadmap: "https://designers.italia.it/roadmap/" developmentStatus: development diff --git a/testdata/v0/valid_with_warnings/valid_with_it_conforme.yml b/testdata/v0/valid_with_warnings/valid_with_it_conforme.yml index 0879ffc..d60515d 100644 --- a/testdata/v0/valid_with_warnings/valid_with_it_conforme.yml +++ b/testdata/v0/valid_with_warnings/valid_with_it_conforme.yml @@ -15,10 +15,6 @@ platforms: categories: - cloud-management -usedBy: - - Comune di Firenze - - Comune di Roma - roadmap: "https://designers.italia.it/roadmap/" developmentStatus: development diff --git a/testdata/v0/valid_with_warnings/valid_with_legal_repoOwner.yml b/testdata/v0/valid_with_warnings/valid_with_legal_repoOwner.yml index 653d2da..51bd8c8 100644 --- a/testdata/v0/valid_with_warnings/valid_with_legal_repoOwner.yml +++ b/testdata/v0/valid_with_warnings/valid_with_legal_repoOwner.yml @@ -15,10 +15,6 @@ platforms: categories: - cloud-management -usedBy: - - Comune di Firenze - - Comune di Roma - roadmap: "https://designers.italia.it/roadmap/" developmentStatus: development diff --git a/testdata/v0/valid_with_warnings/valid_with_lowercase_countries.yml b/testdata/v0/valid_with_warnings/valid_with_lowercase_countries.yml index 68aab88..ca5f813 100644 --- a/testdata/v0/valid_with_warnings/valid_with_lowercase_countries.yml +++ b/testdata/v0/valid_with_warnings/valid_with_lowercase_countries.yml @@ -15,10 +15,6 @@ platforms: categories: - cloud-management -usedBy: - - Comune di Firenze - - Comune di Roma - roadmap: "https://designers.italia.it/roadmap/" developmentStatus: development diff --git a/testdata/v0/valid_with_warnings/valid_with_usedBy.yml b/testdata/v0/valid_with_warnings/valid_with_usedBy.yml new file mode 100644 index 0000000..115be95 --- /dev/null +++ b/testdata/v0/valid_with_warnings/valid_with_usedBy.yml @@ -0,0 +1,54 @@ +publiccodeYmlVersion: "0" + +name: Medusa +url: "https://github.com/italia/developers.italia.it.git" + +platforms: + - web + +categories: + - cloud-management + +usedBy: + - Comune di Firenze + - Comune di Roma + +developmentStatus: development + +softwareType: "standalone/other" + +description: + en-GB: + localisedName: Medusa + shortDescription: > + A rather short description which + is probably useless + longDescription: > + Very long description of this software, also split + on multiple rows. You should note what the software + is and why one should need it. This is 158 characters. + Very long description of this software, also split + on multiple rows. You should note what the software + is and why one should need it. This is 316 characters. + Very long description of this software, also split + on multiple rows. You should note what the software + is and why one should need it. This is 474 characters. + Very long description of this software, also split + on multiple rows. You should note what the software + is and why one should need it. This is 632 characters. + features: + - Just one feature + +legal: + license: AGPL-3.0-or-later + +maintenance: + type: "community" + + contacts: + - name: Francesco Rossi + +localisation: + localisationReady: true + availableLanguages: + - en diff --git a/v0_test.go b/v0_test.go index a93e8e1..1beebe9 100644 --- a/v0_test.go +++ b/v0_test.go @@ -15,7 +15,7 @@ func TestValidTestcasesV0_NoNetwork(t *testing.T) { func TestValidWithWarningTestcasesV0_NoNetwork(t *testing.T) { expected := map[string]error{ "authorsFile.yml": ValidationResults{ - ValidationWarning{"", "legal.authorsFile", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 71, 3}, + ValidationWarning{"", "legal.authorsFile", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 67, 3}, }, } @@ -53,6 +53,7 @@ func TestInvalidTestcasesV0_NoNetwork(t *testing.T) { // Just a syntax check here, no check for reachability as network is disabled ValidationError{"", "landingURL", "landingURL must be an HTTP URL", 8, 1}, ValidationWarning{"", "dependsOn.open", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 104, 3}, + ValidationWarning{"", "usedBy", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 21, 1}, }, // monochromeLogo @@ -153,11 +154,13 @@ func TestInvalidTestcasesV0(t *testing.T) { "landingURL_wrong_type.yml": ValidationResults{ ValidationError{"", "landingURL", "wrong type for this field", 8, 1}, ValidationWarning{"", "dependsOn.open", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 100, 3}, + ValidationWarning{"", "usedBy", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 21, 1}, }, "landingURL_invalid.yml": ValidationResults{ ValidationError{"", "landingURL", "landingURL must be an HTTP URL", 8, 1}, ValidationError{"", "landingURL", "'???' not reachable: missing URL scheme", 8, 1}, ValidationWarning{"", "dependsOn.open", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 104, 3}, + ValidationWarning{"", "usedBy", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 21, 1}, }, // isBasedOn @@ -553,12 +556,14 @@ func TestInvalidTestcasesV0(t *testing.T) { }, "it_IT_duplicated.yml": ValidationResults{ ValidationWarning{"", "dependsOn.open", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 87, 3}, + ValidationWarning{"", "usedBy", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 19, 1}, ValidationWarning{"", "it", "Lowercase country codes are DEPRECATED and will be removed in the future. Use 'IT' instead", 116, 1}, ValidationError{"", "it", "'IT' key already present. Remove this key", 116, 1}, }, "it_wrong_case.yml": ValidationResults{ ValidationError{"", "It", "unknown field \"It\"", 107, 1}, ValidationWarning{"", "dependsOn.open", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 87, 3}, + ValidationWarning{"", "usedBy", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 19, 1}, }, "description_en_gb_invalid_bcp47.yml": ValidationResults{ ValidationError{"", "description", "description must be a valid BCP 47 language", 18, 1}, @@ -636,27 +641,30 @@ func TestValidWithWarningsTestcasesV0(t *testing.T) { ValidationWarning{"", "outputTypes", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 50, 1}, }, "valid_with_it_conforme.yml": ValidationResults{ - ValidationWarning{"", "IT.conforme", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 111, 3}, + ValidationWarning{"", "IT.conforme", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 107, 3}, }, "valid_with_country_specific_section_downcase.yml": ValidationResults{ - ValidationWarning{"", "it", "Lowercase country codes are DEPRECATED and will be removed in the future. Use 'IT' instead", 99, 1}, + ValidationWarning{"", "it", "Lowercase country codes are DEPRECATED and will be removed in the future. Use 'IT' instead", 95, 1}, }, "valid_with_lowercase_countries.yml": ValidationResults{ - ValidationWarning{"", "intendedAudience.countries[0]", "Lowercase country codes are DEPRECATED. Use uppercase instead ('IT')", 31, 7}, - ValidationWarning{"", "intendedAudience.countries[1]", "Lowercase country codes are DEPRECATED. Use uppercase instead ('DE')", 32, 7}, - ValidationWarning{"", "intendedAudience.unsupportedCountries[0]", "Lowercase country codes are DEPRECATED. Use uppercase instead ('US')", 34, 7}, + ValidationWarning{"", "intendedAudience.countries[0]", "Lowercase country codes are DEPRECATED. Use uppercase instead ('IT')", 27, 7}, + ValidationWarning{"", "intendedAudience.countries[1]", "Lowercase country codes are DEPRECATED. Use uppercase instead ('DE')", 28, 7}, + ValidationWarning{"", "intendedAudience.unsupportedCountries[0]", "Lowercase country codes are DEPRECATED. Use uppercase instead ('US')", 30, 7}, }, "valid_with_government_scope.yml": ValidationResults{ ValidationWarning{"", "intendedAudience.scope[1]", "The 'government' scope is DEPRECATED and will be removed in the future. It's safe to drop it", 19, 7}, }, "valid_with_legal_repoOwner.yml": ValidationResults{ - ValidationWarning{"", "legal.repoOwner", "This key is DEPRECATED and will be removed in the future. Use 'organisation.name' instead", 70, 3}, + ValidationWarning{"", "legal.repoOwner", "This key is DEPRECATED and will be removed in the future. Use 'organisation.name' instead", 66, 3}, + }, + "valid_with_usedBy.yml": ValidationResults{ + ValidationWarning{"", "usedBy", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 12, 1}, }, "valid_with_dependsOn_open.yml": ValidationResults{ ValidationWarning{"", "dependsOn.open", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 53, 3}, }, "valid_with_IT_riuso_codiceIPA.yml": ValidationResults{ - ValidationWarning{"", "IT.riuso.codiceIPA", "This key is DEPRECATED and will be removed in the future. Use 'organisation.uri' and set it to 'urn:x-italian-pa:pcm' instead", 111, 5}, + ValidationWarning{"", "IT.riuso.codiceIPA", "This key is DEPRECATED and will be removed in the future. Use 'organisation.uri' and set it to 'urn:x-italian-pa:pcm' instead", 107, 5}, }, } @@ -689,6 +697,7 @@ func TestDecodeValueErrorsRemote(t *testing.T) { ValidationWarning{"", "intendedAudience.countries[1]", "Lowercase country codes are DEPRECATED. Use uppercase instead ('DE')", 32, 7}, ValidationWarning{"", "intendedAudience.unsupportedCountries[0]", "Lowercase country codes are DEPRECATED. Use uppercase instead ('US')", 34, 7}, ValidationWarning{"", "dependsOn.open", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 102, 3}, + ValidationWarning{"", "usedBy", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 18, 1}, }}, } From 4de9de211c1773c2855b7807513c8fb43c1a7639 Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Sun, 18 Oct 2026 21:39:06 +0200 Subject: [PATCH 5/8] feat: add deprecation warning for videos See publiccodeyml/publiccode.yml#352. --- fields.go | 8 +++ .../v0/valid/countryExtensionVersion_1.0.yml | 2 - testdata/v0/valid/dependsOn.yml | 2 - testdata/v0/valid/no-network/valid.yml | 2 - testdata/v0/valid/valid.yml | 2 - testdata/v0/valid/valid_no_it_conforme.yml | 2 - ...ith_country_specific_section_uppercase.yml | 2 - .../no-network/authorsFile.yml | 2 - .../valid_with_IT_riuso_codiceIPA.yml | 2 - ...with_country_specific_section_downcase.yml | 2 - .../valid_with_it_conforme.yml | 2 - .../valid_with_legal_repoOwner.yml | 2 - .../valid_with_lowercase_countries.yml | 2 - .../valid_with_warnings/valid_with_videos.yml | 52 +++++++++++++++++++ v0_test.go | 20 +++++-- 15 files changed, 75 insertions(+), 29 deletions(-) create mode 100644 testdata/v0/valid_with_warnings/valid_with_videos.yml diff --git a/fields.go b/fields.go index fdaaaf9..f755517 100644 --- a/fields.go +++ b/fields.go @@ -223,6 +223,14 @@ func validateFieldsV0(publiccode PublicCode, parser *Parser, network bool, baseU } } + if len(desc.Videos) > 0 { + vr = append(vr, newValidationWarning( + fmt.Sprintf("description.%s.videos", lang), + "This key is DEPRECATED and will be removed in the future. "+ + "Link videos from the documentation or the website instead", + )) + } + for i, v := range desc.Videos { err := parser.checkOEmbedURL((*url.URL)(v)) if err != nil { diff --git a/testdata/v0/valid/countryExtensionVersion_1.0.yml b/testdata/v0/valid/countryExtensionVersion_1.0.yml index 96e0d24..589eb9b 100644 --- a/testdata/v0/valid/countryExtensionVersion_1.0.yml +++ b/testdata/v0/valid/countryExtensionVersion_1.0.yml @@ -55,8 +55,6 @@ description: - Will run without a problem - Has zero bugs - Solves all the problems of the world - videos: - - https://www.youtube.com/watch?v=RaHmGbBOP84 awards: - 1st Price Software of the year diff --git a/testdata/v0/valid/dependsOn.yml b/testdata/v0/valid/dependsOn.yml index 64d4160..06069ed 100644 --- a/testdata/v0/valid/dependsOn.yml +++ b/testdata/v0/valid/dependsOn.yml @@ -56,8 +56,6 @@ description: - Will run without a problem - Has zero bugs - Solves all the problems of the world - videos: # Demo videos of the software - - https://www.youtube.com/watch?v=RaHmGbBOP84 awards: - 1st Price Software of the year diff --git a/testdata/v0/valid/no-network/valid.yml b/testdata/v0/valid/no-network/valid.yml index bfd65cb..0173f16 100644 --- a/testdata/v0/valid/no-network/valid.yml +++ b/testdata/v0/valid/no-network/valid.yml @@ -164,8 +164,6 @@ description: - assets/img/sshot1.png - assets/img/sshot2.png - assets/img/sshot3.png - videos: - - https://www.youtube.com/watch?v=RaHmGbBOP84 awards: - 1st Price Software of the year diff --git a/testdata/v0/valid/valid.yml b/testdata/v0/valid/valid.yml index 43dddba..0b65a3e 100644 --- a/testdata/v0/valid/valid.yml +++ b/testdata/v0/valid/valid.yml @@ -163,8 +163,6 @@ description: - Will run without a problem - Has zero bugs - Solves all the problems of the world - videos: - - https://www.youtube.com/watch?v=RaHmGbBOP84 awards: - 1st Price Software of the year diff --git a/testdata/v0/valid/valid_no_it_conforme.yml b/testdata/v0/valid/valid_no_it_conforme.yml index 54086b9..2cfcb44 100644 --- a/testdata/v0/valid/valid_no_it_conforme.yml +++ b/testdata/v0/valid/valid_no_it_conforme.yml @@ -55,8 +55,6 @@ description: - Will run without a problem - Has zero bugs - Solves all the problems of the world - videos: - - https://www.youtube.com/watch?v=RaHmGbBOP84 awards: - 1st Price Software of the year diff --git a/testdata/v0/valid/valid_with_country_specific_section_uppercase.yml b/testdata/v0/valid/valid_with_country_specific_section_uppercase.yml index 4776f34..d039696 100644 --- a/testdata/v0/valid/valid_with_country_specific_section_uppercase.yml +++ b/testdata/v0/valid/valid_with_country_specific_section_uppercase.yml @@ -55,8 +55,6 @@ description: - Will run without a problem - Has zero bugs - Solves all the problems of the world - videos: - - https://www.youtube.com/watch?v=RaHmGbBOP84 awards: - 1st Price Software of the year diff --git a/testdata/v0/valid_with_warnings/no-network/authorsFile.yml b/testdata/v0/valid_with_warnings/no-network/authorsFile.yml index b860825..d0998cf 100644 --- a/testdata/v0/valid_with_warnings/no-network/authorsFile.yml +++ b/testdata/v0/valid_with_warnings/no-network/authorsFile.yml @@ -56,8 +56,6 @@ description: - Will run without a problem - Has zero bugs - Solves all the problems of the world - videos: # Demo videos of the software - - https://www.youtube.com/watch?v=RaHmGbBOP84 awards: - 1st Price Software of the year diff --git a/testdata/v0/valid_with_warnings/valid_with_IT_riuso_codiceIPA.yml b/testdata/v0/valid_with_warnings/valid_with_IT_riuso_codiceIPA.yml index 04c5f08..1681752 100644 --- a/testdata/v0/valid_with_warnings/valid_with_IT_riuso_codiceIPA.yml +++ b/testdata/v0/valid_with_warnings/valid_with_IT_riuso_codiceIPA.yml @@ -54,8 +54,6 @@ description: - Will run without a problem - Has zero bugs - Solves all the problems of the world - videos: # Demo videos of the software - - https://www.youtube.com/watch?v=RaHmGbBOP84 awards: - 1st Price Software of the year diff --git a/testdata/v0/valid_with_warnings/valid_with_country_specific_section_downcase.yml b/testdata/v0/valid_with_warnings/valid_with_country_specific_section_downcase.yml index 1c0241c..fb7ce32 100644 --- a/testdata/v0/valid_with_warnings/valid_with_country_specific_section_downcase.yml +++ b/testdata/v0/valid_with_warnings/valid_with_country_specific_section_downcase.yml @@ -55,8 +55,6 @@ description: - Will run without a problem - Has zero bugs - Solves all the problems of the world - videos: - - https://www.youtube.com/watch?v=RaHmGbBOP84 awards: - 1st Price Software of the year diff --git a/testdata/v0/valid_with_warnings/valid_with_it_conforme.yml b/testdata/v0/valid_with_warnings/valid_with_it_conforme.yml index d60515d..7d8183d 100644 --- a/testdata/v0/valid_with_warnings/valid_with_it_conforme.yml +++ b/testdata/v0/valid_with_warnings/valid_with_it_conforme.yml @@ -54,8 +54,6 @@ description: - Will run without a problem - Has zero bugs - Solves all the problems of the world - videos: # Demo videos of the software - - https://www.youtube.com/watch?v=RaHmGbBOP84 awards: - 1st Price Software of the year diff --git a/testdata/v0/valid_with_warnings/valid_with_legal_repoOwner.yml b/testdata/v0/valid_with_warnings/valid_with_legal_repoOwner.yml index 51bd8c8..d73553e 100644 --- a/testdata/v0/valid_with_warnings/valid_with_legal_repoOwner.yml +++ b/testdata/v0/valid_with_warnings/valid_with_legal_repoOwner.yml @@ -54,8 +54,6 @@ description: - Will run without a problem - Has zero bugs - Solves all the problems of the world - videos: - - https://www.youtube.com/watch?v=RaHmGbBOP84 awards: - 1st Price Software of the year diff --git a/testdata/v0/valid_with_warnings/valid_with_lowercase_countries.yml b/testdata/v0/valid_with_warnings/valid_with_lowercase_countries.yml index ca5f813..fd64ddc 100644 --- a/testdata/v0/valid_with_warnings/valid_with_lowercase_countries.yml +++ b/testdata/v0/valid_with_warnings/valid_with_lowercase_countries.yml @@ -55,8 +55,6 @@ description: - Will run without a problem - Has zero bugs - Solves all the problems of the world - videos: # Demo videos of the software - - https://www.youtube.com/watch?v=RaHmGbBOP84 awards: - 1st Price Software of the year diff --git a/testdata/v0/valid_with_warnings/valid_with_videos.yml b/testdata/v0/valid_with_warnings/valid_with_videos.yml new file mode 100644 index 0000000..9aaae57 --- /dev/null +++ b/testdata/v0/valid_with_warnings/valid_with_videos.yml @@ -0,0 +1,52 @@ +publiccodeYmlVersion: "0" + +name: Medusa +url: "https://github.com/italia/developers.italia.it.git" + +platforms: + - web + +categories: + - cloud-management + +developmentStatus: development + +softwareType: "standalone/other" + +description: + en-GB: + localisedName: Medusa + shortDescription: > + A rather short description which + is probably useless + longDescription: > + Very long description of this software, also split + on multiple rows. You should note what the software + is and why one should need it. This is 158 characters. + Very long description of this software, also split + on multiple rows. You should note what the software + is and why one should need it. This is 316 characters. + Very long description of this software, also split + on multiple rows. You should note what the software + is and why one should need it. This is 474 characters. + Very long description of this software, also split + on multiple rows. You should note what the software + is and why one should need it. This is 632 characters. + features: + - Just one feature + videos: + - https://www.youtube.com/watch?v=RaHmGbBOP84 + +legal: + license: AGPL-3.0-or-later + +maintenance: + type: "community" + + contacts: + - name: Francesco Rossi + +localisation: + localisationReady: true + availableLanguages: + - en diff --git a/v0_test.go b/v0_test.go index 1beebe9..66fd9c9 100644 --- a/v0_test.go +++ b/v0_test.go @@ -15,7 +15,7 @@ func TestValidTestcasesV0_NoNetwork(t *testing.T) { func TestValidWithWarningTestcasesV0_NoNetwork(t *testing.T) { expected := map[string]error{ "authorsFile.yml": ValidationResults{ - ValidationWarning{"", "legal.authorsFile", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 67, 3}, + ValidationWarning{"", "legal.authorsFile", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 65, 3}, }, } @@ -54,6 +54,7 @@ func TestInvalidTestcasesV0_NoNetwork(t *testing.T) { ValidationError{"", "landingURL", "landingURL must be an HTTP URL", 8, 1}, ValidationWarning{"", "dependsOn.open", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 104, 3}, ValidationWarning{"", "usedBy", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 21, 1}, + ValidationWarning{"", "description.en.videos", "This key is DEPRECATED and will be removed in the future. Link videos from the documentation or the website instead", 64, 5}, }, // monochromeLogo @@ -161,6 +162,7 @@ func TestInvalidTestcasesV0(t *testing.T) { ValidationError{"", "landingURL", "'???' not reachable: missing URL scheme", 8, 1}, ValidationWarning{"", "dependsOn.open", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 104, 3}, ValidationWarning{"", "usedBy", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 21, 1}, + ValidationWarning{"", "description.en.videos", "This key is DEPRECATED and will be removed in the future. Link videos from the documentation or the website instead", 64, 5}, }, // isBasedOn @@ -429,9 +431,11 @@ func TestInvalidTestcasesV0(t *testing.T) { }, "description_en_videos_invalid.yml": ValidationResults{ ValidationError{"", "description.en.videos[0]", "videos[0] must be an HTTP URL", 41, 9}, + ValidationWarning{"", "description.en.videos", "This key is DEPRECATED and will be removed in the future. Link videos from the documentation or the website instead", 39, 5}, ValidationError{"", "description.en.videos[0]", "'ABC' is not a valid video URL supporting oEmbed: invalid oEmbed link: ABC", 41, 9}, }, "description_en_videos_invalid_oembed.yml": ValidationResults{ + ValidationWarning{"", "description.en.videos", "This key is DEPRECATED and will be removed in the future. Link videos from the documentation or the website instead", 39, 5}, ValidationError{"", "description.en.videos[0]", "'https://google.com' is not a valid video URL supporting oEmbed: invalid oEmbed link: https://google.com", 41, 9}, }, @@ -557,6 +561,7 @@ func TestInvalidTestcasesV0(t *testing.T) { "it_IT_duplicated.yml": ValidationResults{ ValidationWarning{"", "dependsOn.open", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 87, 3}, ValidationWarning{"", "usedBy", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 19, 1}, + ValidationWarning{"", "description.en.videos", "This key is DEPRECATED and will be removed in the future. Link videos from the documentation or the website instead", 62, 5}, ValidationWarning{"", "it", "Lowercase country codes are DEPRECATED and will be removed in the future. Use 'IT' instead", 116, 1}, ValidationError{"", "it", "'IT' key already present. Remove this key", 116, 1}, }, @@ -564,6 +569,7 @@ func TestInvalidTestcasesV0(t *testing.T) { ValidationError{"", "It", "unknown field \"It\"", 107, 1}, ValidationWarning{"", "dependsOn.open", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 87, 3}, ValidationWarning{"", "usedBy", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 19, 1}, + ValidationWarning{"", "description.en.videos", "This key is DEPRECATED and will be removed in the future. Link videos from the documentation or the website instead", 62, 5}, }, "description_en_gb_invalid_bcp47.yml": ValidationResults{ ValidationError{"", "description", "description must be a valid BCP 47 language", 18, 1}, @@ -641,10 +647,10 @@ func TestValidWithWarningsTestcasesV0(t *testing.T) { ValidationWarning{"", "outputTypes", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 50, 1}, }, "valid_with_it_conforme.yml": ValidationResults{ - ValidationWarning{"", "IT.conforme", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 107, 3}, + ValidationWarning{"", "IT.conforme", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 105, 3}, }, "valid_with_country_specific_section_downcase.yml": ValidationResults{ - ValidationWarning{"", "it", "Lowercase country codes are DEPRECATED and will be removed in the future. Use 'IT' instead", 95, 1}, + ValidationWarning{"", "it", "Lowercase country codes are DEPRECATED and will be removed in the future. Use 'IT' instead", 93, 1}, }, "valid_with_lowercase_countries.yml": ValidationResults{ ValidationWarning{"", "intendedAudience.countries[0]", "Lowercase country codes are DEPRECATED. Use uppercase instead ('IT')", 27, 7}, @@ -655,7 +661,7 @@ func TestValidWithWarningsTestcasesV0(t *testing.T) { ValidationWarning{"", "intendedAudience.scope[1]", "The 'government' scope is DEPRECATED and will be removed in the future. It's safe to drop it", 19, 7}, }, "valid_with_legal_repoOwner.yml": ValidationResults{ - ValidationWarning{"", "legal.repoOwner", "This key is DEPRECATED and will be removed in the future. Use 'organisation.name' instead", 66, 3}, + ValidationWarning{"", "legal.repoOwner", "This key is DEPRECATED and will be removed in the future. Use 'organisation.name' instead", 64, 3}, }, "valid_with_usedBy.yml": ValidationResults{ ValidationWarning{"", "usedBy", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 12, 1}, @@ -663,8 +669,11 @@ func TestValidWithWarningsTestcasesV0(t *testing.T) { "valid_with_dependsOn_open.yml": ValidationResults{ ValidationWarning{"", "dependsOn.open", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 53, 3}, }, + "valid_with_videos.yml": ValidationResults{ + ValidationWarning{"", "description.en-GB.videos", "This key is DEPRECATED and will be removed in the future. Link videos from the documentation or the website instead", 37, 5}, + }, "valid_with_IT_riuso_codiceIPA.yml": ValidationResults{ - ValidationWarning{"", "IT.riuso.codiceIPA", "This key is DEPRECATED and will be removed in the future. Use 'organisation.uri' and set it to 'urn:x-italian-pa:pcm' instead", 107, 5}, + ValidationWarning{"", "IT.riuso.codiceIPA", "This key is DEPRECATED and will be removed in the future. Use 'organisation.uri' and set it to 'urn:x-italian-pa:pcm' instead", 105, 5}, }, } @@ -698,6 +707,7 @@ func TestDecodeValueErrorsRemote(t *testing.T) { ValidationWarning{"", "intendedAudience.unsupportedCountries[0]", "Lowercase country codes are DEPRECATED. Use uppercase instead ('US')", 34, 7}, ValidationWarning{"", "dependsOn.open", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 102, 3}, ValidationWarning{"", "usedBy", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 18, 1}, + ValidationWarning{"", "description.en.videos", "This key is DEPRECATED and will be removed in the future. Link videos from the documentation or the website instead", 62, 5}, }}, } From 553aa2dd81374c0ac62da2f1a821179cd9e3a864 Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Sun, 18 Oct 2026 21:37:41 +0200 Subject: [PATCH 6/8] feat: add deprecation warning for intendedAudience.unsupportedCountries See publiccodeyml/publiccode.yml#356. --- fields.go | 6 ++ testdata/v0/invalid/it_IT_duplicated.yml | 2 - testdata/v0/invalid/it_wrong_case.yml | 2 - testdata/v0/invalid/landingURL_invalid.yml | 2 - testdata/v0/invalid/landingURL_wrong_type.yml | 2 - .../invalid/no-network/landingURL_invalid.yml | 2 - .../v0/valid/countryExtensionVersion_1.0.yml | 2 - testdata/v0/valid/dependsOn.yml | 2 - testdata/v0/valid/no-network/valid.yml | 2 - testdata/v0/valid/valid.yml | 2 - testdata/v0/valid/valid_no_it_conforme.yml | 2 - ...ith_country_specific_section_uppercase.yml | 2 - .../no-network/authorsFile.yml | 2 - .../valid_with_IT_riuso_codiceIPA.yml | 2 - ...with_country_specific_section_downcase.yml | 2 - .../valid_with_it_conforme.yml | 2 - .../valid_with_legal_repoOwner.yml | 2 - .../valid_with_unsupportedCountries.yml | 56 +++++++++++++++++++ v0_test.go | 40 +++++++------ 19 files changed, 85 insertions(+), 49 deletions(-) create mode 100644 testdata/v0/valid_with_warnings/valid_with_unsupportedCountries.yml diff --git a/fields.go b/fields.go index f755517..416df6c 100644 --- a/fields.go +++ b/fields.go @@ -112,6 +112,12 @@ func validateFieldsV0(publiccode PublicCode, parser *Parser, network bool, baseU } if publiccodev0.IntendedAudience.UnsupportedCountries != nil { + vr = append(vr, newValidationWarning( + "intendedAudience.unsupportedCountries", + "This key is DEPRECATED and will be removed in the future. "+ + "Use 'intendedAudience.countries' to list the targeted countries instead", + )) + for i, c := range *publiccodev0.IntendedAudience.UnsupportedCountries { if sharedValidate.Var(c, "iso3166_1_alpha2_lower_or_upper") == nil && c == strings.ToLower(c) { vr = append(vr, newValidationWarningf( diff --git a/testdata/v0/invalid/it_IT_duplicated.yml b/testdata/v0/invalid/it_IT_duplicated.yml index 7d1b10e..e941abf 100644 --- a/testdata/v0/invalid/it_IT_duplicated.yml +++ b/testdata/v0/invalid/it_IT_duplicated.yml @@ -30,8 +30,6 @@ intendedAudience: countries: - IT - DE - unsupportedCountries: - - US description: en: diff --git a/testdata/v0/invalid/it_wrong_case.yml b/testdata/v0/invalid/it_wrong_case.yml index 859dda7..824c065 100644 --- a/testdata/v0/invalid/it_wrong_case.yml +++ b/testdata/v0/invalid/it_wrong_case.yml @@ -30,8 +30,6 @@ intendedAudience: countries: - IT - DE - unsupportedCountries: - - US description: en: diff --git a/testdata/v0/invalid/landingURL_invalid.yml b/testdata/v0/invalid/landingURL_invalid.yml index d73e47e..d9fefb2 100644 --- a/testdata/v0/invalid/landingURL_invalid.yml +++ b/testdata/v0/invalid/landingURL_invalid.yml @@ -32,8 +32,6 @@ intendedAudience: countries: - IT - DE - unsupportedCountries: - - US description: en: diff --git a/testdata/v0/invalid/landingURL_wrong_type.yml b/testdata/v0/invalid/landingURL_wrong_type.yml index d569bca..62ebb73 100644 --- a/testdata/v0/invalid/landingURL_wrong_type.yml +++ b/testdata/v0/invalid/landingURL_wrong_type.yml @@ -32,8 +32,6 @@ intendedAudience: countries: - IT - DE - unsupportedCountries: - - US description: en: diff --git a/testdata/v0/invalid/no-network/landingURL_invalid.yml b/testdata/v0/invalid/no-network/landingURL_invalid.yml index 7a907ea..ec560cf 100644 --- a/testdata/v0/invalid/no-network/landingURL_invalid.yml +++ b/testdata/v0/invalid/no-network/landingURL_invalid.yml @@ -32,8 +32,6 @@ intendedAudience: countries: - IT - DE - unsupportedCountries: - - US description: en: diff --git a/testdata/v0/valid/countryExtensionVersion_1.0.yml b/testdata/v0/valid/countryExtensionVersion_1.0.yml index 589eb9b..f7402f4 100644 --- a/testdata/v0/valid/countryExtensionVersion_1.0.yml +++ b/testdata/v0/valid/countryExtensionVersion_1.0.yml @@ -26,8 +26,6 @@ intendedAudience: countries: - IT - DE - unsupportedCountries: - - US description: en: diff --git a/testdata/v0/valid/dependsOn.yml b/testdata/v0/valid/dependsOn.yml index 06069ed..5221883 100644 --- a/testdata/v0/valid/dependsOn.yml +++ b/testdata/v0/valid/dependsOn.yml @@ -27,8 +27,6 @@ intendedAudience: countries: - IT - DE - unsupportedCountries: # Explicitly unsupported countries - - US description: en: diff --git a/testdata/v0/valid/no-network/valid.yml b/testdata/v0/valid/no-network/valid.yml index 0173f16..795e603 100644 --- a/testdata/v0/valid/no-network/valid.yml +++ b/testdata/v0/valid/no-network/valid.yml @@ -131,8 +131,6 @@ intendedAudience: countries: - IT - DE - unsupportedCountries: - - US description: en: diff --git a/testdata/v0/valid/valid.yml b/testdata/v0/valid/valid.yml index 0b65a3e..97a4b45 100644 --- a/testdata/v0/valid/valid.yml +++ b/testdata/v0/valid/valid.yml @@ -134,8 +134,6 @@ intendedAudience: countries: - IT - DE - unsupportedCountries: - - US description: en: diff --git a/testdata/v0/valid/valid_no_it_conforme.yml b/testdata/v0/valid/valid_no_it_conforme.yml index 2cfcb44..60a415e 100644 --- a/testdata/v0/valid/valid_no_it_conforme.yml +++ b/testdata/v0/valid/valid_no_it_conforme.yml @@ -26,8 +26,6 @@ intendedAudience: countries: - IT - DE - unsupportedCountries: - - US description: en: diff --git a/testdata/v0/valid/valid_with_country_specific_section_uppercase.yml b/testdata/v0/valid/valid_with_country_specific_section_uppercase.yml index d039696..4d6f9df 100644 --- a/testdata/v0/valid/valid_with_country_specific_section_uppercase.yml +++ b/testdata/v0/valid/valid_with_country_specific_section_uppercase.yml @@ -26,8 +26,6 @@ intendedAudience: countries: - IT - DE - unsupportedCountries: - - US description: en: diff --git a/testdata/v0/valid_with_warnings/no-network/authorsFile.yml b/testdata/v0/valid_with_warnings/no-network/authorsFile.yml index d0998cf..fbfc5b6 100644 --- a/testdata/v0/valid_with_warnings/no-network/authorsFile.yml +++ b/testdata/v0/valid_with_warnings/no-network/authorsFile.yml @@ -27,8 +27,6 @@ intendedAudience: countries: - IT - DE - unsupportedCountries: # Explicitly unsupported countries - - US description: en: diff --git a/testdata/v0/valid_with_warnings/valid_with_IT_riuso_codiceIPA.yml b/testdata/v0/valid_with_warnings/valid_with_IT_riuso_codiceIPA.yml index 1681752..cb8e01a 100644 --- a/testdata/v0/valid_with_warnings/valid_with_IT_riuso_codiceIPA.yml +++ b/testdata/v0/valid_with_warnings/valid_with_IT_riuso_codiceIPA.yml @@ -25,8 +25,6 @@ intendedAudience: countries: - IT - DE - unsupportedCountries: - - US description: en: diff --git a/testdata/v0/valid_with_warnings/valid_with_country_specific_section_downcase.yml b/testdata/v0/valid_with_warnings/valid_with_country_specific_section_downcase.yml index fb7ce32..cff7688 100644 --- a/testdata/v0/valid_with_warnings/valid_with_country_specific_section_downcase.yml +++ b/testdata/v0/valid_with_warnings/valid_with_country_specific_section_downcase.yml @@ -26,8 +26,6 @@ intendedAudience: countries: - IT - DE - unsupportedCountries: - - US description: en: diff --git a/testdata/v0/valid_with_warnings/valid_with_it_conforme.yml b/testdata/v0/valid_with_warnings/valid_with_it_conforme.yml index 7d8183d..378ebd7 100644 --- a/testdata/v0/valid_with_warnings/valid_with_it_conforme.yml +++ b/testdata/v0/valid_with_warnings/valid_with_it_conforme.yml @@ -25,8 +25,6 @@ intendedAudience: countries: - IT - DE - unsupportedCountries: - - US description: en: diff --git a/testdata/v0/valid_with_warnings/valid_with_legal_repoOwner.yml b/testdata/v0/valid_with_warnings/valid_with_legal_repoOwner.yml index d73553e..815b746 100644 --- a/testdata/v0/valid_with_warnings/valid_with_legal_repoOwner.yml +++ b/testdata/v0/valid_with_warnings/valid_with_legal_repoOwner.yml @@ -25,8 +25,6 @@ intendedAudience: countries: - IT - DE - unsupportedCountries: - - US description: en: diff --git a/testdata/v0/valid_with_warnings/valid_with_unsupportedCountries.yml b/testdata/v0/valid_with_warnings/valid_with_unsupportedCountries.yml new file mode 100644 index 0000000..1573457 --- /dev/null +++ b/testdata/v0/valid_with_warnings/valid_with_unsupportedCountries.yml @@ -0,0 +1,56 @@ +publiccodeYmlVersion: "0" + +name: Medusa +url: "https://github.com/italia/developers.italia.it.git" + +platforms: + - web + +categories: + - cloud-management + +developmentStatus: development + +softwareType: "standalone/other" + +intendedAudience: + countries: + - IT + unsupportedCountries: + - US + +description: + en-GB: + localisedName: Medusa + shortDescription: > + A rather short description which + is probably useless + longDescription: > + Very long description of this software, also split + on multiple rows. You should note what the software + is and why one should need it. This is 158 characters. + Very long description of this software, also split + on multiple rows. You should note what the software + is and why one should need it. This is 316 characters. + Very long description of this software, also split + on multiple rows. You should note what the software + is and why one should need it. This is 474 characters. + Very long description of this software, also split + on multiple rows. You should note what the software + is and why one should need it. This is 632 characters. + features: + - Just one feature + +legal: + license: AGPL-3.0-or-later + +maintenance: + type: "community" + + contacts: + - name: Francesco Rossi + +localisation: + localisationReady: true + availableLanguages: + - en diff --git a/v0_test.go b/v0_test.go index 66fd9c9..06f979f 100644 --- a/v0_test.go +++ b/v0_test.go @@ -15,7 +15,7 @@ func TestValidTestcasesV0_NoNetwork(t *testing.T) { func TestValidWithWarningTestcasesV0_NoNetwork(t *testing.T) { expected := map[string]error{ "authorsFile.yml": ValidationResults{ - ValidationWarning{"", "legal.authorsFile", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 65, 3}, + ValidationWarning{"", "legal.authorsFile", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 63, 3}, }, } @@ -52,9 +52,9 @@ func TestInvalidTestcasesV0_NoNetwork(t *testing.T) { "landingURL_invalid.yml": ValidationResults{ // Just a syntax check here, no check for reachability as network is disabled ValidationError{"", "landingURL", "landingURL must be an HTTP URL", 8, 1}, - ValidationWarning{"", "dependsOn.open", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 104, 3}, + ValidationWarning{"", "dependsOn.open", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 102, 3}, ValidationWarning{"", "usedBy", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 21, 1}, - ValidationWarning{"", "description.en.videos", "This key is DEPRECATED and will be removed in the future. Link videos from the documentation or the website instead", 64, 5}, + ValidationWarning{"", "description.en.videos", "This key is DEPRECATED and will be removed in the future. Link videos from the documentation or the website instead", 62, 5}, }, // monochromeLogo @@ -154,15 +154,15 @@ func TestInvalidTestcasesV0(t *testing.T) { // landingURL "landingURL_wrong_type.yml": ValidationResults{ ValidationError{"", "landingURL", "wrong type for this field", 8, 1}, - ValidationWarning{"", "dependsOn.open", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 100, 3}, + ValidationWarning{"", "dependsOn.open", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 98, 3}, ValidationWarning{"", "usedBy", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 21, 1}, }, "landingURL_invalid.yml": ValidationResults{ ValidationError{"", "landingURL", "landingURL must be an HTTP URL", 8, 1}, ValidationError{"", "landingURL", "'???' not reachable: missing URL scheme", 8, 1}, - ValidationWarning{"", "dependsOn.open", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 104, 3}, + ValidationWarning{"", "dependsOn.open", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 102, 3}, ValidationWarning{"", "usedBy", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 21, 1}, - ValidationWarning{"", "description.en.videos", "This key is DEPRECATED and will be removed in the future. Link videos from the documentation or the website instead", 64, 5}, + ValidationWarning{"", "description.en.videos", "This key is DEPRECATED and will be removed in the future. Link videos from the documentation or the website instead", 62, 5}, }, // isBasedOn @@ -355,6 +355,7 @@ func TestInvalidTestcasesV0(t *testing.T) { }, "intendedAudience_unsupportedCountries_invalid_country.yml": ValidationResults{ ValidationError{"", "intendedAudience.unsupportedCountries[0]", "unsupportedCountries[0] must be a valid ISO 3166-1 alpha-2 two-letter country code", 20, 7}, + ValidationWarning{"", "intendedAudience.unsupportedCountries", "This key is DEPRECATED and will be removed in the future. Use 'intendedAudience.countries' to list the targeted countries instead", 18, 3}, }, "intendedAudience_unsupportedCountries_wrong_type.yml": ValidationResults{ ValidationError{"", "intendedAudience.unsupportedCountries", "wrong type for this field", 19, 1}, @@ -559,17 +560,17 @@ func TestInvalidTestcasesV0(t *testing.T) { ValidationError{"", "IT.riuso.codiceIPA", "codiceIPA must be a valid Italian Public Administration Code (iPA) (see https://github.com/publiccodeyml/italian-organizations-ipa-vocabulary)", 55, 5}, }, "it_IT_duplicated.yml": ValidationResults{ - ValidationWarning{"", "dependsOn.open", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 87, 3}, + ValidationWarning{"", "dependsOn.open", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 85, 3}, ValidationWarning{"", "usedBy", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 19, 1}, - ValidationWarning{"", "description.en.videos", "This key is DEPRECATED and will be removed in the future. Link videos from the documentation or the website instead", 62, 5}, - ValidationWarning{"", "it", "Lowercase country codes are DEPRECATED and will be removed in the future. Use 'IT' instead", 116, 1}, - ValidationError{"", "it", "'IT' key already present. Remove this key", 116, 1}, + ValidationWarning{"", "description.en.videos", "This key is DEPRECATED and will be removed in the future. Link videos from the documentation or the website instead", 60, 5}, + ValidationWarning{"", "it", "Lowercase country codes are DEPRECATED and will be removed in the future. Use 'IT' instead", 114, 1}, + ValidationError{"", "it", "'IT' key already present. Remove this key", 114, 1}, }, "it_wrong_case.yml": ValidationResults{ - ValidationError{"", "It", "unknown field \"It\"", 107, 1}, - ValidationWarning{"", "dependsOn.open", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 87, 3}, + ValidationError{"", "It", "unknown field \"It\"", 105, 1}, + ValidationWarning{"", "dependsOn.open", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 85, 3}, ValidationWarning{"", "usedBy", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 19, 1}, - ValidationWarning{"", "description.en.videos", "This key is DEPRECATED and will be removed in the future. Link videos from the documentation or the website instead", 62, 5}, + ValidationWarning{"", "description.en.videos", "This key is DEPRECATED and will be removed in the future. Link videos from the documentation or the website instead", 60, 5}, }, "description_en_gb_invalid_bcp47.yml": ValidationResults{ ValidationError{"", "description", "description must be a valid BCP 47 language", 18, 1}, @@ -647,21 +648,25 @@ func TestValidWithWarningsTestcasesV0(t *testing.T) { ValidationWarning{"", "outputTypes", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 50, 1}, }, "valid_with_it_conforme.yml": ValidationResults{ - ValidationWarning{"", "IT.conforme", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 105, 3}, + ValidationWarning{"", "IT.conforme", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 103, 3}, }, "valid_with_country_specific_section_downcase.yml": ValidationResults{ - ValidationWarning{"", "it", "Lowercase country codes are DEPRECATED and will be removed in the future. Use 'IT' instead", 93, 1}, + ValidationWarning{"", "it", "Lowercase country codes are DEPRECATED and will be removed in the future. Use 'IT' instead", 91, 1}, }, "valid_with_lowercase_countries.yml": ValidationResults{ ValidationWarning{"", "intendedAudience.countries[0]", "Lowercase country codes are DEPRECATED. Use uppercase instead ('IT')", 27, 7}, ValidationWarning{"", "intendedAudience.countries[1]", "Lowercase country codes are DEPRECATED. Use uppercase instead ('DE')", 28, 7}, + ValidationWarning{"", "intendedAudience.unsupportedCountries", "This key is DEPRECATED and will be removed in the future. Use 'intendedAudience.countries' to list the targeted countries instead", 29, 3}, ValidationWarning{"", "intendedAudience.unsupportedCountries[0]", "Lowercase country codes are DEPRECATED. Use uppercase instead ('US')", 30, 7}, }, "valid_with_government_scope.yml": ValidationResults{ ValidationWarning{"", "intendedAudience.scope[1]", "The 'government' scope is DEPRECATED and will be removed in the future. It's safe to drop it", 19, 7}, }, + "valid_with_unsupportedCountries.yml": ValidationResults{ + ValidationWarning{"", "intendedAudience.unsupportedCountries", "This key is DEPRECATED and will be removed in the future. Use 'intendedAudience.countries' to list the targeted countries instead", 19, 3}, + }, "valid_with_legal_repoOwner.yml": ValidationResults{ - ValidationWarning{"", "legal.repoOwner", "This key is DEPRECATED and will be removed in the future. Use 'organisation.name' instead", 64, 3}, + ValidationWarning{"", "legal.repoOwner", "This key is DEPRECATED and will be removed in the future. Use 'organisation.name' instead", 62, 3}, }, "valid_with_usedBy.yml": ValidationResults{ ValidationWarning{"", "usedBy", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 12, 1}, @@ -673,7 +678,7 @@ func TestValidWithWarningsTestcasesV0(t *testing.T) { ValidationWarning{"", "description.en-GB.videos", "This key is DEPRECATED and will be removed in the future. Link videos from the documentation or the website instead", 37, 5}, }, "valid_with_IT_riuso_codiceIPA.yml": ValidationResults{ - ValidationWarning{"", "IT.riuso.codiceIPA", "This key is DEPRECATED and will be removed in the future. Use 'organisation.uri' and set it to 'urn:x-italian-pa:pcm' instead", 105, 5}, + ValidationWarning{"", "IT.riuso.codiceIPA", "This key is DEPRECATED and will be removed in the future. Use 'organisation.uri' and set it to 'urn:x-italian-pa:pcm' instead", 103, 5}, }, } @@ -704,6 +709,7 @@ func TestDecodeValueErrorsRemote(t *testing.T) { {"https://raw.githubusercontent.com/italia/publiccode-parser-go/389af926bcb5bcb723b56d8e390585f2d0f2c7e8/testdata/v0/valid_with_warnings/valid_with_lowercase_countries.yml", ValidationResults{ ValidationWarning{"", "intendedAudience.countries[0]", "Lowercase country codes are DEPRECATED. Use uppercase instead ('IT')", 31, 7}, ValidationWarning{"", "intendedAudience.countries[1]", "Lowercase country codes are DEPRECATED. Use uppercase instead ('DE')", 32, 7}, + ValidationWarning{"", "intendedAudience.unsupportedCountries", "This key is DEPRECATED and will be removed in the future. Use 'intendedAudience.countries' to list the targeted countries instead", 33, 3}, ValidationWarning{"", "intendedAudience.unsupportedCountries[0]", "Lowercase country codes are DEPRECATED. Use uppercase instead ('US')", 34, 7}, ValidationWarning{"", "dependsOn.open", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 102, 3}, ValidationWarning{"", "usedBy", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 18, 1}, From 52c0b25ff53bf5cc6a9b5320ebeda4fe04530f35 Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Sun, 18 Oct 2026 21:39:47 +0200 Subject: [PATCH 7/8] feat: add deprecation warning for the single string form of isBasedOn See publiccodeyml/publiccode.yml#357. --- parser.go | 37 +++++++++++++ testdata/v0/invalid/it_IT_duplicated.yml | 2 +- testdata/v0/invalid/it_wrong_case.yml | 2 +- testdata/v0/invalid/landingURL_invalid.yml | 2 +- testdata/v0/invalid/landingURL_wrong_type.yml | 2 +- .../invalid/no-network/landingURL_invalid.yml | 2 +- .../v0/valid/countryExtensionVersion_1.0.yml | 2 +- testdata/v0/valid/dependsOn.yml | 2 +- testdata/v0/valid/no-network/valid.yml | 2 +- testdata/v0/valid/valid.yml | 2 +- testdata/v0/valid/valid_no_it_conforme.yml | 2 +- ...ith_country_specific_section_uppercase.yml | 2 +- .../no-network/authorsFile.yml | 2 +- .../valid_with_IT_riuso_codiceIPA.yml | 2 +- ...with_country_specific_section_downcase.yml | 2 +- .../valid_with_isBasedOn_string.yml | 52 +++++++++++++++++++ .../valid_with_it_conforme.yml | 2 +- .../valid_with_legal_repoOwner.yml | 2 +- .../valid_with_lowercase_countries.yml | 2 +- v0_test.go | 5 ++ 20 files changed, 111 insertions(+), 17 deletions(-) create mode 100644 testdata/v0/valid_with_warnings/valid_with_isBasedOn_string.yml diff --git a/parser.go b/parser.go index dd669af..bba7191 100644 --- a/parser.go +++ b/parser.go @@ -363,6 +363,19 @@ func (p *Parser) parseAndValidate(in io.Reader, fileURL *url.URL) (PublicCode, e validateFields = validateFieldsV0 decodeResults = decode(b, v0, file) + + if isBasedOnIsString(file) { + line, column := getPositionInFile("isBasedOn", file) + + ve = append(ve, ValidationWarning{ + Key: "isBasedOn", + Description: "The single string form is DEPRECATED and will be removed in the future. " + + "Use a one element array instead", + Line: line, + Column: column, + }) + } + publiccode = v0 } else { v1 := &PublicCodeV1{} @@ -523,6 +536,30 @@ func getPositionInFile(key string, file *ast.File) (int, int) { return line, col } +// isBasedOnIsString reports whether the top level isBasedOn is a single +// string. It has to look at the AST because UrlOrUrlArray folds both forms +// into a slice, losing which one was used. +func isBasedOnIsString(file *ast.File) bool { + if len(file.Docs) == 0 { + return false + } + + root, ok := file.Docs[0].Body.(*ast.MappingNode) + if !ok { + return false + } + + for _, mv := range root.Values { + if tok := mv.Key.GetToken(); tok != nil && tok.Value == "isBasedOn" { + _, isString := mv.Value.(*ast.StringNode) + + return isString + } + } + + return false +} + // splitKeyParts splits a dot-separated key path into parts, preserving array // indices. Eg. "a.b[0].c" -> ["a", "b[0]", "c"]. func splitKeyParts(key string) []string { diff --git a/testdata/v0/invalid/it_IT_duplicated.yml b/testdata/v0/invalid/it_IT_duplicated.yml index e941abf..1932cdb 100644 --- a/testdata/v0/invalid/it_IT_duplicated.yml +++ b/testdata/v0/invalid/it_IT_duplicated.yml @@ -5,7 +5,7 @@ applicationSuite: MegaProductivitySuite url: "https://github.com/italia/developers.italia.it.git" landingURL: "https://developers.italia.it" -isBasedOn: "https://github.com/italia/developers.italia.it.git" +isBasedOn: ["https://github.com/italia/developers.italia.it.git"] softwareVersion: "1.0" releaseDate: 2017-04-15 diff --git a/testdata/v0/invalid/it_wrong_case.yml b/testdata/v0/invalid/it_wrong_case.yml index 824c065..aa2da46 100644 --- a/testdata/v0/invalid/it_wrong_case.yml +++ b/testdata/v0/invalid/it_wrong_case.yml @@ -5,7 +5,7 @@ applicationSuite: MegaProductivitySuite url: "https://github.com/italia/developers.italia.it.git" landingURL: "https://developers.italia.it" -isBasedOn: "https://github.com/italia/developers.italia.it.git" +isBasedOn: ["https://github.com/italia/developers.italia.it.git"] softwareVersion: "1.0" releaseDate: 2017-04-15 diff --git a/testdata/v0/invalid/landingURL_invalid.yml b/testdata/v0/invalid/landingURL_invalid.yml index d9fefb2..012e66b 100644 --- a/testdata/v0/invalid/landingURL_invalid.yml +++ b/testdata/v0/invalid/landingURL_invalid.yml @@ -7,7 +7,7 @@ url: "https://github.com/italia/developers.italia.it.git" # Should not validate: landingURL must be a valid URL landingURL: "???" -isBasedOn: "https://github.com/italia/developers.italia.it.git" +isBasedOn: ["https://github.com/italia/developers.italia.it.git"] softwareVersion: "1.0" releaseDate: 2017-04-15 diff --git a/testdata/v0/invalid/landingURL_wrong_type.yml b/testdata/v0/invalid/landingURL_wrong_type.yml index 62ebb73..9f6a702 100644 --- a/testdata/v0/invalid/landingURL_wrong_type.yml +++ b/testdata/v0/invalid/landingURL_wrong_type.yml @@ -7,7 +7,7 @@ url: "https://github.com/italia/developers.italia.it.git" # Should not validate: landingURL must be a string landingURL: [] -isBasedOn: "https://github.com/italia/developers.italia.it.git" +isBasedOn: ["https://github.com/italia/developers.italia.it.git"] softwareVersion: "1.0" releaseDate: 2017-04-15 diff --git a/testdata/v0/invalid/no-network/landingURL_invalid.yml b/testdata/v0/invalid/no-network/landingURL_invalid.yml index ec560cf..25732c7 100644 --- a/testdata/v0/invalid/no-network/landingURL_invalid.yml +++ b/testdata/v0/invalid/no-network/landingURL_invalid.yml @@ -7,7 +7,7 @@ url: "https://github.com/italia/developers.italia.it.git" # Should not validate: landingURL must be a valid URL landingURL: "???" -isBasedOn: "https://github.com/italia/developers.italia.it.git" +isBasedOn: ["https://github.com/italia/developers.italia.it.git"] softwareVersion: "1.0" releaseDate: 2017-04-15 diff --git a/testdata/v0/valid/countryExtensionVersion_1.0.yml b/testdata/v0/valid/countryExtensionVersion_1.0.yml index f7402f4..2e6b8df 100644 --- a/testdata/v0/valid/countryExtensionVersion_1.0.yml +++ b/testdata/v0/valid/countryExtensionVersion_1.0.yml @@ -5,7 +5,7 @@ applicationSuite: MegaProductivitySuite url: "https://github.com/italia/developers.italia.it.git" landingURL: "https://developers.italia.it" -isBasedOn: "https://github.com/italia/developers.italia.it.git" +isBasedOn: ["https://github.com/italia/developers.italia.it.git"] softwareVersion: "1.0" releaseDate: 2017-04-15 diff --git a/testdata/v0/valid/dependsOn.yml b/testdata/v0/valid/dependsOn.yml index 5221883..3e1f74a 100644 --- a/testdata/v0/valid/dependsOn.yml +++ b/testdata/v0/valid/dependsOn.yml @@ -5,7 +5,7 @@ applicationSuite: MegaProductivitySuite url: "https://github.com/italia/developers.italia.it.git" # URL of this repository landingURL: "https://developers.italia.it" -isBasedOn: "https://github.com/italia/developers.italia.it.git" # The original repository, "Otello" +isBasedOn: ["https://github.com/italia/developers.italia.it.git"] # The original repository, "Otello" softwareVersion: "1.0" # Last stable version releaseDate: 2017-04-15 # Date of last stable software release # monochromeLogo: assets/icons/dt-logo.svg diff --git a/testdata/v0/valid/no-network/valid.yml b/testdata/v0/valid/no-network/valid.yml index 795e603..467adea 100644 --- a/testdata/v0/valid/no-network/valid.yml +++ b/testdata/v0/valid/no-network/valid.yml @@ -8,7 +8,7 @@ applicationSuite: MegaProductivitySuite url: "https://github.com/italia/developers.italia.it.git" landingURL: "https://developers.italia.it" -isBasedOn: "https://github.com/italia/developers.italia.it.git" +isBasedOn: ["https://github.com/italia/developers.italia.it.git"] softwareVersion: "1.0" releaseDate: 2017-04-15 logo: assets/img/logo.png diff --git a/testdata/v0/valid/valid.yml b/testdata/v0/valid/valid.yml index 97a4b45..6a33b2c 100644 --- a/testdata/v0/valid/valid.yml +++ b/testdata/v0/valid/valid.yml @@ -8,7 +8,7 @@ applicationSuite: MegaProductivitySuite url: "https://github.com/italia/developers.italia.it.git" landingURL: "https://developers.italia.it" -isBasedOn: "https://github.com/italia/developers.italia.it.git" +isBasedOn: ["https://github.com/italia/developers.italia.it.git"] softwareVersion: "1.0" releaseDate: 2017-04-15 diff --git a/testdata/v0/valid/valid_no_it_conforme.yml b/testdata/v0/valid/valid_no_it_conforme.yml index 60a415e..398d2e3 100644 --- a/testdata/v0/valid/valid_no_it_conforme.yml +++ b/testdata/v0/valid/valid_no_it_conforme.yml @@ -5,7 +5,7 @@ applicationSuite: MegaProductivitySuite url: "https://github.com/italia/developers.italia.it.git" landingURL: "https://developers.italia.it" -isBasedOn: "https://github.com/italia/developers.italia.it.git" +isBasedOn: ["https://github.com/italia/developers.italia.it.git"] softwareVersion: "1.0" releaseDate: 2017-04-15 diff --git a/testdata/v0/valid/valid_with_country_specific_section_uppercase.yml b/testdata/v0/valid/valid_with_country_specific_section_uppercase.yml index 4d6f9df..7141d04 100644 --- a/testdata/v0/valid/valid_with_country_specific_section_uppercase.yml +++ b/testdata/v0/valid/valid_with_country_specific_section_uppercase.yml @@ -5,7 +5,7 @@ applicationSuite: MegaProductivitySuite url: "https://github.com/italia/developers.italia.it.git" landingURL: "https://developers.italia.it" -isBasedOn: "https://github.com/italia/developers.italia.it.git" +isBasedOn: ["https://github.com/italia/developers.italia.it.git"] softwareVersion: "1.0" releaseDate: 2017-04-15 diff --git a/testdata/v0/valid_with_warnings/no-network/authorsFile.yml b/testdata/v0/valid_with_warnings/no-network/authorsFile.yml index fbfc5b6..e2e638a 100644 --- a/testdata/v0/valid_with_warnings/no-network/authorsFile.yml +++ b/testdata/v0/valid_with_warnings/no-network/authorsFile.yml @@ -5,7 +5,7 @@ applicationSuite: MegaProductivitySuite url: "https://github.com/italia/developers.italia.it.git" # URL of this repository landingURL: "https://developers.italia.it" -isBasedOn: "https://github.com/italia/developers.italia.it.git" # The original repository, "Otello" +isBasedOn: ["https://github.com/italia/developers.italia.it.git"] # The original repository, "Otello" softwareVersion: "1.0" # Last stable version releaseDate: 2017-04-15 # Date of last stable software release # monochromeLogo: assets/icons/dt-logo.svg diff --git a/testdata/v0/valid_with_warnings/valid_with_IT_riuso_codiceIPA.yml b/testdata/v0/valid_with_warnings/valid_with_IT_riuso_codiceIPA.yml index cb8e01a..f39dcfa 100644 --- a/testdata/v0/valid_with_warnings/valid_with_IT_riuso_codiceIPA.yml +++ b/testdata/v0/valid_with_warnings/valid_with_IT_riuso_codiceIPA.yml @@ -4,7 +4,7 @@ name: Medusa applicationSuite: MegaProductivitySuite url: "https://github.com/italia/developers.italia.it.git" -isBasedOn: "https://github.com/italia/developers.italia.it.git" +isBasedOn: ["https://github.com/italia/developers.italia.it.git"] softwareVersion: "1.0" releaseDate: 2017-04-15 diff --git a/testdata/v0/valid_with_warnings/valid_with_country_specific_section_downcase.yml b/testdata/v0/valid_with_warnings/valid_with_country_specific_section_downcase.yml index cff7688..401deb8 100644 --- a/testdata/v0/valid_with_warnings/valid_with_country_specific_section_downcase.yml +++ b/testdata/v0/valid_with_warnings/valid_with_country_specific_section_downcase.yml @@ -5,7 +5,7 @@ applicationSuite: MegaProductivitySuite url: "https://github.com/italia/developers.italia.it.git" landingURL: "https://developers.italia.it" -isBasedOn: "https://github.com/italia/developers.italia.it.git" +isBasedOn: ["https://github.com/italia/developers.italia.it.git"] softwareVersion: "1.0" releaseDate: 2017-04-15 diff --git a/testdata/v0/valid_with_warnings/valid_with_isBasedOn_string.yml b/testdata/v0/valid_with_warnings/valid_with_isBasedOn_string.yml new file mode 100644 index 0000000..2bd1474 --- /dev/null +++ b/testdata/v0/valid_with_warnings/valid_with_isBasedOn_string.yml @@ -0,0 +1,52 @@ +publiccodeYmlVersion: "0" + +name: Medusa +url: "https://github.com/italia/developers.italia.it.git" + +isBasedOn: "https://github.com/italia/developers.italia.it.git" + +platforms: + - web + +categories: + - cloud-management + +developmentStatus: development + +softwareType: "standalone/other" + +description: + en-GB: + localisedName: Medusa + shortDescription: > + A rather short description which + is probably useless + longDescription: > + Very long description of this software, also split + on multiple rows. You should note what the software + is and why one should need it. This is 158 characters. + Very long description of this software, also split + on multiple rows. You should note what the software + is and why one should need it. This is 316 characters. + Very long description of this software, also split + on multiple rows. You should note what the software + is and why one should need it. This is 474 characters. + Very long description of this software, also split + on multiple rows. You should note what the software + is and why one should need it. This is 632 characters. + features: + - Just one feature + +legal: + license: AGPL-3.0-or-later + +maintenance: + type: "community" + + contacts: + - name: Francesco Rossi + +localisation: + localisationReady: true + availableLanguages: + - en diff --git a/testdata/v0/valid_with_warnings/valid_with_it_conforme.yml b/testdata/v0/valid_with_warnings/valid_with_it_conforme.yml index 378ebd7..94b321e 100644 --- a/testdata/v0/valid_with_warnings/valid_with_it_conforme.yml +++ b/testdata/v0/valid_with_warnings/valid_with_it_conforme.yml @@ -4,7 +4,7 @@ name: Medusa applicationSuite: MegaProductivitySuite url: "https://github.com/italia/developers.italia.it.git" -isBasedOn: "https://github.com/italia/developers.italia.it.git" +isBasedOn: ["https://github.com/italia/developers.italia.it.git"] softwareVersion: "1.0" releaseDate: 2017-04-15 diff --git a/testdata/v0/valid_with_warnings/valid_with_legal_repoOwner.yml b/testdata/v0/valid_with_warnings/valid_with_legal_repoOwner.yml index 815b746..c928fd6 100644 --- a/testdata/v0/valid_with_warnings/valid_with_legal_repoOwner.yml +++ b/testdata/v0/valid_with_warnings/valid_with_legal_repoOwner.yml @@ -4,7 +4,7 @@ name: Medusa applicationSuite: MegaProductivitySuite url: "https://github.com/italia/developers.italia.it.git" -isBasedOn: "https://github.com/italia/developers.italia.it.git" +isBasedOn: ["https://github.com/italia/developers.italia.it.git"] softwareVersion: "1.0" releaseDate: 2017-04-15 diff --git a/testdata/v0/valid_with_warnings/valid_with_lowercase_countries.yml b/testdata/v0/valid_with_warnings/valid_with_lowercase_countries.yml index fd64ddc..162d12d 100644 --- a/testdata/v0/valid_with_warnings/valid_with_lowercase_countries.yml +++ b/testdata/v0/valid_with_warnings/valid_with_lowercase_countries.yml @@ -4,7 +4,7 @@ name: Medusa applicationSuite: MegaProductivitySuite url: "https://github.com/italia/developers.italia.it.git" -isBasedOn: "https://github.com/italia/developers.italia.it.git" +isBasedOn: ["https://github.com/italia/developers.italia.it.git"] softwareVersion: "1.0" releaseDate: 2017-04-15 diff --git a/v0_test.go b/v0_test.go index 06f979f..3b11808 100644 --- a/v0_test.go +++ b/v0_test.go @@ -173,6 +173,7 @@ func TestInvalidTestcasesV0(t *testing.T) { ValidationError{"", "isBasedOn[1]", "isBasedOn[1] must be a valid URL", 11, 5}, }, "isBasedOn_bad_url_string.yml": ValidationResults{ + ValidationWarning{"", "isBasedOn", "The single string form is DEPRECATED and will be removed in the future. Use a one element array instead", 9, 1}, ValidationError{"", "isBasedOn[0]", "isBasedOn[0] must be a valid URL", 9, 1}, }, @@ -665,6 +666,9 @@ func TestValidWithWarningsTestcasesV0(t *testing.T) { "valid_with_unsupportedCountries.yml": ValidationResults{ ValidationWarning{"", "intendedAudience.unsupportedCountries", "This key is DEPRECATED and will be removed in the future. Use 'intendedAudience.countries' to list the targeted countries instead", 19, 3}, }, + "valid_with_isBasedOn_string.yml": ValidationResults{ + ValidationWarning{"", "isBasedOn", "The single string form is DEPRECATED and will be removed in the future. Use a one element array instead", 6, 1}, + }, "valid_with_legal_repoOwner.yml": ValidationResults{ ValidationWarning{"", "legal.repoOwner", "This key is DEPRECATED and will be removed in the future. Use 'organisation.name' instead", 62, 3}, }, @@ -707,6 +711,7 @@ func TestDecodeValueErrorsRemote(t *testing.T) { // Pinned to a commit: fetching from main means a testdata change // breaks this test in every PR until the change itself lands. {"https://raw.githubusercontent.com/italia/publiccode-parser-go/389af926bcb5bcb723b56d8e390585f2d0f2c7e8/testdata/v0/valid_with_warnings/valid_with_lowercase_countries.yml", ValidationResults{ + ValidationWarning{"", "isBasedOn", "The single string form is DEPRECATED and will be removed in the future. Use a one element array instead", 7, 1}, ValidationWarning{"", "intendedAudience.countries[0]", "Lowercase country codes are DEPRECATED. Use uppercase instead ('IT')", 31, 7}, ValidationWarning{"", "intendedAudience.countries[1]", "Lowercase country codes are DEPRECATED. Use uppercase instead ('DE')", 32, 7}, ValidationWarning{"", "intendedAudience.unsupportedCountries", "This key is DEPRECATED and will be removed in the future. Use 'intendedAudience.countries' to list the targeted countries instead", 33, 3}, From 8f6cdd09926a961217906e848e4ce49c04ec4893 Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Sun, 18 Oct 2026 21:44:33 +0200 Subject: [PATCH 8/8] feat: warn when a contact phone number is not in E.164 format See publiccodeyml/publiccode.yml#348. --- fields.go | 15 ++++++ testdata/v0/invalid/landingURL_invalid.yml | 6 +-- testdata/v0/invalid/landingURL_wrong_type.yml | 6 +-- .../invalid/no-network/landingURL_invalid.yml | 6 +-- testdata/v0/valid/no-network/valid.yml | 6 +-- testdata/v0/valid/valid.yml | 6 +-- .../maintenance_contacts_phone_not_e164.yml | 51 +++++++++++++++++++ .../valid_with_IT_riuso_codiceIPA.yml | 6 +-- .../valid_with_it_conforme.yml | 6 +-- .../valid_with_legal_repoOwner.yml | 6 +-- .../valid_with_lowercase_countries.yml | 6 +-- v0_test.go | 6 +++ 12 files changed, 99 insertions(+), 27 deletions(-) create mode 100644 testdata/v0/valid_with_warnings/maintenance_contacts_phone_not_e164.yml diff --git a/fields.go b/fields.go index 416df6c..4dc8d6a 100644 --- a/fields.go +++ b/fields.go @@ -129,6 +129,21 @@ func validateFieldsV0(publiccode PublicCode, parser *Parser, network bool, baseU } } + if publiccodev0.Maintenance.Contacts != nil { + for i, contact := range *publiccodev0.Maintenance.Contacts { + if contact.Phone == nil || *contact.Phone == "" { + continue + } + + if sharedValidate.Var(*contact.Phone, "e164") != nil { + vr = append(vr, newValidationWarning( + fmt.Sprintf("maintenance.contacts[%d].phone", i), + "Phone numbers SHOULD use the E.164 format, e.g. '+3923113215112'", + )) + } + } + } + if publiccodev0.Legal.AuthorsFile != nil { vr = append(vr, newValidationWarning( "legal.authorsFile", diff --git a/testdata/v0/invalid/landingURL_invalid.yml b/testdata/v0/invalid/landingURL_invalid.yml index 012e66b..9c49213 100644 --- a/testdata/v0/invalid/landingURL_invalid.yml +++ b/testdata/v0/invalid/landingURL_invalid.yml @@ -80,15 +80,15 @@ maintenance: - name: Francesco Rossi email: "francesco.rossi@comune.reggioemilia.it" affiliation: Comune di Reggio Emilia - phone: +39 231 13215112 + phone: +3923113215112 - name: Dario Bianchi email: "dario.bianchi@fornitore.it" affiliation: Fornitore Privato S.P.A. - phone: +39 16 24231322 + phone: +391624231322 - name: Giancarlo Verdi email: "dario.bianchi@fornitore.it" affiliation: Fornitore Privato S.P.A. - phone: +39 16 24231322 + phone: +391624231322 localisation: localisationReady: true diff --git a/testdata/v0/invalid/landingURL_wrong_type.yml b/testdata/v0/invalid/landingURL_wrong_type.yml index 9f6a702..36394a3 100644 --- a/testdata/v0/invalid/landingURL_wrong_type.yml +++ b/testdata/v0/invalid/landingURL_wrong_type.yml @@ -76,15 +76,15 @@ maintenance: - name: Francesco Rossi email: "francesco.rossi@comune.reggioemilia.it" affiliation: Comune di Reggio Emilia - phone: +39 231 13215112 + phone: +3923113215112 - name: Dario Bianchi email: "dario.bianchi@fornitore.it" affiliation: Fornitore Privato S.P.A. - phone: +39 16 24231322 + phone: +391624231322 - name: Giancarlo Verdi email: "dario.bianchi@fornitore.it" affiliation: Fornitore Privato S.P.A. - phone: +39 16 24231322 + phone: +391624231322 localisation: localisationReady: true diff --git a/testdata/v0/invalid/no-network/landingURL_invalid.yml b/testdata/v0/invalid/no-network/landingURL_invalid.yml index 25732c7..9c2f27a 100644 --- a/testdata/v0/invalid/no-network/landingURL_invalid.yml +++ b/testdata/v0/invalid/no-network/landingURL_invalid.yml @@ -80,15 +80,15 @@ maintenance: - name: Francesco Rossi email: "francesco.rossi@comune.reggioemilia.it" affiliation: Comune di Reggio Emilia - phone: +39 231 13215112 + phone: +3923113215112 - name: Dario Bianchi email: "dario.bianchi@fornitore.it" affiliation: Fornitore Privato S.P.A. - phone: +39 16 24231322 + phone: +391624231322 - name: Giancarlo Verdi email: "dario.bianchi@fornitore.it" affiliation: Fornitore Privato S.P.A. - phone: +39 16 24231322 + phone: +391624231322 localisation: localisationReady: true diff --git a/testdata/v0/valid/no-network/valid.yml b/testdata/v0/valid/no-network/valid.yml index 467adea..bd5a931 100644 --- a/testdata/v0/valid/no-network/valid.yml +++ b/testdata/v0/valid/no-network/valid.yml @@ -181,15 +181,15 @@ maintenance: - name: Francesco Rossi email: "francesco.rossi@example.org" affiliation: Comune di Reggio Emilia - phone: +39 231 13215112 + phone: +3923113215112 - name: Dario Bianchi email: "dario.bianchi@example.org" affiliation: Fornitore Privato S.P.A. - phone: +39 16 24231322 + phone: +391624231322 - name: Giancarlo Verdi email: "dario.bianchi@example.org" affiliation: Fornitore Privato S.P.A. - phone: +39 16 24231322 + phone: +391624231322 localisation: localisationReady: true diff --git a/testdata/v0/valid/valid.yml b/testdata/v0/valid/valid.yml index 6a33b2c..d210bb6 100644 --- a/testdata/v0/valid/valid.yml +++ b/testdata/v0/valid/valid.yml @@ -184,15 +184,15 @@ maintenance: - name: Francesco Rossi email: "francesco.rossi@example.org" affiliation: Comune di Reggio Emilia - phone: +39 231 13215112 + phone: +3923113215112 - name: Dario Bianchi email: "dario.bianchi@example.org" affiliation: Fornitore Privato S.P.A. - phone: +39 16 24231322 + phone: +391624231322 - name: Giancarlo Verdi email: "dario.bianchi@example.org" affiliation: Fornitore Privato S.P.A. - phone: +39 16 24231322 + phone: +391624231322 localisation: localisationReady: true diff --git a/testdata/v0/valid_with_warnings/maintenance_contacts_phone_not_e164.yml b/testdata/v0/valid_with_warnings/maintenance_contacts_phone_not_e164.yml new file mode 100644 index 0000000..700d048 --- /dev/null +++ b/testdata/v0/valid_with_warnings/maintenance_contacts_phone_not_e164.yml @@ -0,0 +1,51 @@ +publiccodeYmlVersion: "0" + +name: Medusa +url: "https://github.com/italia/developers.italia.it.git" + +platforms: + - web + +categories: + - cloud-management + +developmentStatus: development + +softwareType: "standalone/other" + +description: + en-GB: + localisedName: Medusa + shortDescription: > + A rather short description which + is probably useless + longDescription: > + Very long description of this software, also split + on multiple rows. You should note what the software + is and why one should need it. This is 158 characters. + Very long description of this software, also split + on multiple rows. You should note what the software + is and why one should need it. This is 316 characters. + Very long description of this software, also split + on multiple rows. You should note what the software + is and why one should need it. This is 474 characters. + Very long description of this software, also split + on multiple rows. You should note what the software + is and why one should need it. This is 632 characters. + features: + - Just one feature + +legal: + license: AGPL-3.0-or-later + +maintenance: + type: "community" + + contacts: + - name: Francesco Rossi + phone: "+39 231 13215112" + +localisation: + localisationReady: true + availableLanguages: + - en diff --git a/testdata/v0/valid_with_warnings/valid_with_IT_riuso_codiceIPA.yml b/testdata/v0/valid_with_warnings/valid_with_IT_riuso_codiceIPA.yml index f39dcfa..0127ffb 100644 --- a/testdata/v0/valid_with_warnings/valid_with_IT_riuso_codiceIPA.yml +++ b/testdata/v0/valid_with_warnings/valid_with_IT_riuso_codiceIPA.yml @@ -71,15 +71,15 @@ maintenance: - name: Francesco Rossi email: "francesco.rossi@comune.reggioemilia.it" affiliation: Comune di Reggio Emilia - phone: +39 231 13215112 + phone: +3923113215112 - name: Dario Bianchi email: "dario.bianchi@fornitore.it" affiliation: Fornitore Privato S.P.A. - phone: +39 16 24231322 + phone: +391624231322 - name: Giancarlo Verdi email: "dario.bianchi@fornitore.it" affiliation: Fornitore Privato S.P.A. - phone: +39 16 24231322 + phone: +391624231322 localisation: localisationReady: true diff --git a/testdata/v0/valid_with_warnings/valid_with_it_conforme.yml b/testdata/v0/valid_with_warnings/valid_with_it_conforme.yml index 94b321e..69d8d3b 100644 --- a/testdata/v0/valid_with_warnings/valid_with_it_conforme.yml +++ b/testdata/v0/valid_with_warnings/valid_with_it_conforme.yml @@ -71,15 +71,15 @@ maintenance: - name: Francesco Rossi email: "francesco.rossi@comune.reggioemilia.it" affiliation: Comune di Reggio Emilia - phone: +39 231 13215112 + phone: +3923113215112 - name: Dario Bianchi email: "dario.bianchi@fornitore.it" affiliation: Fornitore Privato S.P.A. - phone: +39 16 24231322 + phone: +391624231322 - name: Giancarlo Verdi email: "dario.bianchi@fornitore.it" affiliation: Fornitore Privato S.P.A. - phone: +39 16 24231322 + phone: +391624231322 localisation: localisationReady: true diff --git a/testdata/v0/valid_with_warnings/valid_with_legal_repoOwner.yml b/testdata/v0/valid_with_warnings/valid_with_legal_repoOwner.yml index c928fd6..9c5d839 100644 --- a/testdata/v0/valid_with_warnings/valid_with_legal_repoOwner.yml +++ b/testdata/v0/valid_with_warnings/valid_with_legal_repoOwner.yml @@ -73,15 +73,15 @@ maintenance: - name: Francesco Rossi email: "francesco.rossi@comune.reggioemilia.it" affiliation: Comune di Reggio Emilia - phone: +39 231 13215112 + phone: +3923113215112 - name: Dario Bianchi email: "dario.bianchi@fornitore.it" affiliation: Fornitore Privato S.P.A. - phone: +39 16 24231322 + phone: +391624231322 - name: Giancarlo Verdi email: "dario.bianchi@fornitore.it" affiliation: Fornitore Privato S.P.A. - phone: +39 16 24231322 + phone: +391624231322 localisation: localisationReady: true diff --git a/testdata/v0/valid_with_warnings/valid_with_lowercase_countries.yml b/testdata/v0/valid_with_warnings/valid_with_lowercase_countries.yml index 162d12d..6d8f858 100644 --- a/testdata/v0/valid_with_warnings/valid_with_lowercase_countries.yml +++ b/testdata/v0/valid_with_warnings/valid_with_lowercase_countries.yml @@ -74,15 +74,15 @@ maintenance: - name: Francesco Rossi email: "francesco.rossi@comune.reggioemilia.it" affiliation: Comune di Reggio Emilia - phone: +39 231 13215112 + phone: +3923113215112 - name: Dario Bianchi email: "dario.bianchi@fornitore.it" affiliation: Fornitore Privato S.P.A. - phone: +39 16 24231322 + phone: +391624231322 - name: Giancarlo Verdi email: "dario.bianchi@fornitore.it" affiliation: Fornitore Privato S.P.A. - phone: +39 16 24231322 + phone: +391624231322 localisation: localisationReady: true diff --git a/v0_test.go b/v0_test.go index 3b11808..d7e62b3 100644 --- a/v0_test.go +++ b/v0_test.go @@ -632,6 +632,9 @@ func TestValidWithWarningsTestcasesV0(t *testing.T) { "unicode_grapheme_clusters.yml": ValidationResults{ ValidationWarning{"", "description.en.genericName", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 23, 5}, }, + "maintenance_contacts_phone_not_e164.yml": ValidationResults{ + ValidationWarning{"", "maintenance.contacts[0].phone", "Phone numbers SHOULD use the E.164 format, e.g. '+3923113215112'", 46, 7}, + }, "valid.minimal.v0.2.yml": ValidationResults{ ValidationWarning{"", "publiccodeYmlVersion", "v0.2 is not the latest version, use '0'. Parsing this file as v0.8.", 1, 1}, }, @@ -716,6 +719,9 @@ func TestDecodeValueErrorsRemote(t *testing.T) { ValidationWarning{"", "intendedAudience.countries[1]", "Lowercase country codes are DEPRECATED. Use uppercase instead ('DE')", 32, 7}, ValidationWarning{"", "intendedAudience.unsupportedCountries", "This key is DEPRECATED and will be removed in the future. Use 'intendedAudience.countries' to list the targeted countries instead", 33, 3}, ValidationWarning{"", "intendedAudience.unsupportedCountries[0]", "Lowercase country codes are DEPRECATED. Use uppercase instead ('US')", 34, 7}, + ValidationWarning{"", "maintenance.contacts[0].phone", "Phone numbers SHOULD use the E.164 format, e.g. '+3923113215112'", 83, 7}, + ValidationWarning{"", "maintenance.contacts[1].phone", "Phone numbers SHOULD use the E.164 format, e.g. '+3923113215112'", 87, 7}, + ValidationWarning{"", "maintenance.contacts[2].phone", "Phone numbers SHOULD use the E.164 format, e.g. '+3923113215112'", 91, 7}, ValidationWarning{"", "dependsOn.open", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 102, 3}, ValidationWarning{"", "usedBy", "This key is DEPRECATED and will be removed in the future. It's safe to drop it", 18, 1}, ValidationWarning{"", "description.en.videos", "This key is DEPRECATED and will be removed in the future. Link videos from the documentation or the website instead", 62, 5},