https://github.com/bytedance/gg

🔥gg is a basic library of generics for Go language developed by ByteDance. It is based on the Go 1.18+ generic features and provides efficient, type-safe and rich generic data structures and tool functions.

https://github.com/bytedance/gg

Science Score: 26.0%

This score indicates how likely this project is to be science-related based on various indicators:

  • CITATION.cff file
  • codemeta.json file
    Found codemeta.json file
  • .zenodo.json file
    Found .zenodo.json file
  • DOI references
  • Academic publication links
  • Academic email domains
  • Institutional organization owner
  • JOSS paper metadata
  • Scientific vocabulary similarity
    Low similarity (12.0%) to scientific vocabulary

Keywords

generics go golang
Last synced: 5 months ago · JSON representation

Repository

🔥gg is a basic library of generics for Go language developed by ByteDance. It is based on the Go 1.18+ generic features and provides efficient, type-safe and rich generic data structures and tool functions.

Basic Info
Statistics
  • Stars: 243
  • Watchers: 5
  • Forks: 24
  • Open Issues: 1
  • Releases: 2
Topics
generics go golang
Created 9 months ago · Last pushed 6 months ago
Metadata Files
Readme Contributing License Code of conduct

README.md

gg: Go Generics

GoDoc Go Report Card Go Coverage License

English | 简体中文

🔥bytedance/gg is a basic library of generics for Go language developed by ByteDance. It is based on the Go 1.18+ generic features and provides efficient, type-safe and rich generic data structures and tool functions.

Why this name?

Take the first letter of Go Generics, short and simple.

Why choose gg?

  • Stable and reliable: It is a necessary tool library for ByteDance R&D team, and it has 1w+ repository references inside.
  • Easy to use: With the design principle of simplicity and self-consistent, subcontracted according to functions, modular, semantic intuitive and unified, and low learning cost.
  • High Performance: Provides high-performance concurrent data structures, with performance 10+ times faster than standard library.
  • No three-party dependencies: Generic libraries will not introduce any three-party dependencies.
  • Version control: Follow the SemVer, guaranteeing backward compatibility.

🚀 Install

sh go get github.com/bytedance/gg

🔎 Table of contents

  • Generic Functional Programming
    • goption:Option type, simplifying the processing of (T, bool)
    • gresult:Result type, simplifying the processing of (T, error)
  • Generic Data Processing
    • gcond:Conditional operation
    • gvalue:Processing value T
    • gptr:Processing pointer *T
    • gslice:Processing slice []T
    • gmap:Processing map map[K]V
    • gfunc:Processing function func
    • gconv:Data type conversion
    • gson:Processing JSON
  • Generic Standard Wrapper
  • Generic Data Structures
    • tuple:Implementation of tuple provides definition of generic n-ary tuples
    • set:Implementation of set based on map[T]struct{}
    • list:Implementation of doubly linked list
    • skipset:High-performance, scalable, concurrent-safe set based on skip-list, up to 15x faster than the built-in sync.Map below Go 1.24
    • skipmap:High-performance, scalable, concurrent-safe map based on skip-list, up to 10x faster than the built-in sync.Map below Go 1.24

✨ Generic Functional Programming

goption

Option type, simplifying the processing of (T, bool)

Usage:

go import ( "github.com/bytedance/gg/goption" )

Example:

go goption.Of(1, true).Value() // 1 goption.Nil[int]().IsNil() // true goption.Nil[int]().ValueOr(10) // 10 goption.OK(1).IsOK() // true goption.OK(1).ValueOrZero() // 1 goption.OfPtr((*int)(nil)).Ptr() // nil goption.Map(goption.OK(1), strconv.Itoa).Get() // "1" true

gresult

Result type, simplifying the processing of (T, error)

Usage:

go import ( "github.com/bytedance/gg/gresult" )

Example:

go gresult.Of(strconv.Atoi("1")).Value() // 1 gresult.Err[int](io.EOF).IsErr() // true gresult.Err[int](io.EOF).ValueOr(10) // 10 gresult.OK(1).IsOK() // true gresult.OK(1).ValueOrZero() // 1 gresult.Of(strconv.Atoi("x")).Option().Get() // 0 false gresult.Map(gresult.OK(1), strconv.Itoa).Get() // "1" nil

✨ Generic Data Processing

gcond:

