【cobra】手写你的第一个命令行脚手架工具 | cobra整合go template通过终端以命令行方式生成.drone.yml 模板

零、前言

本次教程使用的开源框架如下:

名字 开源地址 作用
Cobra 命令行工具 https://github.com/spf13/cobra
Aurora 字体颜色 https://github.com/logrusorgru/aurora
go-zero go-z框架 模板功能 https://github.com/zeromicro/go-zero

本项目完整源码https://github.com/ctra-wang/cobra-gen-drone

一、初识 Cobra

在这里插入图片描述

1、Cobra作用

概述:Cobra 是一个 Golang 包,它提供了简单的接口来创建命令行程序。同时,Cobra 也是一个应用程序,用来生成应用框架,从而开发以 Cobra 为基础的应用。
代表作dockerk8shelm

详细使用就不在这里详细介绍了

  • 推荐文章如下:

官方文档:https://cobra.dev/

Go 语言现代命令行框架 Cobra 详解:https://jianghushinian.cn/2023/05/08/go-modern-command-line-framework-cobra-details/

Cobra 快速入门 - 专为命令行程序而生:https://blog.csdn.net/xcbeyond/article/details/119429114

  • 推荐视频如下:

cobra的基本使用

二、go template

这里是我们要渲染模板(.tpl格式结尾的文件)
通过渲染模板,才能输出我们想要的最终文件

1、go template 使用

详细使用和说明接不介绍了

关于template
我们可以使用 .tpl的文件,也可以直接用 ``字符串包裹进行渲染。主要使用go中 { {}} 双大括号的特性

三、开始项目

整个项目目录如下:
在这里插入图片描述

1、创建项目整理目录

1.1、创建go.mod 和 cmd文件夹

go mod init xxxx

mkdir cmd

1.2、创建main文件

package main

import (
	"app/cmd"
)

func main() {
    
    
	cmd.Execute()
}

1.3、在cmd文件夹创建cmd.go

代码如下

package cmd

import (
	"fmt"
	"github.com/logrusorgru/aurora"
	"github.com/spf13/cobra"
	"os"
)

// droneCmd represents the drone command
var droneCmd = &cobra.Command{
    
    
	Use:   "drone",
	Short: "drone is very good",
	Long:  `创建drone的指令`,
	RunE:  DroneGenerator, //步骤一
}

var (
	//步骤三
	DroneName   string
	GoPrivate   string
	ServiceName string
	ServiceType string
	GitBranch   string
	Registry    string
	Repo        string
	Tag         string
)

func Execute() {
    
    
	if err := droneCmd.Execute(); err != nil {
    
    
		fmt.Println(aurora.Red(err.Error()))
		os.Exit(1)
	}
}

