Repository: ariga/atlas
Pull request #792 (2022-05-13 09:02:06)

cmd/atlascmd: move and fix test for version command and build


Patch:
diff --git a/.golangci.yml b/.golangci.yml
index c9b9f330..7e736406 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -12,8 +12,16 @@ issues:
       linters:
         - gosec
 
+linters-settings:
+  goheader:
+    template: |-
+      Copyright 2021-present The Atlas Authors. All rights reserved.
+      This source code is licensed under the Apache 2.0 license found
+      in the LICENSE file in the root directory of this source tree.
+
 linters:
   disable-all: true
   enable:
     - gosec
     - revive
+    - goheader
diff --git a/cmd/atlas/doc.go b/cmd/atlas/doc.go
index bc422dc8..1640a691 100644
--- a/cmd/atlas/doc.go
+++ b/cmd/atlas/doc.go
@@ -1,3 +1,7 @@
+// Copyright 2021-present The Atlas Authors. All rights reserved.
+// This source code is licensed under the Apache 2.0 license found
+// in the LICENSE file in the root directory of this source tree.
+
 //go:build ignore
 // +build ignore
 
diff --git a/cmd/atlas/generate.go b/cmd/atlas/generate.go
index 437af339..92a6aacd 100644
--- a/cmd/atlas/generate.go
+++ b/cmd/atlas/generate.go
@@ -1,3 +1,7 @@
+// Copyright 2021-present The Atlas Authors. All rights reserved.
+// This source code is licensed under the Apache 2.0 license found
+// in the LICENSE file in the root directory of this source tree.
+
 package main
 
 //go:generate go run -mod=mod doc.go
