ci(drone): 添加 Go 模块和构建缓存

- 在 restore cache 和 rebuild cache 步骤中添加了 go-mod-cache 和 go
This commit is contained in:
hxt
2025-07-10 21:16:25 +08:00
parent d36a8bec21
commit 9293db3809
5 changed files with 103 additions and 141 deletions

View File

@@ -1 +1,20 @@
package consts package consts
const (
// 笑门官网查询英雄名称和神器名称,用作中文翻译
SimileHeroName = "https://static.smilegatemegaport.com/gameRecord/epic7/epic7_hero.json?_=1729322698936"
SimileArtifactName = "https://static.smilegatemegaport.com/gameRecord/epic7/epic7_artifact.json?_=1729322698936"
// 获取角色信息
HeroListURL = "https://e7-optimizer-game-data.s3-accelerate.amazonaws.com/herodata.json"
// 获取神器信息
ArtifactDataURL = "https://e7-optimizer-game-data.s3-accelerate.amazonaws.com/artifactdata.json"
// 根据角色名字查询配装
HeroNameURL = "https://krivpfvxi0.execute-api.us-west-2.amazonaws.com/dev/getBuilds"
// 官方数据接口示例https://static.smilegatemegaport.com/event/live/epic7/guide/images/hero/c2027_s.png
// 角色图片基础 URL
GfHeroPngURL = "https://static.smilegatemegaport.com/event/live/epic7/guide/images/hero/"
)

View File

@@ -1,114 +0,0 @@
package cron
import (
"context"
"testing"
"time"
)
func TestCronLogic_AddJob(t *testing.T) {
ctx := context.Background()
logic := New()
// 测试添加任务
err := logic.AddJob(ctx, "test_job", "* * * * *", func() {
t.Log("Test job executed")
})
if err != nil {
t.Errorf("Failed to add job: %v", err)
}
// 测试重复添加同名任务
err = logic.AddJob(ctx, "test_job", "* * * * *", func() {
t.Log("Test job executed again")
})
if err == nil {
t.Error("Expected error when adding duplicate job name")
}
// 清理
logic.RemoveJob(ctx, "test_job")
}
func TestCronLogic_GetJobStatus(t *testing.T) {
ctx := context.Background()
logic := New()
// 添加任务
err := logic.AddJob(ctx, "status_test_job", "* * * * *", func() {
t.Log("Status test job executed")
})
if err != nil {
t.Fatalf("Failed to add job: %v", err)
}
// 测试获取任务状态
status, err := logic.GetJobStatus(ctx, "status_test_job")
if err != nil {
t.Errorf("Failed to get job status: %v", err)
}
if !status {
t.Error("Expected job to be active")
}
// 测试获取不存在的任务状态
status, err = logic.GetJobStatus(ctx, "non_existent_job")
if err != nil {
t.Errorf("Failed to get non-existent job status: %v", err)
}
if status {
t.Error("Expected non-existent job to be inactive")
}
// 清理
logic.RemoveJob(ctx, "status_test_job")
}
func TestCronLogic_RemoveJob(t *testing.T) {
ctx := context.Background()
logic := New()
// 添加任务
err := logic.AddJob(ctx, "remove_test_job", "* * * * *", func() {
t.Log("Remove test job executed")
})
if err != nil {
t.Fatalf("Failed to add job: %v", err)
}
// 测试移除任务
err = logic.RemoveJob(ctx, "remove_test_job")
if err != nil {
t.Errorf("Failed to remove job: %v", err)
}
// 测试移除不存在的任务
err = logic.RemoveJob(ctx, "non_existent_job")
if err == nil {
t.Error("Expected error when removing non-existent job")
}
}
func TestCronLogic_StartStopJobs(t *testing.T) {
ctx := context.Background()
logic := New()
// 启动任务
err := logic.StartAllJobs(ctx)
if err != nil {
t.Errorf("Failed to start jobs: %v", err)
}
// 等待一段时间让任务执行
time.Sleep(2 * time.Second)
// 停止任务
err = logic.StopAllJobs(ctx)
if err != nil {
t.Errorf("Failed to stop jobs: %v", err)
}
}

View File