Conditional operation

Usage:

go import ( "github.com/bytedance/gg/gcond" )

Example:

```go gcond.If(true, 1, 2) // 1 var a *struct{ A int } getA := func() int { return a.A } get1 := func() int { return 1 } gcond.IfLazy(a != nil, getA, get1) // 1 gcond.IfLazyL(a != nil, getA, 1) // 1 gcond.IfLazyR(a == nil, 1, getA) // 1

gcond.Switchstring. Case(1, "1"). CaseLazy(2, func() string { return "3" }). When(3, 4).Then("3/4"). When(5, 6).ThenLazy(func() string { return "5/6" }). Default("other") // 3/4 ```

gvalue

Processing value T

Usage:

go import ( "github.com/bytedance/gg/gvalue" )

Example1:Zero Value

go a := gvalue.Zero[int]() // 0 gvalue.IsZero(a) // true b := gvalue.Zero[*int]() // nil gvalue.IsNil(b) // true gvalue.Or(0, 1, 2) // 1

Example2:Math Operation

go gvalue.Max(1, 2, 3) // 3 gvalue.Min(1, 2, 3) // 1 gvalue.MinMax(1, 2, 3) // 1 3 gvalue.Clamp(5, 1, 10) // 5 gvalue.Add(1, 2) // 3

Example3:Comparison

go gvalue.Equal(1, 1) // true gvalue.Between(2, 1, 3) // true

Example4:Type Assertion

go gvalue.TypeAssert[int](any(1)) // 1 gvalue.TryAssert[int](any(1)) // 1 true

gptr

Processing pointer *T

Usage:

go import ( "github.com/bytedance/gg/gptr" )

Example:

```go a := Of(1) gptr.Indirect(a) // 1

b := OfNotZero(1) gptr.IsNotNil(b) // true gptr.IndirectOr(b, 2) // 1 gptr.Indirect(gptr.Map(b, strconv.Itoa)) // "1"

c := OfNotZero(0) // nil gptr.IsNil(c) // true gptr.IndirectOr(c, 2) // 2 ```

gslice

Processing slice []T

Usage:

go import ( "github.com/bytedance/gg/gslice" )

Example1:High-order Function

go gslice.Map([]int{1, 2, 3, 4, 5}, strconv.Itoa) // ["1", "2", "3", "4", "5"] isEven := func(i int) bool { return i%2 == 0 } gslice.Filter([]int{1, 2, 3, 4, 5}, isEven) // [2, 4] gslice.Reduce([]int{1, 2, 3, 4, 5}, gvalue.Add[int].Value()) // 15 gslice.Any([]int{1, 2, 3, 4, 5}, isEven) // true gslice.All([]int{1, 2, 3, 4, 5}, isEven) // false

Example2:CURD Operation

go gslice.Contains([]int{1, 2, 3, 4, 5}, 2) // true gslice.ContainsAny([]int{1, 2, 3, 4, 5}, 2, 6) // true gslice.ContainsAll([]int{1, 2, 3, 4, 5}, 2, 6) // false gslice.Index([]int{1, 2, 3, 4, 5}, 3.Value()) // 2 gslice.Find([]int{1, 2, 3, 4, 5}, isEven).Value() // 2 gslice.First([]int{1, 2, 3, 4, 5}).Value() // 1 gslice.Get([]int{1, 2, 3, 4, 5}, 1).Value() // 2 gslice.Get([]int{1, 2, 3, 4, 5}, -1).Value() // Access element with negative index // 5

Example3:Partion Operation

go gslice.Range(1, 5) // [1, 2, 3, 4] gslice.RangeWithStep(5, 1, -2) // [5, 3] gslice.Take([]int{1, 2, 3, 4, 5}, 2) // [1, 2] gslice.Take([]int{1, 2, 3, 4, 5}, -2) // [4, 5] gslice.Slice([]int{1, 2, 3, 4, 5}, 1, 3) // [2, 3] gslice.Chunk([]int{1, 2, 3, 4, 5}, 2) // [[1, 2], [3, 4], [5]] gslice.Divide([]int{1, 2, 3, 4, 5}, 2) // [[1, 2, 3], [4, 5]] gslice.Concat([]int{1, 2}, []int{3, 4, 5}) // [1, 2, 3, 4, 5] gslice.Flatten([][]int{{1, 2}, {3, 4, 5}}) // [1, 2, 3, 4, 5] gslice.Partition([]int{1, 2, 3, 4, 5}, isEven) // [2, 4], [1, 3, 5]

