package config_handler import ( "context" "encoding/json" "errors" "strings" "git.icechen.cn/pkg/drone_plugin/consts" "git.icechen.cn/pkg/drone_plugin/git" "github.com/drone/drone-go/drone" "github.com/drone/drone-go/plugin/config" "github.com/sirupsen/logrus" ) // New returns a new conversion plugin. func New() config.Plugin { return &plugin{} } type plugin struct{} type Handler interface { ToDestinationConfig() (string, error) } func (p *plugin) Find(ctx context.Context, req *config.Request) (*drone.Config, error) { resp, err := json.Marshal(req) if err != nil { logrus.Error(err) return nil, err } logrus.Infof("%s", string(resp)) // 1. 获取原始配置文件信息 cfg, err := getRealConfig(getGitClient(req)) if err != nil { logrus.Error(err) return nil, err } // 2. 是否部署 // 2.1 非 monorepo 的直接返回 if cfg.Type != TypeMonorepo { // 返回 nil 按照 204 处理 return nil, nil } // 2.2 无部署环境报错返回,阻断部署 if getDeployEnv(req) == consts.EnvNone { return nil, errors.New("ignore event") } // 3. 获取提交文件树 modifiedFileList, err := getGitClient(req).GetCommitModifiedFileList() if err != nil { logrus.Error(err) return nil, err } // 4. 根据文件树以及原始配置文件的信息,组装需要构建的服务的ci信息 // 4.1 api modifiedApiList := getModifiedApi(cfg.Api, modifiedFileList, foundAppByMessage(req.Build.Message), foundAppByParams(req.Build.Params)) destinationApi, err := modifiedApiList.toDestinationConfig(getDeployEnv(req)) if err != nil { logrus.Error(err) return nil, err } // 4.2 service modifiedServiceList := getModifiedService(cfg.Service, modifiedFileList, foundAppByMessage(req.Build.Message), foundAppByParams(req.Build.Params)) destinationService, err := modifiedServiceList.toDestinationConfig(getDeployEnv(req)) if err != nil { logrus.Error(err) return nil, err } if len(modifiedApiList) == 0 && len(modifiedServiceList) == 0 { // 返回空 return &drone.Config{ Data: "", Kind: "", }, errors.New("skipping build") } retData := destinationApi + "\n\n" + destinationService n := strings.LastIndex(retData, "---") if n > 0 { retData = retData[:n] } logrus.Info(retData) // 5. 组装所有ci信息并输出 return &drone.Config{ Data: retData, Kind: "pipeline", }, nil } func getGitClient(req *config.Request) git.Client { return git.New(req.Repo.Namespace, req.Repo.Name, req.Build.After, req.Repo.Config) } func getDeployEnv(req *config.Request) consts.Env { switch req.Build.Event { case "push": fallthrough case "custom": if req.Build.Target == "master" { return consts.EnvTest } case "tag": return consts.EnvProduction } return consts.EnvNone } func getModifiedApi(api ApiList, modifiedFileList []string, appByMessage []string, appByParams []string) ApiList { ret := make(ApiList, 0) tempIndex := NewSet() for i, a := range api { for _, file := range modifiedFileList { if strings.HasPrefix(file, a.Root) { tempIndex.Add(i) } } } for _, i := range tempIndex.ToSlice() { ret = append(ret, api[i]) } ret = append(ret, getDeployApiByAppSlice(api, append(appByMessage, appByParams...))...) return ret } func getDeployApiByAppSlice(api ApiList, appSlice []string) ApiList { ret := make(ApiList, 0) for _, app := range appSlice { for _, a := range api { appWithNamespace := strings.Split(app, ".") if len(appWithNamespace) == 2 { name := appWithNamespace[0] namespace := appWithNamespace[1] if a.Namespace == strings.TrimSpace(namespace) && "api-"+a.Name == strings.TrimSpace(name) { ret = append(ret, a) } } } } return ret } func getModifiedService(service ServiceList, modifiedFileList []string, appByMessage []string, appByParams []string) ServiceList { ret := make(ServiceList, 0) tempIndex := NewSet() for i, s := range service { for _, file := range modifiedFileList { if strings.HasPrefix(file, s.Root) { tempIndex.Add(i) } } } for _, i := range tempIndex.ToSlice() { ret = append(ret, service[i]) } ret = append(ret, getDeployServiceByAppSlice(service, append(appByMessage, appByParams...))...) return ret } func getDeployServiceByAppSlice(service ServiceList, appSlice []string) ServiceList { ret := make(ServiceList, 0) for _, app := range appSlice { for _, s := range service { appWithNamespace := strings.Split(app, ".") if len(appWithNamespace) == 2 { name := appWithNamespace[0] namespace := appWithNamespace[1] if s.Namespace == strings.TrimSpace(namespace) && "service-"+s.Name == strings.TrimSpace(name) { ret = append(ret, s) } } } } return ret } func foundAppByMessage(message string) []string { i := strings.Index(message, "[") if i >= 0 { j := strings.Index(message[i:], "]") if j >= 0 { return append(strings.Split(message[i+1:j+i], ","), foundAppByMessage(message[j+i:])...) } } return []string{} } func foundAppByParams(params map[string]string) []string { app, has := params["app"] if has { return strings.Split(app, ",") } return []string{} }