Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions .github/workflows/kodo.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: Kodo E2E

on:
push:
branches:
- "**"
- "!dependabot/**"
- "!xgopilot/**"
pull_request_target:
branches: [ "**" ]

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: false

jobs:
kodo-artifact:
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v4
with:
repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }}
ref: ${{ github.event.pull_request.head.sha || github.sha }}
persist-credentials: false

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: 1.24.x

- name: Download Go modules
run: go mod download

- name: Check Kodo secrets
env:
QINIU_ACCESS_KEY: ${{ secrets.QINIU_ACCESS_KEY }}
QINIU_SECRET_KEY: ${{ secrets.QINIU_SECRET_KEY }}
QINIU_BUCKET: ${{ secrets.QINIU_BUCKET }}
run: |
test -n "$QINIU_ACCESS_KEY"
test -n "$QINIU_SECRET_KEY"
test -n "$QINIU_BUCKET"

- name: Run Kodo artifact E2E
env:
QINIU_ACCESS_KEY: ${{ secrets.QINIU_ACCESS_KEY }}
QINIU_SECRET_KEY: ${{ secrets.QINIU_SECRET_KEY }}
QINIU_BUCKET: ${{ secrets.QINIU_BUCKET }}
QINIU_PREFIX: ${{ secrets.QINIU_PREFIX }}
run: go test -v -ldflags="-checklinkname=0" ./internal/artifact -run '^TestKodoArtifactE2E$' -count=1
7 changes: 7 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ require (
github.com/goplus/xgo v1.6.1
github.com/jessevdk/go-flags v1.6.1
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
github.com/qiniu/go-sdk/v7 v7.26.14
github.com/qiniu/x v1.16.0
github.com/spf13/cobra v1.10.2
golang.org/x/mod v0.32.0
Expand All @@ -18,17 +19,22 @@ require (
)

require (
github.com/BurntSushi/toml v1.3.2 // indirect
github.com/alex-ant/gomath v0.0.0-20160516115720-89013a210a82 // indirect
github.com/containerd/stargz-snapshotter/estargz v0.18.1 // indirect
github.com/docker/cli v29.0.3+incompatible // indirect
github.com/docker/distribution v2.8.3+incompatible // indirect
github.com/docker/docker-credential-helpers v0.9.3 // indirect
github.com/gammazero/toposort v0.1.1 // indirect
github.com/gofrs/flock v0.8.1 // indirect
github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 // indirect
github.com/goplus/gogen v1.20.6 // indirect
github.com/goplus/reflectx v1.5.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/klauspost/compress v1.18.1 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/mattn/go-sqlite3 v1.14.22 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
Expand All @@ -44,4 +50,5 @@ require (
golang.org/x/sync v0.19.0 // indirect
golang.org/x/text v0.20.0 // indirect
golang.org/x/tools v0.40.0 // indirect
modernc.org/fileutil v1.0.0 // indirect
)
27 changes: 25 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/alex-ant/gomath v0.0.0-20160516115720-89013a210a82 h1:7dONQ3WNZ1zy960TmkxJPuwoolZwL7xKtpcM04MBnt4=
github.com/alex-ant/gomath v0.0.0-20160516115720-89013a210a82/go.mod h1:nLnM0KdK1CmygvjpDUO6m1TjSsiQtL61juhNsvV/JVI=
github.com/containerd/stargz-snapshotter/estargz v0.18.1 h1:cy2/lpgBXDA3cDKSyEfNOFMA/c10O1axL69EU7iirO8=
github.com/containerd/stargz-snapshotter/estargz v0.18.1/go.mod h1:ALIEqa7B6oVDsrF37GkGN20SuvG/pIMm7FwP7ZmRb0Q=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
Expand All @@ -10,6 +15,10 @@ github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBi
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker-credential-helpers v0.9.3 h1:gAm/VtF9wgqJMoxzT3Gj5p4AqIjCBS4wrsOh9yRqcz8=
github.com/docker/docker-credential-helpers v0.9.3/go.mod h1:x+4Gbw9aGmChi3qTLZj8Dfn0TD20M/fuWy0E5+WDeCo=
github.com/gammazero/toposort v0.1.1 h1:OivGxsWxF3U3+U80VoLJ+f50HcPU1MIqE1JlKzoJ2Eg=
github.com/gammazero/toposort v0.1.1/go.mod h1:H2cozTnNpMw0hg2VHAYsAxmkHXBYroNangj2NTBQDvw=
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/go-containerregistry v0.20.7 h1:24VGNpS0IwrOZ2ms2P1QE3Xa5X9p4phx0aUgzYzHW6I=
Expand All @@ -27,6 +36,8 @@ github.com/goplus/reflectx v1.5.0 h1:d6THLWzrQJCIAnNzyXJDA7J1sxj8ELzKH+Wj17X/dtE
github.com/goplus/reflectx v1.5.0/go.mod h1:wHOS9ilbB4zrecI0W1dMmkW9JMcpXV7VjALVbNU9xfM=
github.com/goplus/xgo v1.6.1 h1:xe4ezrXkBvK5317inkPIqsKVZR3/J0oyT4lcvT9mYPc=
github.com/goplus/xgo v1.6.1/go.mod h1:vEnp8PO5JCJBNXYjnsSTJ1hgAEvbP/IUWzC17pVz4R8=
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jessevdk/go-flags v1.6.1 h1:Cvu5U8UGrLay1rZfv/zP7iLpSHGUZ/Ou68T0iX1bBK4=
Expand All @@ -37,10 +48,14 @@ github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3JH2co=
github.com/klauspost/compress v1.18.1/go.mod h1:ZQFFVG+MdnR0P+l6wpXgIL4NTtwiKIdBnrBd8Nrxr+0=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
Expand All @@ -51,8 +66,12 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/qiniu/go-sdk/v7 v7.26.14 h1:kV9zdvTOM0w9/lgeYffDDw0Fj8FH14/XgCjk4Wb80k8=
github.com/qiniu/go-sdk/v7 v7.26.14/go.mod h1:ri7fGwbio0pRDFr8EK5TUpx0DbnpIMJ2bMSDxGWfCbk=
github.com/qiniu/x v1.16.0 h1:W2VOecyIT3Uxwjm6vJinUR7G3gpwgUgHZA9OpeHArdE=
github.com/qiniu/x v1.16.0/go.mod h1:AiovSOCaRijaf3fj+0CBOpR1457pn24b0Vdb1JpwhII=
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
Expand Down Expand Up @@ -95,6 +114,8 @@ golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA=
golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
Expand All @@ -104,3 +125,5 @@ gorm.io/gorm v1.31.1 h1:7CA8FTFz/gRfgqgpeKIBcervUn3xSyPUmr6B2WXJ7kg=
gorm.io/gorm v1.31.1/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs=
gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0=
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
modernc.org/fileutil v1.0.0 h1:Z1AFLZwl6BO8A5NldQg/xTSjGLetp+1Ubvl4alfGx8w=
modernc.org/fileutil v1.0.0/go.mod h1:JHsWpkrk/CnVV1H/eGlFf85BEpfkrp56ro8nojIq9Q8=
File renamed without changes.
File renamed without changes.
38 changes: 38 additions & 0 deletions internal/artfact/gorm_test.go → internal/artifact/gorm_test.go

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

用不到后面就删除吧?经过讨论现在放Kodo了

Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,44 @@ func TestGormStoreDelete(t *testing.T) {
}
}

func TestGormStoreDatabaseErrors(t *testing.T) {
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{
Logger: logger.Default.LogMode(logger.Silent),
})
if err != nil {
t.Fatalf("gorm.Open: %v", err)
}
sqlDB, err := db.DB()
if err != nil {
t.Fatalf("db.DB: %v", err)
}
store, err := NewGormStore(db)
if err != nil {
t.Fatalf("NewGormStore: %v", err)
}
if err := sqlDB.Close(); err != nil {
t.Fatalf("db.Close: %v", err)
}

ctx := context.Background()
key := Key{Module: "madler/zlib", Version: "v1.3.1", MatrixStr: "amd64-linux"}
value := Artifact{
Source: Source{Type: "ghcr", URL: "https://ghcr.io/v2/meteorsliu/llar/blobs/sha256:abc"},
Type: "tar.gz",
Metadata: "-lz",
Checksum: "abc",
}
if _, _, err := store.Get(ctx, key); err == nil {
t.Fatal("Get with closed database = nil, want error")
}
if _, err := store.Put(ctx, key, value); err == nil {
t.Fatal("Put with closed database = nil, want error")
}
if err := store.Delete(ctx, key); err == nil {
t.Fatal("Delete with closed database = nil, want error")
}
}