Example4:Math Operation

go gslice.Max([]int{1, 2, 3, 4, 5}).Value() // 5 gslice.Min([]int{1, 2, 3, 4, 5}).Value() // 1 gslice.MinMax([]int{1, 2, 3, 4, 5}).Value().Values() // 1 5 gslice.Sum([]int{1, 2, 3, 4, 5}) // 15

Example5:Convert to map

go ToMap([]int{1, 2, 3, 4, 5}, func(i int) (string, int) { return strconv.Itoa(i), i }) // {"1":1, "2":2, "3":3, "4":4, "5":5} ToBoolMap([]int{1, 2, 3, 3, 2}) // {1: true, 2: true, 3: true} ToMapValues([]int{1, 2, 3, 4, 5}, strconv.Itoa) // {"1":1, "2":2, "3":3, "4":4, "5":5} GroupBy([]int{1, 2, 3, 4, 5}, func(i int) string { if i%2 == 0 { return "even" } else { return "odd" } }) // {"even":[2,4], "odd":[1,3,5]}

Example6:Set Operation

go gslice.Union([]int{1, 2, 3}, []int{3, 4, 5}) // [1, 2, 3, 4, 5] gslice.Intersect([]int{1, 2, 3}, []int{3, 4, 5}) // [3] gslice.Diff([]int{1, 2, 3}, []int{3, 4, 5}) // [1, 2] gslice.Uniq([]int{1, 1, 2, 2, 3}) // [1, 2, 3] gslice.Dup([]int{1, 1, 2, 2, 3}) // [1, 2]

Example7:Re-order Operation

go s1 := []int{5, 1, 2, 3, 4} s2, s3, s4 := Clone(s1), Clone(s1), Clone(s1) Sort(s1) // [1, 2, 3, 4, 5] SortBy(s2, func(i, j int) bool { return i > j }) // [5, 4, 3, 2, 1] StableSortBy(s3, func(i, j int) bool { return i > j }) // [5, 4, 3, 2, 1] Reverse(s4) // [4, 3, 2, 1, 5]

gmap

Processing map map[K]V

Usage:

go import ( "github.com/bytedance/gg/gmap" )

Example1:Keys / Values Getter

go gmap.Keys(map[int]int{1: 2}) // [1] gmap.Values(map[int]int{1: 2}) // [2] gmap.Items(map[int]int{1: 2}).Unzip() // [1] [2] gmap.OrderedKeys(map[int]int{1: 2, 2: 3, 3: 4}) // [1, 2, 3] gmap.OrderedValues(map[int]int{1: 2, 2: 3, 3: 4}) // [2, 3, 4] gmap.OrderedItems(map[int]int{1: 2, 2: 3, 3: 4}).Unzip() // [1, 2, 3] [2, 3, 4] f := func(k, v int) string { return strconv.Itoa(k) + ":" + strconv.Itoa(v) } gmap.ToSlice(map[int]int{1: 2}, f) // ["1:2"] gmap.ToOrderedSlice(map[int]int{1: 2, 2: 3, 3: 4}, f) // ["1:2", "2:3", "3:4"]

Example2:High-order Function

go gmap.Map(map[int]int{1: 2, 2: 3, 3: 4}, func(k int, v int) (string, string) { return strconv.Itoa(k), strconv.Itoa(k + 1) }) // {"1":"2", "2":"3", "3":"4"} gmap.Filter(map[int]int{1: 2, 2: 3, 3: 4}, func(k int, v int) bool { return k+v > 3 }) // {"2":2, "3":3}

Example3:CURD Operation

go gmap.Contains(map[int]int{1: 2, 2: 3, 3: 4}, 1) // true gmap.ContainsAny(map[int]int{1: 2, 2: 3, 3: 4}, 1, 4) // true gmap.ContainsAll(map[int]int{1: 2, 2: 3, 3: 4}, 1, 4) // false gmap.Load(map[int]int{1: 2, 2: 3, 3: 4}, 1).Value() // 2 gmap.LoadAny(map[int]int{1: 2, 2: 3, 3: 4}, 1, 4).Value() // 2 gmap.LoadAll(map[int]int{1: 2, 2: 3, 3: 4}, 1, 4) // [] gmap.LoadSome(map[int]int{1: 2, 2: 3, 3: 4}, 1, 4) // [2]

