Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

always do beta release for first release & refactor generator #24070

Merged
merged 6 commits into from
Feb 10, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
879 changes: 524 additions & 355 deletions eng/tools/generator/cmd/v2/common/generation.go
Original file line number Diff line number Diff line change
@@ -18,14 +18,17 @@ import (
)

type GenerateContext struct {
SDKPath string
SDKRepo *repo.SDKRepository
SpecPath string
SpecCommitHash string
SpecReadmeFile string
SpecReadmeGoFile string
SpecRepoURL string
UpdateSpecVersion bool
SDKPath string
SDKRepo *repo.SDKRepository
SpecPath string
SpecCommitHash string
SpecReadmeFile string
SpecReadmeGoFile string
SpecRepoURL string
UpdateSpecVersion bool
PackagePath string
PackageModuleRelativePath string
Version *semver.Version

// typespec
TypeSpecConfig *typespec.TypeSpecConfig
@@ -57,6 +60,43 @@ type GenerateParam struct {
TspClientOptions []string
}

type Generator interface {
PreGenerate(generateParam *GenerateParam) error
Generate(generateParam *GenerateParam) error
PreChangeLog(generateParam *GenerateParam) (*exports.Content, error)
GenChangeLog(oriExports *exports.Content, newExports *exports.Content) (*Changelog, error)
AfterGenerate(generateParam *GenerateParam, changelog *Changelog, newExports exports.Content) (*GenerateResult, error)
}

// Common steps for onboard and normal service
type SwaggerCommonGenerator struct {
*GenerateContext
}

type SwaggerOnBoardGenerator struct {
*SwaggerCommonGenerator
}

type SwaggerUpdateGenerator struct {
*SwaggerCommonGenerator
PreviousVersion string
IsCurrentPreview bool
}

type TypeSpecCommonGenerator struct {
*GenerateContext
}

type TypeSpecOnBoardGenerator struct {
*TypeSpecCommonGenerator
}

type TypeSpecUpdateGeneraor struct {
*TypeSpecCommonGenerator
PreviousVersion string
IsCurrentPreview bool
}

func (ctx *GenerateContext) GenerateForAutomation(readme, repo, goVersion string) ([]GenerateResult, []error) {
absReadme, err := filepath.Abs(filepath.Join(ctx.SpecPath, readme))
if err != nil {
@@ -105,8 +145,14 @@ func (ctx *GenerateContext) GenerateForAutomation(readme, repo, goVersion string
func (ctx *GenerateContext) GenerateForSingleRPNamespace(generateParam *GenerateParam) (*GenerateResult, error) {
packagePath := filepath.Join(ctx.SDKPath, "sdk", "resourcemanager", generateParam.RPName, generateParam.NamespaceName)
changelogPath := filepath.Join(packagePath, ChangelogFileName)

onBoard := false
// check if the package is onboard or update, to init different generator
var generator Generator
commonGenerator := &SwaggerCommonGenerator{GenerateContext: ctx}
if _, err := os.Stat(changelogPath); os.IsNotExist(err) {
generator = &SwaggerOnBoardGenerator{SwaggerCommonGenerator: commonGenerator}
} else {
generator = &SwaggerUpdateGenerator{SwaggerCommonGenerator: commonGenerator}
}

version, err := semver.NewVersion("0.1.0")
if err != nil {
@@ -119,50 +165,53 @@ func (ctx *GenerateContext) GenerateForSingleRPNamespace(generateParam *Generate
return nil, err
}
}
ctx.PackagePath = packagePath
ctx.Version = version

if _, err := os.Stat(changelogPath); os.IsNotExist(err) {
onBoard = true
log.Printf("Package '%s' changelog not exist, do onboard process", packagePath)
err = generator.PreGenerate(generateParam)
if err != nil {
return nil, err
}

if generateParam.SpecificPackageTitle == "" {
generateParam.SpecificPackageTitle = strings.Title(generateParam.RPName)
}
err = generator.Generate(generateParam)
if err != nil {
return nil, err
}

log.Printf("Start to use template to generate new rp folder and basic package files...")
if err = template.GeneratePackageByTemplate(generateParam.RPName, generateParam.NamespaceName, template.Flags{
SDKRoot: ctx.SDKPath,
TemplatePath: "eng/tools/generator/template/rpName/packageName",
PackageTitle: generateParam.SpecificPackageTitle,
Commit: ctx.SpecCommitHash,
PackageConfig: generateParam.NamespaceConfig,
GoVersion: generateParam.GoVersion,
PackageVersion: version.String(),
ReleaseDate: generateParam.ReleaseDate,
}); err != nil {
return nil, err
}
} else {
log.Printf("Package '%s' existed, do update process", packagePath)
oriExports, err := generator.PreChangeLog(generateParam)
if err != nil {
return nil, err
}

log.Printf("Remove all the generated files ...")
if err = CleanSDKGeneratedFiles(packagePath); err != nil {
return nil, err
}
log.Printf("Start to generate changelog for package...")
newExports, err := exports.Get(packagePath)
if err != nil {
return nil, err
}

changelog, err := generator.GenChangeLog(oriExports, &newExports)
if err != nil {
return nil, err
}

return generator.AfterGenerate(generateParam, changelog, newExports)
}

func (t *SwaggerCommonGenerator) PreGenerate(generateParam *GenerateParam) error {
packagePath := t.PackagePath
// same step for onboard and update
if ctx.SpecCommitHash == "" {
if t.SpecCommitHash == "" {
log.Printf("Change swagger config in `autorest.md` according to local path...")
autorestMdPath := filepath.Join(packagePath, "autorest.md")
if err := ChangeConfigWithLocalPath(autorestMdPath, ctx.SpecReadmeFile, ctx.SpecReadmeGoFile); err != nil {
return nil, err
if err := ChangeConfigWithLocalPath(autorestMdPath, t.SpecReadmeFile, t.SpecReadmeGoFile); err != nil {
return err
}
} else {
log.Printf("Change swagger config in `autorest.md` according to repo URL and commit ID...")
autorestMdPath := filepath.Join(packagePath, "autorest.md")
if ctx.UpdateSpecVersion {
if err := ChangeConfigWithCommitID(autorestMdPath, ctx.SpecRepoURL, ctx.SpecCommitHash, generateParam.SpecRPName); err != nil {
return nil, err
if t.UpdateSpecVersion {
if err := ChangeConfigWithCommitID(autorestMdPath, t.SpecRepoURL, t.SpecCommitHash, generateParam.SpecRPName); err != nil {
return err
}
}
}
@@ -172,24 +221,133 @@ func (ctx *GenerateContext) GenerateForSingleRPNamespace(generateParam *Generate
log.Printf("Remove tag set for swagger config in `autorest.md`...")
autorestMdPath := filepath.Join(packagePath, "autorest.md")
if err := RemoveTagSet(autorestMdPath); err != nil {
return err
}
}

return nil
}

func (t *SwaggerCommonGenerator) Generate(generateParam *GenerateParam) error {
packagePath := t.PackagePath
log.Printf("Start to run `go generate` to regenerate the code...")
if err := ExecuteGoGenerate(packagePath); err != nil {
return err
}
return nil
}

func (t *SwaggerCommonGenerator) PreChangeLog(generateParam *GenerateParam) (*exports.Content, error) {
return nil, nil
}

func (t *SwaggerCommonGenerator) GenChangeLog(oriExports *exports.Content, newExports *exports.Content) (*Changelog, error) {
changelog, err := GetChangelogForPackage(oriExports, newExports)
if err != nil {
return nil, err
}

log.Printf("filter changelog...")
FilterChangelog(changelog, NonExportedFilter, MarshalUnmarshalFilter, EnumFilter, FuncFilter, LROFilter, PageableFilter, InterfaceToAnyFilter)
return changelog, nil
}

func (t *SwaggerCommonGenerator) AfterGenerate(generateParam *GenerateParam, changelog *Changelog, newExports exports.Content) (*GenerateResult, error) {
return nil, nil
}

func (t *SwaggerOnBoardGenerator) PreGenerate(generateParam *GenerateParam) error {
var err error
version := t.Version
packagePath := t.PackagePath
log.Printf("Package '%s' changelog not exist, do onboard process", packagePath)

if generateParam.SpecificPackageTitle == "" {
generateParam.SpecificPackageTitle = strings.Title(generateParam.RPName)
}

log.Printf("Start to use template to generate new rp folder and basic package files...")
if err = template.GeneratePackageByTemplate(generateParam.RPName, generateParam.NamespaceName, template.Flags{
SDKRoot: t.SDKPath,
TemplatePath: "eng/tools/generator/template/rpName/packageName",
PackageTitle: generateParam.SpecificPackageTitle,
Commit: t.SpecCommitHash,
PackageConfig: generateParam.NamespaceConfig,
GoVersion: generateParam.GoVersion,
PackageVersion: version.String(),
ReleaseDate: generateParam.ReleaseDate,
}); err != nil {
return err
}
if err = t.SwaggerCommonGenerator.PreGenerate(generateParam); err != nil {
return err
}
return nil
}

func (t *SwaggerOnBoardGenerator) AfterGenerate(generateParam *GenerateParam, changelog *Changelog, newExports exports.Content) (*GenerateResult, error) {
var err error
var prl PullRequestLabel
version := t.Version
packagePath := t.PackagePath
log.Printf("Replace {{NewClientName}} placeholder in the README.md ")
if err = ReplaceNewClientNamePlaceholder(packagePath, newExports); err != nil {
return nil, err
}

if !generateParam.SkipGenerateExample {
log.Printf("Start to generate examples...")
flag, err := GetAlwaysSetBodyParamRequiredFlag(filepath.Join(packagePath, "build.go"))
if err != nil {
return nil, err
}
if err := ExecuteExampleGenerate(packagePath, filepath.Join("resourcemanager", generateParam.RPName, generateParam.NamespaceName), flag); err != nil {
return nil, err
}
}

// issue: https://github.com/Azure/azure-sdk-for-go/issues/23877
prl = FirstBetaLabel

return &GenerateResult{
Version: version.String(),
RPName: generateParam.RPName,
PackageName: generateParam.NamespaceName,
PackageAbsPath: packagePath,
Changelog: *changelog,
ChangelogMD: changelog.ToCompactMarkdown() + "\n" + changelog.GetChangeSummary(),
PullRequestLabels: string(prl),
}, nil
}

func (t *SwaggerUpdateGenerator) PreGenerate(generateParam *GenerateParam) error {
packagePath := t.PackagePath
var err error
log.Printf("Package '%s' existed, do update process", packagePath)

log.Printf("Remove all the generated files ...")
if err = CleanSDKGeneratedFiles(packagePath); err != nil {
return err
}

if err = t.SwaggerCommonGenerator.PreGenerate(generateParam); err != nil {
return err
}

// add tag set
if !generateParam.RemoveTagSet && generateParam.NamespaceConfig != "" && !onBoard {
if !generateParam.RemoveTagSet && generateParam.NamespaceConfig != "" {
log.Printf("Add tag in `autorest.md`...")
autorestMdPath := filepath.Join(packagePath, "autorest.md")
if err := AddTagSet(autorestMdPath, generateParam.NamespaceConfig); err != nil {
return nil, err
return err
}
}
return nil
}

log.Printf("Start to run `go generate` to regenerate the code...")
if err := ExecuteGoGenerate(packagePath); err != nil {
return nil, err
}

func (t *SwaggerUpdateGenerator) PreChangeLog(generateParam *GenerateParam) (*exports.Content, error) {
var err error
packagePath := t.PackagePath
previousVersion := ""
isCurrentPreview := false
var oriExports *exports.Content
@@ -210,168 +368,117 @@ func (ctx *GenerateContext) GenerateForSingleRPNamespace(generateParam *Generate
}
}

if !onBoard {
log.Printf("Get ori exports for changelog generation...")
log.Printf("Get ori exports for changelog generation...")

tags, err := GetAllVersionTags(fmt.Sprintf("sdk/resourcemanager/%s/%s", generateParam.RPName, generateParam.NamespaceName))
if err != nil {
return nil, err
}
tags, err := GetAllVersionTags(fmt.Sprintf("sdk/resourcemanager/%s/%s", generateParam.RPName, generateParam.NamespaceName))
if err != nil {
return nil, err
}

if len(tags) == 0 {
return nil, fmt.Errorf("github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/%s/%s hasn't been released, it's supposed to OnBoard", generateParam.RPName, generateParam.NamespaceName)
}
if len(tags) == 0 {
return nil, fmt.Errorf("github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/%s/%s hasn't been released, it's supposed to OnBoard", generateParam.RPName, generateParam.NamespaceName)
}

previousVersionTag := GetPreviousVersionTag(isCurrentPreview, tags)

oriExports, err = GetExportsFromTag(*t.SDKRepo, packagePath, previousVersionTag)
if err != nil {
return nil, err
}

previousVersionTag := GetPreviousVersionTag(isCurrentPreview, tags)
tagSplit := strings.Split(previousVersionTag, "/")
previousVersion = strings.TrimLeft(tagSplit[len(tagSplit)-1], "v")
t.PreviousVersion = previousVersion
t.IsCurrentPreview = isCurrentPreview
return oriExports, nil
}

oriExports, err = GetExportsFromTag(*ctx.SDKRepo, packagePath, previousVersionTag)
func (t *SwaggerUpdateGenerator) AfterGenerate(generateParam *GenerateParam, changelog *Changelog, newExports exports.Content) (*GenerateResult, error) {
var prl PullRequestLabel
var err error
version := t.Version
isCurrentPreview := t.IsCurrentPreview
previousVersion := t.PreviousVersion
packagePath := t.PackagePath

log.Printf("Calculate new version...")
if generateParam.SpecificVersion == "" {
version, prl, err = CalculateNewVersion(changelog, previousVersion, isCurrentPreview)
if err != nil {
return nil, err
}

tagSplit := strings.Split(previousVersionTag, "/")
previousVersion = strings.TrimLeft(tagSplit[len(tagSplit)-1], "v")
}

log.Printf("Start to generate changelog for package...")
newExports, err := exports.Get(packagePath)
log.Printf("Add changelog to file...")
changelogMd, err := AddChangelogToFile(changelog, version, packagePath, generateParam.ReleaseDate)
if err != nil {
return nil, err
}
changelog, err := GetChangelogForPackage(oriExports, &newExports)

log.Printf("Update module definition if v2+...")
err = UpdateModuleDefinition(packagePath, fmt.Sprintf("sdk/resourcemanager/%s/%s", generateParam.RPName, generateParam.NamespaceName), version)
if err != nil {
return nil, err
}

log.Printf("filter changelog...")
FilterChangelog(changelog, NonExportedFilter, MarshalUnmarshalFilter, EnumFilter, FuncFilter, LROFilter, PageableFilter, InterfaceToAnyFilter)

var prl PullRequestLabel
if onBoard {
log.Printf("Replace {{NewClientName}} placeholder in the README.md ")
if err = ReplaceNewClientNamePlaceholder(packagePath, newExports); err != nil {
return nil, err
}

if !generateParam.SkipGenerateExample {
log.Printf("Start to generate examples...")
flag, err := GetAlwaysSetBodyParamRequiredFlag(filepath.Join(packagePath, "build.go"))
if err != nil {
return nil, err
}
if err := ExecuteExampleGenerate(packagePath, filepath.Join("resourcemanager", generateParam.RPName, generateParam.NamespaceName), flag); err != nil {
return nil, err
}
}

prl = FirstBetaLabel
if !isCurrentPreview {
version, err = semver.NewVersion("1.0.0")
if err != nil {
return nil, err
}

log.Printf("Replace version in CHANGELOG.md...")
if err = UpdateOnboardChangelogVersion(packagePath, version.String()); err != nil {
return nil, err
}

log.Printf("Replace version in autorest.md and constants...")
if err = ReplaceVersion(packagePath, version.String()); err != nil {
return nil, err
}
prl = FirstGALabel
}

return &GenerateResult{
Version: version.String(),
RPName: generateParam.RPName,
PackageName: generateParam.NamespaceName,
PackageAbsPath: packagePath,
Changelog: *changelog,
ChangelogMD: changelog.ToCompactMarkdown() + "\n" + changelog.GetChangeSummary(),
PullRequestLabels: string(prl),
}, nil
} else {
log.Printf("Calculate new version...")
if generateParam.SpecificVersion == "" {
version, prl, err = CalculateNewVersion(changelog, previousVersion, isCurrentPreview)
if err != nil {
return nil, err
}
}

log.Printf("Add changelog to file...")
changelogMd, err := AddChangelogToFile(changelog, version, packagePath, generateParam.ReleaseDate)
if err != nil {
return nil, err
}
oldModuleVersion, err := getModuleVersion(filepath.Join(packagePath, "autorest.md"))
if err != nil {
return nil, err
}

log.Printf("Update module definition if v2+...")
err = UpdateModuleDefinition(packagePath, fmt.Sprintf("sdk/resourcemanager/%s/%s", generateParam.RPName, generateParam.NamespaceName), version)
if err != nil {
return nil, err
}
log.Printf("Replace version in autorest.md and constants...")
if err = ReplaceVersion(packagePath, version.String()); err != nil {
return nil, err
}

oldModuleVersion, err := getModuleVersion(filepath.Join(packagePath, "autorest.md"))
if err != nil {
if _, err := os.Stat(filepath.Join(packagePath, "fake")); !os.IsNotExist(err) && oldModuleVersion.Major() != version.Major() {
log.Printf("Replace fake module v2+...")
if err = replaceModuleImport(packagePath, generateParam.RPName, generateParam.NamespaceName, oldModuleVersion.String(), version.String(),
"fake", ".go"); err != nil {
return nil, err
}
}

log.Printf("Replace version in autorest.md and constants...")
if err = ReplaceVersion(packagePath, version.String()); err != nil {
// When sdk has major version bump, the live test needs to update the module referenced in the code.
if oldModuleVersion.Major() != version.Major() && existSuffixFile(packagePath, "_live_test.go") {
log.Printf("Replace live test module v2+...")
if err = replaceModuleImport(packagePath, generateParam.RPName, generateParam.NamespaceName, oldModuleVersion.String(), version.String(),
"", "_live_test.go"); err != nil {
return nil, err
}
}

if _, err := os.Stat(filepath.Join(packagePath, "fake")); !os.IsNotExist(err) && oldModuleVersion.Major() != version.Major() {
log.Printf("Replace fake module v2+...")
if err = replaceModuleImport(packagePath, generateParam.RPName, generateParam.NamespaceName, oldModuleVersion.String(), version.String(),
"fake", ".go"); err != nil {
return nil, err
}
}
log.Printf("Replace README.md module...")
if err = replaceReadmeModule(packagePath, fmt.Sprintf("sdk/resourcemanager/%s/%s", generateParam.RPName, generateParam.NamespaceName), version.String()); err != nil {
return nil, err
}

// When sdk has major version bump, the live test needs to update the module referenced in the code.
if oldModuleVersion.Major() != version.Major() && existSuffixFile(packagePath, "_live_test.go") {
log.Printf("Replace live test module v2+...")
if err = replaceModuleImport(packagePath, generateParam.RPName, generateParam.NamespaceName, oldModuleVersion.String(), version.String(),
"", "_live_test.go"); err != nil {
return nil, err
}
}
log.Printf("Replace README.md NewClient name...")
if err = ReplaceReadmeNewClientName(packagePath, newExports); err != nil {
return nil, err
}

log.Printf("Replace README.md module...")
if err = replaceReadmeModule(packagePath, fmt.Sprintf("sdk/resourcemanager/%s/%s", generateParam.RPName, generateParam.NamespaceName), version.String()); err != nil {
// Example generation should be the last step because the package import relay on the new calculated version
if !generateParam.SkipGenerateExample {
log.Printf("Start to generate examples...")
flag, err := GetAlwaysSetBodyParamRequiredFlag(filepath.Join(packagePath, "build.go"))
if err != nil {
return nil, err
}

log.Printf("Replace README.md NewClient name...")
if err = ReplaceReadmeNewClientName(packagePath, newExports); err != nil {
if err := ExecuteExampleGenerate(packagePath, filepath.Join("resourcemanager", generateParam.RPName, generateParam.NamespaceName), flag); err != nil {
return nil, err
}

// Example generation should be the last step because the package import relay on the new calculated version
if !generateParam.SkipGenerateExample {
log.Printf("Start to generate examples...")
flag, err := GetAlwaysSetBodyParamRequiredFlag(filepath.Join(packagePath, "build.go"))
if err != nil {
return nil, err
}
if err := ExecuteExampleGenerate(packagePath, filepath.Join("resourcemanager", generateParam.RPName, generateParam.NamespaceName), flag); err != nil {
return nil, err
}
}

return &GenerateResult{
Version: version.String(),
RPName: generateParam.RPName,
PackageName: generateParam.NamespaceName,
PackageAbsPath: packagePath,
Changelog: *changelog,
ChangelogMD: changelogMd + "\n" + changelog.GetChangeSummary(),
PullRequestLabels: string(prl),
}, nil
}

return &GenerateResult{
Version: version.String(),
RPName: generateParam.RPName,
PackageName: generateParam.NamespaceName,
PackageAbsPath: packagePath,
Changelog: *changelog,
ChangelogMD: changelogMd + "\n" + changelog.GetChangeSummary(),
PullRequestLabels: string(prl),
}, nil
}

func (ctx *GenerateContext) GenerateForTypeSpec(generateParam *GenerateParam, packageModuleRelativePath string) (*GenerateResult, error) {
@@ -389,244 +496,306 @@ func (ctx *GenerateContext) GenerateForTypeSpec(generateParam *GenerateParam, pa
return nil, err
}
}
ctx.Version = version
ctx.PackagePath = packagePath
ctx.PackageModuleRelativePath = packageModuleRelativePath

onBoard := false
// check if the package is onboard or update, to init different generator
var generator Generator
commonGenerator := &TypeSpecCommonGenerator{GenerateContext: ctx}
if _, err := os.Stat(changelogPath); os.IsNotExist(err) {
onBoard = true
log.Printf("Package '%s' changelog not exist, do onboard process", packagePath)
if generateParam.SpecificPackageTitle == "" {
generateParam.SpecificPackageTitle = strings.Title(generateParam.RPName)
}

log.Printf("Start to use template to generate new rp folder and basic package files...")
sdkBasicInfo := map[string]any{
"rpName": generateParam.RPName,
"packageName": generateParam.NamespaceName,
"packageTitle": generateParam.SpecificPackageTitle,
"packageVersion": version.String(),
"releaseDate": generateParam.ReleaseDate,
"goVersion": generateParam.GoVersion,
}
err = typespec.ParseTypeSpecTemplates(filepath.Join(ctx.SDKPath, "eng/tools/generator/template/typespec"), packagePath, sdkBasicInfo, nil)
if err != nil {
return nil, err
}
generator = &TypeSpecOnBoardGenerator{TypeSpecCommonGenerator: commonGenerator}
} else {
log.Printf("Package '%s' existed, do update process", packagePath)
log.Printf("Remove all the generated files ...")
if err = CleanSDKGeneratedFiles(packagePath); err != nil {
return nil, err
}
generator = &TypeSpecUpdateGeneraor{TypeSpecCommonGenerator: commonGenerator}
}

err = generator.PreGenerate(generateParam)
if err != nil {
return nil, err
}

err = generator.Generate(generateParam)
if err != nil {
return nil, err
}

oriExports, err := generator.PreChangeLog(generateParam)
if err != nil {
return nil, err
}

log.Printf("Start to generate changelog for package...")
newExports, err := exports.Get(packagePath)
if err != nil {
return nil, err
}
changelog, err := generator.GenChangeLog(oriExports, &newExports)
if err != nil {
return nil, err
}

return generator.AfterGenerate(generateParam, changelog, newExports)
}

func (t *TypeSpecCommonGenerator) PreGenerate(generateParam *GenerateParam) error {
return nil
}

func (t *TypeSpecCommonGenerator) Generate(generateParam *GenerateParam) error {
version := t.Version
ctx := t.GenerateContext
log.Printf("Start to run `tsp-client init` to generate the code...")
defaultModuleVersion := version.String()
emitOption := fmt.Sprintf("module-version=%s", defaultModuleVersion)
if generateParam.TypeSpecEmitOption != "" {
emitOption = fmt.Sprintf("%s;%s", emitOption, generateParam.TypeSpecEmitOption)
}
err = ExecuteTypeSpecGenerate(ctx, emitOption, generateParam.TspClientOptions)
err := ExecuteTypeSpecGenerate(ctx, emitOption, generateParam.TspClientOptions)
if err != nil {
return err
}
return nil
}

func (t *TypeSpecCommonGenerator) PreChangeLog(generateParam *GenerateParam) (*exports.Content, error) {
return nil, nil
}

func (t *TypeSpecCommonGenerator) GenChangeLog(oriExports *exports.Content, newExports *exports.Content) (*Changelog, error) {
changelog, err := GetChangelogForPackage(oriExports, newExports)
if err != nil {
return nil, err
}

previousVersion := ""
isCurrentPreview := false
var oriExports *exports.Content
if generateParam.SpecificVersion != "" {
isCurrentPreview, err = IsBetaVersion(version.String())
if err != nil {
return nil, err
}
} else {
isCurrentPreview, err = ContainsPreviewAPIVersion(packagePath)
if err != nil {
return nil, err
}
log.Printf("filter changelog...")
FilterChangelog(changelog, NonExportedFilter, MarshalUnmarshalFilter, EnumFilter, FuncFilter, LROFilter, PageableFilter, InterfaceToAnyFilter)
return changelog, nil
}

func (t *TypeSpecCommonGenerator) AfterGenerate(generateParam *GenerateParam, changelog *Changelog, newExports exports.Content) (*GenerateResult, error) {
packagePath := t.PackagePath
log.Printf("##[command]Executing gofmt -s -w . in %s\n", packagePath)
if err := ExecuteGoFmt(packagePath, "-s", "-w", "."); err != nil {
return nil, err
}

if !onBoard {
log.Printf("Get ori exports for changelog generation...")
log.Printf("##[command]Executing go mod tidy in %s\n", packagePath)
if err := ExecuteGo(packagePath, "mod", "tidy"); err != nil {
return nil, err
}
return nil, nil
}

tags, err := GetAllVersionTags(packageModuleRelativePath)
if err != nil {
return nil, err
}
func (t *TypeSpecOnBoardGenerator) PreGenerate(generateParam *GenerateParam) error {
version := t.Version
log.Printf("Package '%s' changelog not exist, do onboard process", t.PackagePath)
if generateParam.SpecificPackageTitle == "" {
generateParam.SpecificPackageTitle = strings.Title(generateParam.RPName)
}
log.Printf("Start to use template to generate new rp folder and basic package files...")
sdkBasicInfo := map[string]any{
"rpName": generateParam.RPName,
"packageName": generateParam.NamespaceName,
"packageTitle": generateParam.SpecificPackageTitle,
"packageVersion": version.String(),
"releaseDate": generateParam.ReleaseDate,
"goVersion": generateParam.GoVersion,
}
return typespec.ParseTypeSpecTemplates(filepath.Join(t.SDKPath, "eng/tools/generator/template/typespec"), t.PackagePath, sdkBasicInfo, nil)
}

if len(tags) == 0 {
return nil, fmt.Errorf("github.com/Azure/azure-sdk-for-go/%s hasn't been released, it's supposed to OnBoard", packageModuleRelativePath)
}
func (t *TypeSpecOnBoardGenerator) PreChangeLog(generateParam *GenerateParam) (*exports.Content, error) {
return nil, nil
}

previousVersionTag := GetPreviousVersionTag(isCurrentPreview, tags)
func (t *TypeSpecOnBoardGenerator) AfterGenerate(generateParam *GenerateParam, changelog *Changelog, newExports exports.Content) (*GenerateResult, error) {
var err error
version := t.Version
packagePath := t.PackagePath

oriExports, err = GetExportsFromTag(*ctx.SDKRepo, packagePath, previousVersionTag)
if err != nil {
return nil, err
}
var prl PullRequestLabel
log.Printf("Replace {{NewClientName}} placeholder in the README.md ")
if err = ReplaceNewClientNamePlaceholder(packagePath, newExports); err != nil {
return nil, err
}

tagSplit := strings.Split(previousVersionTag, "/")
previousVersion = strings.TrimLeft(tagSplit[len(tagSplit)-1], "v")
if !generateParam.SkipGenerateExample {
log.Printf("Generate examples...")
}

log.Printf("Start to generate changelog for package...")
newExports, err := exports.Get(packagePath)
if err != nil {
// issue: https://github.com/Azure/azure-sdk-for-go/issues/23877
prl = FirstBetaLabel

if _, err := t.TypeSpecCommonGenerator.AfterGenerate(generateParam, changelog, newExports); err != nil {
return nil, err
}
changelog, err := GetChangelogForPackage(oriExports, &newExports)
if err != nil {
return nil, err

return &GenerateResult{
Version: version.String(),
RPName: generateParam.RPName,
PackageName: generateParam.NamespaceName,
PackageAbsPath: packagePath,
Changelog: *changelog,
ChangelogMD: changelog.ToCompactMarkdown() + "\n" + changelog.GetChangeSummary(),
PullRequestLabels: string(prl),
}, nil
}

func (t *TypeSpecUpdateGeneraor) PreGenerate(generateParam *GenerateParam) error {
log.Printf("Package '%s' existed, do update process", t.PackagePath)
log.Printf("Remove all the generated files ...")
if err := CleanSDKGeneratedFiles(t.PackagePath); err != nil {
return err
}
return nil
}

log.Printf("filter changelog...")
FilterChangelog(changelog, NonExportedFilter, MarshalUnmarshalFilter, EnumFilter, FuncFilter, LROFilter, PageableFilter, InterfaceToAnyFilter)
func (t *TypeSpecUpdateGeneraor) PreChangeLog(generateParam *GenerateParam) (*exports.Content, error) {
var err error
version := t.Version
packagePath := t.PackagePath
packageModuleRelativePath := t.PackageModuleRelativePath

var prl PullRequestLabel
if onBoard {
log.Printf("Replace {{NewClientName}} placeholder in the README.md ")
if err = ReplaceNewClientNamePlaceholder(packagePath, newExports); err != nil {
previousVersion := ""
isCurrentPreview := false
var oriExports *exports.Content
if generateParam.SpecificVersion != "" {
isCurrentPreview, err = IsBetaVersion(version.String())
if err != nil {
return nil, err
}

if !generateParam.SkipGenerateExample {
log.Printf("Generate examples...")
} else {
isCurrentPreview, err = ContainsPreviewAPIVersion(packagePath)
if err != nil {
return nil, err
}
}

prl = FirstBetaLabel
if !isCurrentPreview {
version, err = semver.NewVersion("1.0.0")
if err != nil {
return nil, err
}
log.Printf("Get ori exports for changelog generation...")

log.Printf("Replace version in CHANGELOG.md...")
if err = UpdateOnboardChangelogVersion(packagePath, version.String()); err != nil {
return nil, err
}
tags, err := GetAllVersionTags(packageModuleRelativePath)
if err != nil {
return nil, err
}

log.Printf("Replace version in constants.go...")
if err = ReplaceConstModuleVersion(packagePath, version.String()); err != nil {
return nil, err
}
prl = FirstGALabel
}
if len(tags) == 0 {
return nil, fmt.Errorf("github.com/Azure/azure-sdk-for-go/%s hasn't been released, it's supposed to OnBoard", packageModuleRelativePath)
}

log.Printf("##[command]Executing gofmt -s -w . in %s\n", packagePath)
if err = ExecuteGoFmt(packagePath, "-s", "-w", "."); err != nil {
return nil, err
}
previousVersionTag := GetPreviousVersionTag(isCurrentPreview, tags)

log.Printf("##[command]Executing go mod tidy in %s\n", packagePath)
if err = ExecuteGo(packagePath, "mod", "tidy"); err != nil {
return nil, err
}
oriExports, err = GetExportsFromTag(*t.SDKRepo, packagePath, previousVersionTag)
if err != nil {
return nil, err
}

return &GenerateResult{
Version: version.String(),
RPName: generateParam.RPName,
PackageName: generateParam.NamespaceName,
PackageAbsPath: packagePath,
Changelog: *changelog,
ChangelogMD: changelog.ToCompactMarkdown() + "\n" + changelog.GetChangeSummary(),
PullRequestLabels: string(prl),
}, nil
} else {
log.Printf("Calculate new version...")
if generateParam.SpecificVersion == "" {
version, prl, err = CalculateNewVersion(changelog, previousVersion, isCurrentPreview)
if err != nil {
return nil, err
}
}
tagSplit := strings.Split(previousVersionTag, "/")
previousVersion = strings.TrimLeft(tagSplit[len(tagSplit)-1], "v")

log.Printf("Add changelog to file...")
changelogMd, err := AddChangelogToFile(changelog, version, packagePath, generateParam.ReleaseDate)
if err != nil {
return nil, err
}
t.PreviousVersion = previousVersion
t.IsCurrentPreview = isCurrentPreview
return oriExports, nil
}

log.Printf("Update module definition if v2+...")
err = UpdateModuleDefinition(packagePath, packageModuleRelativePath, version)
func (t *TypeSpecUpdateGeneraor) AfterGenerate(generateParam *GenerateParam, changelog *Changelog, newExports exports.Content) (*GenerateResult, error) {
var prl PullRequestLabel
var err error
version := t.Version
defaultModuleVersion := version.String()
packagePath := t.PackagePath
packageModuleRelativePath := t.PackageModuleRelativePath
previousVersion := t.PreviousVersion
isCurrentPreview := t.IsCurrentPreview

log.Printf("Calculate new version...")
if generateParam.SpecificVersion == "" {
version, prl, err = CalculateNewVersion(changelog, previousVersion, isCurrentPreview)
if err != nil {
return nil, err
}
}

log.Printf("Replace version in constants.go...")
if err = ReplaceConstModuleVersion(packagePath, version.String()); err != nil {
return nil, err
}
log.Printf("Add changelog to file...")
changelogMd, err := AddChangelogToFile(changelog, version, packagePath, generateParam.ReleaseDate)
if err != nil {
return nil, err
}

oldModuleVersion, err := semver.NewVersion(defaultModuleVersion)
if err != nil {
return nil, err
}
log.Printf("Update module definition if v2+...")
err = UpdateModuleDefinition(packagePath, packageModuleRelativePath, version)
if err != nil {
return nil, err
}

baseModule := fmt.Sprintf("%s/%s", "github.com/Azure/azure-sdk-for-go", packageModuleRelativePath)
if _, err := os.Stat(filepath.Join(packagePath, "fake")); !os.IsNotExist(err) && oldModuleVersion.Major() != version.Major() {
log.Printf("Replace fake module v2+...")
if err = ReplaceModule(version, packagePath, baseModule, ".go"); err != nil {
return nil, err
}
}
log.Printf("Replace version in constants.go...")
if err = ReplaceConstModuleVersion(packagePath, version.String()); err != nil {
return nil, err
}

// When sdk has major version bump, the live test needs to update the module referenced in the code.
if existSuffixFile(packagePath, "_live_test.go") {
log.Printf("Replace live test module v2+...")
if err = ReplaceModule(version, packagePath, baseModule, "_live_test.go"); err != nil {
return nil, err
}
}
oldModuleVersion, err := semver.NewVersion(defaultModuleVersion)
if err != nil {
return nil, err
}

log.Printf("Replace README.md module...")
if err = replaceReadmeModule(packagePath, packageModuleRelativePath, version.String()); err != nil {
baseModule := fmt.Sprintf("%s/%s", "github.com/Azure/azure-sdk-for-go", packageModuleRelativePath)
if _, err := os.Stat(filepath.Join(packagePath, "fake")); !os.IsNotExist(err) && oldModuleVersion.Major() != version.Major() {
log.Printf("Replace fake module v2+...")
if err = ReplaceModule(version, packagePath, baseModule, ".go"); err != nil {
return nil, err
}
}

log.Printf("Replace README.md NewClient name...")
if err = ReplaceReadmeNewClientName(packagePath, newExports); err != nil {
// When sdk has major version bump, the live test needs to update the module referenced in the code.
if existSuffixFile(packagePath, "_live_test.go") {
log.Printf("Replace live test module v2+...")
if err = ReplaceModule(version, packagePath, baseModule, "_live_test.go"); err != nil {
return nil, err
}
}

// Example generation should be the last step because the package import relay on the new calculated version
if !generateParam.SkipGenerateExample {
log.Printf("Generate examples...")
}
log.Printf("Replace README.md module...")
if err = replaceReadmeModule(packagePath, packageModuleRelativePath, version.String()); err != nil {
return nil, err
}

// remove autorest.md and build.go
autorestMdPath := filepath.Join(packagePath, "autorest.md")
if _, err := os.Stat(autorestMdPath); !os.IsNotExist(err) {
log.Println("Remove autorest.md...")
if err = os.Remove(autorestMdPath); err != nil {
return nil, err
}
log.Printf("Replace README.md NewClient name...")
if err = ReplaceReadmeNewClientName(packagePath, newExports); err != nil {
return nil, err
}

}
buildGoPath := filepath.Join(packagePath, "build.go")
if _, err := os.Stat(buildGoPath); !os.IsNotExist(err) {
log.Println("Remove build.go...")
if err = os.Remove(buildGoPath); err != nil {
return nil, err
}
}
// Example generation should be the last step because the package import relay on the new calculated version
if !generateParam.SkipGenerateExample {
log.Printf("Generate examples...")
}

log.Printf("##[command]Executing gofmt -s -w . in %s\n", packagePath)
if err = ExecuteGoFmt(packagePath, "-s", "-w", "."); err != nil {
// remove autorest.md and build.go
autorestMdPath := filepath.Join(packagePath, "autorest.md")
if _, err := os.Stat(autorestMdPath); !os.IsNotExist(err) {
log.Println("Remove autorest.md...")
if err = os.Remove(autorestMdPath); err != nil {
return nil, err
}

log.Printf("##[command]Executing go mod tidy in %s\n", packagePath)
if err = ExecuteGo(packagePath, "mod", "tidy"); err != nil {
}
buildGoPath := filepath.Join(packagePath, "build.go")
if _, err := os.Stat(buildGoPath); !os.IsNotExist(err) {
log.Println("Remove build.go...")
if err = os.Remove(buildGoPath); err != nil {
return nil, err
}
}

return &GenerateResult{
Version: version.String(),
RPName: generateParam.RPName,
PackageName: generateParam.NamespaceName,
PackageAbsPath: packagePath,
Changelog: *changelog,
ChangelogMD: changelogMd + "\n" + changelog.GetChangeSummary(),
PullRequestLabels: string(prl),
}, nil
if _, err := t.TypeSpecCommonGenerator.AfterGenerate(generateParam, changelog, newExports); err != nil {
return nil, err
}

return &GenerateResult{
Version: version.String(),
RPName: generateParam.RPName,
PackageName: generateParam.NamespaceName,
PackageAbsPath: packagePath,
Changelog: *changelog,
ChangelogMD: changelogMd + "\n" + changelog.GetChangeSummary(),
PullRequestLabels: string(prl),
}, nil
}