nebius/SWE-rebench-V2-PRs huggingface dataset:
Repository: hetznercloud/hcloud-go
Pull request #151 (2020-08-26 12:50:07)

Add `PrimaryDiskSize` Field to `Server`


Patch:
diff --git a/CHANGES.md b/CHANGES.md
index e85d986..f850e4e 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,5 +1,9 @@
 # Changes
 
+## master
+
+* Add `PrimaryDiskSize` Field to `Server`
+
 ## v1.21.1
 
 * Don't send `Authorization` Header when `WithToken` was not called 
diff --git a/hcloud/schema.go b/hcloud/schema.go
index ba5c117..beac330 100644
--- a/hcloud/schema.go
+++ b/hcloud/schema.go
@@ -140,6 +140,7 @@ func ServerFromSchema(s schema.Server) *Server {
 		RescueEnabled:   s.RescueEnabled,
 		Datacenter:      DatacenterFromSchema(s.Datacenter),
 		Locked:          s.Locked,
+		PrimaryDiskSize: s.PrimaryDiskSize,
 		Protection: ServerProtection{
 			Delete:  s.Protection.Delete,
 			Rebuild: s.Protection.Rebuild,
diff --git a/hcloud/schema/server.go b/hcloud/schema/server.go
index 836b3bf..2e10fb2 100644
--- a/hcloud/schema/server.go
+++ b/hcloud/schema/server.go
@@ -23,6 +23,7 @@ type Server struct {
 	Protection      ServerProtection   `json:"protection"`
 	Labels          map[string]string  `json:"labels"`
 	Volumes         []int              `json:"volumes"`
+	PrimaryDiskSize int                `json:"primary_disk_size"`
 }
 
 // ServerProtection defines the schema of a server's resource protection.
diff --git a/hcloud/server.go b/hcloud/server.go
index 4c53f8e..772e658 100644
--- a/hcloud/server.go
+++ b/hcloud/server.go
@@ -35,6 +35,7 @@ type Server struct {
 	Protection      ServerProtection
 	Labels          map[string]string
 	Volumes         []*Volume
+	PrimaryDiskSize int
 }
 
 // ServerProtection represents the protection level of a server.


Test patch:
diff --git a/hcloud/schema_test.go b/hcloud/schema_test.go
index 76c667c..6f90417 100644
--- a/hcloud/schema_test.go
+++ b/hcloud/schema_test.go
@@ -392,6 +392,7 @@ func TestServerFromSchema(t *testing.T) {
 		"included_traffic": 654321,
 		"backup_window": "22-02",
 		"rescue_enabled": true,
+		"primary_disk_size": 20,
 		"image": {
 			"id": 4711,
 			"type": "system",
@@ -479,6 +480,9 @@ func TestServerFromSchema(t *testing.T) {
 	if server.BackupWindow != "22-02" {
 		t.Errorf("unexpected backup window: %v", server.BackupWindow)
 	}
+	if server.PrimaryDiskSize != 20 {
+		t.Errorf("unexpected primary disk size: %v", server.PrimaryDiskSize)
+	}
 	if !server.RescueEnabled {
 		t.Errorf("unexpected rescue enabled state: %v", server.RescueEnabled)
 	}
Repository: hetznercloud/hcloud-go
Pull request #172 (2021-06-02 04:42:28)

Add deleted property to image
Signed-off-by: Lukas Kämmerling <lukas.kaemmerling@hetzner-cloud.de>


Patch:
diff --git a/hcloud/image.go b/hcloud/image.go
index 87e9271..4391200 100644
--- a/hcloud/image.go
+++ b/hcloud/image.go
@@ -32,6 +32,7 @@ type Image struct {
 	Protection ImageProtection
 	Deprecated time.Time // The zero value denotes the image is not deprecated.
 	Labels     map[string]string
+	Deleted    time.Time
 }
 
 // IsDeprecated returns whether the image is deprecated.
@@ -39,6 +40,11 @@ func (image *Image) IsDeprecated() bool {
 	return !image.Deprecated.IsZero()
 }
 
+// IsDeleted returns whether the image is deleted.
+func (image *Image) IsDeleted() bool {
+	return !image.Deleted.IsZero()
+}
+
 // ImageProtection represents the protection level of an image.
 type ImageProtection struct {
 	Delete bool
diff --git a/hcloud/schema.go b/hcloud/schema.go
index a50cafe..940fefc 100644
--- a/hcloud/schema.go
+++ b/hcloud/schema.go
@@ -291,6 +291,7 @@ func ImageFromSchema(s schema.Image) *Image {
 			Delete: s.Protection.Delete,
 		},
 		Deprecated: s.Deprecated,
+		Deleted:    s.Deleted,
 	}
 	if s.Name != nil {
 		i.Name = *s.Name
diff --git a/hcloud/schema/image.go b/hcloud/schema/image.go
index c354d9e..7a3be88 100644
--- a/hcloud/schema/image.go
+++ b/hcloud/schema/image.go
@@ -19,6 +19,7 @@ type Image struct {
 	RapidDeploy bool              `json:"rapid_deploy"`
 	Protection  ImageProtection   `json:"protection"`
 	Deprecated  time.Time         `json:"deprecated"`
+	Deleted     time.Time         `json:"deleted"`
 	Labels      map[string]string `json:"labels"`
 }
 


Test patch:
diff --git a/hcloud/schema_test.go b/hcloud/schema_test.go
index a76c1c7..76895a9 100644
--- a/hcloud/schema_test.go
+++ b/hcloud/schema_test.go
@@ -925,6 +925,7 @@ func TestImageFromSchema(t *testing.T) {
 			"delete": true
 		},
 		"deprecated": "2018-02-28T00:00:00+00:00",
+		"deleted": "2016-01-30T23:55:01+00:00",
 		"labels": {
 			"key": "value",
 			"key2": "value2"
@@ -961,6 +962,9 @@ func TestImageFromSchema(t *testing.T) {
 	if !image.Created.Equal(time.Date(2016, 1, 30, 23, 55, 1, 0, time.UTC)) {
 		t.Errorf("unexpected Created: %v", image.Created)
 	}
+	if !image.Deleted.Equal(time.Date(2016, 1, 30, 23, 55, 1, 0, time.UTC)) {
+		t.Errorf("unexpected Deleted: %v", image.Deleted)
+	}
 	if image.CreatedFrom == nil || image.CreatedFrom.ID != 1 || image.CreatedFrom.Name != "my-server1" {
 		t.Errorf("unexpected CreatedFrom: %v", image.CreatedFrom)
 	}
Repository: hetznercloud/hcloud-go
Pull request #178 (2021-08-05 10:18:34)

Fix firewall rule description


Patch:
diff --git a/hcloud/schema.go b/hcloud/schema.go
index 7c5f52b..8523084 100644
--- a/hcloud/schema.go
+++ b/hcloud/schema.go
@@ -759,6 +759,7 @@ func FirewallFromSchema(s schema.Firewall) *Firewall {
 			DestinationIPs: destinationIPs,
 			Protocol:       FirewallRuleProtocol(rule.Protocol),
 			Port:           rule.Port,
+			Description:    rule.Description,
 		})
 	}
 	return f


Test patch:
diff --git a/hcloud/schema_test.go b/hcloud/schema_test.go
index 76895a9..cea77dc 100644
--- a/hcloud/schema_test.go
+++ b/hcloud/schema_test.go
@@ -2722,7 +2722,8 @@ func TestFirewallFromSchema(t *testing.T) {
 				"ff21:1eac:9a3b:ee58:5ca:990c:8bc9:c03b/128"
 			  ],
 			  "protocol": "tcp",
-			  "port": "80"
+			  "port": "80",
+			  "description": "allow http in"
 			}
 		],
 		"applied_to": [
@@ -2777,6 +2778,9 @@ func TestFirewallFromSchema(t *testing.T) {
 	if *firewall.Rules[0].Port != "80" {
 		t.Errorf("unexpected Rule Port: %s", *firewall.Rules[0].Port)
 	}
+	if *firewall.Rules[0].Description != "allow http in" {
+		t.Errorf("unexpected Rule Description: %s", *firewall.Rules[0].Description)
+	}
 	if len(firewall.AppliedTo) != 2 {
 		t.Errorf("unexpected UsedBy count: %d", len(firewall.AppliedTo))
 	}
Repository: hetznercloud/hcloud-go
Pull request #193 (2022-02-19 08:34:13)

Fix metadata client error detection
Fixes two issues:

1. Metadata client does not recognise unsuccessful HTTP response codes
2. Closed a potential memory leak (not closed HTTP response)


Patch:
diff --git a/hcloud/metadata/client.go b/hcloud/metadata/client.go
index c56f1b9..a95fb10 100644
--- a/hcloud/metadata/client.go
+++ b/hcloud/metadata/client.go
@@ -1,6 +1,7 @@
 package metadata
 
 import (
+	"fmt"
 	"io/ioutil"
 	"net"
 	"net/http"
@@ -71,12 +72,16 @@ func (c *Client) get(path string) (string, error) {
 	if err != nil {
 		return "", err
 	}
-	body, err := ioutil.ReadAll(resp.Body)
+	defer resp.Body.Close()
+	bodyBytes, err := ioutil.ReadAll(resp.Body)
 	if err != nil {
 		return "", err
 	}
-	resp.Body.Close()
-	return string(body), nil
+	body := string(bodyBytes)
+	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
+		return body, fmt.Errorf("response status was %d", resp.StatusCode)
+	}
+	return body, nil
 }
 
 // IsHcloudServer checks if the currently called server is a hcloud server by calling a metadata endpoint


Test patch:
diff --git a/hcloud/metadata/client_test.go b/hcloud/metadata/client_test.go
index 001e76e..ba1e59e 100644
--- a/hcloud/metadata/client_test.go
+++ b/hcloud/metadata/client_test.go
@@ -34,6 +34,24 @@ func newTestEnv() testEnv {
 	}
 }
 
+func TestClient_Base(t *testing.T) {
+	env := newTestEnv()
+	env.Mux.HandleFunc("/ok", func(w http.ResponseWriter, r *http.Request) {
+		w.Write([]byte("ok"))
+	})
+	env.Mux.HandleFunc("/not-found", func(w http.ResponseWriter, r *http.Request) {
+		w.WriteHeader(404)
+		w.Write([]byte("not found"))
+	})
+
+	if body, err := env.Client.get("/ok"); assert.NoError(t, err) {
+		assert.Equal(t, "ok", body)
+	}
+	if body, err := env.Client.get("/not-found"); assert.EqualError(t, err, "response status was 404") {
+		assert.Equal(t, "not found", body)
+	}
+}
+
 func TestClient_IsHcloudServer(t *testing.T) {
 	env := newTestEnv()
 	env.Mux.HandleFunc("/hostname", func(w http.ResponseWriter, r *http.Request) {
Repository: hetznercloud/hcloud-go
Pull request #197 (2022-04-26 10:03:46)

Add labels.go to validate resource labels


Patch:
diff --git a/hcloud/labels.go b/hcloud/labels.go
new file mode 100644
index 0000000..a8c3b4f
--- /dev/null
+++ b/hcloud/labels.go
@@ -0,0 +1,23 @@
+package hcloud
+
+import (
+	"fmt"
+	"regexp"
+)
+
+var keyRegexp = regexp.MustCompile(
+	`^([a-z0-9A-Z]((?:[\-_.]|[a-z0-9A-Z]){0,253}[a-z0-9A-Z])?/)?[a-z0-9A-Z]((?:[\-_.]|[a-z0-9A-Z]|){0,62}[a-z0-9A-Z])?$`)
+var valueRegexp = regexp.MustCompile(`^([a-z0-9A-Z](?:[\-_.]|[a-z0-9A-Z]){0,62})?[a-z0-9A-Z]$`)
+
+func ValidateResourceLabels(labels map[string]interface{}) (bool, error) {
+	for k, v := range labels {
+		if match := keyRegexp.MatchString(k); !match {
+			return false, fmt.Errorf("label key '%s' is not correctly formatted", k)
+		}
+
+		if match := valueRegexp.MatchString(v.(string)); !match {
+			return false, fmt.Errorf("label value '%s' (key: %s) is not correctly formatted", v, k)
+		}
+	}
+	return true, nil
+}


Test patch:
diff --git a/hcloud/labels_test.go b/hcloud/labels_test.go
new file mode 100644
index 0000000..394520e
--- /dev/null
+++ b/hcloud/labels_test.go
@@ -0,0 +1,69 @@
+package hcloud
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestCheckLabels(t *testing.T) {
+	t.Run("correct labels", func(t *testing.T) {
+		labelMap := map[string]interface{}{
+			"label1":                    "correct.de",
+			"label2.de/hallo":           "1correct2.de",
+			"label3-test.de/hallo.welt": "233344444443",
+			"d/d":                       "d",
+		}
+
+		ok, err := ValidateResourceLabels(labelMap)
+		if err != nil {
+			t.Fatal(err)
+		}
+		assert.True(t, ok)
+	})
+	t.Run("incorrect string label values", func(t *testing.T) {
+		incorrectLabels := []string{
+			"incorrect .com",
+			"-incorrect.com",
+			"incorrect.com-",
+			"incorr,ect.com-",
+			"incorrect-111111111111111111111111111111111111111111111111111111111111.com",
+		}
+
+		for _, label := range incorrectLabels {
+			labelMap := map[string]interface{}{
+				"test1": "valid",
+				"test2": label,
+			}
+			ok, err := ValidateResourceLabels(labelMap)
+			assert.Error(t, err)
+			assert.False(t, ok)
+		}
+	})
+	t.Run("incorrect string label keys", func(t *testing.T) {
+		incorrectLabels := []string{
+			"incorrect.de/",
+			"incor rect.de/",
+			"incorrect.de/+",
+			"-incorrect.de",
+			"incorrect.de-",
+			"incorrect.de/tes t",
+			"incorrect.de/test-",
+			"incorrect.de/test-dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
+			"incorrect-11111111111111111111111111111111111111111111111111111111111111111111111111111111" +
+				"11111111111111111111111111111111111111111111111111111111111111111111111111111111" +
+				"11111111111111111111111111111111111111111111111111111111111111111111111111111111" +
+				"11111111111111111111111111111111111111111111111111111111111111111111111111111111" +
+				".de/test",
+		}
+
+		for _, label := range incorrectLabels {
+			labelMap := map[string]interface{}{
+				label: "cor-rect.de",
+			}
+			ok, err := ValidateResourceLabels(labelMap)
+			assert.Error(t, err)
+			assert.False(t, ok)
+		}
+	})
+}
Repository: hetznercloud/hcloud-go
Pull request #207 (2022-07-29 09:10:35)

Allow empty labels


Patch:
diff --git a/hcloud/labels.go b/hcloud/labels.go
index a8c3b4f..e22000a 100644
--- a/hcloud/labels.go
+++ b/hcloud/labels.go
@@ -7,7 +7,7 @@ import (
 
 var keyRegexp = regexp.MustCompile(
 	`^([a-z0-9A-Z]((?:[\-_.]|[a-z0-9A-Z]){0,253}[a-z0-9A-Z])?/)?[a-z0-9A-Z]((?:[\-_.]|[a-z0-9A-Z]|){0,62}[a-z0-9A-Z])?$`)
-var valueRegexp = regexp.MustCompile(`^([a-z0-9A-Z](?:[\-_.]|[a-z0-9A-Z]){0,62})?[a-z0-9A-Z]$`)
+var valueRegexp = regexp.MustCompile(`^(([a-z0-9A-Z](?:[\-_.]|[a-z0-9A-Z]){0,62})?[a-z0-9A-Z]$|$)`)
 
 func ValidateResourceLabels(labels map[string]interface{}) (bool, error) {
 	for k, v := range labels {


Test patch:
diff --git a/hcloud/labels_test.go b/hcloud/labels_test.go
index 394520e..0c43d7f 100644
--- a/hcloud/labels_test.go
+++ b/hcloud/labels_test.go
@@ -13,6 +13,7 @@ func TestCheckLabels(t *testing.T) {
 			"label2.de/hallo":           "1correct2.de",
 			"label3-test.de/hallo.welt": "233344444443",
 			"d/d":                       "d",
+			"empty/label":               "",
 		}
 
 		ok, err := ValidateResourceLabels(labelMap)
Repository: hetznercloud/hcloud-go
Pull request #222 (2022-12-25 20:04:28)

Fix schema for primary IP pricing to reflect the current API response
The /pricing API endpoint for primary IPs does not return individual DCs anymore but just regions ("fsn1", "nbg1", ...). I have changed the key name in the schema and updated the test for the new format.

apricote: Looks like we changed the API after implementing it in `hcloud-go`. I will try to make sure that such things do not happen in the future.

Patch:
diff --git a/hcloud/pricing.go b/hcloud/pricing.go
index 67be21f..b562fc1 100644
--- a/hcloud/pricing.go
+++ b/hcloud/pricing.go
@@ -56,7 +56,8 @@ type FloatingIPTypePricing struct {
 // PrimaryIPTypePricing defines the schema of pricing information for a primary IP
 // type at a datacenter.
 type PrimaryIPTypePricing struct {
-	Datacenter string
+	Datacenter string // Deprecated: the API does not return pricing for the individual DCs anymore
+	Location   string
 	Hourly     PrimaryIPPrice
 	Monthly    PrimaryIPPrice
 }
diff --git a/hcloud/schema.go b/hcloud/schema.go
index 100917a..091426b 100644
--- a/hcloud/schema.go
+++ b/hcloud/schema.go
@@ -721,7 +721,7 @@ func PricingFromSchema(s schema.Pricing) Pricing {
 		var pricings []PrimaryIPTypePricing
 		for _, price := range primaryIPType.Prices {
 			p := PrimaryIPTypePricing{
-				Datacenter: price.Datacenter,
+				Location: price.Location,
 				Monthly: PrimaryIPPrice{
 					Net:   price.PriceMonthly.Net,
 					Gross: price.PriceMonthly.Gross,
diff --git a/hcloud/schema/pricing.go b/hcloud/schema/pricing.go
index b97a2f8..da3837e 100644
--- a/hcloud/schema/pricing.go
+++ b/hcloud/schema/pricing.go
@@ -97,7 +97,8 @@ type PricingGetResponse struct {
 // PricingPrimaryIPTypePrice defines the schema of pricing information for a primary IP
 // type at a datacenter.
 type PricingPrimaryIPTypePrice struct {
-	Datacenter   string `json:"datacenter"`
+	Datacenter   string `json:"datacenter"` // Deprecated: the API does not return pricing for the individual DCs anymore
+	Location     string `json:"location"`
 	PriceHourly  Price  `json:"price_hourly"`
 	PriceMonthly Price  `json:"price_monthly"`
 }


Test patch:
diff --git a/hcloud/schema_test.go b/hcloud/schema_test.go
index a4313a1..fd0a364 100644
--- a/hcloud/schema_test.go
+++ b/hcloud/schema_test.go
@@ -2044,7 +2044,7 @@ func TestPricingFromSchema(t *testing.T) {
 			{
 				"prices": [
 				{
-					"datacenter": "fsn1-dc8",
+					"location": "fsn1",
 					"price_hourly": {
 					"gross": "1.1900000000000000",
 					"net": "1.0000000000"
@@ -2185,8 +2185,8 @@ func TestPricingFromSchema(t *testing.T) {
 		if len(ip.Pricings) != 1 {
 			t.Errorf("unexpected number of prices: %d", len(ip.Pricings))
 		} else {
-			if ip.Pricings[0].Datacenter != "fsn1-dc8" {
-				t.Errorf("unexpected Datacenter: %v", ip.Pricings[0].Datacenter)
+			if ip.Pricings[0].Location != "fsn1" {
+				t.Errorf("unexpected Location: %v", ip.Pricings[0].Location)
 			}
 			if ip.Pricings[0].Monthly.Net != "1.0000000000" {
 				t.Errorf("unexpected Monthly.Net: %v", ip.Pricings[0].Monthly.Net)
Repository: hetznercloud/hcloud-go
Pull request #254 (2023-05-05 13:59:44)

feat(iso): extend ISOClient by AllWithOpts method


Patch:
diff --git a/hcloud/iso.go b/hcloud/iso.go
index d5814cb..d0a2a13 100644
--- a/hcloud/iso.go
+++ b/hcloud/iso.go
@@ -134,10 +134,12 @@ func (c *ISOClient) List(ctx context.Context, opts ISOListOpts) ([]*ISO, *Respon
 
 // All returns all ISOs.
 func (c *ISOClient) All(ctx context.Context) ([]*ISO, error) {
-	allISOs := []*ISO{}
+	return c.AllWithOpts(ctx, ISOListOpts{ListOpts: ListOpts{PerPage: 50}})
+}
 
-	opts := ISOListOpts{}
-	opts.PerPage = 50
+// AllWithOpts returns all ISOs for the given options.
+func (c *ISOClient) AllWithOpts(ctx context.Context, opts ISOListOpts) ([]*ISO, error) {
+	allISOs := make([]*ISO, 0)
 
 	err := c.client.all(func(page int) (*Response, error) {
 		opts.Page = page


Test patch:
diff --git a/hcloud/iso_test.go b/hcloud/iso_test.go
index 5c05e06..1d010a7 100644
--- a/hcloud/iso_test.go
+++ b/hcloud/iso_test.go
@@ -242,4 +242,65 @@ func TestISOClient(t *testing.T) {
 			t.Errorf("unexpected isos")
 		}
 	})
+
+	t.Run("AllWithOpts", func(t *testing.T) {
+		env := newTestEnv()
+		defer env.Teardown()
+
+		env.Mux.HandleFunc("/isos", func(w http.ResponseWriter, r *http.Request) {
+			if name := r.URL.Query().Get("name"); name != "my-iso" {
+				t.Errorf("unexpected name: %s", name)
+			}
+			w.Header().Set("Content-Type", "application/json")
+			var isos []schema.ISO
+			var meta schema.Meta
+			if name := r.URL.Query().Get("page"); name == "1" {
+				isos = []schema.ISO{
+					{ID: 1},
+					{ID: 2},
+				}
+				meta = schema.Meta{
+					Pagination: &schema.MetaPagination{
+						Page:         1,
+						NextPage:     2,
+						LastPage:     2,
+						PerPage:      2,
+						TotalEntries: 3,
+					},
+				}
+			} else {
+				isos = []schema.ISO{
+					{ID: 3},
+				}
+				meta = schema.Meta{
+					Pagination: &schema.MetaPagination{
+						Page:         2,
+						LastPage:     2,
+						PerPage:      2,
+						TotalEntries: 3,
+					},
+				}
+			}
+			json.NewEncoder(w).Encode(struct {
+				ISOs []schema.ISO `json:"isos"`
+				Meta schema.Meta  `json:"meta"`
+			}{
+				ISOs: isos,
+				Meta: meta,
+			})
+		})
+
+		ctx := context.Background()
+		opts := ISOListOpts{Name: "my-iso"}
+		isos, err := env.Client.ISO.AllWithOpts(ctx, opts)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if len(isos) != 3 {
+			t.Fatalf("expected 3 isos; got %d", len(isos))
+		}
+		if isos[0].ID != 1 || isos[1].ID != 2 || isos[2].ID != 3 {
+			t.Errorf("unexpected isos")
+		}
+	})
 }
Repository: hetznercloud/hcloud-go
Pull request #273 (2023-06-16 10:52:12)

fix: adjust label validation for max length of 63 characters
According to the api documentation, the length of a label value must be a string of 63 characters or fewer.
The currently used regex for the validation allows 64 char long values.


Patch:
diff --git a/hcloud/labels.go b/hcloud/labels.go
index e22000a..3dc7d78 100644
--- a/hcloud/labels.go
+++ b/hcloud/labels.go
@@ -6,8 +6,8 @@ import (
 )
 
 var keyRegexp = regexp.MustCompile(
-	`^([a-z0-9A-Z]((?:[\-_.]|[a-z0-9A-Z]){0,253}[a-z0-9A-Z])?/)?[a-z0-9A-Z]((?:[\-_.]|[a-z0-9A-Z]|){0,62}[a-z0-9A-Z])?$`)
-var valueRegexp = regexp.MustCompile(`^(([a-z0-9A-Z](?:[\-_.]|[a-z0-9A-Z]){0,62})?[a-z0-9A-Z]$|$)`)
+	`^([a-z0-9A-Z]((?:[\-_.]|[a-z0-9A-Z]){0,253}[a-z0-9A-Z])?/)?[a-z0-9A-Z]((?:[\-_.]|[a-z0-9A-Z]|){0,61}[a-z0-9A-Z])?$`)
+var valueRegexp = regexp.MustCompile(`^(([a-z0-9A-Z](?:[\-_.]|[a-z0-9A-Z]){0,61})?[a-z0-9A-Z]$|$)`)
 
 func ValidateResourceLabels(labels map[string]interface{}) (bool, error) {
 	for k, v := range labels {


Test patch:
diff --git a/hcloud/labels_test.go b/hcloud/labels_test.go
index 0c43d7f..48ffe40 100644
--- a/hcloud/labels_test.go
+++ b/hcloud/labels_test.go
@@ -29,6 +29,7 @@ func TestCheckLabels(t *testing.T) {
 			"incorrect.com-",
 			"incorr,ect.com-",
 			"incorrect-111111111111111111111111111111111111111111111111111111111111.com",
+			"63-characters-are-allowed-in-a-label__this-is-one-character-more",
 		}
 
 		for _, label := range incorrectLabels {
Repository: losisin/helm-values-schema-json
Pull request #166 (2025-06-06 11:31:00)

Format loaded bytes with B, KB, and MB
Shows different units depending on size.

This is mostly to prevent it from showing `0KB` when file is below 1 KB

The threshold to switch from B to KB at 2 KB is completely arbitrary. I just felt like showing something like `1200B` is better than `1KB`



Patch:
diff --git a/pkg/bundle.go b/pkg/bundle.go
index 11773b1..178182b 100644
--- a/pkg/bundle.go
+++ b/pkg/bundle.go
@@ -437,7 +437,7 @@ func (loader FileLoader) Load(_ context.Context, ref *url.URL) (*Schema, error)
 		return nil, fmt.Errorf("read $ref=%q file: %w", ref, err)
 	}
 
-	fmt.Printf("=> got %dKB\n", len(b)/1000)
+	fmt.Printf("=> got %s\n", formatSizeBytes(len(b)))
 
 	switch filepath.Ext(path) {
 	case ".yml", ".yaml":
@@ -593,7 +593,7 @@ func (loader HTTPLoader) Load(ctx context.Context, ref *url.URL) (*Schema, error
 	}
 
 	duration := time.Since(start)
-	fmt.Printf("=> got %dKB in %s\n", len(b)/1000, duration.Truncate(time.Millisecond))
+	fmt.Printf("=> got %s in %s\n", formatSizeBytes(len(b)), duration.Truncate(time.Millisecond))
 
 	if isYAML {
 		var schema Schema
@@ -617,3 +617,14 @@ var loaderContextReferrer = loaderContextKey(1)
 func ContextWithLoaderReferrer(parent context.Context, referrer string) context.Context {
 	return context.WithValue(parent, loaderContextReferrer, referrer)
 }
+
+func formatSizeBytes(size int) string {
+	switch {
+	case size < 2_000:
+		return fmt.Sprintf("%dB", size)
+	case size < 2_000_000:
+		return fmt.Sprintf("%dKB", size/1_000)
+	default:
+		return fmt.Sprintf("%dMB", size/1_000_000)
+	}
+}


Test patch:
diff --git a/pkg/bundle_test.go b/pkg/bundle_test.go
index 9c6a659..a139214 100644
--- a/pkg/bundle_test.go
+++ b/pkg/bundle_test.go
@@ -1293,6 +1293,34 @@ func TestHTTPLoader_Error(t *testing.T) {
 	})
 }
 
+func TestFormatSizeBytes(t *testing.T) {
+	tests := []struct {
+		name string
+		size int
+		want string
+	}{
+		{size: 0, want: "0B"},
+		{size: 1000, want: "1000B"},
+		{size: 1999, want: "1999B"},
+		{size: 2000, want: "2KB"},
+		{size: 10_000, want: "10KB"},
+		{size: 1_000_000, want: "1000KB"},
+		{size: 1_999_999, want: "1999KB"},
+		{size: 2_000_000, want: "2MB"},
+		{size: 10_000_000, want: "10MB"},
+		{size: 3_000_000_000_000, want: "3000000MB"},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.want, func(t *testing.T) {
+			got := formatSizeBytes(tt.size)
+			if got != tt.want {
+				t.Errorf("wrong result\nwant: %q\ngot:  %q", tt.want, got)
+			}
+		})
+	}
+}
+
 func mustParseURL(rawURL string) *url.URL {
 	u, err := url.Parse(rawURL)
 	if err != nil {