Example4:Partion Operation

go Chunk(map[int]int{1: 2, 2: 3, 3: 4, 4: 5, 5: 6}, 2) // possible result: [{1:2, 2:3}, {3:4, 4:5}, {5:6}] Divide(map[int]int{1: 2, 2: 3, 3: 4, 4: 5, 5: 6}, 2) // possible result: [{1:2, 2:3, 3:4}, {4:5, 5:6}]

Example5:Math Operation

go gmap.Max(map[int]int{1: 2, 2: 3, 3: 4}).Value() // 4 gmap.Min(map[int]int{1: 2, 2: 3, 3: 4}).Value() // 2 gmap.MinMax(map[int]int{1: 2, 2: 3, 3: 4}).Value().Values() // 2 4 gmap.Sum(map[int]int{1: 2, 2: 3, 3: 4}) // 9

Example6:Set Operation

go gmap.Union(map[int]int{1: 2, 2: 3, 3: 4}, map[int]int{3: 14, 4: 15, 5: 16}) // {1:2, 2:3, 3:14, 4:15, 5:16} gmap.Intersect(map[int]int{1: 2, 2: 3, 3: 4}, map[int]int{3: 14, 4: 15, 5: 16}) // {3:14} gmap.Diff(map[int]int{1: 2, 2: 3, 3: 4}, map[int]int{3: 14, 4: 15, 5: 16}) // {1:2, 2:3} gmap.UnionBy(gslice.Of(map[int]int{1: 2, 2: 3, 3: 4}, map[int]int{3: 14, 4: 15, 5: 16}), DiscardNew[int, int]()) // {1:2, 2:3, 3:4, 4:15, 5:16} gmap.IntersectBy(gslice.Of(map[int]int{1: 2, 2: 3, 3: 4}, map[int]int{3: 14, 4: 15, 5: 16}), DiscardNew[int, int]()) // {3:4}

gfunc

Processing function func

Usage:

go import ( "github.com/bytedance/gg/gfunc" )

Example1:Partial Application

go add := Partial2(gvalue.Add[int]) // convert the Add function into a partial function add1 := add.Partial(1) // Bind (i.e., "freeze") the first argument to 1 add1(0) // 0 + 1 = 1 // 1 add1(1) // Reuse the partially applied function: 1 + 1 = 2 // 2 add1n2 := add1.PartialR(2) // Bind the remaining (rightmost) argument to 2; all arguments are now fixed add1n2() // 1 + 2 = 3

gconv

Data type conversion

Usage:

go import ( "github.com/bytedance/gg/gconv" )

Example:

```go gconv.Tostring // "1" gconv.Toint // 1 gconv.Toint // 0 gconv.Tobool // true gconv.Tobool // false gconv.Toint // 1 type myInt int type myString string gconv.TomyInt // 1 gconv.TomyString // "1"

gconv.ToEint // 0 strconv.ParseInt: parsing "x": invalid syntax ```

gson

Processing JSON

Usage:

go import ( "github.com/bytedance/gg/gson" )

Example:

``go type testStruct struct { Name stringjson:"name" Age intjson:"age"` } testcase := testStruct{Name: "test", Age: 10}

gson.Marshal(testcase) // []byte({"name":"test","age":10}) nil gson.MarshalString(testcase) // {"name":"test","age":10} nil gson.ToString(testcase) // {"name":"test","age":10} gson.MarshalIndent(testcase, "", " ") // "{\n \"name\": \"test\",\n \"age\": 10\n}" nil gson.ToStringIndent(testcase, "", " ") // "{\n \"name\": \"test\",\n \"age\": 10\n}" gson.Valid({"name":"test","age":10}) // true gson.UnmarshaltestStruct // {test 10} nil

// Use high-performance JSON codecs such as Sonic or json-iterator, instead of the standard library's encoding/json. import "github.com/bytedance/sonic"

gson.MarshalBy(sonic.ConfigDefault, testcase) // []byte({"name":"test","age":10}) nil gson.MarshalString(sonic.ConfigDefault, testcase) // {"name":"test","age":10}, nil gson.UnmarshalBy[testStruct](sonic.ConfigDefault,{"name":"test","age":10}`) // testStruct{Name: "test", Age: 10}, nil

