Allow repo metadata files to use either .yaml or .yml (#729)

Signed-off-by: austin ce <austin.cawley@gmail.com>
This commit is contained in:
Austin Cawley-Edwards 2020-10-14 11:29:53 -04:00 committed by GitHub
parent d2919c736b
commit a951419e24
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 79 additions and 22 deletions

View File

@ -10,7 +10,7 @@ import (
const (
// RepositoryMetadataFile represents the name of the file where the
// Artifact Hub metadata for a given repository is stored.
RepositoryMetadataFile = "artifacthub-repo.yml"
RepositoryMetadataFile = "artifacthub-repo"
)
// RepositoryKind represents the kind of a given repository.

View File

@ -321,8 +321,38 @@ func (m *Manager) GetByName(ctx context.Context, name string) (*hub.Repository,
}
// GetMetadata reads and parses the repository metadata file provided, which
// can be a remote URL or a local file path.
// can be a remote URL or a local file path. The .yml and .yaml extensions will
// be implicitly appended to the given path.
func (m *Manager) GetMetadata(mdFile string) (*hub.RepositoryMetadata, error) {
var data []byte
var err error
for _, extension := range []string{".yml", ".yaml"} {
data, err = m.readMetadataFile(mdFile + extension)
if err == nil {
break
}
}
if err != nil {
return nil, err
}
var md *hub.RepositoryMetadata
if err = yaml.Unmarshal(data, &md); err != nil || md == nil {
return nil, fmt.Errorf("error unmarshaling repository metadata file: %w", err)
}
// repo IDs must be valid UUIDs
if md.RepositoryID != "" {
if _, err := uuid.FromString(md.RepositoryID); err != nil {
return nil, fmt.Errorf("%w: %s", ErrInvalidMetadata, "invalid repository id")
}
}
return md, nil
}
func (m *Manager) readMetadataFile(mdFile string) ([]byte, error) {
var data []byte
u, err := url.Parse(mdFile)
if err != nil || u.Scheme == "" || u.Host == "" {
@ -344,18 +374,7 @@ func (m *Manager) GetMetadata(mdFile string) (*hub.RepositoryMetadata, error) {
return nil, fmt.Errorf("error reading repository metadata file: %w", err)
}
}
var md *hub.RepositoryMetadata
if err = yaml.Unmarshal(data, &md); err != nil || md == nil {
return nil, fmt.Errorf("error unmarshaling repository metadata file: %w", err)
}
if md.RepositoryID != "" {
if _, err := uuid.FromString(md.RepositoryID); err != nil {
return nil, fmt.Errorf("%w: %s", ErrInvalidMetadata, "invalid repository id")
}
}
return md, nil
return data, nil
}
// GetPackagesDigest returns the digests for all packages in the repository

View File

@ -402,6 +402,10 @@ func TestClaimOwnership(t *testing.T) {
Body: ioutil.NopCloser(strings.NewReader("")),
StatusCode: http.StatusNotFound,
}, nil)
hg.On("Get", "http://repo.url/artifacthub-repo.yaml").Return(&http.Response{
Body: ioutil.NopCloser(strings.NewReader("")),
StatusCode: http.StatusNotFound,
}, nil)
m := NewManager(cfg, db, nil, withHTTPGetter(hg))
err := m.ClaimOwnership(ctx, "repo1", org)
@ -887,7 +891,8 @@ func TestGetMetadata(t *testing.T) {
t.Run("remote file: error downloading repository metadata file", func(t *testing.T) {
hg := &tests.HTTPGetterMock{}
hg.On("Get", "http://url.test/not-found").Return(nil, tests.ErrFake)
hg.On("Get", "http://url.test/not-found.yml").Return(nil, tests.ErrFake)
hg.On("Get", "http://url.test/not-found.yaml").Return(nil, tests.ErrFake)
m := NewManager(nil, nil, nil, withHTTPGetter(hg))
_, err := m.GetMetadata("http://url.test/not-found")
assert.Error(t, err)
@ -896,7 +901,11 @@ func TestGetMetadata(t *testing.T) {
t.Run("remote file: unexpected status code received", func(t *testing.T) {
hg := &tests.HTTPGetterMock{}
hg.On("Get", "http://url.test/not-found").Return(&http.Response{
hg.On("Get", "http://url.test/not-found.yml").Return(&http.Response{
Body: ioutil.NopCloser(strings.NewReader("")),
StatusCode: http.StatusNotFound,
}, nil)
hg.On("Get", "http://url.test/not-found.yaml").Return(&http.Response{
Body: ioutil.NopCloser(strings.NewReader("")),
StatusCode: http.StatusNotFound,
}, nil)
@ -908,7 +917,11 @@ func TestGetMetadata(t *testing.T) {
t.Run("remote file: error reading repository metadata file", func(t *testing.T) {
hg := &tests.HTTPGetterMock{}
hg.On("Get", "http://url.test/not-found").Return(&http.Response{
hg.On("Get", "http://url.test/not-found.yml").Return(&http.Response{
Body: ioutil.NopCloser(tests.ErrReader(0)),
StatusCode: http.StatusOK,
}, nil)
hg.On("Get", "http://url.test/not-found.yaml").Return(&http.Response{
Body: ioutil.NopCloser(tests.ErrReader(0)),
StatusCode: http.StatusOK,
}, nil)
@ -920,27 +933,33 @@ func TestGetMetadata(t *testing.T) {
t.Run("error unmarshaling repository metadata file", func(t *testing.T) {
m := NewManager(nil, nil, nil)
_, err := m.GetMetadata("testdata/invalid.yml")
_, err := m.GetMetadata("testdata/invalid")
assert.Error(t, err)
assert.Contains(t, err.Error(), "error unmarshaling repository metadata file")
})
t.Run("invalid repository id", func(t *testing.T) {
m := NewManager(nil, nil, nil)
_, err := m.GetMetadata("testdata/invalid-repo-id.yml")
_, err := m.GetMetadata("testdata/invalid-repo-id")
assert.Error(t, err)
assert.Contains(t, err.Error(), "invalid repository id")
})
t.Run("local file: success", func(t *testing.T) {
t.Run("local file: success fetching .yml", func(t *testing.T) {
m := NewManager(nil, nil, nil)
_, err := m.GetMetadata("testdata/artifacthub-repo.yml")
_, err := m.GetMetadata("testdata/artifacthub-repo")
assert.NoError(t, err)
})
t.Run("local file: success .yaml", func(t *testing.T) {
m := NewManager(nil, nil, nil)
_, err := m.GetMetadata("testdata/test-yaml-repo")
assert.NoError(t, err)
})
t.Run("remote file: success", func(t *testing.T) {
hg := &tests.HTTPGetterMock{}
hg.On("Get", "http://url.test/ok").Return(&http.Response{
hg.On("Get", "http://url.test/ok.yml").Return(&http.Response{
Body: ioutil.NopCloser(strings.NewReader("repositoryID: 00000000-0000-0000-0000-000000000001")),
StatusCode: http.StatusOK,
}, nil)
@ -948,6 +967,21 @@ func TestGetMetadata(t *testing.T) {
_, err := m.GetMetadata("http://url.test/ok")
assert.NoError(t, err)
})
t.Run("remote file: success on yaml", func(t *testing.T) {
hg := &tests.HTTPGetterMock{}
hg.On("Get", "http://url.test/ok.yaml").Return(&http.Response{
Body: ioutil.NopCloser(strings.NewReader("repositoryID: 00000000-0000-0000-0000-000000000001")),
StatusCode: http.StatusOK,
}, nil)
hg.On("Get", "http://url.test/ok.yml").Return(&http.Response{
Body: ioutil.NopCloser(strings.NewReader("")),
StatusCode: http.StatusNotFound,
}, nil)
m := NewManager(nil, nil, nil, withHTTPGetter(hg))
_, err := m.GetMetadata("http://url.test/ok")
assert.NoError(t, err)
})
}
func TestGetPackagesDigest(t *testing.T) {

View File

@ -0,0 +1,4 @@
repositoryID: 00000000-0000-0000-0000-000000000001
owners:
- name: owner1
email: owner1@email.com