func init() {
    
    
	// drone --droneName="base" --go_private="gitee.com" --service_name="baserpc.go" --service_type="rpc" --gitBranch="master" --registry="registry.cn-beijing.aliyuncs.com" --repo="registry.cn-beijing.aliyuncs.com/ctra_test/ctra-go-zhiye-rpc" --tag="latest"
	// drone -d="base" -g="gitee.com" -s="baserpc.go" -x="rpc" -b="master" -r="registry.cn-beijing.aliyuncs.com" -o="registry.cn-beijing.aliyuncs.com/ctra_test/ctra-go-zhiye-rpc" -t="latest"

	// 步骤二
	droneCmd.Flags().StringVarP(&DroneName, aurora.Yellow("droneName").String(), "d", "", aurora.Green(`The Drone name`).String())
	droneCmd.Flags().StringVarP(&GoPrivate, "go_private", "g", "", aurora.Green(`Go private (default "gitee.com")`).String())
	droneCmd.Flags().StringVarP(&ServiceName, "service_name", "s", "", aurora.Green(`The service name of the project`).String())
	droneCmd.Flags().StringVarP(&ServiceType, "service_type", "x", "", aurora.Green(`The service type, such as rpc | api`).String())
	droneCmd.Flags().StringVarP(&GitBranch, "gitBranch", "b", "", `The branch of the remote repo, it does work with --remote (default "master")`)
	droneCmd.Flags().StringVarP(&Registry, "registry", "r", "", `The remote git repo of the template, --home and --remote cannot be set at the same time, if they are, --remote has higher priority  
    The git repo directory must be consistent with the https://github.com/zeromicro/go-zero-template directory structure`)
	droneCmd.Flags().StringVarP(&Repo, "repo", "o", "", aurora.Green(`The project git repository`).String())
	droneCmd.Flags().StringVarP(&Tag, "tag", "t", "", aurora.Green("Git tag (default \"latest\")").String())

	// Here you will define your flags and configuration settings.

	// Cobra supports Persistent Flags which will work for this command
	// and all subcommands, e.g.:
	droneCmd.PersistentFlags().String("droneName", "", "A help for foo")

	// Cobra supports local flags which will only run when this command
	// is called directly, e.g.:
	// droneCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}

1.4、在cmd文件夹创建 drone.go

package cmd

import (
	_ "embed"
	"fmt"
	"github.com/logrusorgru/aurora"
	"github.com/spf13/cobra"
	"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
	"os"
	"strings"
	"text/template"
)

var (
	//go:embed drone.tpl
	UsageTpl string
)

type Drone struct {
    
    
	//步骤三
	DroneName   string
	GoPrivate   string
	ServiceName string
	ServiceType string
	GitBranch   string
	Registry    string
	Repo        string
	Tag         string
}

func DroneGenerator(_ *cobra.Command, _ []string) error {
    
    

	// 步骤四
	// 对所有的传入的参数进行一一判断
	dronename := DroneName
	if len(dronename) == 0 {
    
    
		dronename = "dronegen-greet"
	}

	goprivate := GoPrivate
	fmt.Println(len(strings.Split(goprivate, ".")))
	if len(strings.Split(goprivate, ".")) <= 1 {
    
    
		return fmt.Errorf("error go private!")
	}

	serviceName := ServiceName
	serviceType := ServiceType
	gitBranch := GitBranch
	registry := Registry
	repo := Repo
	tag := Tag

	file, err := os.Create("drone.yml")
	if err != nil {
    
    
		fmt.Println("文件创建失败:", err)
		return err
	} else {
    
    
		fmt.Println("文件创建成功!")
	}

	defer file.Close()

	text, err := pathx.LoadTemplate("dronegen", "drone.tpl", UsageTpl)
	if err != nil {
    
    
		fmt.Println("打开模板失败:", err)
		return err
	} else {
    
    
		fmt.Println("打开模板成功!")
	}

	t := template.Must(template.New("dronegen").Parse(text))
	return t.Execute(file, Drone{
    
    
		DroneName:   dronename,
		GoPrivate:   goprivate,
		ServiceName: serviceName,
		ServiceType: serviceType,
		GitBranch:   gitBranch,
		Registry:    registry,
		Repo:        repo,
		Tag:         tag,
	})
	fmt.Println(aurora.Green("Done."))

	return nil
}

1.5、创建 drone.tpl 模板文件

kind: pipeline
type: docker
name: {
    
    {
    
    .DroneName}}-{
    
    {
    
    .ServiceType}}
steps:
  - name: build-go
    image: golang:1.20.3
    depends_on: [clone]
    volumes:
      - name: go_cache
        path: /go/pkg/mod
    commands:
      - go env -w CGO_ENABLED=0
      - go env -w GOPROXY=https://goproxy.cn,direct
      - go env -w GOPRIVATE= {
    
    {
    
    .GoPrivate}}
      - go mod tidy && go build -trimpath -ldflags "-s -w" -o app {
    
    {
    
    .ServiceName}}.go

  - name: build-{
    
    {
    
    .ServiceType}}
    image: plugins/docker:20
    environment:
      DRONE_REPO_BRANCH: {
    
    {
    
    .GitBranch}}
    depends_on: [build-go]
    settings:
      dockerfile: Dockerfile
      registry: {
    
    {
    
    .Registry}}
      repo: {
    
    {
    
    .Repo}}:{
    
    {
    
    .Tag}}
      auto_tag: true
      insecure: true
      username:
        from_secret: docker_username
      password:
        from_secret: docker_password
trigger:
  ref:
    - refs/tags/*
    - refs/heads/master

volumes:
  - name: go_cache
    host:
      path: /root/.go/cache

2、goland中如何调试?

这种命令行的代码调试和传统的main入口程序调试是完全不一样的

2.1、Edit configurations

配置这里
在这里插入图片描述

2.2、program argument

这里很重要,如果这里不设置我们需要输入的指令值,则无法进入对应的断点

在这里插入图片描述

3、编译执行

3.1、将文件编译成二进制文件

go build main.go

3.2、执行

长指令

drone -d="base" -g="gitee.com" -s="baserpc.go" -x="rpc" -b="master" -r="registry.cn-beijing.aliyuncs.com" -o="registry.cn-beijing.aliyuncs.com/ctra_test/ctra-go-zhiye-rpc" -t="latest"

短指令

drone --droneName="base" --go_private="gitee.com" --service_name="baserpc.go" --service_type="rpc" --gitBranch="master" --registry="registry.cn-beijing.aliyuncs.com" --repo="registry.cn-beijing.aliyuncs.com/ctra_test/ctra-go-zhiye-rpc" --tag="latest"

可以看到drone.yml 文件已经生成
在这里插入图片描述

4、注意这里踩得大坑

来看一下在 Drone 的配置页面中
Configuration 默认的文件名的前缀 是 点!!!

在这里插入图片描述

Golang中的 os.create()函数

	file, err := os.Create("drone.yml")
	if err != nil {
    
    
		fmt.Println("文件创建失败:", err)
		return err
	} else {
    
    
		fmt.Println("文件创建成功!")
	}

如果我们使用默认的 .drone.yml,则我们将编译好的文件在哪执行都不会产生这个文件!!十分之坑

file, err := os.Create(".drone.yml")

猜你喜欢

转载自blog.csdn.net/wanglei19891210/article/details/131847587