nebius/SWE-rebench-V2-PRs huggingface dataset:
Repository: ariga/atlas
Pull request #2932 (2024-07-08 11:12:50)

schemahcl: support variables in dynamic blocks


Patch:
diff --git a/schemahcl/schemahcl.go b/schemahcl/schemahcl.go
index 12d51125..c75ef282 100644
--- a/schemahcl/schemahcl.go
+++ b/schemahcl/schemahcl.go
@@ -368,7 +368,7 @@ func (s *State) Eval(parsed *hclparse.Parser, v any, input map[string]cty.Value)
 		blocks := make([]*hclsyntax.Block, 0, len(metaBlocks))
 		for name, bs := range metaBlocks {
 			for _, b := range bs {
-				nb, err := forEachBlocks(ctx, b)
+				nb, err := s.forEachBlocks(ctx, b)
 				if err != nil {
 					return err
 				}
@@ -1020,7 +1020,7 @@ func hclList(items []hclwrite.Tokens) hclwrite.Tokens {
 	return t
 }
 
-func forEachBlocks(ctx *hcl.EvalContext, b *hclsyntax.Block) ([]*hclsyntax.Block, error) {
+func (s *State) forEachBlocks(ctx *hcl.EvalContext, b *hclsyntax.Block) ([]*hclsyntax.Block, error) {
 	forEach, diags := b.Body.Attributes[forEachAttr].Expr.Value(ctx)
 	if diags.HasErrors() {
 		return nil, diags
@@ -1039,7 +1039,7 @@ func forEachBlocks(ctx *hcl.EvalContext, b *hclsyntax.Block) ([]*hclsyntax.Block
 				"value": v,
 			}),
 		}
-		nb, err := copyBlock(nctx, b)
+		nb, err := s.copyBlock(nctx, b, []string{b.Type})
 		if err != nil {
 			return nil, fmt.Errorf("schemahcl: evaluate block for value %q: %w", v, err)
 		}
@@ -1048,7 +1048,7 @@ func forEachBlocks(ctx *hcl.EvalContext, b *hclsyntax.Block) ([]*hclsyntax.Block
 	return blocks, nil
 }
 
-func copyBlock(ctx *hcl.EvalContext, b *hclsyntax.Block) (*hclsyntax.Block, error) {
+func (s *State) copyBlock(ctx *hcl.EvalContext, b *hclsyntax.Block, scope []string) (*hclsyntax.Block, error) {
 	nb := &hclsyntax.Block{
 		Type:      b.Type,
 		Labels:    b.Labels,
@@ -1059,7 +1059,7 @@ func copyBlock(ctx *hcl.EvalContext, b *hclsyntax.Block) (*hclsyntax.Block, erro
 		},
 	}
 	for k, v := range b.Body.Attributes {
-		x, diags := v.Expr.Value(ctx)
+		x, diags := v.Expr.Value(s.mayScopeContext(ctx, append(scope, k)))
 		if diags.HasErrors() {
 			return nil, diags
 		}
@@ -1068,7 +1068,7 @@ func copyBlock(ctx *hcl.EvalContext, b *hclsyntax.Block) (*hclsyntax.Block, erro
 		nb.Body.Attributes[k] = &nv
 	}
 	for _, v := range b.Body.Blocks {
-		nv, err := copyBlock(ctx, v)
+		nv, err := s.copyBlock(ctx, v, append(scope, v.Type))
 		if err != nil {
 			return nil, err
 		}


Test patch:
diff --git a/schemahcl/schemahcl_test.go b/schemahcl/schemahcl_test.go
index f7d58bdd..ad00c17e 100644
--- a/schemahcl/schemahcl_test.go
+++ b/schemahcl/schemahcl_test.go
@@ -433,6 +433,7 @@ env "prod" {
 env "staging" {
   for_each = toset(var.domains)
   url = "${each.value.name}:${each.value.port}"
+  driver = MYSQL
 }
 
 env "dev" {
@@ -445,6 +446,7 @@ env "dev" {
 `)
 	)
 	require.NoError(t, New(
+		WithScopedEnums("env.driver", "MYSQL", "POSTGRES"),
 		WithDataSource("sql", func(_ context.Context, ectx *hcl.EvalContext, b *hclsyntax.Block) (cty.Value, error) {
 			attrs, diags := b.Body.JustAttributes()
 			if diags.HasErrors() {
Repository: ariga/atlas
Pull request #2935 (2024-07-09 04:58:43)

schemahcl: attach position to remain field


Patch:
diff --git a/schemahcl/extension.go b/schemahcl/extension.go
index 09d01399..16ac86c9 100644
--- a/schemahcl/extension.go
+++ b/schemahcl/extension.go
@@ -221,6 +221,11 @@ func (r *Resource) as(target any) error {
 		children := childrenOfType(r, childType)
 		extras.Children = append(extras.Children, children...)
 	}
+	// In case the resource contains a remain (DefaultExtension)
+	// field, attach to it the position.
+	if r.rang != nil && rem.Remain() != nil {
+		rem.Remain().SetRange(r.rang)
+	}
 	return nil
 }
 


Test patch:
diff --git a/schemahcl/schemahcl_test.go b/schemahcl/schemahcl_test.go
index ad00c17e..315547f3 100644
--- a/schemahcl/schemahcl_test.go
+++ b/schemahcl/schemahcl_test.go
@@ -1101,6 +1101,10 @@ mixed3 = ["string1", "string1"]
 func Test_WithPos(t *testing.T) {
 	var (
 		doc struct {
+			Bar struct {
+				A int `spec:"a"`
+				DefaultExtension
+			} `spec:"bar"`
 			DefaultExtension
 		}
 		b = []byte(`
@@ -1111,6 +1115,9 @@ foo {
   }
 }
 baz = 1
+bar {
+  a = 1
+}
 `)
 	)
 	require.NoError(t, New(WithPos()).EvalBytes(b, &doc, nil))
@@ -1123,6 +1130,7 @@ baz = 1
 	require.Equal(t, 3, rs[1].Range().Start.Line)
 	require.Equal(t, 4, rs[1].Children[0].Range().Start.Line)
 	require.Equal(t, 5, rs[1].Children[0].Attrs[0].Range().Start.Line)
+	require.NotNil(t, doc.Bar.Extra.Range(), "position should be attached to the resource")
 }
 
 func TestExtendedBlockDef(t *testing.T) {
Repository: ariga/atlas
Pull request #2995 (2024-07-23 08:09:04)

sql/internal/specutil: add mightheredoc helper


Patch:
diff --git a/sql/internal/specutil/convert.go b/sql/internal/specutil/convert.go
index 7d47ab5b..5273ac03 100644
--- a/sql/internal/specutil/convert.go
+++ b/sql/internal/specutil/convert.go
@@ -5,6 +5,7 @@
 package specutil
 
 import (
+	"bytes"
 	"errors"
 	"fmt"
 	"slices"
@@ -680,12 +681,9 @@ func FromView(v *schema.View, colFn ViewColumnSpecFunc, idxFn IndexSpecFunc) (*s
 		}
 		spec.Indexes = append(spec.Indexes, i)
 	}
-	as := normalizeCRLF(v.Def)
 	// In case the view definition is multi-line,
 	// format it as indented heredoc with two spaces.
-	if lines := strings.Split(as, "\n"); len(lines) > 1 {
-		as = fmt.Sprintf("<<-SQL\n  %s\n  SQL", strings.Join(lines, "\n  "))
-	}
+	as := MightHeredoc(v.Def)
 	embed := &schemahcl.Resource{
 		Attrs: []*schemahcl.Attr{
 			schemahcl.StringAttr("as", as),
@@ -717,6 +715,30 @@ func normalizeCRLF(s string) string {
 	return s
 }
 
+// MightHeredoc returns the string as an indented heredoc if it has multiple lines.
+func MightHeredoc(s string) string {
+	s = normalizeCRLF(strings.TrimSpace(s))
+	// In case the given definition is multi-line,
+	// format it as indented heredoc with two spaces.
+	if lines := strings.Split(s, "\n"); len(lines) > 1 {
+		var b bytes.Buffer
+		b.Grow(len(s))
+		b.WriteString("<<-SQL\n")
+		for _, l := range lines {
+			// Skip spaces-only lines, as editors stripped these spaces off,
+			// and HCL parser results a different string for them.
+			if strings.TrimSpace(l) != "" {
+				b.WriteString("  ")
+				b.WriteString(l)
+			}
+			b.WriteByte('\n')
+		}
+		b.WriteString("  SQL")
+		s = b.String()
+	}
+	return s
+}
+
 // dependsOn returns the depends_on attribute for the given objects.
 func dependsOn(realm *schema.Realm, objects []schema.Object) (*schemahcl.Attr, bool) {
 	var (


Test patch:
diff --git a/sql/internal/specutil/convert_test.go b/sql/internal/specutil/convert_test.go
index 6b00d20d..c4fb8dea 100644
--- a/sql/internal/specutil/convert_test.go
+++ b/sql/internal/specutil/convert_test.go
@@ -159,3 +159,49 @@ func TestFromView(t *testing.T) {
 	require.NoError(t, err)
 	require.Equal(t, "<<-SQL\n  SELECT * FROM users\n   WHERE c NOT LIKE \"\\r\\n\"\n  SQL", s)
 }
+
+func TestMightHeredoc(t *testing.T) {
+	for _, tt := range []struct {
+		input    string
+		expected string
+	}{
+		{
+			input:    "SELECT * FROM users",
+			expected: "SELECT * FROM users",
+		},
+		{
+			input: `
+SELECT
+  *
+  FROM users
+  WHERE active`,
+			expected: `<<-SQL
+  SELECT
+    *
+    FROM users
+    WHERE active
+  SQL`,
+		},
+		{
+			input: `
+-- The line below includes spaces.
+  
+	
+SELECT
+  *
+  FROM users
+  WHERE active`,
+			expected: `<<-SQL
+  -- The line below includes spaces.
+
+
+  SELECT
+    *
+    FROM users
+    WHERE active
+  SQL`,
+		},
+	} {
+		require.Equal(t, tt.expected, MightHeredoc(tt.input))
+	}
+}
Repository: ariga/atlas
Pull request #2997 (2024-07-24 09:46:52)

sql/internal/specutil: use cty.String for literal numbers used in tex…
…t-like types


Patch:
diff --git a/sql/internal/specutil/convert.go b/sql/internal/specutil/convert.go
index 5273ac03..852d8211 100644
--- a/sql/internal/specutil/convert.go
+++ b/sql/internal/specutil/convert.go
@@ -940,6 +940,13 @@ func ConvertGenExpr(r *schemahcl.Resource, c *schema.Column, t func(string) stri
 
 // ColumnDefault converts the column default into cty.Value.
 func ColumnDefault(c *schema.Column) (cty.Value, error) {
+	var textlike bool
+	if c.Type != nil {
+		switch c.Type.Type.(type) {
+		case *schema.StringType, *schema.EnumType:
+			textlike = true
+		}
+	}
 	switch x := schema.UnderlyingExpr(c.Default).(type) {
 	case nil:
 		return cty.NilVal, nil
@@ -964,7 +971,7 @@ func ColumnDefault(c *schema.Column) (cty.Value, error) {
 				return cty.NilVal, err
 			}
 			return cty.NumberFloatVal(f), nil
-		case sqlx.IsLiteralNumber(x.V):
+		case sqlx.IsLiteralNumber(x.V) && !textlike:
 			switch i, err := strconv.ParseInt(x.V, 10, 64); {
 			case errors.Is(err, strconv.ErrRange):
 				u, err := strconv.ParseUint(x.V, 10, 64)
@@ -978,14 +985,12 @@ func ColumnDefault(c *schema.Column) (cty.Value, error) {
 				return cty.NumberIntVal(i), nil
 			}
 		default:
-			switch c.Type.Type.(type) {
 			// Literal values (non-expressions) are returned
 			// as strings for text-like types.
-			case *schema.StringType, *schema.EnumType:
+			if textlike {
 				return cty.StringVal(x.V), nil
-			default:
-				return cty.NilVal, fmt.Errorf("unsupported literal value %s for column %s", x.V, c.Name)
 			}
+			return cty.NilVal, fmt.Errorf("unsupported literal value %s for column %s", x.V, c.Name)
 		}
 	default:
 		return cty.NilVal, fmt.Errorf("converting expr %T to literal value for column %s", x, c.Name)


Test patch:
diff --git a/sql/internal/specutil/convert_test.go b/sql/internal/specutil/convert_test.go
index c4fb8dea..e9f33454 100644
--- a/sql/internal/specutil/convert_test.go
+++ b/sql/internal/specutil/convert_test.go
@@ -146,6 +146,19 @@ func TestDefault(t *testing.T) {
 	}
 }
 
+func TestColumnDefault_LiteralNumber(t *testing.T) {
+	v, err := ColumnDefault(
+		schema.NewColumn("").SetDefault(&schema.Literal{V: "0"}),
+	)
+	require.NoError(t, err)
+	require.True(t, cty.NumberIntVal(0).Equals(v).True())
+	v, err = ColumnDefault(
+		schema.NewStringColumn("", "text").SetDefault(&schema.Literal{V: "0"}),
+	)
+	require.NoError(t, err)
+	require.True(t, cty.StringVal("0").Equals(v).True())
+}
+
 func TestFromView(t *testing.T) {
 	spec, err := FromView(&schema.View{
 		Name:   "view",
Repository: ariga/atlas
Pull request #3001 (2024-07-25 09:51:20)

sql/internal/specutil: use string values for non number/bool literal


Patch:
diff --git a/sql/internal/specutil/convert.go b/sql/internal/specutil/convert.go
index 852d8211..ada57f79 100644
--- a/sql/internal/specutil/convert.go
+++ b/sql/internal/specutil/convert.go
@@ -965,13 +965,14 @@ func ColumnDefault(c *schema.Column) (cty.Value, error) {
 			return cty.StringVal(s), nil
 		case strings.ToLower(x.V) == "true", strings.ToLower(x.V) == "false":
 			return cty.BoolVal(strings.ToLower(x.V) == "true"), nil
-		case strings.Contains(x.V, "."):
-			f, err := strconv.ParseFloat(x.V, 64)
-			if err != nil {
-				return cty.NilVal, err
-			}
-			return cty.NumberFloatVal(f), nil
 		case sqlx.IsLiteralNumber(x.V) && !textlike:
+			if strings.Contains(x.V, ".") {
+				f, err := strconv.ParseFloat(x.V, 64)
+				if err != nil {
+					return cty.NilVal, err
+				}
+				return cty.NumberFloatVal(f), nil
+			}
 			switch i, err := strconv.ParseInt(x.V, 10, 64); {
 			case errors.Is(err, strconv.ErrRange):
 				u, err := strconv.ParseUint(x.V, 10, 64)
@@ -985,12 +986,8 @@ func ColumnDefault(c *schema.Column) (cty.Value, error) {
 				return cty.NumberIntVal(i), nil
 			}
 		default:
-			// Literal values (non-expressions) are returned
-			// as strings for text-like types.
-			if textlike {
-				return cty.StringVal(x.V), nil
-			}
-			return cty.NilVal, fmt.Errorf("unsupported literal value %s for column %s", x.V, c.Name)
+			// Literal values (non-expressions) are returned as strings.
+			return cty.StringVal(x.V), nil
 		}
 	default:
 		return cty.NilVal, fmt.Errorf("converting expr %T to literal value for column %s", x, c.Name)


Test patch:
diff --git a/sql/internal/specutil/convert_test.go b/sql/internal/specutil/convert_test.go
index e9f33454..dabf339c 100644
--- a/sql/internal/specutil/convert_test.go
+++ b/sql/internal/specutil/convert_test.go
@@ -134,6 +134,14 @@ func TestDefault(t *testing.T) {
 			v: cty.NumberFloatVal(-1024.1024),
 			x: "-1024.1024",
 		},
+		{
+			v: cty.StringVal("{}"),
+			x: "{}",
+		},
+		{
+			v: cty.StringVal("1a.1"),
+			x: "1a.1",
+		},
 	} {
 		// From cty.Value (HCL) to database literal.
 		x, err := Default(tt.v)
Repository: ariga/atlas
Pull request #3012 (2024-07-30 17:12:07)

sql/postgres: support renaming index with qualifiers
Fixed https://github.com/ariga/atlas/issues/3011


Patch:
diff --git a/sql/postgres/migrate.go b/sql/postgres/migrate.go
index ee994085..bc051914 100644
--- a/sql/postgres/migrate.go
+++ b/sql/postgres/migrate.go
@@ -427,8 +427,8 @@ func (s *state) modifyTable(modify *schema.ModifyTable) error {
 			changes = append(changes, &migrate.Change{
 				Source:  change,
 				Comment: fmt.Sprintf("rename an index from %q to %q", change.From.Name, change.To.Name),
-				Cmd:     s.Build("ALTER INDEX").Ident(change.From.Name).P("RENAME TO").Ident(change.To.Name).String(),
-				Reverse: s.Build("ALTER INDEX").Ident(change.To.Name).P("RENAME TO").Ident(change.From.Name).String(),
+				Cmd:     s.Build("ALTER INDEX").SchemaResource(modify.T.Schema, change.From.Name).P("RENAME TO").Ident(change.To.Name).String(),
+				Reverse: s.Build("ALTER INDEX").SchemaResource(modify.T.Schema, change.To.Name).P("RENAME TO").Ident(change.From.Name).String(),
 			})
 		case *schema.ModifyForeignKey:
 			// Foreign-key modification is translated into 2 steps.


Test patch:
diff --git a/sql/postgres/migrate_test.go b/sql/postgres/migrate_test.go
index 1f5d9df9..3cde8a36 100644
--- a/sql/postgres/migrate_test.go
+++ b/sql/postgres/migrate_test.go
@@ -1489,6 +1489,9 @@ func TestPlanChanges(t *testing.T) {
 					},
 				},
 			},
+			options: []migrate.PlanOption{
+				func(o *migrate.PlanOptions) { o.SchemaQualifier = new(string) },
+			},
 			wantPlan: &migrate.Plan{
 				Reversible:    true,
 				Transactional: true,
@@ -1500,6 +1503,29 @@ func TestPlanChanges(t *testing.T) {
 				},
 			},
 		},
+		{
+			changes: []schema.Change{
+				&schema.ModifyTable{
+					T: schema.NewTable("t1").SetSchema(schema.New("s1")),
+					Changes: []schema.Change{
+						&schema.RenameIndex{
+							From: schema.NewIndex("a"),
+							To:   schema.NewIndex("b"),
+						},
+					},
+				},
+			},
+			wantPlan: &migrate.Plan{
+				Reversible:    true,
+				Transactional: true,
+				Changes: []*migrate.Change{
+					{
+						Cmd:     `ALTER INDEX "s1"."a" RENAME TO "b"`,
+						Reverse: `ALTER INDEX "s1"."b" RENAME TO "a"`,
+					},
+				},
+			},
+		},
 		// Invalid serial type.
 		{
 			changes: []schema.Change{
Repository: ariga/atlas
Pull request #3018 (2024-08-02 14:04:09)

sql/postgres: add xid/xid8 to builtin spec types
Closed https://github.com/ariga/atlas/issues/2771


Patch:
diff --git a/sql/postgres/convert.go b/sql/postgres/convert.go
index 30bea838..abac3708 100644
--- a/sql/postgres/convert.go
+++ b/sql/postgres/convert.go
@@ -54,6 +54,7 @@ func FormatType(t schema.Type) (string, error) {
 		f = t.T
 	case *schema.IntegerType:
 		switch f = strings.ToLower(t.T); f {
+		case TypeXID, TypeXID8:
 		case TypeSmallInt, TypeInteger, TypeBigInt:
 		case TypeInt2:
 			f = TypeSmallInt
@@ -214,7 +215,7 @@ func ParseType(typ string) (schema.Type, error) {
 func columnType(c *columnDesc) (schema.Type, error) {
 	var typ schema.Type
 	switch t := c.typ; strings.ToLower(t) {
-	case TypeBigInt, TypeInt8, TypeInt, TypeInteger, TypeInt4, TypeSmallInt, TypeInt2, TypeInt64:
+	case TypeBigInt, TypeInt8, TypeInt, TypeInteger, TypeInt4, TypeSmallInt, TypeInt2, TypeInt64, TypeXID, TypeXID8:
 		typ = &schema.IntegerType{T: t}
 	case TypeBit, TypeBitVar:
 		typ = &BitType{T: t, Len: c.size}
diff --git a/sql/postgres/driver.go b/sql/postgres/driver.go
index 91dec5b0..551a9c65 100644
--- a/sql/postgres/driver.go
+++ b/sql/postgres/driver.go
@@ -438,6 +438,9 @@ const (
 	TypeInt4     = "int4" // integer.
 	TypeInt8     = "int8" // bigint.
 
+	TypeXID  = "xid"  // transaction identifier.
+	TypeXID8 = "xid8" // 64-bit transaction identifier.
+
 	TypeCIDR     = "cidr"
 	TypeInet     = "inet"
 	TypeMACAddr  = "macaddr"
diff --git a/sql/postgres/sqlspec.go b/sql/postgres/sqlspec.go
index 32430c7d..b537272b 100644
--- a/sql/postgres/sqlspec.go
+++ b/sql/postgres/sqlspec.go
@@ -1032,6 +1032,8 @@ var TypeRegistry = schemahcl.NewRegistry(
 		schemahcl.NewTypeSpec(TypeDateRange),
 		schemahcl.NewTypeSpec(TypeDateMultiRange),
 		schemahcl.NewTypeSpec("hstore"),
+		schemahcl.NewTypeSpec(TypeXID),
+		schemahcl.NewTypeSpec(TypeXID8),
 	),
 	// PostgreSQL internal, pseudo, and special types.
 	schemahcl.WithSpecs(func() (specs []*schemahcl.TypeSpec) {


Test patch:
diff --git a/sql/postgres/sqlspec_test.go b/sql/postgres/sqlspec_test.go
index f4df7db6..cb1923d5 100644
--- a/sql/postgres/sqlspec_test.go
+++ b/sql/postgres/sqlspec_test.go
@@ -1986,6 +1986,14 @@ func TestTypes(t *testing.T) {
 			typeExpr: "name",
 			expected: &schema.StringType{T: typeName},
 		},
+		{
+			typeExpr: "xid",
+			expected: &schema.IntegerType{T: TypeXID},
+		},
+		{
+			typeExpr: "xid8",
+			expected: &schema.IntegerType{T: TypeXID8},
+		},
 	} {
 		t.Run(tt.typeExpr, func(t *testing.T) {
 			var test schema.Schema
Repository: ariga/atlas
Pull request #3055 (2024-08-19 18:08:17)

cmdapi: added `glob` function


Patch:
diff --git a/cmd/atlas/internal/cmdapi/project.go b/cmd/atlas/internal/cmdapi/project.go
index 3cf0a836..af764e13 100644
--- a/cmd/atlas/internal/cmdapi/project.go
+++ b/cmd/atlas/internal/cmdapi/project.go
@@ -606,6 +606,7 @@ func parseConfig(ctx context.Context, path, env string, vars map[string]cty.Valu
 			}),
 			schemahcl.WithFunctions(map[string]function.Function{
 				"file":   schemahcl.MakeFileFunc(base),
+				"glob":   schemahcl.MakeGlobFunc(base),
 				"getenv": getEnvFunc,
 			}),
 		)...,
diff --git a/schemahcl/stdlib.go b/schemahcl/stdlib.go
index 10f3f5b7..261be6a2 100644
--- a/schemahcl/stdlib.go
+++ b/schemahcl/stdlib.go
@@ -487,3 +487,39 @@ func MakeFileFunc(base string) function.Function {
 		},
 	})
 }
+
+// MakeGlobFunc returns a function that returns the names of all files
+// matching pattern or nil if there is no matching file
+func MakeGlobFunc(base string) function.Function {
+	return function.New(&function.Spec{
+		Params: []function.Parameter{
+			{
+				Name: "pattern",
+				Type: cty.String,
+			},
+		},
+		Type: function.StaticReturnType(cty.List(cty.String)),
+		Impl: func(args []cty.Value, _ cty.Type) (cty.Value, error) {
+			if !filepath.IsAbs(base) {
+				return cty.NilVal, fmt.Errorf("base directory must be an absolute path. got: %s", base)
+			}
+			path := args[0].AsString()
+			if !filepath.IsAbs(path) {
+				path = filepath.Clean(filepath.Join(base, path))
+			}
+			matches, err := filepath.Glob(path)
+			switch {
+			case err != nil:
+				return cty.NilVal, err
+			case len(matches) == 0:
+				return cty.ListValEmpty(cty.String), nil
+			default:
+				vals := make([]cty.Value, len(matches))
+				for i, match := range matches {
+					vals[i] = cty.StringVal(match)
+				}
+				return cty.ListVal(vals), nil
+			}
+		},
+	})
+}


Test patch:
diff --git a/schemahcl/stdlib_test.go b/schemahcl/stdlib_test.go
index ff74d76d..70b813f6 100644
--- a/schemahcl/stdlib_test.go
+++ b/schemahcl/stdlib_test.go
@@ -177,6 +177,26 @@ func TestMakeFileFunc(t *testing.T) {
 	require.Equal(t, "person \"rotemtam\" {\n  hobby = var.hobby\n}", v.AsString())
 }
 
+func TestMakeGlobFunc(t *testing.T) {
+	fn := MakeGlobFunc("testdata")
+	_, err := fn.Call([]cty.Value{cty.StringVal("foo")})
+	require.EqualError(t, err, "base directory must be an absolute path. got: testdata")
+
+	base, err := filepath.Abs("testdata")
+	require.NoError(t, err)
+	fn = MakeGlobFunc(base)
+	v, err := fn.Call([]cty.Value{cty.StringVal("*.hcl")})
+	require.NoError(t, err)
+
+	var result []string
+	for _, f := range v.AsValueSlice() {
+		p, err := filepath.Rel(base, f.AsString())
+		require.NoError(t, err)
+		result = append(result, p)
+	}
+	require.Equal(t, []string{"a.hcl", "b.hcl", "variables.hcl"}, result)
+}
+
 func Example_RegexpEscapeFunc() {
 	for _, f := range []string{
 		`v  = regexpescape("a|b|c")`,
Repository: ariga/atlas
Pull request #3060 (2024-08-20 11:50:46)

schemahcl: support explicitly skipping spec fields


Patch:
diff --git a/schemahcl/extension.go b/schemahcl/extension.go
index 16ac86c9..0ca5ee0f 100644
--- a/schemahcl/extension.go
+++ b/schemahcl/extension.go
@@ -572,7 +572,7 @@ func specFields(ext any) []fieldDesc {
 	for i := 0; i < t.NumField(); i++ {
 		f := t.Field(i)
 		tag, ok := f.Tag.Lookup("spec")
-		if !ok {
+		if !ok || tag == "-" {
 			continue
 		}
 		d := fieldDesc{tag: tag, StructField: f}


Test patch:
diff --git a/schemahcl/schemahcl_test.go b/schemahcl/schemahcl_test.go
index 315547f3..431581a8 100644
--- a/schemahcl/schemahcl_test.go
+++ b/schemahcl/schemahcl_test.go
@@ -202,6 +202,27 @@ func ExampleMarshal() {
 	// }
 }
 
+func TestIgnore(t *testing.T) {
+	var test struct {
+		IgnoreAttr    string `spec:"-"`
+		NotIgnoreAttr string `spec:"not_ignore_attr"`
+		IgnoreBlock   struct {
+			Name string `spec:",name"`
+		} `spec:"-"`
+		NotIgnore struct {
+			Name string `spec:",name"`
+		} `spec:"not_ignore_block"`
+	}
+	test.IgnoreAttr, test.NotIgnoreAttr = "ignore", "not ignore"
+	test.IgnoreBlock.Name, test.NotIgnore.Name = "ignore", "not ignore"
+	buf, err := Marshal(&test)
+	require.NoError(t, err)
+	require.Equal(t, `not_ignore_attr = "not ignore"
+not_ignore_block "not ignore" {
+}
+`, string(buf))
+}
+
 func TestInterface(t *testing.T) {
 	type (
 		Animal interface {
Repository: ariga/atlas
Pull request #3129 (2024-09-19 08:17:53)

sql/migrate: add code for checking verify migrate versions


Patch:
diff --git a/cmd/atlas/internal/cmdapi/project.go b/cmd/atlas/internal/cmdapi/project.go
index 455d74d7..6f96489d 100644
--- a/cmd/atlas/internal/cmdapi/project.go
+++ b/cmd/atlas/internal/cmdapi/project.go
@@ -190,6 +190,8 @@ type (
 			Apply string `spec:"apply"`
 			// Apply configures the formatting for 'schema diff'.
 			Diff string `spec:"diff"`
+			// Push configures the formatting for 'schema push'.
+			Push string `spec:"push"`
 		} `spec:"schema"`
 		schemahcl.DefaultExtension
 	}
diff --git a/cmd/atlas/internal/cmdapi/schema.go b/cmd/atlas/internal/cmdapi/schema.go
index ac8ebd88..94f78826 100644
--- a/cmd/atlas/internal/cmdapi/schema.go
+++ b/cmd/atlas/internal/cmdapi/schema.go
@@ -574,6 +574,9 @@ func setSchemaEnvFlags(cmd *cobra.Command, env *Env) error {
 		if err := maySetFlag(cmd, flagURL, strings.Join(srcs, ",")); err != nil {
 			return err
 		}
+		if err := maySetFlag(cmd, flagFormat, env.Format.Schema.Push); err != nil {
+			return err
+		}
 	case "test":
 		// Give the "src" precedence over the "url" argument.
 		if len(srcs) > 0 {
diff --git a/sql/migrate/dir.go b/sql/migrate/dir.go
index 3690ab17..38b04540 100644
--- a/sql/migrate/dir.go
+++ b/sql/migrate/dir.go
@@ -513,9 +513,19 @@ func (d *MemDir) Path() string {
 	return d.path
 }
 
+const versionFormat = "20060102150405"
+
 // NewVersion generates a new migration version.
 func NewVersion() string {
-	return time.Now().UTC().Format("20060102150405")
+	return time.Now().UTC().Format(versionFormat)
+}
+
+// CheckVersion checks if the given version is valid Atlas version.
+func CheckVersion(v string) error {
+	if _, err := time.Parse(versionFormat, v); err != nil {
+		return fmt.Errorf("invalid version: %w. Expected format is: %s", err, versionFormat)
+	}
+	return nil
 }
 
 var (


Test patch:
diff --git a/sql/migrate/dir_test.go b/sql/migrate/dir_test.go
index 3170fc14..d330dff2 100644
--- a/sql/migrate/dir_test.go
+++ b/sql/migrate/dir_test.go
@@ -575,6 +575,11 @@ create table t2(c int);
 	require.Nil(t, f)
 }
 
+func TestCheckVersion(t *testing.T) {
+	require.Error(t, migrate.CheckVersion("1"))
+	require.NoError(t, migrate.CheckVersion(migrate.NewVersion()))
+}
+
 func fileNames(r io.Reader) ([]string, error) {
 	var out []string
 	tr := tar.NewReader(r)