@@ -2,6 +2,7 @@ package cron
import ( import (
"context" "context"
"epic/internal/consts"
"epic/internal/model/dto" "epic/internal/model/dto"
"epic/utility" "epic/utility"
"fmt" "fmt"
@@ -30,7 +31,7 @@ func (t *ThirdPartyDataSync) SyncHeroData(ctx context.Context) error {
// 示例从第三方API获取英雄数据 // 示例从第三方API获取英雄数据
heroData, err := t.fetchHeroDataFromAPI(ctx) heroData, err := t.fetchHeroDataFromAPI(ctx)
if err != nil { if err != nil || heroData == nil {
g.Log().Error(ctx, "获取英雄数据失败:", err) g.Log().Error(ctx, "获取英雄数据失败:", err)
return err return err
} }
@@ -71,7 +72,7 @@ func (t *ThirdPartyDataSync) SyncArtifactData(ctx context.Context) error {
// fetchHeroDataFromAPI 从API获取英雄数据 // fetchHeroDataFromAPI 从API获取英雄数据
func (t *ThirdPartyDataSync) fetchHeroDataFromAPI(ctx context.Context) ([]byte, error) { func (t *ThirdPartyDataSync) fetchHeroDataFromAPI(ctx context.Context) ([]byte, error) {
// 示例API地址实际使用时需要替换为真实的API // 示例API地址实际使用时需要替换为真实的API
apiURL := "https://api.example.com/heroes" apiURL := consts.HeroListURL
// 添加请求头 // 添加请求头
headers := map[string]string{ headers := map[string]string{
@@ -128,23 +129,24 @@ func (t *ThirdPartyDataSync) fetchArtifactDataFromAPI(ctx context.Context) (stri
func (t *ThirdPartyDataSync) processAndSaveHeroData(ctx context.Context, data []byte) error { func (t *ThirdPartyDataSync) processAndSaveHeroData(ctx context.Context, data []byte) error {
// 使用 gjson 解析 // 使用 gjson 解析
j := gjson.New(data) j := gjson.New(data)
// 检查json对象本身和其内部值并使用 .Var().IsSlice() 这种更可靠的方式判断是否为数组
if j == nil || j.IsNil() || !j.Var().IsSlice() { if j == nil || j.IsNil() {
return fmt.Errorf("英雄数据格式错误期望是一个JSON数组") return fmt.Errorf("英雄数据格式错误期望是一个JSON对象")
} }
var heroes []*dto.ThirdPartyHeroDTO // 先解析为 map[string]*ThirdPartyHeroDTO
var heroes map[string]*dto.ThirdPartyHeroDTO
if err := j.Scan(&heroes); err != nil { if err := j.Scan(&heroes); err != nil {
return fmt.Errorf("解析英雄数据到DTO失败: %v", err) return fmt.Errorf("解析英雄数据到DTO失败: %v", err)
} }
g.Log().Info(ctx, "解析到", len(heroes), "个英雄数据") g.Log().Info(ctx, "解析到", len(heroes), "个英雄数据")
// 批量处理数据 // 遍历 map设置 Name 字段,并保存
for _, hero := range heroes { for name, hero := range heroes {
hero.Name = name // 将 map 的 key 作为 Name 字段
if err := t.saveHeroData(ctx, hero); err != nil { if err := t.saveHeroData(ctx, hero); err != nil {
g.Log().Error(ctx, "保存英雄数据失败:", err) g.Log().Error(ctx, "保存英雄数据失败:", err)
// 继续处理其他数据,不中断整个流程
continue continue
} }
} }

View File

@@ -13,7 +13,7 @@ import (
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
// 必须在任何import和g.Cfg()调用前设置环境变量 // 必须在任何import和g.Cfg()调用前设置环境变量
genv.Set("GF_GCFG_FILE", "D:/code/go/epic/manifest/config/config.yaml") genv.Set("GF_GCFG_FILE", "../../../../manifest/config/config.yaml")
ctx := gctx.New() ctx := gctx.New()
_ = g.Cfg().MustGet(ctx, "server.address") _ = g.Cfg().MustGet(ctx, "server.address")
fmt.Println(g.Cfg().Get(ctx, "redis.default.address")) fmt.Println(g.Cfg().Get(ctx, "redis.default.address"))
@@ -50,17 +50,18 @@ func (m *mockSync) processAndSaveArtifactData(ctx context.Context, data []byte)
return m.processArtifactErr return m.processArtifactErr
} }
//func TestSyncHeroData_Success(t *testing.T) { /**
// sync := &ThirdPartyDataSync{} * 测试同步英雄数据
// // 替换方法为mock */
// sync.fetchHeroDataFromAPI = (&mockSync{}).fetchHeroDataFromAPI func TestSyncHeroData(t *testing.T) {
// sync.processAndSaveHeroData = (&mockSync{}).processAndSaveHeroData thirdPartyDataSync := NewThirdPartyDataSync()
//
// err := sync.SyncHeroData(context.Background()) err := thirdPartyDataSync.SyncHeroData(context.Background())
// if err != nil { if err != nil {
// t.Errorf("expected success, got error: %v", err) t.Errorf("expected success, got error: %v", err)
// } }
//} }
// //
//func TestSyncHeroData_FetchError(t *testing.T) { //func TestSyncHeroData_FetchError(t *testing.T) {
// sync := &ThirdPartyDataSync{} // sync := &ThirdPartyDataSync{}
@@ -96,6 +97,7 @@ func (m *mockSync) processAndSaveArtifactData(ctx context.Context, data []byte)
//} //}
// //
//func TestSyncArtifactData_FetchError(t *testing.T) { //func TestSyncArtifactData_FetchError(t *testing.T) {
// sync := &ThirdPartyDataSync{} // sync := &ThirdPartyDataSync{}
// sync.fetchArtifactDataFromAPI = (&mockSync{fetchArtifactDataErr: errors.New("fetch error")}).fetchArtifactDataFromAPI // sync.fetchArtifactDataFromAPI = (&mockSync{fetchArtifactDataErr: errors.New("fetch error")}).fetchArtifactDataFromAPI
// sync.processAndSaveArtifactData = (&mockSync{}).processAndSaveArtifactData // sync.processAndSaveArtifactData = (&mockSync{}).processAndSaveArtifactData

View File

@@ -17,10 +17,63 @@ type ThirdPartyArtifactDTO struct {
// ThirdPartyHeroDTO represents a hero from the third-party API. // ThirdPartyHeroDTO represents a hero from the third-party API.
// Note: This is a placeholder structure. Adjust it according to the actual API response. // Note: This is a placeholder structure. Adjust it according to the actual API response.
// ThirdPartyHeroDTO 第三方英雄数据传输对象
type ThirdPartyHeroDTO struct { type ThirdPartyHeroDTO struct {
Code string `json:"code"` Code string `json:"code"`
Name string `json:"name"` ID string `json:"_id"`
Rarity int `json:"rarity"` Name string `json:"-"`
Attribute string `json:"attribute"` Rarity int `json:"rarity"`
Role string `json:"role"` Attribute string `json:"attribute"`
} Role string `json:"role"`
Zodiac string `json:"zodiac"`
SelfDevotion SelfDevotion `json:"self_devotion"`
Assets Assets `json:"assets"`
ExEquip []ExEquip `json:"ex_equip"`
Skills map[string]Skill `json:"skills"`
CalculatedStatus map[string]Status `json:"calculatedStatus"`
}
type SelfDevotion struct {
Type string `json:"type"`
Grades map[string]float64 `json:"grades"`
}
type Assets struct {
Icon string `json:"icon"`
Image string `json:"image"`
Thumbnail string `json:"thumbnail"`
}
type ExEquip struct {
Stat struct {
Type string `json:"type"`
Value float64 `json:"value"`
} `json:"stat"`
}
type Skill struct {
HitTypes []string `json:"hitTypes"`
Rate float64 `json:"rate,omitempty"`
Pow float64 `json:"pow,omitempty"`
Targets int `json:"targets,omitempty"`
SelfHpScale float64 `json:"selfHpScaling,omitempty"`
SelfDefScale float64 `json:"selfDefScaling,omitempty"`
Options []any `json:"options"`
}
type Status struct {
Lv50FiveStarFullyAwakened Stats `json:"lv50FiveStarFullyAwakened"`
Lv60SixStarFullyAwakened Stats `json:"lv60SixStarFullyAwakened"`
}
type Stats struct {
CP int `json:"cp"`
ATK int `json:"atk"`
HP int `json:"hp"`
SPD int `json:"spd"`
DEF int `json:"def"`
CHC float64 `json:"chc"`
CHD float64 `json:"chd"`
DAC float64 `json:"dac"`
EFF int `json:"eff"`
EFR int `json:"efr"`
}