all: apply formatter changes

This commit is contained in:
Kristoffer Dalby
2026-04-13 12:38:29 +00:00
parent 814226f327
commit 93860a5c06
16 changed files with 72 additions and 64 deletions

View File

@@ -175,8 +175,10 @@ Use --disable to disable key expiry (node will never expire).`,
now := time.Now() now := time.Now()
expiryTime := now expiryTime := now
if expiry != "" { if expiry != "" {
var err error var err error
expiryTime, err = time.Parse(time.RFC3339, expiry) expiryTime, err = time.Parse(time.RFC3339, expiry)
if err != nil { if err != nil {
return fmt.Errorf("parsing expiry time: %w", err) return fmt.Errorf("parsing expiry time: %w", err)
@@ -397,6 +399,7 @@ func nodesToPtables(
} }
var ipBuilder strings.Builder var ipBuilder strings.Builder
for _, addr := range node.GetIpAddresses() { for _, addr := range node.GetIpAddresses() {
ip, err := netip.ParseAddr(addr) ip, err := netip.ParseAddr(addr)
if err == nil { if err == nil {

View File

@@ -63,6 +63,7 @@ var getPolicy = &cobra.Command{
Aliases: []string{"show", "view", "fetch"}, Aliases: []string{"show", "view", "fetch"},
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
var policyData string var policyData string
if bypass, _ := cmd.Flags().GetBool(bypassFlag); bypass { if bypass, _ := cmd.Flags().GetBool(bypassFlag); bypass {
if !confirmAction(cmd, "DO NOT run this command if an instance of headscale is running, are you sure headscale is not running?") { if !confirmAction(cmd, "DO NOT run this command if an instance of headscale is running, are you sure headscale is not running?") {
return errAborted return errAborted

View File

@@ -379,7 +379,7 @@ func TestEphemeralGarbageCollectorConcurrentScheduleAndClose(t *testing.T) {
stopScheduling := make(chan struct{}) stopScheduling := make(chan struct{})
// Track how many nodes have been scheduled // Track how many nodes have been scheduled
var scheduledCount int64 var scheduledCount atomic.Int64
// Launch goroutines that continuously schedule nodes // Launch goroutines that continuously schedule nodes
for schedulerIndex := range numSchedulers { for schedulerIndex := range numSchedulers {
@@ -396,7 +396,7 @@ func TestEphemeralGarbageCollectorConcurrentScheduleAndClose(t *testing.T) {
default: default:
nodeID := types.NodeID(baseNodeID + j + 1) //nolint:gosec // safe conversion in test nodeID := types.NodeID(baseNodeID + j + 1) //nolint:gosec // safe conversion in test
gc.Schedule(nodeID, 1*time.Hour) // Long expiry to ensure it doesn't trigger during test gc.Schedule(nodeID, 1*time.Hour) // Long expiry to ensure it doesn't trigger during test
atomic.AddInt64(&scheduledCount, 1) scheduledCount.Add(1)
// Yield to other goroutines to introduce variability // Yield to other goroutines to introduce variability
runtime.Gosched() runtime.Gosched()
@@ -410,7 +410,7 @@ func TestEphemeralGarbageCollectorConcurrentScheduleAndClose(t *testing.T) {
defer wg.Done() defer wg.Done()
// Wait until enough nodes have been scheduled // Wait until enough nodes have been scheduled
for atomic.LoadInt64(&scheduledCount) < int64(numSchedulers*closeAfterNodes) { for scheduledCount.Load() < int64(numSchedulers*closeAfterNodes) {
runtime.Gosched() runtime.Gosched()
} }

View File

@@ -633,7 +633,7 @@ func TestEphemeralGarbageCollectorLoads(t *testing.T) {
want := 1000 want := 1000
var deletedCount int64 var deletedCount atomic.Int64
e := NewEphemeralGarbageCollector(func(ni types.NodeID) { e := NewEphemeralGarbageCollector(func(ni types.NodeID) {
mu.Lock() mu.Lock()
@@ -644,7 +644,7 @@ func TestEphemeralGarbageCollectorLoads(t *testing.T) {
got = append(got, ni) got = append(got, ni)
atomic.AddInt64(&deletedCount, 1) deletedCount.Add(1)
}) })
go e.Start() go e.Start()
@@ -655,7 +655,7 @@ func TestEphemeralGarbageCollectorLoads(t *testing.T) {
// Wait for all deletions to complete // Wait for all deletions to complete
assert.EventuallyWithT(t, func(c *assert.CollectT) { assert.EventuallyWithT(t, func(c *assert.CollectT) {
count := atomic.LoadInt64(&deletedCount) count := deletedCount.Load()
assert.Equal(c, int64(want), count, "all nodes should be deleted") assert.Equal(c, int64(want), count, "all nodes should be deleted")
}, 10*time.Second, 50*time.Millisecond, "waiting for all deletions") }, 10*time.Second, 50*time.Millisecond, "waiting for all deletions")

View File

@@ -395,13 +395,13 @@ func (h *Headscale) debugBatcher() string {
} }
if node.activeConnections > 0 { if node.activeConnections > 0 {
sb.WriteString(fmt.Sprintf("Node %d:\t%s (%d connections)\n", node.id, status, node.activeConnections)) fmt.Fprintf(&sb, "Node %d:\t%s (%d connections)\n", node.id, status, node.activeConnections)
} else { } else {
sb.WriteString(fmt.Sprintf("Node %d:\t%s\n", node.id, status)) fmt.Fprintf(&sb, "Node %d:\t%s\n", node.id, status)
} }
} }
sb.WriteString(fmt.Sprintf("\nSummary: %d connected, %d total\n", connectedCount, totalNodes)) fmt.Fprintf(&sb, "\nSummary: %d connected, %d total\n", connectedCount, totalNodes)
return sb.String() return sb.String()
} }

View File

@@ -786,6 +786,7 @@ func TestBug3_CleanupOfflineNodes_TOCTOU(t *testing.T) {
entry.lastUsed.Store(time.Now().Unix()) entry.lastUsed.Store(time.Now().Unix())
mc.addConnection(entry) mc.addConnection(entry)
mc.markConnected() mc.markConnected()
lb.channels[targetNode] = newCh lb.channels[targetNode] = newCh
// Now run cleanup. Node 3 is in the candidates list (old disconnect // Now run cleanup. Node 3 is in the candidates list (old disconnect

View File

@@ -141,9 +141,9 @@ type node struct {
ch chan *tailcfg.MapResponse ch chan *tailcfg.MapResponse
// Update tracking (all accessed atomically for thread safety) // Update tracking (all accessed atomically for thread safety)
updateCount int64 updateCount atomic.Int64
patchCount int64 patchCount atomic.Int64
fullCount int64 fullCount atomic.Int64
maxPeersCount atomic.Int64 maxPeersCount atomic.Int64
lastPeerCount atomic.Int64 lastPeerCount atomic.Int64
stop chan struct{} stop chan struct{}
@@ -404,14 +404,14 @@ func (n *node) start() {
for { for {
select { select {
case data := <-n.ch: case data := <-n.ch:
atomic.AddInt64(&n.updateCount, 1) n.updateCount.Add(1)
// Parse update and track detailed stats // Parse update and track detailed stats
info := parseUpdateAndAnalyze(data) info := parseUpdateAndAnalyze(data)
{ {
// Track update types // Track update types
if info.IsFull { if info.IsFull {
atomic.AddInt64(&n.fullCount, 1) n.fullCount.Add(1)
n.lastPeerCount.Store(int64(info.PeerCount)) n.lastPeerCount.Store(int64(info.PeerCount))
// Update max peers seen using compare-and-swap for thread safety // Update max peers seen using compare-and-swap for thread safety
for { for {
@@ -427,7 +427,7 @@ func (n *node) start() {
} }
if info.IsPatch { if info.IsPatch {
atomic.AddInt64(&n.patchCount, 1) n.patchCount.Add(1)
// For patches, we track how many patch items using compare-and-swap // For patches, we track how many patch items using compare-and-swap
for { for {
current := n.maxPeersCount.Load() current := n.maxPeersCount.Load()
@@ -466,9 +466,9 @@ func (n *node) cleanup() NodeStats {
} }
return NodeStats{ return NodeStats{
TotalUpdates: atomic.LoadInt64(&n.updateCount), TotalUpdates: n.updateCount.Load(),
PatchUpdates: atomic.LoadInt64(&n.patchCount), PatchUpdates: n.patchCount.Load(),
FullUpdates: atomic.LoadInt64(&n.fullCount), FullUpdates: n.fullCount.Load(),
MaxPeersSeen: int(n.maxPeersCount.Load()), MaxPeersSeen: int(n.maxPeersCount.Load()),
LastPeerCount: int(n.lastPeerCount.Load()), LastPeerCount: int(n.lastPeerCount.Load()),
} }
@@ -509,7 +509,7 @@ func TestEnhancedNodeTracking(t *testing.T) {
// Wait for tracking goroutine to process the update // Wait for tracking goroutine to process the update
assert.EventuallyWithT(t, func(c *assert.CollectT) { assert.EventuallyWithT(t, func(c *assert.CollectT) {
assert.GreaterOrEqual(c, atomic.LoadInt64(&testNode.updateCount), int64(1), "should have processed the update") assert.GreaterOrEqual(c, testNode.updateCount.Load(), int64(1), "should have processed the update")
}, time.Second, 10*time.Millisecond, "waiting for update to be processed") }, time.Second, 10*time.Millisecond, "waiting for update to be processed")
// Check stats // Check stats
@@ -553,7 +553,7 @@ func TestEnhancedTrackingWithBatcher(t *testing.T) {
// Wait for updates to be processed (at least 1 update received) // Wait for updates to be processed (at least 1 update received)
assert.EventuallyWithT(t, func(c *assert.CollectT) { assert.EventuallyWithT(t, func(c *assert.CollectT) {
assert.GreaterOrEqual(c, atomic.LoadInt64(&testNode.updateCount), int64(1), "should have received updates") assert.GreaterOrEqual(c, testNode.updateCount.Load(), int64(1), "should have received updates")
}, time.Second, 10*time.Millisecond, "waiting for updates to be processed") }, time.Second, 10*time.Millisecond, "waiting for updates to be processed")
// Check stats // Check stats
@@ -2141,8 +2141,8 @@ func TestNodeDeletedWhileChangesPending(t *testing.T) {
assert.EventuallyWithT(t, func(c *assert.CollectT) { assert.EventuallyWithT(t, func(c *assert.CollectT) {
// Node 1 and 2 should receive updates // Node 1 and 2 should receive updates
stats1 := NodeStats{TotalUpdates: atomic.LoadInt64(&node1.updateCount)} stats1 := NodeStats{TotalUpdates: node1.updateCount.Load()}
stats2 := NodeStats{TotalUpdates: atomic.LoadInt64(&node2.updateCount)} stats2 := NodeStats{TotalUpdates: node2.updateCount.Load()}
assert.Positive(c, stats1.TotalUpdates, "node1 should have received updates") assert.Positive(c, stats1.TotalUpdates, "node1 should have received updates")
assert.Positive(c, stats2.TotalUpdates, "node2 should have received updates") assert.Positive(c, stats2.TotalUpdates, "node2 should have received updates")
}, 5*time.Second, 100*time.Millisecond, "waiting for remaining nodes to receive updates") }, 5*time.Second, 100*time.Millisecond, "waiting for remaining nodes to receive updates")

View File

@@ -60,6 +60,7 @@ func ReduceFilterRules(node types.NodeView, rules []tailcfg.FilterRule) []tailcf
if tsaddr.IsExitRoute(routableIP) { if tsaddr.IsExitRoute(routableIP) {
continue continue
} }
if expanded.OverlapsPrefix(routableIP) { if expanded.OverlapsPrefix(routableIP) {
dests = append(dests, dest) dests = append(dests, dest)
continue DEST_LOOP continue DEST_LOOP

View File

@@ -69,7 +69,7 @@ func (s *State) DebugOverview() string {
sb.WriteString("=== Headscale State Overview ===\n\n") sb.WriteString("=== Headscale State Overview ===\n\n")
// Node statistics // Node statistics
sb.WriteString(fmt.Sprintf("Nodes: %d total\n", allNodes.Len())) fmt.Fprintf(&sb, "Nodes: %d total\n", allNodes.Len())
userNodeCounts := make(map[string]int) userNodeCounts := make(map[string]int)
onlineCount := 0 onlineCount := 0
@@ -97,26 +97,26 @@ func (s *State) DebugOverview() string {
} }
} }
sb.WriteString(fmt.Sprintf(" - Online: %d\n", onlineCount)) fmt.Fprintf(&sb, " - Online: %d\n", onlineCount)
sb.WriteString(fmt.Sprintf(" - Expired: %d\n", expiredCount)) fmt.Fprintf(&sb, " - Expired: %d\n", expiredCount)
sb.WriteString(fmt.Sprintf(" - Ephemeral: %d\n", ephemeralCount)) fmt.Fprintf(&sb, " - Ephemeral: %d\n", ephemeralCount)
sb.WriteString("\n") sb.WriteString("\n")
// User statistics // User statistics
sb.WriteString(fmt.Sprintf("Users: %d total\n", len(users))) fmt.Fprintf(&sb, "Users: %d total\n", len(users))
for userName, nodeCount := range userNodeCounts { for userName, nodeCount := range userNodeCounts {
sb.WriteString(fmt.Sprintf(" - %s: %d nodes\n", userName, nodeCount)) fmt.Fprintf(&sb, " - %s: %d nodes\n", userName, nodeCount)
} }
sb.WriteString("\n") sb.WriteString("\n")
// Policy information // Policy information
sb.WriteString("Policy:\n") sb.WriteString("Policy:\n")
sb.WriteString(fmt.Sprintf(" - Mode: %s\n", s.cfg.Policy.Mode)) fmt.Fprintf(&sb, " - Mode: %s\n", s.cfg.Policy.Mode)
if s.cfg.Policy.Mode == types.PolicyModeFile { if s.cfg.Policy.Mode == types.PolicyModeFile {
sb.WriteString(fmt.Sprintf(" - Path: %s\n", s.cfg.Policy.Path)) fmt.Fprintf(&sb, " - Path: %s\n", s.cfg.Policy.Path)
} }
sb.WriteString("\n") sb.WriteString("\n")
@@ -124,7 +124,7 @@ func (s *State) DebugOverview() string {
// DERP information // DERP information
derpMap := s.derpMap.Load() derpMap := s.derpMap.Load()
if derpMap != nil { if derpMap != nil {
sb.WriteString(fmt.Sprintf("DERP: %d regions configured\n", len(derpMap.Regions))) fmt.Fprintf(&sb, "DERP: %d regions configured\n", len(derpMap.Regions))
} else { } else {
sb.WriteString("DERP: not configured\n") sb.WriteString("DERP: not configured\n")
} }
@@ -137,7 +137,7 @@ func (s *State) DebugOverview() string {
routeCount = 0 routeCount = 0
} }
sb.WriteString(fmt.Sprintf("Primary Routes: %d active\n", routeCount)) fmt.Fprintf(&sb, "Primary Routes: %d active\n", routeCount)
sb.WriteString("\n") sb.WriteString("\n")
// Registration cache // Registration cache
@@ -163,18 +163,18 @@ func (s *State) DebugDERPMap() string {
sb.WriteString("=== DERP Map Configuration ===\n\n") sb.WriteString("=== DERP Map Configuration ===\n\n")
sb.WriteString(fmt.Sprintf("Total Regions: %d\n\n", len(derpMap.Regions))) fmt.Fprintf(&sb, "Total Regions: %d\n\n", len(derpMap.Regions))
for regionID, region := range derpMap.Regions { for regionID, region := range derpMap.Regions {
sb.WriteString(fmt.Sprintf("Region %d: %s\n", regionID, region.RegionName)) fmt.Fprintf(&sb, "Region %d: %s\n", regionID, region.RegionName)
sb.WriteString(fmt.Sprintf(" - Nodes: %d\n", len(region.Nodes))) fmt.Fprintf(&sb, " - Nodes: %d\n", len(region.Nodes))
for _, node := range region.Nodes { for _, node := range region.Nodes {
sb.WriteString(fmt.Sprintf(" - %s (%s:%d)\n", fmt.Fprintf(&sb, " - %s (%s:%d)\n",
node.Name, node.HostName, node.DERPPort)) node.Name, node.HostName, node.DERPPort)
if node.STUNPort != 0 { if node.STUNPort != 0 {
sb.WriteString(fmt.Sprintf(" STUN: %d\n", node.STUNPort)) fmt.Fprintf(&sb, " STUN: %d\n", node.STUNPort)
} }
} }

View File

@@ -526,8 +526,8 @@ func (s *NodeStore) DebugString() string {
sb.WriteString("=== NodeStore Debug Information ===\n\n") sb.WriteString("=== NodeStore Debug Information ===\n\n")
// Basic counts // Basic counts
sb.WriteString(fmt.Sprintf("Total Nodes: %d\n", len(snapshot.nodesByID))) fmt.Fprintf(&sb, "Total Nodes: %d\n", len(snapshot.nodesByID))
sb.WriteString(fmt.Sprintf("Users with Nodes: %d\n", len(snapshot.nodesByUser))) fmt.Fprintf(&sb, "Users with Nodes: %d\n", len(snapshot.nodesByUser))
sb.WriteString("\n") sb.WriteString("\n")
// User distribution (shows internal UserID tracking, not display owner) // User distribution (shows internal UserID tracking, not display owner)
@@ -541,7 +541,7 @@ func (s *NodeStore) DebugString() string {
userName = nodes[0].User().Name() userName = nodes[0].User().Name()
} }
sb.WriteString(fmt.Sprintf(" - User %d (%s): %d nodes\n", userID, userName, len(nodes))) fmt.Fprintf(&sb, " - User %d (%s): %d nodes\n", userID, userName, len(nodes))
} }
} }
@@ -557,20 +557,20 @@ func (s *NodeStore) DebugString() string {
totalPeers += peerCount totalPeers += peerCount
if node, exists := snapshot.nodesByID[nodeID]; exists { if node, exists := snapshot.nodesByID[nodeID]; exists {
sb.WriteString(fmt.Sprintf(" - Node %d (%s): %d peers\n", fmt.Fprintf(&sb, " - Node %d (%s): %d peers\n",
nodeID, node.Hostname, peerCount)) nodeID, node.Hostname, peerCount)
} }
} }
if len(snapshot.peersByNode) > 0 { if len(snapshot.peersByNode) > 0 {
avgPeers := float64(totalPeers) / float64(len(snapshot.peersByNode)) avgPeers := float64(totalPeers) / float64(len(snapshot.peersByNode))
sb.WriteString(fmt.Sprintf(" - Average peers per node: %.1f\n", avgPeers)) fmt.Fprintf(&sb, " - Average peers per node: %.1f\n", avgPeers)
} }
sb.WriteString("\n") sb.WriteString("\n")
// Node key index // Node key index
sb.WriteString(fmt.Sprintf("NodeKey Index: %d entries\n", len(snapshot.nodesByNodeKey))) fmt.Fprintf(&sb, "NodeKey Index: %d entries\n", len(snapshot.nodesByNodeKey))
sb.WriteString("\n") sb.WriteString("\n")
return sb.String() return sb.String()

View File

@@ -1790,10 +1790,12 @@ func (s *State) HandleNodeFromAuthPath(
// the initial Hostinfo from the cached client-supplied Hostinfo (or // the initial Hostinfo from the cached client-supplied Hostinfo (or
// an empty stub if the client did not send one). // an empty stub if the client did not send one).
hostname := regData.Hostname hostname := regData.Hostname
hostinfo := &tailcfg.Hostinfo{} hostinfo := &tailcfg.Hostinfo{}
if regData.Hostinfo != nil { if regData.Hostinfo != nil {
hostinfo = regData.Hostinfo.Clone() hostinfo = regData.Hostinfo.Clone()
} }
hostinfo.Hostname = hostname hostinfo.Hostname = hostname
// Lookup existing nodes // Lookup existing nodes

View File

@@ -933,7 +933,7 @@ func warnBanner(lines []string) {
b.WriteString("### ###\n") b.WriteString("### ###\n")
for _, line := range lines { for _, line := range lines {
b.WriteString(fmt.Sprintf("### %-54s ###\n", line)) fmt.Fprintf(&b, "### %-54s ###\n", line)
} }
b.WriteString("### ###\n") b.WriteString("### ###\n")

View File

@@ -30,10 +30,10 @@ func (v *VersionInfo) String() string {
version += "-dirty" version += "-dirty"
} }
sb.WriteString(fmt.Sprintf("headscale version %s\n", version)) fmt.Fprintf(&sb, "headscale version %s\n", version)
sb.WriteString(fmt.Sprintf("commit: %s\n", v.Commit)) fmt.Fprintf(&sb, "commit: %s\n", v.Commit)
sb.WriteString(fmt.Sprintf("build time: %s\n", v.BuildTime)) fmt.Fprintf(&sb, "build time: %s\n", v.BuildTime)
sb.WriteString(fmt.Sprintf("built with: %s %s/%s\n", v.Go.Version, v.Go.OS, v.Go.Arch)) fmt.Fprintf(&sb, "built with: %s %s/%s\n", v.Go.Version, v.Go.OS, v.Go.Arch)
return sb.String() return sb.String()
} }

View File

@@ -98,12 +98,12 @@ func TailcfgFilterRulesToString(rules []tailcfg.FilterRule) string {
var sb strings.Builder var sb strings.Builder
for index, rule := range rules { for index, rule := range rules {
sb.WriteString(fmt.Sprintf(` fmt.Fprintf(&sb, `
{ {
SrcIPs: %v SrcIPs: %v
DstIPs: %v DstIPs: %v
} }
`, rule.SrcIPs, rule.DstPorts)) `, rule.SrcIPs, rule.DstPorts)
if index < len(rules)-1 { if index < len(rules)-1 {
sb.WriteString(", ") sb.WriteString(", ")

View File

@@ -341,11 +341,11 @@ func requireAllClientsOnlineWithSingleTimeout(t *testing.T, headscale ControlSer
stateStr = stateOnline stateStr = stateOnline
} }
failureReport.WriteString(fmt.Sprintf("node:%d is not fully %s (timestamp: %s):\n", nodeID, stateStr, time.Now().Format(TimestampFormat))) fmt.Fprintf(&failureReport, "node:%d is not fully %s (timestamp: %s):\n", nodeID, stateStr, time.Now().Format(TimestampFormat))
failureReport.WriteString(fmt.Sprintf(" - batcher: %t (expected: %t)\n", status.Batcher, expectedOnline)) fmt.Fprintf(&failureReport, " - batcher: %t (expected: %t)\n", status.Batcher, expectedOnline)
failureReport.WriteString(fmt.Sprintf(" - conn count: %d\n", status.BatcherConnCount)) fmt.Fprintf(&failureReport, " - conn count: %d\n", status.BatcherConnCount)
failureReport.WriteString(fmt.Sprintf(" - mapresponses: %t (expected: %t, down with at least one peer)\n", status.MapResponses, expectedOnline)) fmt.Fprintf(&failureReport, " - mapresponses: %t (expected: %t, down with at least one peer)\n", status.MapResponses, expectedOnline)
failureReport.WriteString(fmt.Sprintf(" - nodestore: %t (expected: %t)\n", status.NodeStore, expectedOnline)) fmt.Fprintf(&failureReport, " - nodestore: %t (expected: %t)\n", status.NodeStore, expectedOnline)
} }
} }
@@ -359,7 +359,7 @@ func requireAllClientsOnlineWithSingleTimeout(t *testing.T, headscale ControlSer
prevReport = failureReport.String() prevReport = failureReport.String()
} }
failureReport.WriteString(fmt.Sprintf("validation_timestamp: %s\n", time.Now().Format(TimestampFormat))) fmt.Fprintf(&failureReport, "validation_timestamp: %s\n", time.Now().Format(TimestampFormat))
// Note: timeout_remaining not available in this context // Note: timeout_remaining not available in this context
assert.Fail(c, failureReport.String()) assert.Fail(c, failureReport.String())

View File

@@ -359,7 +359,7 @@ func writeTestDataFile(versions map[string]tailcfg.CapabilityVersion, minSupport
content.WriteString("\t{3, false, []string{") content.WriteString("\t{3, false, []string{")
for i, version := range latest3 { for i, version := range latest3 {
content.WriteString(fmt.Sprintf("\"%s\"", version)) fmt.Fprintf(&content, "\"%s\"", version)
if i < len(latest3)-1 { if i < len(latest3)-1 {
content.WriteString(", ") content.WriteString(", ")
@@ -374,7 +374,7 @@ func writeTestDataFile(versions map[string]tailcfg.CapabilityVersion, minSupport
for i, version := range latest2 { for i, version := range latest2 {
// Strip v prefix for this test case // Strip v prefix for this test case
verNoV := strings.TrimPrefix(version, "v") verNoV := strings.TrimPrefix(version, "v")
content.WriteString(fmt.Sprintf("\"%s\"", verNoV)) fmt.Fprintf(&content, "\"%s\"", verNoV)
if i < len(latest2)-1 { if i < len(latest2)-1 {
content.WriteString(", ") content.WriteString(", ")
@@ -384,11 +384,11 @@ func writeTestDataFile(versions map[string]tailcfg.CapabilityVersion, minSupport
content.WriteString("}},\n") content.WriteString("}},\n")
// Latest N without v prefix (all supported) // Latest N without v prefix (all supported)
content.WriteString(fmt.Sprintf("\t{%d, true, []string{\n", supportedMajorMinorVersions)) fmt.Fprintf(&content, "\t{%d, true, []string{\n", supportedMajorMinorVersions)
for _, version := range latest10 { for _, version := range latest10 {
verNoV := strings.TrimPrefix(version, "v") verNoV := strings.TrimPrefix(version, "v")
content.WriteString(fmt.Sprintf("\t\t\"%s\",\n", verNoV)) fmt.Fprintf(&content, "\t\t\"%s\",\n", verNoV)
} }
content.WriteString("\t}},\n") content.WriteString("\t}},\n")
@@ -417,7 +417,7 @@ func writeTestDataFile(versions map[string]tailcfg.CapabilityVersion, minSupport
// Add minimum supported version // Add minimum supported version
minVersionString := capVerToTailscaleVer[minSupportedCapVer] minVersionString := capVerToTailscaleVer[minSupportedCapVer]
content.WriteString(fmt.Sprintf("\t{%d, \"%s\"},\n", minSupportedCapVer, minVersionString)) fmt.Fprintf(&content, "\t{%d, \"%s\"},\n", minSupportedCapVer, minVersionString)
// Add a few more test cases // Add a few more test cases
capsSorted := xmaps.Keys(capVerToTailscaleVer) capsSorted := xmaps.Keys(capVerToTailscaleVer)
@@ -431,7 +431,7 @@ func writeTestDataFile(versions map[string]tailcfg.CapabilityVersion, minSupport
if capVer != minSupportedCapVer { // Don't duplicate the min version test if capVer != minSupportedCapVer { // Don't duplicate the min version test
version := capVerToTailscaleVer[capVer] version := capVerToTailscaleVer[capVer]
content.WriteString(fmt.Sprintf("\t{%d, \"%s\"},\n", capVer, version)) fmt.Fprintf(&content, "\t{%d, \"%s\"},\n", capVer, version)
testCount++ testCount++
} }