Skip to content

Commit 86ae556

Browse files
committed
Restore normalization of library version metadata
When the code was switched to using Arduino Lint for release validation, the `metadata.Validate()` function was removed. At a closer look, it turns out that this function did normalization in addition to validation of the metadata. One such normalization was to convert the "relaxed semver" version format which is allowed to be used in Arduino Library metadata to be compliant with the standardized "semver" version specification, which is used in the Library Manager index. Here, the version normalization is restored. Rather than using bespoke code for this purpose as before, the `go.bug.st/relaxed-semver` package is used, as in Arduino CLI and Arduino Lint. This will provide consistency and reduce maintenance burden.
1 parent 2ee48e4 commit 86ae556

File tree

4 files changed

+176
-0
lines changed

4 files changed

+176
-0
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ require (
99
github.com/google/go-cmp v0.5.2 // indirect
1010
github.com/stretchr/testify v1.7.0
1111
github.com/vaughan0/go-ini v0.0.0-20130923145212-a98ad7ee00ec
12+
go.bug.st/relaxed-semver v0.0.0-20190922224835-391e10178d18
1213
)

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ github.com/vaughan0/go-ini v0.0.0-20130923145212-a98ad7ee00ec h1:DGmKwyZwEB8dI7t
7171
github.com/vaughan0/go-ini v0.0.0-20130923145212-a98ad7ee00ec/go.mod h1:owBmyHYMLkxyrugmfwE/DLJyW8Ro9mkphwuVErQ0iUw=
7272
github.com/xanzy/ssh-agent v0.3.0 h1:wUMzuKtKilRgBAD1sUb8gOwwRr2FGoBVumcjoOACClI=
7373
github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0=
74+
go.bug.st/relaxed-semver v0.0.0-20190922224835-391e10178d18 h1:F1qxtaFuewctYc/SsHRn+Q7Dtwi+yJGPgVq8YLtQz98=
75+
go.bug.st/relaxed-semver v0.0.0-20190922224835-391e10178d18/go.mod h1:Cx1VqMtEhE9pIkEyUj3LVVVPkv89dgW8aCKrRPDR/uE=
7476
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
7577
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w=
7678
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=

libraries/metadata/metadata.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import (
3939
"bytes"
4040

4141
ini "github.com/vaughan0/go-ini"
42+
semver "go.bug.st/relaxed-semver"
4243
)
4344

4445
// LibraryMetadata contains metadata for a library.properties file
@@ -88,5 +89,26 @@ func Parse(propertiesData []byte) (*LibraryMetadata, error) {
8889
Includes: get("includes"),
8990
Depends: get("depends"),
9091
}
92+
93+
library.normalize()
94+
9195
return library, nil
9296
}
97+
98+
// normalize normalizes library metadata.
99+
func (library *LibraryMetadata) normalize() {
100+
library.Version = normalizeVersion(library.Version)
101+
library.Category = normalizeCategory(library.Category)
102+
}
103+
104+
// normalizeVersion converts "relaxed semver" to semver-compliant versions.
105+
func normalizeVersion(version string) string {
106+
versionObject, err := semver.Parse(version)
107+
if err != nil {
108+
// Enforcement is handled by Arduino Lint.
109+
return version
110+
}
111+
112+
versionObject.Normalize()
113+
return versionObject.String()
114+
}

