diff --git a/.drone.jsonnet b/.drone.jsonnet index 01c6110..6d97aa4 100644 --- a/.drone.jsonnet +++ b/.drone.jsonnet @@ -28,7 +28,6 @@ 'make test', 'make test-integration', ], - depends_on: ["gomod"] }, steps: [ @@ -43,7 +42,7 @@ build('1.11'), build('1.12'), build('1.13'), - build('1.14-rc') + {depends_on: ["build-1.11", "build-1.12", "build-1.13"]}, + build('1.14-rc'), golang() { name: 'generate', @@ -52,7 +51,6 @@ 'make generate', 'git diff --exit-code', ], - depends_on: ["build-1.13"] }, ], } diff --git a/.drone.yml b/.drone.yml index 9641363..22c5086 100644 --- a/.drone.yml +++ b/.drone.yml @@ -35,8 +35,6 @@ steps: event: exclude: - tag - depends_on: - - gomod - name: build-1.12 pull: always @@ -52,8 +50,6 @@ steps: event: exclude: - tag - depends_on: - - gomod - name: build-1.13 pull: always @@ -69,8 +65,6 @@ steps: event: exclude: - tag - depends_on: - - gomod - name: build-1.14-rc pull: always @@ -86,10 +80,6 @@ steps: event: exclude: - tag - depends_on: - - build-1.11 - - build-1.12 - - build-1.13 - name: generate pull: always @@ -105,7 +95,5 @@ steps: event: exclude: - tag - depends_on: - - build-1.13 ... diff --git a/cmd/jb/init.go b/cmd/jb/init.go index 0e7a56a..2f7be4c 100644 --- a/cmd/jb/init.go +++ b/cmd/jb/init.go @@ -19,10 +19,10 @@ import ( "io/ioutil" "path/filepath" - kingpin "gopkg.in/alecthomas/kingpin.v2" + "gopkg.in/alecthomas/kingpin.v2" "github.com/jsonnet-bundler/jsonnet-bundler/pkg/jsonnetfile" - "github.com/jsonnet-bundler/jsonnet-bundler/spec" + v1 "github.com/jsonnet-bundler/jsonnet-bundler/spec/v1" ) func initCommand(dir string) int { @@ -34,7 +34,7 @@ func initCommand(dir string) int { return 1 } - s := spec.New() + s := v1.New() // TODO: disable them by default eventually // s.LegacyImports = false diff --git a/cmd/jb/install.go b/cmd/jb/install.go index e4c4605..292b92d 100644 --- a/cmd/jb/install.go +++ b/cmd/jb/install.go @@ -22,12 +22,12 @@ import ( "reflect" "github.com/pkg/errors" - kingpin "gopkg.in/alecthomas/kingpin.v2" + "gopkg.in/alecthomas/kingpin.v2" "github.com/jsonnet-bundler/jsonnet-bundler/pkg" "github.com/jsonnet-bundler/jsonnet-bundler/pkg/jsonnetfile" - "github.com/jsonnet-bundler/jsonnet-bundler/spec" - "github.com/jsonnet-bundler/jsonnet-bundler/spec/deps" + v1 "github.com/jsonnet-bundler/jsonnet-bundler/spec/v1" + "github.com/jsonnet-bundler/jsonnet-bundler/spec/v1/deps" ) func installCommand(dir, jsonnetHome string, uris []string) int { @@ -78,7 +78,7 @@ func installCommand(dir, jsonnetHome string, uris []string) int { "updating jsonnetfile.json") kingpin.FatalIfError( - writeChangedJsonnetFile(jblockfilebytes, &spec.JsonnetFile{Dependencies: locked}, filepath.Join(dir, jsonnetfile.LockFile)), + writeChangedJsonnetFile(jblockfilebytes, &v1.JsonnetFile{Dependencies: locked}, filepath.Join(dir, jsonnetfile.LockFile)), "updating jsonnetfile.lock.json") return 0 @@ -102,7 +102,7 @@ func writeJSONFile(name string, d interface{}) error { return ioutil.WriteFile(name, b, 0644) } -func writeChangedJsonnetFile(originalBytes []byte, modified *spec.JsonnetFile, path string) error { +func writeChangedJsonnetFile(originalBytes []byte, modified *v1.JsonnetFile, path string) error { origJsonnetFile, err := jsonnetfile.Unmarshal(originalBytes) if err != nil { return err diff --git a/cmd/jb/install_test.go b/cmd/jb/install_test.go index 81160cc..894c6ea 100644 --- a/cmd/jb/install_test.go +++ b/cmd/jb/install_test.go @@ -24,12 +24,11 @@ import ( "github.com/stretchr/testify/assert" "github.com/jsonnet-bundler/jsonnet-bundler/pkg/jsonnetfile" - "github.com/jsonnet-bundler/jsonnet-bundler/spec" - "github.com/jsonnet-bundler/jsonnet-bundler/spec/deps" + v1 "github.com/jsonnet-bundler/jsonnet-bundler/spec/v1" + "github.com/jsonnet-bundler/jsonnet-bundler/spec/v1/deps" ) -// TODO: Change legacyImports to false eventually -const initContents = `{"dependencies": [], "legacyImports": true}` +const initContents = `{"version": 1, "dependencies": [], "legacyImports": false}` func TestInstallCommand(t *testing.T) { testInstallCommandWithJsonnetHome(t, "vendor") @@ -60,15 +59,15 @@ func testInstallCommandWithJsonnetHome(t *testing.T, jsonnetHome string) { Name: "OneURL", URIs: []string{"github.com/jsonnet-bundler/jsonnet-bundler@v0.1.0"}, ExpectedCode: 0, - ExpectedJsonnetFile: []byte(`{"dependencies": [{"source": {"git": {"remote": "https://github.com/jsonnet-bundler/jsonnet-bundler", "subdir": ""}}, "version": "v0.1.0"}], "legacyImports": true}`), - ExpectedJsonnetLockFile: []byte(`{"dependencies": [{"source": {"git": {"remote": "https://github.com/jsonnet-bundler/jsonnet-bundler", "subdir": ""}}, "version": "080f157c7fb85ad0281ea78f6c641eaa570a582f", "sum": "W1uI550rQ66axRpPXA2EZDquyPg/5PHZlvUz1NEzefg="}], "legacyImports": false}`), + ExpectedJsonnetFile: []byte(`{"version": 1, "dependencies": [{"source": {"git": {"remote": "https://github.com/jsonnet-bundler/jsonnet-bundler", "subdir": ""}}, "version": "v0.1.0"}], "legacyImports": false}`), + ExpectedJsonnetLockFile: []byte(`{"version": 1, "dependencies": [{"source": {"git": {"remote": "https://github.com/jsonnet-bundler/jsonnet-bundler", "subdir": ""}}, "version": "080f157c7fb85ad0281ea78f6c641eaa570a582f", "sum": "W1uI550rQ66axRpPXA2EZDquyPg/5PHZlvUz1NEzefg="}], "legacyImports": false}`), }, { Name: "Local", URIs: []string{"jsonnet/foobar"}, ExpectedCode: 0, - ExpectedJsonnetFile: []byte(`{"dependencies": [{"source": {"local": {"directory": "jsonnet/foobar"}}, "version": ""}], "legacyImports": true}`), - ExpectedJsonnetLockFile: []byte(`{"dependencies": [{"source": {"local": {"directory": "jsonnet/foobar"}}, "version": ""}], "legacyImports": false}`), + ExpectedJsonnetFile: []byte(`{"version": 1, "dependencies": [{"source": {"local": {"directory": "jsonnet/foobar"}}, "version": ""}], "legacyImports": false}`), + ExpectedJsonnetLockFile: []byte(`{"version": 1, "dependencies": [{"source": {"local": {"directory": "jsonnet/foobar"}}, "version": ""}], "legacyImports": false}`), }, } @@ -118,19 +117,19 @@ func TestWriteChangedJsonnetFile(t *testing.T) { testcases := []struct { Name string JsonnetFileBytes []byte - NewJsonnetFile spec.JsonnetFile + NewJsonnetFile v1.JsonnetFile ExpectWrite bool }{ { Name: "NoDiffEmpty", JsonnetFileBytes: []byte(`{}`), - NewJsonnetFile: spec.New(), + NewJsonnetFile: v1.New(), ExpectWrite: false, }, { Name: "NoDiffNotEmpty", JsonnetFileBytes: []byte(`{"dependencies": [{"version": "master"}]}`), - NewJsonnetFile: spec.JsonnetFile{ + NewJsonnetFile: v1.JsonnetFile{ Dependencies: map[string]deps.Dependency{ "": { Version: "master", @@ -142,7 +141,7 @@ func TestWriteChangedJsonnetFile(t *testing.T) { { Name: "DiffVersion", JsonnetFileBytes: []byte(`{"dependencies": [{"version": "1.0"}]}`), - NewJsonnetFile: spec.JsonnetFile{ + NewJsonnetFile: v1.JsonnetFile{ Dependencies: map[string]deps.Dependency{ "": { Version: "2.0", @@ -154,7 +153,7 @@ func TestWriteChangedJsonnetFile(t *testing.T) { { Name: "Diff", JsonnetFileBytes: []byte(`{}`), - NewJsonnetFile: spec.JsonnetFile{ + NewJsonnetFile: v1.JsonnetFile{ Dependencies: map[string]deps.Dependency{ "github.com/foobar/foobar": { Source: deps.Source{ diff --git a/cmd/jb/main_test.go b/cmd/jb/main_test.go index 3e1e1de..91346fb 100644 --- a/cmd/jb/main_test.go +++ b/cmd/jb/main_test.go @@ -20,7 +20,7 @@ import ( "github.com/stretchr/testify/assert" - "github.com/jsonnet-bundler/jsonnet-bundler/spec/deps" + "github.com/jsonnet-bundler/jsonnet-bundler/spec/v1/deps" ) func TestParseDependency(t *testing.T) { diff --git a/cmd/jb/update.go b/cmd/jb/update.go index e8623aa..f339782 100644 --- a/cmd/jb/update.go +++ b/cmd/jb/update.go @@ -19,12 +19,12 @@ import ( "os" "path/filepath" - kingpin "gopkg.in/alecthomas/kingpin.v2" + "gopkg.in/alecthomas/kingpin.v2" "github.com/jsonnet-bundler/jsonnet-bundler/pkg" "github.com/jsonnet-bundler/jsonnet-bundler/pkg/jsonnetfile" - "github.com/jsonnet-bundler/jsonnet-bundler/spec" - "github.com/jsonnet-bundler/jsonnet-bundler/spec/deps" + v1 "github.com/jsonnet-bundler/jsonnet-bundler/spec/v1" + "github.com/jsonnet-bundler/jsonnet-bundler/spec/v1/deps" ) func updateCommand(dir, jsonnetHome string, urls ...*url.URL) int { @@ -48,7 +48,7 @@ func updateCommand(dir, jsonnetHome string, urls ...*url.URL) int { writeJSONFile(filepath.Join(dir, jsonnetfile.File), jsonnetFile), "updating jsonnetfile.json") kingpin.FatalIfError( - writeJSONFile(filepath.Join(dir, jsonnetfile.LockFile), spec.JsonnetFile{Dependencies: locked}), + writeJSONFile(filepath.Join(dir, jsonnetfile.LockFile), v1.JsonnetFile{Dependencies: locked}), "updating jsonnetfile.lock.json") return 0 } diff --git a/pkg/git.go b/pkg/git.go index 7427a17..26d20d3 100644 --- a/pkg/git.go +++ b/pkg/git.go @@ -33,7 +33,7 @@ import ( "github.com/fatih/color" "github.com/pkg/errors" - "github.com/jsonnet-bundler/jsonnet-bundler/spec/deps" + "github.com/jsonnet-bundler/jsonnet-bundler/spec/v1/deps" ) type GitPackage struct { diff --git a/pkg/jsonnetfile/jsonnetfile.go b/pkg/jsonnetfile/jsonnetfile.go index 3022e8a..a576b5e 100644 --- a/pkg/jsonnetfile/jsonnetfile.go +++ b/pkg/jsonnetfile/jsonnetfile.go @@ -21,8 +21,9 @@ import ( "github.com/pkg/errors" - "github.com/jsonnet-bundler/jsonnet-bundler/spec" - "github.com/jsonnet-bundler/jsonnet-bundler/spec/deps" + v0 "github.com/jsonnet-bundler/jsonnet-bundler/spec/v0" + v1 "github.com/jsonnet-bundler/jsonnet-bundler/spec/v1" + depsv1 "github.com/jsonnet-bundler/jsonnet-bundler/spec/v1/deps" ) const ( @@ -30,13 +31,15 @@ const ( LockFile = "jsonnetfile.lock.json" ) -var ErrNoFile = errors.New("no jsonnetfile") +var ( + ErrUpdateJB = errors.New("jsonnetfile version unknown, update jb") +) // Load reads a jsonnetfile.(lock).json from disk -func Load(filepath string) (spec.JsonnetFile, error) { +func Load(filepath string) (v1.JsonnetFile, error) { bytes, err := ioutil.ReadFile(filepath) if err != nil { - return spec.New(), err + return v1.New(), err } return Unmarshal(bytes) @@ -44,19 +47,56 @@ func Load(filepath string) (spec.JsonnetFile, error) { // Unmarshal creates a spec.JsonnetFile from bytes. Empty bytes // will create an empty spec. -func Unmarshal(bytes []byte) (spec.JsonnetFile, error) { - m := spec.New() +func Unmarshal(bytes []byte) (v1.JsonnetFile, error) { + m := v1.New() + if len(bytes) == 0 { return m, nil } - if err := json.Unmarshal(bytes, &m); err != nil { - return m, errors.Wrap(err, "failed to unmarshal file") - } - if m.Dependencies == nil { - m.Dependencies = make(map[string]deps.Dependency) + + versions := struct { + Version uint `json:"version"` + }{} + + err := json.Unmarshal(bytes, &versions) + if err != nil { + return m, err } - return m, nil + if versions.Version > v1.Version { + return m, ErrUpdateJB + } + + if versions.Version == v1.Version { + if err := json.Unmarshal(bytes, &m); err != nil { + return m, errors.Wrap(err, "failed to unmarshal v1 file") + } + + return m, nil + } else { + var mv0 v0.JsonnetFile + if err := json.Unmarshal(bytes, &mv0); err != nil { + return m, errors.Wrap(err, "failed to unmarshal jsonnetfile") + } + + for name, dep := range mv0.Dependencies { + var d depsv1.Dependency + if dep.Source.GitSource != nil { + d = *depsv1.Parse("", dep.Source.GitSource.Remote) + d.Source.GitSource.Subdir = dep.Source.GitSource.Subdir + } + if dep.Source.LocalSource != nil { + d = *depsv1.Parse(dep.Source.LocalSource.Directory, dep.Source.GitSource.Remote) + } + + d.Sum = dep.Sum + d.Version = dep.Version + + m.Dependencies[name] = d + } + + return m, nil + } } // Exists returns whether the file at the given path exists diff --git a/pkg/jsonnetfile/jsonnetfile_test.go b/pkg/jsonnetfile/jsonnetfile_test.go index dfe655f..ad1afcf 100644 --- a/pkg/jsonnetfile/jsonnetfile_test.go +++ b/pkg/jsonnetfile/jsonnetfile_test.go @@ -23,47 +23,167 @@ import ( "github.com/stretchr/testify/assert" "github.com/jsonnet-bundler/jsonnet-bundler/pkg/jsonnetfile" - "github.com/jsonnet-bundler/jsonnet-bundler/spec" - "github.com/jsonnet-bundler/jsonnet-bundler/spec/deps" + v1 "github.com/jsonnet-bundler/jsonnet-bundler/spec/v1" + "github.com/jsonnet-bundler/jsonnet-bundler/spec/v1/deps" ) const notExist = "/this/does/not/exist" -func TestLoad(t *testing.T) { - jsonnetfileContent := ` -{ - "legacyImports": false, - "dependencies": [ - { - "source": { - "git": { - "remote": "https://github.com/foobar/foobar", - "subdir": "" - } - }, - "version": "master" +const v0JSON = `{ + "dependencies": [ + { + "name": "grafana-builder", + "source": { + "git": { + "remote": "https://github.com/grafana/jsonnet-libs", + "subdir": "grafana-builder" } - ] -} -` + }, + "version": "54865853ebc1f901964e25a2e7a0e4d2cb6b9648", + "sum": "ELsYwK+kGdzX1mee2Yy+/b2mdO4Y503BOCDkFzwmGbE=" + }, + { + "name": "prometheus-mixin", + "source": { + "git": { + "remote": "https://github.com/prometheus/prometheus", + "subdir": "documentation/prometheus-mixin" + } + }, + "version": "7c039a6b3b4b2a9d7c613ac8bd3fc16e8ca79684", + "sum": "bVGOsq3hLOw2irNPAS91a5dZJqQlBUNWy3pVwM4+kIY=" + } + ] +}` - jsonnetFileExpected := spec.JsonnetFile{ - LegacyImports: false, - Dependencies: map[string]deps.Dependency{ - "github.com/foobar/foobar": { - Source: deps.Source{ - GitSource: &deps.Git{ - Scheme: deps.GitSchemeHTTPS, - Host: "github.com", - User: "foobar", - Repo: "foobar", - Subdir: "", - }, +var v0Jsonnetfile = v1.JsonnetFile{ + Dependencies: map[string]deps.Dependency{ + "grafana-builder": { + Source: deps.Source{ + GitSource: &deps.Git{ + Scheme: deps.GitSchemeHTTPS, + Host: "github.com", + User: "grafana", + Repo: "jsonnet-libs", + Subdir: "grafana-builder", }, - Version: "master", - }}, + }, + Version: "54865853ebc1f901964e25a2e7a0e4d2cb6b9648", + Sum: "ELsYwK+kGdzX1mee2Yy+/b2mdO4Y503BOCDkFzwmGbE=", + }, + "prometheus-mixin": { + Source: deps.Source{ + GitSource: &deps.Git{ + Scheme: deps.GitSchemeHTTPS, + Host: "github.com", + User: "prometheus", + Repo: "prometheus", + Subdir: "documentation/prometheus-mixin", + }, + }, + Version: "7c039a6b3b4b2a9d7c613ac8bd3fc16e8ca79684", + Sum: "bVGOsq3hLOw2irNPAS91a5dZJqQlBUNWy3pVwM4+kIY=", + }, + }, + LegacyImports: true, +} + +const v1JSON = `{ + "version": 1, + "dependencies": [ + { + "source": { + "git": { + "remote": "https://github.com/grafana/jsonnet-libs", + "subdir": "grafana-builder" + } + }, + "version": "54865853ebc1f901964e25a2e7a0e4d2cb6b9648", + "sum": "ELsYwK+kGdzX1mee2Yy+/b2mdO4Y503BOCDkFzwmGbE=" + }, + { + "name": "prometheus", + "source": { + "git": { + "remote": "https://github.com/prometheus/prometheus", + "subdir": "documentation/prometheus-mixin" + } + }, + "version": "7c039a6b3b4b2a9d7c613ac8bd3fc16e8ca79684", + "sum": "bVGOsq3hLOw2irNPAS91a5dZJqQlBUNWy3pVwM4+kIY=" + } + ], + "legacyImports": false +}` + +var v1Jsonnetfile = v1.JsonnetFile{ + Dependencies: map[string]deps.Dependency{ + "github.com/grafana/jsonnet-libs/grafana-builder": { + Source: deps.Source{ + GitSource: &deps.Git{ + Scheme: deps.GitSchemeHTTPS, + Host: "github.com", + User: "grafana", + Repo: "jsonnet-libs", + Subdir: "/grafana-builder", + }, + }, + Version: "54865853ebc1f901964e25a2e7a0e4d2cb6b9648", + Sum: "ELsYwK+kGdzX1mee2Yy+/b2mdO4Y503BOCDkFzwmGbE=", + }, + "github.com/prometheus/prometheus/documentation/prometheus-mixin": { + LegacyNameCompat: "prometheus", + Source: deps.Source{ + GitSource: &deps.Git{ + Scheme: deps.GitSchemeHTTPS, + Host: "github.com", + User: "prometheus", + Repo: "prometheus", + Subdir: "/documentation/prometheus-mixin", + }, + }, + Version: "7c039a6b3b4b2a9d7c613ac8bd3fc16e8ca79684", + Sum: "bVGOsq3hLOw2irNPAS91a5dZJqQlBUNWy3pVwM4+kIY=", + }, + }, + LegacyImports: false, +} + +func TestVersions(t *testing.T) { + tests := []struct { + Name string + JSON string + Jsonnetfile v1.JsonnetFile + Error error + }{ + { + Name: "v0", + JSON: v0JSON, + Jsonnetfile: v0Jsonnetfile, + }, + { + Name: "v1", + JSON: v1JSON, + Jsonnetfile: v1Jsonnetfile, + }, + { + Name: "v100", + JSON: `{"version": 100}`, + Jsonnetfile: v1.New(), + Error: jsonnetfile.ErrUpdateJB, + }, } + for _, tc := range tests { + t.Run(tc.Name, func(t *testing.T) { + jf, err := jsonnetfile.Unmarshal([]byte(tc.JSON)) + assert.Equal(t, tc.Error, err) + assert.Equal(t, tc.Jsonnetfile, jf) + }) + } +} + +func TestLoadV1(t *testing.T) { tempDir, err := ioutil.TempDir("", "jb-load-jsonnetfile") if err != nil { t.Fatal(err) @@ -71,12 +191,12 @@ func TestLoad(t *testing.T) { defer os.RemoveAll(tempDir) tempFile := filepath.Join(tempDir, jsonnetfile.File) - err = ioutil.WriteFile(tempFile, []byte(jsonnetfileContent), os.ModePerm) + err = ioutil.WriteFile(tempFile, []byte(v1JSON), os.ModePerm) assert.Nil(t, err) jf, err := jsonnetfile.Load(tempFile) assert.Nil(t, err) - assert.Equal(t, jsonnetFileExpected, jf) + assert.Equal(t, v1Jsonnetfile, jf) } func TestLoadEmpty(t *testing.T) { @@ -88,18 +208,18 @@ func TestLoadEmpty(t *testing.T) { // write empty json file tempFile := filepath.Join(tempDir, jsonnetfile.File) - err = ioutil.WriteFile(tempFile, []byte(`{}`), os.ModePerm) + err = ioutil.WriteFile(tempFile, []byte(`{"version":1}`), os.ModePerm) assert.Nil(t, err) // expect it to be loaded properly got, err := jsonnetfile.Load(tempFile) assert.Nil(t, err) - assert.Equal(t, spec.New(), got) + assert.Equal(t, v1.New(), got) } func TestLoadNotExist(t *testing.T) { jf, err := jsonnetfile.Load(notExist) - assert.Equal(t, spec.New(), jf) + assert.Equal(t, v1.New(), jf) assert.Error(t, err) } diff --git a/pkg/local.go b/pkg/local.go index f91b1bc..d91d733 100644 --- a/pkg/local.go +++ b/pkg/local.go @@ -21,7 +21,7 @@ import ( "github.com/pkg/errors" - "github.com/jsonnet-bundler/jsonnet-bundler/spec/deps" + "github.com/jsonnet-bundler/jsonnet-bundler/spec/v1/deps" ) type LocalPackage struct { diff --git a/pkg/packages.go b/pkg/packages.go index d02984c..63f521d 100644 --- a/pkg/packages.go +++ b/pkg/packages.go @@ -28,8 +28,8 @@ import ( "github.com/pkg/errors" "github.com/jsonnet-bundler/jsonnet-bundler/pkg/jsonnetfile" - "github.com/jsonnet-bundler/jsonnet-bundler/spec" - "github.com/jsonnet-bundler/jsonnet-bundler/spec/deps" + v1 "github.com/jsonnet-bundler/jsonnet-bundler/spec/v1" + "github.com/jsonnet-bundler/jsonnet-bundler/spec/v1/deps" ) var ( @@ -49,7 +49,7 @@ var ( // // Finally, all unknown files and directories are removed from vendor/ // The full list of locked depedencies is returned -func Ensure(direct spec.JsonnetFile, vendorDir string, oldLocks map[string]deps.Dependency) (map[string]deps.Dependency, error) { +func Ensure(direct v1.JsonnetFile, vendorDir string, oldLocks map[string]deps.Dependency) (map[string]deps.Dependency, error) { // ensure all required files are in vendor // This is the actual installation locks, err := ensure(direct.Dependencies, vendorDir, oldLocks) diff --git a/pkg/packages_test.go b/pkg/packages_test.go index 8c025b3..1319475 100644 --- a/pkg/packages_test.go +++ b/pkg/packages_test.go @@ -17,7 +17,7 @@ package pkg import ( "testing" - "github.com/jsonnet-bundler/jsonnet-bundler/spec/deps" + "github.com/jsonnet-bundler/jsonnet-bundler/spec/v1/deps" ) func TestKnown(t *testing.T) { diff --git a/spec/v0/spec.go b/spec/v0/spec.go new file mode 100644 index 0000000..6d1bf2c --- /dev/null +++ b/spec/v0/spec.go @@ -0,0 +1,89 @@ +// Copyright 2018 jsonnet-bundler authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package spec + +import ( + "encoding/json" + "sort" +) + +// JsonnetFile is the structure of a `.json` file describing a set of jsonnet +// dependencies. It is used for both, the jsonnetFile and the lockFile. +type JsonnetFile struct { + Dependencies map[string]Dependency +} + +// New returns a new JsonnetFile with the dependencies map initialized +func New() JsonnetFile { + return JsonnetFile{ + Dependencies: make(map[string]Dependency), + } +} + +// jsonFile is the json representation of a JsonnetFile, which is different for +// compatibility reasons. +type jsonFile struct { + Dependencies []Dependency `json:"dependencies"` +} + +// UnmarshalJSON unmarshals a `jsonFile`'s json into a JsonnetFile +func (jf *JsonnetFile) UnmarshalJSON(data []byte) error { + var s jsonFile + if err := json.Unmarshal(data, &s); err != nil { + return err + } + + jf.Dependencies = make(map[string]Dependency) + for _, d := range s.Dependencies { + jf.Dependencies[d.Name] = d + } + return nil +} + +// MarshalJSON serializes a JsonnetFile into json of the format of a `jsonFile` +func (jf JsonnetFile) MarshalJSON() ([]byte, error) { + var s jsonFile + for _, d := range jf.Dependencies { + s.Dependencies = append(s.Dependencies, d) + } + + sort.SliceStable(s.Dependencies, func(i int, j int) bool { + return s.Dependencies[i].Name < s.Dependencies[j].Name + }) + + return json.Marshal(s) +} + +type Dependency struct { + Name string `json:"name"` + Source Source `json:"source"` + Version string `json:"version"` + Sum string `json:"sum,omitempty"` + DepSource string `json:"-"` +} + +type Source struct { + GitSource *GitSource `json:"git,omitempty"` + LocalSource *LocalSource `json:"local,omitempty"` +} + +type GitSource struct { + Remote string `json:"remote"` + Subdir string `json:"subdir"` +} + +type LocalSource struct { + Directory string `json:"directory"` +} diff --git a/spec/v0/spec_test.go b/spec/v0/spec_test.go new file mode 100644 index 0000000..3b7607f --- /dev/null +++ b/spec/v0/spec_test.go @@ -0,0 +1,109 @@ +// Copyright 2018 jsonnet-bundler authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package spec + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +const jsonJF = `{ + "dependencies": [ + { + "name": "grafana-builder", + "source": { + "git": { + "remote": "https://github.com/grafana/jsonnet-libs", + "subdir": "grafana-builder" + } + }, + "version": "54865853ebc1f901964e25a2e7a0e4d2cb6b9648", + "sum": "ELsYwK+kGdzX1mee2Yy+/b2mdO4Y503BOCDkFzwmGbE=" + }, + { + "name": "prometheus-mixin", + "source": { + "git": { + "remote": "https://github.com/prometheus/prometheus", + "subdir": "documentation/prometheus-mixin" + } + }, + "version": "7c039a6b3b4b2a9d7c613ac8bd3fc16e8ca79684", + "sum": "bVGOsq3hLOw2irNPAS91a5dZJqQlBUNWy3pVwM4+kIY=" + } + ] +}` + +func testData() JsonnetFile { + return JsonnetFile{ + Dependencies: map[string]Dependency{ + "grafana-builder": { + Name: "grafana-builder", + Source: Source{ + GitSource: &GitSource{ + Remote: "https://github.com/grafana/jsonnet-libs", + Subdir: "grafana-builder", + }, + }, + Version: "54865853ebc1f901964e25a2e7a0e4d2cb6b9648", + Sum: "ELsYwK+kGdzX1mee2Yy+/b2mdO4Y503BOCDkFzwmGbE=", + }, + "prometheus-mixin": { + Name: "prometheus-mixin", + Source: Source{ + GitSource: &GitSource{ + Remote: "https://github.com/prometheus/prometheus", + Subdir: "documentation/prometheus-mixin", + }, + }, + Version: "7c039a6b3b4b2a9d7c613ac8bd3fc16e8ca79684", + Sum: "bVGOsq3hLOw2irNPAS91a5dZJqQlBUNWy3pVwM4+kIY=", + }, + }, + } +} + +// TestUnmarshal checks that unmarshalling works +func TestUnmarshal(t *testing.T) { + var dst JsonnetFile + err := json.Unmarshal([]byte(jsonJF), &dst) + require.NoError(t, err) + assert.Equal(t, testData(), dst) +} + +// TestMarshal checks that marshalling works +func TestMarshal(t *testing.T) { + data, err := json.Marshal(testData()) + require.NoError(t, err) + assert.JSONEq(t, jsonJF, string(data)) +} + +// TestRemarshal checks that unmarshalling a previously marshalled object yields +// the same object +func TestRemarshal(t *testing.T) { + jf := testData() + + data, err := json.Marshal(jf) + require.NoError(t, err) + + var dst JsonnetFile + err = json.Unmarshal(data, &dst) + require.NoError(t, err) + + assert.Equal(t, jf, dst) +} diff --git a/spec/deps/dependencies.go b/spec/v1/deps/dependencies.go similarity index 100% rename from spec/deps/dependencies.go rename to spec/v1/deps/dependencies.go diff --git a/spec/deps/dependencies_test.go b/spec/v1/deps/dependencies_test.go similarity index 100% rename from spec/deps/dependencies_test.go rename to spec/v1/deps/dependencies_test.go diff --git a/spec/deps/git.go b/spec/v1/deps/git.go similarity index 100% rename from spec/deps/git.go rename to spec/v1/deps/git.go diff --git a/spec/deps/git_test.go b/spec/v1/deps/git_test.go similarity index 100% rename from spec/deps/git_test.go rename to spec/v1/deps/git_test.go diff --git a/spec/spec.go b/spec/v1/spec.go similarity index 93% rename from spec/spec.go rename to spec/v1/spec.go index d24359e..a83b9cb 100644 --- a/spec/spec.go +++ b/spec/v1/spec.go @@ -18,9 +18,11 @@ import ( "encoding/json" "sort" - "github.com/jsonnet-bundler/jsonnet-bundler/spec/deps" + "github.com/jsonnet-bundler/jsonnet-bundler/spec/v1/deps" ) +const Version uint = 1 + // JsonnetFile is the structure of a `.json` file describing a set of jsonnet // dependencies. It is used for both, the jsonnetFile and the lockFile. type JsonnetFile struct { @@ -42,6 +44,7 @@ func New() JsonnetFile { // jsonFile is the json representation of a JsonnetFile, which is different for // compatibility reasons. type jsonFile struct { + Version uint `json:"version"` Dependencies []deps.Dependency `json:"dependencies"` LegacyImports bool `json:"legacyImports"` } @@ -59,14 +62,18 @@ func (jf *JsonnetFile) UnmarshalJSON(data []byte) error { for _, d := range s.Dependencies { jf.Dependencies[d.Name()] = d } + jf.LegacyImports = s.LegacyImports + return nil } // MarshalJSON serializes a JsonnetFile into json of the format of a `jsonFile` func (jf JsonnetFile) MarshalJSON() ([]byte, error) { var s jsonFile - s.LegacyImports = jf.LegacyImports + + s.Version = Version + for _, d := range jf.Dependencies { s.Dependencies = append(s.Dependencies, d) } diff --git a/spec/spec_test.go b/spec/v1/spec_test.go similarity index 97% rename from spec/spec_test.go rename to spec/v1/spec_test.go index 02dc9de..73c3353 100644 --- a/spec/spec_test.go +++ b/spec/v1/spec_test.go @@ -18,12 +18,14 @@ import ( "encoding/json" "testing" - "github.com/jsonnet-bundler/jsonnet-bundler/spec/deps" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/jsonnet-bundler/jsonnet-bundler/spec/v1/deps" ) const jsonJF = `{ + "version": 1, "dependencies": [ { "source": { diff --git a/tool/rewrite/rewrite.go b/tool/rewrite/rewrite.go index 3fc31d0..0e07c0c 100644 --- a/tool/rewrite/rewrite.go +++ b/tool/rewrite/rewrite.go @@ -24,7 +24,7 @@ import ( "regexp" "strings" - "github.com/jsonnet-bundler/jsonnet-bundler/spec/deps" + "github.com/jsonnet-bundler/jsonnet-bundler/spec/v1/deps" ) var expr = regexp.MustCompile(`(?mU)(import ["'])(.*)(\/.*["'])`) diff --git a/tool/rewrite/rewrite_test.go b/tool/rewrite/rewrite_test.go index 67721f8..6cd9549 100644 --- a/tool/rewrite/rewrite_test.go +++ b/tool/rewrite/rewrite_test.go @@ -22,7 +22,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/jsonnet-bundler/jsonnet-bundler/spec/deps" + "github.com/jsonnet-bundler/jsonnet-bundler/spec/v1/deps" ) const sample = `