func newTestGormStore(t *testing.T) (*GormStore, *sql.DB) {
t.Helper()
return newTestGormStoreWithLogger(t, logger.Default.LogMode(logger.Silent))
Expand Down
128 changes: 128 additions & 0 deletions internal/artifact/kodo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package artifact

import (
"context"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"strings"

qiniuclient "github.com/qiniu/go-sdk/v7/client"
"github.com/qiniu/go-sdk/v7/storagev2/credentials"
httpclient "github.com/qiniu/go-sdk/v7/storagev2/http_client"
"github.com/qiniu/go-sdk/v7/storagev2/objects"
)

const (
kodoArtifactContentType = "application/gzip"
kodoArtifactMetadataKey = "llar-artifact"
)

type KodoArtifactConfig struct {
AccessKey string
SecretKey string
Bucket string
Prefix string
}

type kodoArtifact struct {
bucket string
prefix string
objects *objects.ObjectsManager
}

func NewKodoArtifact(cfg KodoArtifactConfig) Store {
cred := credentials.NewCredentials(cfg.AccessKey, cfg.SecretKey)
return &kodoArtifact{
bucket: cfg.Bucket,
prefix: strings.Trim(cfg.Prefix, "/"),
objects: objects.NewObjectsManager(&objects.ObjectsManagerOptions{
Options: httpclient.Options{Credentials: cred},
}),
}
}

func (s *kodoArtifact) Get(ctx context.Context, key Key) (Artifact, bool, error) {
objectName := s.objectName(key)
object, err := s.objects.Bucket(s.bucket).Object(objectName).Stat().Call(ctx)
if err != nil {
if kodoArtifactObjectNotFound(err) {
return Artifact{}, false, nil
}
return Artifact{}, false, err
}
got, ok := kodoArtifactFromMetadata(object.Metadata)
if !ok {
return Artifact{}, false, fmt.Errorf("read kodo artifact metadata for %s", objectName)
}
return got, true, nil
}

func (s *kodoArtifact) Put(ctx context.Context, key Key, art Artifact) (Artifact, error) {
raw, err := encodeKodoArtifact(art)
if err != nil {
return art, err
}
err = s.objects.Bucket(s.bucket).Object(s.objectName(key)).SetMetadata(kodoArtifactContentType).
Metadata(map[string]string{kodoArtifactMetadataKey: raw}).
Call(ctx)
if err != nil {
return art, err
}
return art, nil
}

func (s *kodoArtifact) Delete(ctx context.Context, key Key) error {
err := s.objects.Bucket(s.bucket).Object(s.objectName(key)).Delete().Call(ctx)
if err != nil && !kodoArtifactObjectNotFound(err) {
return err
}
return nil
}

func (s *kodoArtifact) objectName(key Key) string {
parts := make([]string, 0, 4)
if s.prefix != "" {
parts = append(parts, s.prefix)
}
parts = append(parts, strings.Trim(key.Module, "/"), strings.Trim(key.Version, "/"), key.MatrixStr+".tar.gz")
return strings.Join(parts, "/")
}

func encodeKodoArtifact(art Artifact) (string, error) {
data, err := json.Marshal(art)
if err != nil {
return "", err
}
return base64.RawURLEncoding.EncodeToString(data), nil
}

func kodoArtifactFromMetadata(metadata map[string]string) (Artifact, bool) {
raw := kodoArtifactMetadataValue(metadata, kodoArtifactMetadataKey)
if raw == "" {
return Artifact{}, false
}
data, err := base64.RawURLEncoding.DecodeString(raw)
if err != nil {
return Artifact{}, false
}
var art Artifact
if err := json.Unmarshal(data, &art); err != nil {
return Artifact{}, false
}
return art, true
}

func kodoArtifactMetadataValue(metadata map[string]string, key string) string {
value := metadata[key]
if value == "" {
value = metadata["x-qn-meta-"+key]
}
Comment on lines +119 to +121

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mark 这里link一下文档

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return value
}

func kodoArtifactObjectNotFound(err error) bool {
var info *qiniuclient.ErrorInfo
return errors.As(err, &info) && info.Code == 612
}
Loading
Loading