diff --git a/cmd/atlas/main.go b/cmd/atlas/main.go
index aa1636ba..ea1ecd75 100644
--- a/cmd/atlas/main.go
+++ b/cmd/atlas/main.go
@@ -1,3 +1,7 @@
+// Copyright 2021-present The Atlas Authors. All rights reserved.
+// This source code is licensed under the Apache 2.0 license found
+// in the LICENSE file in the root directory of this source tree.
+
 package main
 
 import (
diff --git a/cmd/atlascmd/migrate/ent/schema/revision.go b/cmd/atlascmd/migrate/ent/schema/revision.go
index dcf3f4c0..a6ef6544 100644
--- a/cmd/atlascmd/migrate/ent/schema/revision.go
+++ b/cmd/atlascmd/migrate/ent/schema/revision.go
@@ -1,3 +1,7 @@
+// Copyright 2021-present The Atlas Authors. All rights reserved.
+// This source code is licensed under the Apache 2.0 license found
+// in the LICENSE file in the root directory of this source tree.
+
 package schema
 
 import (
diff --git a/internal/ci/main.go b/internal/ci/main.go
index aa885aa0..7823e544 100644
--- a/internal/ci/main.go
+++ b/internal/ci/main.go
@@ -1,3 +1,7 @@
+// Copyright 2021-present The Atlas Authors. All rights reserved.
+// This source code is licensed under the Apache 2.0 license found
+// in the LICENSE file in the root directory of this source tree.
+
 package main
 
 import (
diff --git a/internal/typedoc/main.go b/internal/typedoc/main.go
index 2356fa23..8eb48e61 100644
--- a/internal/typedoc/main.go
+++ b/internal/typedoc/main.go
@@ -1,3 +1,7 @@
+// Copyright 2021-present The Atlas Authors. All rights reserved.
+// This source code is licensed under the Apache 2.0 license found
+// in the LICENSE file in the root directory of this source tree.
+
 package main
 
 import (
diff --git a/schema/schemaspec/doc.go b/schema/schemaspec/doc.go
index 2d66b939..e6ed6b8c 100644
--- a/schema/schemaspec/doc.go
+++ b/schema/schemaspec/doc.go
@@ -1,3 +1,7 @@
+// Copyright 2021-present The Atlas Authors. All rights reserved.
+// This source code is licensed under the Apache 2.0 license found
+// in the LICENSE file in the root directory of this source tree.
+
 // Package schemaspec provides types designed to capture atlas schema elements, and create
 // type-safe extensions to the configuration language. This package is designed to provide
 // an intermediate representation between a serialized configuration language representation
diff --git a/schema/schemaspec/extension.go b/schema/schemaspec/extension.go
index 8d820ae6..c3f8edb8 100644
--- a/schema/schemaspec/extension.go
+++ b/schema/schemaspec/extension.go
@@ -1,3 +1,7 @@
+// Copyright 2021-present The Atlas Authors. All rights reserved.
+// This source code is licensed under the Apache 2.0 license found
+// in the LICENSE file in the root directory of this source tree.
+
 package schemaspec
 
 import (
diff --git a/schema/schemaspec/internal/schemautil/schemautil.go b/schema/schemaspec/internal/schemautil/schemautil.go
index cae78fde..938b80fa 100644
--- a/schema/schemaspec/internal/schemautil/schemautil.go
+++ b/schema/schemaspec/internal/schemautil/schemautil.go
@@ -1,3 +1,7 @@
+// Copyright 2021-present The Atlas Authors. All rights reserved.
+// This source code is licensed under the Apache 2.0 license found
+// in the LICENSE file in the root directory of this source tree.
+
 package schemautil
 
 import (
diff --git a/schema/schemaspec/schemahcl/hcl.go b/schema/schemaspec/schemahcl/hcl.go
index 8f2be5cb..6693326d 100644
--- a/schema/schemaspec/schemahcl/hcl.go
+++ b/schema/schemaspec/schemahcl/hcl.go
@@ -1,3 +1,7 @@
+// Copyright 2021-present The Atlas Authors. All rights reserved.
+// This source code is licensed under the Apache 2.0 license found
+// in the LICENSE file in the root directory of this source tree.
+
 package schemahcl
 
 import (
diff --git a/schema/schemaspec/schemahcl/opts.go b/schema/schemaspec/schemahcl/opts.go
index 30e3d5e5..5548d44c 100644
--- a/schema/schemaspec/schemahcl/opts.go
+++ b/schema/schemaspec/schemahcl/opts.go
@@ -1,3 +1,7 @@
+// Copyright 2021-present The Atlas Authors. All rights reserved.
+// This source code is licensed under the Apache 2.0 license found
+// in the LICENSE file in the root directory of this source tree.
+
 package schemahcl
 
 import (
diff --git a/schema/schemaspec/schemahcl/types.go b/schema/schemaspec/schemahcl/types.go
index d5f3d224..a63769ab 100644
--- a/schema/schemaspec/schemahcl/types.go
+++ b/schema/schemaspec/schemahcl/types.go
@@ -1,3 +1,7 @@
+// Copyright 2021-present The Atlas Authors. All rights reserved.
+// This source code is licensed under the Apache 2.0 license found
+// in the LICENSE file in the root directory of this source tree.
+
 package schemahcl
 
 import (
diff --git a/schema/schemaspec/spec.go b/schema/schemaspec/spec.go
index f5f50558..43a7273d 100644
--- a/schema/schemaspec/spec.go
+++ b/schema/schemaspec/spec.go
@@ -1,3 +1,7 @@
+// Copyright 2021-present The Atlas Authors. All rights reserved.
+// This source code is licensed under the Apache 2.0 license found
+// in the LICENSE file in the root directory of this source tree.
+
 package schemaspec
 
 import (
diff --git a/sql/internal/specutil/spec.go b/sql/internal/specutil/spec.go
index ea955488..9dfaae47 100644
--- a/sql/internal/specutil/spec.go
+++ b/sql/internal/specutil/spec.go
@@ -1,3 +1,7 @@
+// Copyright 2021-present The Atlas Authors. All rights reserved.
+// This source code is licensed under the Apache 2.0 license found
+// in the LICENSE file in the root directory of this source tree.
+
 package specutil
 
 import (
diff --git a/sql/mysql/sqlspec.go b/sql/mysql/sqlspec.go
index 9ea71d4b..9f06b9f1 100644
--- a/sql/mysql/sqlspec.go
+++ b/sql/mysql/sqlspec.go
@@ -1,3 +1,7 @@
+// Copyright 2021-present The Atlas Authors. All rights reserved.
+// This source code is licensed under the Apache 2.0 license found
+// in the LICENSE file in the root directory of this source tree.
+
 package mysql
 
 import (
diff --git a/sql/postgres/sqlspec.go b/sql/postgres/sqlspec.go
index 0d75e3d5..ed0596c8 100644
--- a/sql/postgres/sqlspec.go
+++ b/sql/postgres/sqlspec.go
@@ -1,3 +1,7 @@
+// Copyright 2021-present The Atlas Authors. All rights reserved.
+// This source code is licensed under the Apache 2.0 license found
+// in the LICENSE file in the root directory of this source tree.
+
 package postgres
 
 import (
diff --git a/sql/sqlite/driver.go b/sql/sqlite/driver.go
index 0a862111..7cd54b9f 100644
--- a/sql/sqlite/driver.go
+++ b/sql/sqlite/driver.go
@@ -6,9 +6,15 @@ package sqlite
 
 import (
 	"context"
+	"errors"
 	"fmt"
+	"io/ioutil"
 	"net/url"
+	"os"
+	"path/filepath"
+	"strconv"
 	"strings"
+	"time"
 
 	"ariga.io/atlas/sql/internal/sqlx"
 	"ariga.io/atlas/sql/migrate"
@@ -99,6 +105,39 @@ func (d *Driver) Clean(ctx context.Context) error {
 	return nil
 }
 
+// Lock implements the schema.Locker interface.
+func (d *Driver) Lock(_ context.Context, name string, timeout time.Duration) (schema.UnlockFunc, error) {
+	path := filepath.Join(os.TempDir(), name+".lock")
+	c, err := ioutil.ReadFile(path)
+	if errors.Is(err, os.ErrNotExist) {
+		return acquireLock(path, timeout)
+	}
+	if err != nil {
+		return nil, fmt.Errorf("sql/sqlite: reading lock dir: %w", err)
+	}
+	expires, err := strconv.ParseInt(string(c), 10, 64)
+	if err != nil {
+		return nil, fmt.Errorf("sql/sqlite: invalid lock file format: parsing expiration date: %w", err)
+	}
+	if time.Unix(0, expires).After(time.Now()) {
+		// Lock is still valid.
+		return nil, fmt.Errorf("sql/sqlite: lock on %q already taken", name)
+	}
+	return acquireLock(path, timeout)
+}
+
+func acquireLock(path string, timeout time.Duration) (schema.UnlockFunc, error) {
+	lock, err := os.Create(path)
+	if err != nil {
+		return nil, fmt.Errorf("sql/sqlite: creating lockfile %q: %w", path, err)
+	}
+	if _, err := lock.Write([]byte(strconv.FormatInt(time.Now().Add(timeout).UnixNano(), 10))); err != nil {
+		return nil, fmt.Errorf("sql/sqlite: writing to lockfile %q: %w", path, err)
+	}
+	defer lock.Close()
+	return func() error { return os.Remove(path) }, nil
+}
+
 // SQLite standard data types as defined in its codebase and documentation.
 // https://www.sqlite.org/datatype3.html
 // https://github.com/sqlite/sqlite/blob/master/src/global.c
diff --git a/sql/sqlite/sqlspec.go b/sql/sqlite/sqlspec.go
index 16eb6c0f..88170a6b 100644
--- a/sql/sqlite/sqlspec.go
+++ b/sql/sqlite/sqlspec.go
@@ -1,3 +1,7 @@
+// Copyright 2021-present The Atlas Authors. All rights reserved.
+// This source code is licensed under the Apache 2.0 license found
+// in the LICENSE file in the root directory of this source tree.
+
 package sqlite
 
 import (
diff --git a/sql/sqlspec/migratespec.go b/sql/sqlspec/migratespec.go
index fc72b5b9..c835defc 100644
--- a/sql/sqlspec/migratespec.go
+++ b/sql/sqlspec/migratespec.go
@@ -1,3 +1,7 @@
+// Copyright 2021-present The Atlas Authors. All rights reserved.
+// This source code is licensed under the Apache 2.0 license found
+// in the LICENSE file in the root directory of this source tree.
+
 package sqlspec
 
 import (
diff --git a/sql/sqlspec/sqlspec.go b/sql/sqlspec/sqlspec.go
index faeba647..974f261f 100644
--- a/sql/sqlspec/sqlspec.go
+++ b/sql/sqlspec/sqlspec.go
@@ -1,3 +1,7 @@
+// Copyright 2021-present The Atlas Authors. All rights reserved.
+// This source code is licensed under the Apache 2.0 license found
+// in the LICENSE file in the root directory of this source tree.
+
 package sqlspec
 
 import (


Test patch:
diff --git a/cmd/atlascmd/atlascmd_test.go b/cmd/atlascmd/atlascmd_test.go
index e09efe37..9ee0d368 100644
--- a/cmd/atlascmd/atlascmd_test.go
+++ b/cmd/atlascmd/atlascmd_test.go
@@ -5,7 +5,9 @@
 package atlascmd
 
 import (
+	"bytes"
 	"os"
+	"os/exec"
 	"testing"
 
 	"ariga.io/atlas/cmd/atlascmd/update"
@@ -26,3 +28,50 @@ func TestEnv_Set(t *testing.T) {
 	require.NoError(t, err)
 	require.Equal(t, "ATLAS_NO_UPDATE_NOTIFIER=test\n", out)
 }
+
+func TestCLI_Version(t *testing.T) {
+	// Required to have a clean "stderr" while running first time.
+	require.NoError(t, exec.Command("go", "run", "-mod=mod", "ariga.io/atlas/cmd/atlas").Run())
+	tests := []struct {
+		name     string
+		cmd      *exec.Cmd
+		expected string
+	}{
+		{
+			name: "dev mode",
+			cmd: exec.Command("go", "run", "ariga.io/atlas/cmd/atlas",
+				"version",
+			),
+			expected: "atlas version - development\nhttps://github.com/ariga/atlas/releases/latest\n",
+		},
+		{
+			name: "release",
+			cmd: exec.Command("go", "run",
+				"-ldflags",
+				"-X ariga.io/atlas/cmd/atlascmd.version=v1.2.3",
+				"ariga.io/atlas/cmd/atlas",
+				"version",
+			),
+			expected: "atlas version v1.2.3\nhttps://github.com/ariga/atlas/releases/tag/v1.2.3\n",
+		},
+		{
+			name: "canary",
+			cmd: exec.Command("go", "run",
+				"-ldflags",
+				"-X ariga.io/atlas/cmd/atlascmd.version=v0.3.0-6539f2704b5d-canary",
+				"ariga.io/atlas/cmd/atlas",
+				"version",
+			),
+			expected: "atlas version v0.3.0-6539f2704b5d-canary\nhttps://github.com/ariga/atlas/releases/latest\n",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			t.Setenv("ATLAS_NO_UPDATE_NOTIFIER", "true")
+			stdout := bytes.NewBuffer(nil)
+			tt.cmd.Stdout = stdout
+			require.NoError(t, tt.cmd.Run())
+			require.Equal(t, tt.expected, stdout.String())
+		})
+	}
+}
diff --git a/cmd/atlascmd/update/update_test.go b/cmd/atlascmd/update/update_test.go
index 84b1eb46..0096e8cd 100644
--- a/cmd/atlascmd/update/update_test.go
+++ b/cmd/atlascmd/update/update_test.go
@@ -1,3 +1,7 @@
+// Copyright 2021-present The Atlas Authors. All rights reserved.
+// This source code is licensed under the Apache 2.0 license found
+// in the LICENSE file in the root directory of this source tree.
+
 package update
 
 import (
diff --git a/internal/integration/hclsqlspec/hclsqlspec_test.go b/internal/integration/hclsqlspec/hclsqlspec_test.go
index 5cb97011..a228a87a 100644
--- a/internal/integration/hclsqlspec/hclsqlspec_test.go
+++ b/internal/integration/hclsqlspec/hclsqlspec_test.go
@@ -1,3 +1,7 @@
+// Copyright 2021-present The Atlas Authors. All rights reserved.
+// This source code is licensed under the Apache 2.0 license found
+// in the LICENSE file in the root directory of this source tree.
+
 package hclsqlspec
 
 import (
diff --git a/internal/integration/hclsqlspec/migrate_test.go b/internal/integration/hclsqlspec/migrate_test.go
index cc7e8355..3fd56328 100644
--- a/internal/integration/hclsqlspec/migrate_test.go
+++ b/internal/integration/hclsqlspec/migrate_test.go
@@ -1,3 +1,7 @@
+// Copyright 2021-present The Atlas Authors. All rights reserved.
+// This source code is licensed under the Apache 2.0 license found
+// in the LICENSE file in the root directory of this source tree.
+
 package hclsqlspec
 
 import (
diff --git a/internal/integration/integration_test.go b/internal/integration/integration_test.go
index 107e53e7..c97075de 100644
--- a/internal/integration/integration_test.go
+++ b/internal/integration/integration_test.go
@@ -1,3 +1,7 @@
+// Copyright 2021-present The Atlas Authors. All rights reserved.
+// This source code is licensed under the Apache 2.0 license found
+// in the LICENSE file in the root directory of this source tree.
+
 package integration
 
 import (
@@ -406,53 +410,6 @@ func testCLISchemaDiff(t T, dsn string) {
 	require.Contains(t, stdout.String(), "Schemas are synced, no changes to be made.")
 }
 
-func TestCLI_Version(t *testing.T) {
-
-	require.NoError(t, exec.Command("go", "run", "-mod=mod", "ariga.io/atlas/cmd/atlas").Run())
-	tests := []struct {
-		name     string
-		cmd      *exec.Cmd
-		expected string
-	}{
-		{
-			name: "dev mode",
-			cmd: exec.Command("go", "run", "ariga.io/atlas/cmd/atlas",
-				"version",
-			),
-			expected: "atlas CLI version - development\nhttps://github.com/ariga/atlas/releases/latest\n",
-		},
-		{
-			name: "release",
-			cmd: exec.Command("go", "run",
-				"-ldflags",
-				"-X ariga.io/atlas/cmd/action.version=v1.2.3",
-				"ariga.io/atlas/cmd/atlas",
-				"version",
-			),
-			expected: "atlas CLI version v1.2.3\nhttps://github.com/ariga/atlas/releases/tag/v1.2.3\n",
-		},
-		{
-			name: "canary",
-			cmd: exec.Command("go", "run",
-				"-ldflags",
-				"-X ariga.io/atlas/cmd/action.version=v0.3.0-6539f2704b5d-canary",
-				"ariga.io/atlas/cmd/atlas",
-				"version",
-			),
-			expected: "atlas CLI version v0.3.0-6539f2704b5d-canary\nhttps://github.com/ariga/atlas/releases/latest\n",
-		},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			t.Setenv("ATLAS_NO_UPDATE_NOTIFIER", "true")
-			stdout := bytes.NewBuffer(nil)
-			tt.cmd.Stdout = stdout
-			require.NoError(t, tt.cmd.Run())
-			require.Equal(t, tt.expected, stdout.String())
-		})
-	}
-}
-
 func ensureNoChange(t T, tables ...*schema.Table) {
 	realm := t.loadRealm()
 	require.Equal(t, len(realm.Schemas[0].Tables), len(tables))
diff --git a/schema/schemaspec/extension_test.go b/schema/schemaspec/extension_test.go
index 23af261d..e749fe3c 100644
--- a/schema/schemaspec/extension_test.go
+++ b/schema/schemaspec/extension_test.go
@@ -1,3 +1,7 @@
+// Copyright 2021-present The Atlas Authors. All rights reserved.
+// This source code is licensed under the Apache 2.0 license found
+// in the LICENSE file in the root directory of this source tree.
+
 package schemaspec_test
 
 import (
diff --git a/schema/schemaspec/schemahcl/hcl_test.go b/schema/schemaspec/schemahcl/hcl_test.go
index ce54a6e1..348401c3 100644
--- a/schema/schemaspec/schemahcl/hcl_test.go
+++ b/schema/schemaspec/schemahcl/hcl_test.go
@@ -1,3 +1,7 @@
+// Copyright 2021-present The Atlas Authors. All rights reserved.
+// This source code is licensed under the Apache 2.0 license found
+// in the LICENSE file in the root directory of this source tree.
+
 package schemahcl
 
 import (
diff --git a/schema/schemaspec/schemahcl/types_test.go b/schema/schemaspec/schemahcl/types_test.go
index 3cf4ed93..d4384b81 100644
--- a/schema/schemaspec/schemahcl/types_test.go
+++ b/schema/schemaspec/schemahcl/types_test.go
@@ -1,3 +1,7 @@
+// Copyright 2021-present The Atlas Authors. All rights reserved.
+// This source code is licensed under the Apache 2.0 license found
+// in the LICENSE file in the root directory of this source tree.
+
 package schemahcl
 
 import (
diff --git a/schema/schemaspec/spec_test.go b/schema/schemaspec/spec_test.go
index 8022d6fb..eef214e7 100644
--- a/schema/schemaspec/spec_test.go
+++ b/schema/schemaspec/spec_test.go
@@ -1,3 +1,7 @@
+// Copyright 2021-present The Atlas Authors. All rights reserved.
+// This source code is licensed under the Apache 2.0 license found
+// in the LICENSE file in the root directory of this source tree.
+
 package schemaspec
 
 import (
diff --git a/sql/internal/specutil/convert_test.go b/sql/internal/specutil/convert_test.go
index 568a1930..422d56e5 100644
--- a/sql/internal/specutil/convert_test.go
+++ b/sql/internal/specutil/convert_test.go
@@ -1,3 +1,7 @@
+// Copyright 2021-present The Atlas Authors. All rights reserved.
+// This source code is licensed under the Apache 2.0 license found
+// in the LICENSE file in the root directory of this source tree.
+
 package specutil
 
 import (
diff --git a/sql/mysql/sqlspec_test.go b/sql/mysql/sqlspec_test.go
index e8f7dafe..86ab2a4f 100644
--- a/sql/mysql/sqlspec_test.go
+++ b/sql/mysql/sqlspec_test.go
@@ -1,3 +1,7 @@
+// Copyright 2021-present The Atlas Authors. All rights reserved.
+// This source code is licensed under the Apache 2.0 license found
+// in the LICENSE file in the root directory of this source tree.
+
 package mysql
 
 import (
diff --git a/sql/postgres/sqlspec_test.go b/sql/postgres/sqlspec_test.go
index f8b752a4..f19c9967 100644
--- a/sql/postgres/sqlspec_test.go
+++ b/sql/postgres/sqlspec_test.go
@@ -1,3 +1,7 @@
+// Copyright 2021-present The Atlas Authors. All rights reserved.
+// This source code is licensed under the Apache 2.0 license found
+// in the LICENSE file in the root directory of this source tree.
+
 package postgres
 
 import (
diff --git a/sql/sqlite/driver_test.go b/sql/sqlite/driver_test.go
new file mode 100644
index 00000000..bc123cdf
--- /dev/null
+++ b/sql/sqlite/driver_test.go
@@ -0,0 +1,48 @@
+// Copyright 2021-present The Atlas Authors. All rights reserved.
+// This source code is licensed under the Apache 2.0 license found
+// in the LICENSE file in the root directory of this source tree.
+
+package sqlite
+
+import (
+	"context"
+	"os"
+	"path/filepath"
+	"strconv"
+	"testing"
+	"time"
+
+	"github.com/stretchr/testify/require"
+)
+
+func TestDriver_LockAcquired(t *testing.T) {
+	drv := &Driver{}
+
+	// Acquiring a lock does work.
+	unlock, err := drv.Lock(context.Background(), "lock", time.Second)
+	require.NoError(t, err)
+	require.NotNil(t, unlock)
+
+	// Acquiring a lock on the same value will fail.
+	_, err = drv.Lock(context.Background(), "lock", time.Second)
+	require.Error(t, err)
+
+	// After unlock it will succeed again.
+	require.NoError(t, unlock())
+	_, err = drv.Lock(context.Background(), "lock", time.Second)
+	require.NoError(t, err)
+	require.NotNil(t, unlock)
+
+	// Acquiring a lock on a value that has been expired works.
+	dir, err := os.UserCacheDir()
+	require.NoError(t, err)
+	require.NoError(t, os.WriteFile(
+		filepath.Join(dir, "lock.lock"),
+		[]byte(strconv.FormatInt(time.Now().Add(-time.Second).UnixNano(), 10)),
+		0666,
+	))
+	_, err = drv.Lock(context.Background(), "lock", time.Second)
+
+	// Acquiring a lock on another value works as well.
+	_, err = drv.Lock(context.Background(), "another", time.Second)
+}