// Example using Json-Iterator: import jsoniter "github.com/json-iterator/go"

gson.MarshalBy(jsoniter.ConfigDefault, testcase) // []byte({"name":"test","age":10}) nil gson.MarshalString(jsoniter.ConfigDefault, testcase) // {"name":"test","age":10}, nil gson.UnmarshalBy[testStruct](jsoniter.ConfigDefault,{"name":"test","age":10}) // testStruct{Name: "test", Age: 10}, nil ``

✨ Generic Standard Wrapper

gsync

Wrap sync

Usage:

go import ( "github.com/bytedance/gg/gstd/gsync" )

Example1:gsync.Map wraps sync.Map

go sm := gsync.Map[string, int]{} sm.Store("k", 1) sm.Load("k") // 1 true sm.LoadO("k").Value() // 1 sm.Store("k", 2) sm.Load("k") // 2 true sm.LoadAndDelete("k") // 2 true sm.Load("k") // 0 false sm.LoadOrStore("k", 3) // 3 false sm.Load("k") // 3 true sm.ToMap() // {"k":3}

Example2:gsync.Pool wraps sync.Pool

go pool := Pool[*int]{ New: func() *int { i := 1 return &i }, } a := pool.Get() *a // 1 *a = 2 pool.Put(a) *pool.Get() // possible result: 1 or 2

Example3:gsync.OnceXXX wraps sync.Once

```go onceFunc := gsync.OnceFunc(func() { fmt.Println("OnceFunc") }) onceFunc() // "OnceFunc" onceFunc() // (no output) onceFunc() // (no output)

i := 1 onceValue := gsync.OnceValue(func() int { i++; return i }) onceValue() // 2 onceValue() // 2

onceValues := gsync.OnceValues(func() (int, error) { i++; return i, nil }) onceValues() // 3 nil onceValues() // 3 nil ```

✨ Generic Data Structures

tuple

Implementation of tuple provides definition of generic n-ary tuples

Usage

go import( "github.com/bytedance/gg/collection/tuple" )

Example:

```go addr := Make2("localhost", 8080) fmt.Printf("%s:%d\n", addr.First, addr.Second) // localhost:8080

s := Zip2([]string{"red", "green", "blue"}, []int{14, 15, 16}) for _, v := range s { fmt.Printf("%s:%d\n", v.First, v.Second) } // red:14 // green:15 // blue:16

s.Unzip() // ["red", "green", "blue"] [14, 15, 16] ```

set

Implementation of set based on map[T]struct{}

Usage

go import ( "github.com/bytedance/gg/collection/set" )

Example:

```go s := New(10, 10, 12, 15) s.Len() // 3 s.Add(10) // false s.Add(11) // true s.Remove(11) && s.Remove(12) // true

s.ContainsAny(10, 15) // true s.ContainsAny(11, 12) // false s.ContainsAny() // false s.ContainsAll(10, 15) // true s.ContainsAll(10, 11) // false s.ContainsAll() // true

len(s.ToSlice()) // 2 ```

list

Implementation of doubly linked list

Usage

go import ( "github.com/bytedance/gg/collection/list" )

Example:

```go l := Newint e1 := l.PushFront(1) // 1 e2 := l.PushBack(2) // 1->2 e3 := l.InsertBefore(3, e2) // 1->3->2 e4 := l.InsertAfter(4, e1) // 1->4->3->2

l.MoveToFront(e4) // 4->1->3->2 l.MoveToBack(e1) // 4->3->2->1 l.MoveAfter(e3, e2) // 4->2->3->1 l.MoveBefore(e4, e1) // 2->3->4->1

l.Len() // 4 l.Front().Value // 2 l.Back().Value // 1

for e := l.Front(); e != nil; e = e.Next() { fmt.Println(e.Value) // 2 3 4 1 } ```

skipset

High-performance, scalable, concurrent-safe set based on skip-list, up to 15x faster than the built-in sync.Map below Go 1.24

⚠️ NOTICE: Go 1.24 or later, please consider using the std sync.Map, which has better performance compared to skipset in about 90% of use cases.

Usage

go import ( "github.com/bytedance/gg/collection/skipset" )

Example:

