mirror of
				https://github.com/openimsdk/open-im-server.git
				synced 2025-10-27 05:52:29 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			199 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			199 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package main
 | |
| 
 | |
| import (
 | |
| 	"encoding/json"
 | |
| 	"fmt"
 | |
| 	"io"
 | |
| 	"net/http"
 | |
| 	"os"
 | |
| 	"regexp"
 | |
| 	"strings"
 | |
| )
 | |
| 
 | |
| // You can specify a tag as a command line argument to generate the changelog for a specific version.
 | |
| // Example: go run tools/changelog/changelog.go v0.0.33
 | |
| // If no tag is provided, the latest release will be used.
 | |
| 
 | |
| // Setting repo owner and repo name by generate changelog
 | |
| const (
 | |
| 	repoOwner = "openimsdk"
 | |
| 	repoName  = "open-im-server"
 | |
| )
 | |
| 
 | |
| // GitHubRepo struct represents the repo details.
 | |
| type GitHubRepo struct {
 | |
| 	Owner         string
 | |
| 	Repo          string
 | |
| 	FullChangelog string
 | |
| }
 | |
| 
 | |
| // ReleaseData represents the JSON structure for release data.
 | |
| type ReleaseData struct {
 | |
| 	TagName   string `json:"tag_name"`
 | |
| 	Body      string `json:"body"`
 | |
| 	HtmlUrl   string `json:"html_url"`
 | |
| 	Published string `json:"published_at"`
 | |
| }
 | |
| 
 | |
| // Method to classify and format release notes.
 | |
