package main import ( "crypto/tls" "fmt" "net/http" "os" "path/filepath" "strconv" "strings" "code.gitea.io/sdk/gitea" gha "github.com/sethvargo/go-githubactions" ) func main() { ctx, err := gha.Context() if err != nil { gha.Fatalf("failed to get context: %v", err) } if !strings.HasPrefix(ctx.Ref, "refs/tags/") { gha.Fatalf("ref %s is not a tag", ctx.Ref) } files := gha.GetInput("files") title := gha.GetInput("title") body := gha.GetInput("body") note := gha.GetInput("note") apiKey := gha.GetInput("api_key") preRelease, _ := strconv.ParseBool(gha.GetInput("pre_release")) draft, _ := strconv.ParseBool(gha.GetInput("draft")) if title == "" { title = ctx.RefName } if apiKey == "" { apiKey = os.Getenv("GITHUB_TOKEN") } insecure, _ := strconv.ParseBool(gha.GetInput("insecure")) client := http.DefaultClient if insecure { tr := &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, } client = &http.Client{Transport: tr} } c, err := gitea.NewClient(ctx.ServerURL, gitea.SetToken(apiKey), gitea.SetHTTPClient(client)) if err != nil { gha.Fatalf("failed to create gitea client: %v", err) } owner := ctx.RepositoryOwner repo := strings.Split(ctx.Repository, "/")[1] // 获取上一个 tag 的 SHA tags, _, err := c.ListRepoTags(owner, repo, gitea.ListRepoTagsOptions{ ListOptions: gitea.ListOptions{ Page: 1, PageSize: 100, }, }) if err != nil { gha.Fatalf("failed to get tags: %v", err) } previewTagSHA := "" if len(tags) > 1 { previewTagSHA = tags[1].Commit.SHA } // 获取上一个 tag 至当前 tag 之间的所有 commit 信息,列出提交信息 commits, _, err := c.ListRepoCommits(owner, repo, gitea.ListCommitOptions{}) if err != nil { gha.Fatalf("failed to get commits: %v", err) } commitCount := 1 commitHistory := "" for _, commit := range commits { if previewTagSHA == commit.SHA { break } commitHistory += fmt.Sprintf("%d. %s\n", commitCount, commit.RepoCommit.Message) commitCount++ } if body == "" { body = "\n## 内容\n" + commitHistory } body += "## 提示\n" + note fmt.Printf("Creating release for %s/%s with tag %s\n", owner, repo, ctx.RefName) fmt.Printf("Title: %s\n", title) fmt.Printf("Note: %s\n", body) rel, err := createOrGetRelease(ctx, c, owner, repo, gitea.CreateReleaseOption{ TagName: ctx.RefName, IsDraft: draft, IsPrerelease: preRelease, Title: title, Target: ctx.SHA, Note: body, }) if err != nil { gha.Fatalf("failed to create release: %v", err) } matchedFiles, err := getFiles(ctx.Workspace, files) if err != nil { gha.Fatalf("failed to get files: %v", err) } if err := uploadFiles(ctx, c, owner, repo, rel.ID, matchedFiles); err != nil { gha.Fatalf("Failed to upload files: %v", err) } gha.SetOutput("status", "success") } func getDirFiles(dir string) ([]string, error) { d, err := os.Open(dir) if err != nil { return nil, err } defer d.Close() info, err := d.Stat() if err != nil { return nil, err } if !info.IsDir() { return []string{dir}, nil } list, err := d.Readdirnames(0) if err != nil { return nil, err } res := make([]string, 0, len(list)) for _, f := range list { subs, err := getDirFiles(filepath.Join(dir, f)) if err != nil { return nil, err } res = append(res, subs...) } return res, nil } func getFiles(parentDir, files string) ([]string, error) { var fileList []string lines := strings.Split(files, "\n") for _, line := range lines { line = strings.Trim(line, "'") line = strings.TrimSpace(strings.Trim(line, `"`)) if line == "" { continue } if filepath.IsAbs(line) { return nil, fmt.Errorf("file path %s is absolute", line) } line = filepath.Join(parentDir, line) matches, err := filepath.Glob(line) if err != nil { return nil, err } for _, match := range matches { files, err := getDirFiles(match) if err != nil { return nil, err } fileList = append(fileList, files...) } } return fileList, nil } func createOrGetRelease(ctx *gha.GitHubContext, c *gitea.Client, owner, repo string, opts gitea.CreateReleaseOption) (*gitea.Release, error) { // Get the release by tag release, resp, err := c.GetReleaseByTag(owner, repo, opts.TagName) if err == nil { return release, nil } errMessage := fmt.Errorf("failed to get release for tag: %s with error: %w", opts.TagName, err) if resp.StatusCode != 404 { return nil, errMessage } fmt.Printf("%s trying to create it\n", errMessage) // Create the release release, _, err = c.CreateRelease(owner, repo, opts) if err != nil { return nil, fmt.Errorf("failed to create release: %w and %s", err, errMessage) } return release, nil } func uploadFiles(ctx *gha.GitHubContext, c *gitea.Client, owner, repo string, releaseID int64, files []string) error { attachments, _, err := c.ListReleaseAttachments(owner, repo, releaseID, gitea.ListReleaseAttachmentsOptions{}) if err != nil { return fmt.Errorf("failed to fetch existing release attachments: %w", err) } for _, file := range files { f, err := os.Open(file) if err != nil { return fmt.Errorf("failed to open release attachment %s: %w", file, err) } for _, attachment := range attachments { if attachment.Name == filepath.Base(file) { if _, err := c.DeleteReleaseAttachment(owner, repo, releaseID, attachment.ID); err != nil { f.Close() return fmt.Errorf("failed to delete release attachment %s: %w", file, err) } fmt.Printf("Successfully deleted old release attachment %s\n", attachment.Name) } } if _, _, err = c.CreateReleaseAttachment(owner, repo, releaseID, f, filepath.Base(file)); err != nil { f.Close() return fmt.Errorf("failed to upload release attachment %s: %w", file, err) } f.Close() fmt.Printf("Successfully uploaded release attachment %s\n", file) } return nil }