```go s := skipset.Newint s.Add(10) // true s.Add(10) // false s.Add(11) // true s.Add(12) // true s.Len() // 3

s.Contains(10) // true s.Remove(10) // true s.Contains(10) // false

s.ToSlice() // [11, 12]

var wg sync.WaitGroup wg.Add(1000) for i := 0; i < 1000; i++ { i := i go func() { defer wg.Done() s.Add(i) }() } wg.Wait() s.Len() // 1000 ```

skipmap

High-performance, scalable, concurrent-safe map based on skip-list, up to 10x faster than the built-in sync.Map below Go 1.24

⚠️ Go 1.24 or later, please consider using the std sync.Map, which has better performance compared to skipmap in about 90% of use cases.

Usage

go import ( "github.com/bytedance/gg/collection/skipmap" )

Example:

```go s := Newstring, int s.Store("a", 0) s.Store("a", 1) s.Store("b", 2) s.Store("c", 3) s.Len() // 3

s.Load("a") // 1 true s.LoadAndDelete("a") // 1 true s.LoadOrStore("a", 11) // 11 false

gson.ToString(s.ToMap()) // {"a":11, "b":2, "c": 3}

s.Delete("a") s.Delete("b") s.Delete("c") var wg sync.WaitGroup wg.Add(1000) for i := 0; i < 1000; i++ { i := i go func() { defer wg.Done() s.Store(strconv.Itoa(i), i) }() } wg.Wait() s.Len() // 1000 ```

License

gg is licensed under the Apache-2.0 license. See LICENSE for details.

2025 © Bytedance

Owner

  • Name: Bytedance Inc.
  • Login: bytedance
  • Kind: organization
  • Location: Singapore

GitHub Events

Total
  • Create event: 2
  • Issues event: 2
  • Release event: 2
  • Watch event: 171
  • Issue comment event: 29
  • Public event: 1
  • Push event: 61
  • Pull request review comment event: 28
  • Pull request event: 29
  • Pull request review event: 45
  • Fork event: 18
Last Year
  • Create event: 2
  • Issues event: 2
  • Release event: 2
  • Watch event: 171
  • Issue comment event: 29
  • Public event: 1
  • Push event: 61
  • Pull request review comment event: 28
  • Pull request event: 29
  • Pull request review event: 45
  • Fork event: 18

Issues and Pull Requests

Last synced: 5 months ago

All Time
  • Total issues: 2
  • Total pull requests: 19
  • Average time to close issues: 21 days
  • Average time to close pull requests: 5 days
  • Total issue authors: 2
  • Total pull request authors: 8
  • Average comments per issue: 0.5
  • Average comments per pull request: 1.16
  • Merged pull requests: 10
  • Bot issues: 0
  • Bot pull requests: 0
Past Year
  • Issues: 2
  • Pull requests: 19
  • Average time to close issues: 21 days
  • Average time to close pull requests: 5 days
  • Issue authors: 2
  • Pull request authors: 8
  • Average comments per issue: 0.5
  • Average comments per pull request: 1.16
  • Merged pull requests: 10
  • Bot issues: 0
  • Bot pull requests: 0
Top Authors
Issue Authors
  • vijayvenkat704 (1)
  • eddiearc (1)
Pull Request Authors
  • XQ-Gang (6)
  • 785172550 (4)
  • SilverRainZ (3)
  • limits220284 (2)
  • crazyfrankie (1)
  • someblue (1)
  • kumakichi (1)
  • GarrickZ2 (1)
Top Labels
Issue Labels
enhancement (1)
Pull Request Labels

Packages

  • Total packages: 1
  • Total downloads: unknown
  • Total dependent packages: 0
  • Total dependent repositories: 0
  • Total versions: 2
proxy.golang.org: github.com/bytedance/gg
  • Versions: 2
  • Dependent Packages: 0
  • Dependent Repositories: 0
Rankings
Dependent packages count: 5.4%
Average: 5.6%
Dependent repos count: 5.8%
Last synced: 6 months ago

Dependencies

.github/workflows/license.yml actions
  • actions/checkout v4 composite
  • apache/skywalking-eyes/header v0.7.0 composite
.github/workflows/test.yml actions
  • actions/cache v4 composite
  • actions/checkout v4 composite
  • actions/setup-go v5 composite
  • codecov/codecov-action v5 composite
go.mod go
go.sum go