| func (g *GitHubRepo) classifyReleaseNotes(body string) map[string][]string {
 | |
| 	result := map[string][]string{
 | |
| 		"feat":     {},
 | |
| 		"fix":      {},
 | |
| 		"chore":    {},
 | |
| 		"refactor": {},
 | |
| 		"build":    {},
 | |
| 		"other":    {},
 | |
| 	}
 | |
| 
 | |
| 	// Regular expression to extract PR number and URL (case insensitive)
 | |
| 	rePR := regexp.MustCompile(`(?i)in (https://github\.com/[^\s]+/pull/(\d+))`)
 | |
| 
 | |
| 	// Split the body into individual lines.
 | |
| 	lines := strings.Split(body, "\n")
 | |
| 
 | |
| 	for _, line := range lines {
 | |
| 		// Skip lines that contain "deps: Merge"
 | |
| 		if strings.Contains(strings.ToLower(line), "deps: merge #") {
 | |
| 			continue
 | |
| 		}
 | |
| 
 | |
| 		// Use a regular expression to extract Full Changelog link and its title (case insensitive).
 | |
| 		if strings.Contains(strings.ToLower(line), "**full changelog**") {
 | |
| 			matches := regexp.MustCompile(`(?i)\*\*full changelog\*\*: (https://github\.com/[^\s]+/compare/([^\s]+))`).FindStringSubmatch(line)
 | |
| 			if len(matches) > 2 {
 | |
| 				// Format the Full Changelog link with title
 | |
| 				g.FullChangelog = fmt.Sprintf("[%s](%s)", matches[2], matches[1])
 | |
| 			}
 | |
| 			continue // Skip further processing for this line.
 | |
| 		}
 | |
| 
 | |
| 		if strings.HasPrefix(line, "*") {
 | |
| 			var category string
 | |
| 
 | |
| 			// Use strings.ToLower to make the matching case insensitive
 | |
| 			lowerLine := strings.ToLower(line)
 | |
| 
 | |
| 			// Determine the category based on the prefix (case insensitive).
 | |
| 			if strings.HasPrefix(lowerLine, "* feat") {
 | |
| 				category = "feat"
 | |
| 			} else if strings.HasPrefix(lowerLine, "* fix") {
 | |
| 				category = "fix"
 | |
| 			} else if strings.HasPrefix(lowerLine, "* chore") {
 | |
| 				category = "chore"
 | |
| 			} else if strings.HasPrefix(lowerLine, "* refactor") {
 | |
| 				category = "refactor"
 | |
| 			} else if strings.HasPrefix(lowerLine, "* build") {
 | |
| 				category = "build"
 | |
| 			} else {
 | |
| 				category = "other"
 | |
| 			}
 | |
| 
 | |
| 			// Extract PR number and URL (case insensitive)
 | |
| 			matches := rePR.FindStringSubmatch(line)
 | |
| 			if len(matches) == 3 {
 | |
| 				prURL := matches[1]
 | |
| 				prNumber := matches[2]
 | |
| 				// Format the line with the PR link and use original content for the final result
 | |
| 				formattedLine := fmt.Sprintf("* %s [#%s](%s)", strings.Split(line, " by ")[0][2:], prNumber, prURL)
 | |
| 				result[category] = append(result[category], formattedLine)
 | |
| 			} else {
 | |
| 				// If no PR link is found, just add the line as is
 | |
| 				result[category] = append(result[category], line)
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return result
 | |
| }
 | |
| 
 | |
| // Method to generate the final changelog.
 | |
| func (g *GitHubRepo) generateChangelog(tag, date, htmlURL, body string) string {
 | |
| 	sections := g.classifyReleaseNotes(body)
 | |
| 
 | |
| 	// Convert ISO 8601 date to simpler format (YYYY-MM-DD)
 | |
| 	formattedDate := date[:10]
 | |
| 
 | |
| 	// Changelog header with tag, date, and links.
 | |
| 	changelog := fmt.Sprintf("## [%s](%s) \t(%s)\n\n", tag, htmlURL, formattedDate)
 | |
| 
 | |
| 	if len(sections["feat"]) > 0 {
 | |
| 		changelog += "### New Features\n" + strings.Join(sections["feat"], "\n") + "\n\n"
 | |
| 	}
 | |
| 	if len(sections["fix"]) > 0 {
 | |
| 		changelog += "### Bug Fixes\n" + strings.Join(sections["fix"], "\n") + "\n\n"
 | |
| 	}
 | |
| 	if len(sections["chore"]) > 0 {
 | |
| 		changelog += "### Chores\n" + strings.Join(sections["chore"], "\n") + "\n\n"
 | |
| 	}
 | |
| 	if len(sections["refactor"]) > 0 {
 | |
| 		changelog += "### Refactors\n" + strings.Join(sections["refactor"], "\n") + "\n\n"
 | |
| 	}
 | |
| 	if len(sections["build"]) > 0 {
 | |
| 		changelog += "### Builds\n" + strings.Join(sections["build"], "\n") + "\n\n"
 | |
| 	}
 | |
| 	if len(sections["other"]) > 0 {
 | |
| 		changelog += "### Others\n" + strings.Join(sections["other"], "\n") + "\n\n"
 | |
| 	}
 | |
| 
 | |
| 	if g.FullChangelog != "" {
 | |
| 		changelog += fmt.Sprintf("**Full Changelog**: %s\n", g.FullChangelog)
 | |
| 	}
 | |
| 
 | |
| 	return changelog
 | |
| }
 | |
| 
 | |
| // Method to fetch release data from GitHub API.
 | |
| func (g *GitHubRepo) fetchReleaseData(version string) (*ReleaseData, error) {
 | |
| 	var apiURL string
 | |
| 
 | |
| 	if version == "" {
 | |
| 		// Fetch the latest release.
 | |
| 		apiURL = fmt.Sprintf("https://api.github.com/repos/%s/%s/releases/latest", g.Owner, g.Repo)
 | |
| 	} else {
 | |
| 		// Fetch a specific version.
 | |
| 		apiURL = fmt.Sprintf("https://api.github.com/repos/%s/%s/releases/tags/%s", g.Owner, g.Repo, version)
 | |
| 	}
 | |
| 
 | |
| 	resp, err := http.Get(apiURL)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	defer resp.Body.Close()
 | |
| 
 | |
| 	body, err := io.ReadAll(resp.Body)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	var releaseData ReleaseData
 | |
| 	err = json.Unmarshal(body, &releaseData)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	return &releaseData, nil
 | |
| }
 | |
| 
 | |
| func main() {
 | |
| 	repo := &GitHubRepo{Owner: repoOwner, Repo: repoName}
 | |
| 
 | |
| 	// Get the version from command line arguments, if provided
 | |
| 	var version string // Default is use latest
 | |
| 
 | |
| 	if len(os.Args) > 1 {
 | |
| 		version = os.Args[1] // Use the provided version
 | |
| 	}
 | |
| 
 | |
| 	// Fetch release data (either for latest or specific version)
 | |
| 	releaseData, err := repo.fetchReleaseData(version)
 | |
| 	if err != nil {
 | |
| 		fmt.Println("Error fetching release data:", err)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	// Generate and print the formatted changelog
 | |
| 	changelog := repo.generateChangelog(releaseData.TagName, releaseData.Published, releaseData.HtmlUrl, releaseData.Body)
 | |
| 	fmt.Println(changelog)
 | |
| }
 |