libraries/metadata/metadata_test.go

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
// This file is part of libraries-repository-engine.
2+
//
3+
// Copyright 2021 ARDUINO SA (http://www.arduino.cc/)
4+
//
5+
// This program is free software: you can redistribute it and/or modify
6+
// it under the terms of the GNU Affero General Public License as published
7+
// by the Free Software Foundation, either version 3 of the License, or
8+
// (at your option) any later version.
9+
//
10+
// This program is distributed in the hope that it will be useful,
11+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
// GNU Affero General Public License for more details.
14+
//
15+
// You should have received a copy of the GNU Affero General Public License
16+
// along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
//
18+
// You can be released from the requirements of the above licenses by purchasing
19+
// a commercial license. Buying such a license is mandatory if you want to
20+
// modify or otherwise use the software for commercial activities involving the
21+
// Arduino software without disclosing the source code of your own applications.
22+
// To purchase a commercial license, send an email to license@arduino.cc.
23+
24+
package metadata
25+
26+
import (
27+
"fmt"
28+
"testing"
29+
30+
"github.com/stretchr/testify/assert"
31+
)
32+
33+
func TestParse(t *testing.T) {
34+
testTables := []struct {
35+
testName string
36+
propertiesData []byte
37+
libraryMetadataAssertion *LibraryMetadata
38+
errorAssertion assert.ErrorAssertionFunc
39+
}{
40+
{
41+
testName: "Invalid",
42+
propertiesData: []byte(`broken`),
43+
libraryMetadataAssertion: nil,
44+
errorAssertion: assert.Error,
45+
},
46+
{
47+
testName: "Compliant",
48+
propertiesData: []byte(`
49+
name=WebServer
50+
version=1.0.0
51+
author=Cristian Maglie <c.maglie@example.com>, Pippo Pluto <pippo@example.com>
52+
maintainer=Cristian Maglie <c.maglie@example.com>
53+
sentence=A library that makes coding a Webserver a breeze.
54+
paragraph=Supports HTTP1.1 and you can do GET and POST.
55+
category=Communication
56+
url=http://example.com/
57+
architectures=avr
58+
includes=WebServer.h
59+
depends=ArduinoHttpClient
60+
`),
61+
libraryMetadataAssertion: &LibraryMetadata{
62+
Name: "WebServer",
63+
Version: "1.0.0",
64+
Author: "Cristian Maglie <c.maglie@example.com>, Pippo Pluto <pippo@example.com>",
65+
Maintainer: "Cristian Maglie <c.maglie@example.com>",
66+
License: "",
67+
Sentence: "A library that makes coding a Webserver a breeze.",
68+
Paragraph: "Supports HTTP1.1 and you can do GET and POST.",
69+
URL: "http://example.com/",
70+
Architectures: "avr",
71+
Category: "Communication",
72+
Types: nil,
73+
Includes: "WebServer.h",
74+
Depends: "ArduinoHttpClient",
75+
},
76+
errorAssertion: assert.NoError,
77+
},
78+
{
79+
testName: "Invalid version",
80+
propertiesData: []byte(`
81+
name=WebServer
82+
version=foo
83+
author=Cristian Maglie <c.maglie@example.com>, Pippo Pluto <pippo@example.com>
84+
maintainer=Cristian Maglie <c.maglie@example.com>
85+
sentence=A library that makes coding a Webserver a breeze.
86+
paragraph=Supports HTTP1.1 and you can do GET and POST.
87+
category=Communication
88+
url=http://example.com/
89+
architectures=avr
90+
includes=WebServer.h
91+
depends=ArduinoHttpClient
92+
`),
93+
libraryMetadataAssertion: &LibraryMetadata{
94+
Name: "WebServer",
95+
Version: "foo",
96+
Author: "Cristian Maglie <c.maglie@example.com>, Pippo Pluto <pippo@example.com>",
97+
Maintainer: "Cristian Maglie <c.maglie@example.com>",
98+
License: "",
99+
Sentence: "A library that makes coding a Webserver a breeze.",
100+
Paragraph: "Supports HTTP1.1 and you can do GET and POST.",
101+
URL: "http://example.com/",
102+
Architectures: "avr",
103+
Category: "Communication",
104+
Types: nil,
105+
Includes: "WebServer.h",
106+
Depends: "ArduinoHttpClient",
107+
},
108+
errorAssertion: assert.NoError,
109+
},
110+
{
111+
testName: "Non-semver version",
112+
propertiesData: []byte(`
113+
name=WebServer
114+
version=1.0
115+
author=Cristian Maglie <c.maglie@example.com>, Pippo Pluto <pippo@example.com>
116+
maintainer=Cristian Maglie <c.maglie@example.com>
117+
sentence=A library that makes coding a Webserver a breeze.
118+
paragraph=Supports HTTP1.1 and you can do GET and POST.
119+
category=Communication
120+
url=http://example.com/
121+
architectures=avr
122+
includes=WebServer.h
123+
depends=ArduinoHttpClient
124+
`),
125+
libraryMetadataAssertion: &LibraryMetadata{
126+
Name: "WebServer",
127+
Version: "1.0.0",
128+
Author: "Cristian Maglie <c.maglie@example.com>, Pippo Pluto <pippo@example.com>",
129+
Maintainer: "Cristian Maglie <c.maglie@example.com>",
130+
License: "",
131+
Sentence: "A library that makes coding a Webserver a breeze.",
132+
Paragraph: "Supports HTTP1.1 and you can do GET and POST.",
133+
URL: "http://example.com/",
134+
Architectures: "avr",
135+
Category: "Communication",
136+
Types: nil,
137+
Includes: "WebServer.h",
138+
Depends: "ArduinoHttpClient",
139+
},
140+
errorAssertion: assert.NoError,
141+
},
142+
}
143+
144+
for _, testTable := range testTables {
145+
metadata, err := Parse(testTable.propertiesData)
146+
testTable.errorAssertion(t, err, fmt.Sprintf("%s error", testTable.testName))
147+
if err == nil {
148+
assert.Equal(t, testTable.libraryMetadataAssertion, metadata, fmt.Sprintf("%s metadata", testTable.testName))
149+
}
150+
}
151+
}

0 commit comments

Comments
 (0)