in commands/release/create/create.go [268:512]
func createRun(opts *CreateOpts) error {
client, err := opts.HTTPClient()
if err != nil {
return err
}
repo, err := opts.BaseRepo()
if err != nil {
return err
}
color := opts.IO.Color()
var tag *gitlab.Tag
var resp *gitlab.Response
if opts.Ref == "" {
opts.IO.Log(color.ProgressIcon(), "Validating tag", opts.TagName)
tag, resp, err = client.Tags.GetTag(repo.FullName(), opts.TagName)
if err != nil && resp != nil && resp.StatusCode != http.StatusNotFound {
return cmdutils.WrapError(err, "could not fetch tag")
}
if tag == nil && resp != nil && resp.StatusCode == http.StatusNotFound {
opts.IO.Log(color.DotWarnIcon(), "Tag does not exist.")
opts.IO.Log(color.DotWarnIcon(), "No ref provided. Creating the tag from the latest state of the default branch.")
project, err := repo.Project(client)
if err == nil {
opts.IO.Logf("%s using default branch %q as ref\n", color.ProgressIcon(), project.DefaultBranch)
opts.Ref = project.DefaultBranch
}
}
// new line
opts.IO.Log()
}
if opts.IO.PromptEnabled() && !opts.NoteProvided {
editorCommand, err := cmdutils.GetEditor(opts.Config)
if err != nil {
return err
}
var tagDescription string
var generatedChangelog string
if tag == nil {
tag, _, _ = client.Tags.GetTag(repo.FullName(), opts.TagName)
}
if tag != nil {
tagDescription = tag.Message
}
if opts.RepoOverride == "" {
headRef := opts.TagName
if tagDescription == "" {
if opts.Ref != "" {
headRef = opts.Ref
brCfg := git.ReadBranchConfig(opts.Ref)
if brCfg.MergeRef != "" {
headRef = brCfg.MergeRef
}
} else {
headRef = "HEAD"
}
}
if prevTag, err := detectPreviousTag(headRef); err == nil {
commits, _ := changelogForRange(fmt.Sprintf("%s..%s", prevTag, headRef))
generatedChangelog = generateChangelog(commits)
}
}
editorOptions := []string{noteOptionsNames[noteOptMyOwn]}
if generatedChangelog != "" {
editorOptions = append(editorOptions, noteOptionsNames[noteOptCommitLog])
}
if tagDescription != "" {
editorOptions = append(editorOptions, noteOptionsNames[noteOptGitTagMessage])
}
editorOptions = append(editorOptions, noteOptionsNames[noteOptLeaveBlank])
qs := []*survey.Question{
{
Name: "name",
Prompt: &survey.Input{
Message: "Release title (optional)",
Default: opts.Name,
},
},
{
Name: "releaseNotesAction",
Prompt: &survey.Select{
Message: "Release notes",
Options: editorOptions,
},
},
}
err = prompt.Ask(qs, opts)
if err != nil {
return fmt.Errorf("could not prompt: %w", err)
}
var openEditor bool
var editorContents string
switch opts.ReleaseNotesAction {
case noteOptionsNames[noteOptMyOwn]:
openEditor = true
case noteOptionsNames[noteOptCommitLog]:
openEditor = true
editorContents = generatedChangelog
case noteOptionsNames[noteOptGitTagMessage]:
openEditor = true
editorContents = tagDescription
case noteOptionsNames[noteOptLeaveBlank]:
openEditor = false
default:
return fmt.Errorf("invalid action: %v", opts.ReleaseNotesAction)
}
if openEditor {
txt, err := surveyext.Edit(editorCommand, "*.md", editorContents, opts.IO.In, opts.IO.StdOut, opts.IO.StdErr, nil)
if err != nil {
return err
}
opts.Notes = txt
}
}
start := time.Now()
opts.IO.Logf("%s Creating or updating release %s=%s %s=%s\n",
color.ProgressIcon(),
color.Blue("repo"), repo.FullName(),
color.Blue("tag"), opts.TagName)
release, resp, err := client.Releases.GetRelease(repo.FullName(), opts.TagName)
if err != nil && (resp == nil || (resp.StatusCode != http.StatusForbidden && resp.StatusCode != http.StatusNotFound)) {
return releaseFailedErr(err, start)
}
var releasedAt time.Time
if opts.ReleasedAt != "" {
// Parse the releasedAt to the expected format of the API
// From the API docs "Expected in ISO 8601 format (2019-03-15T08:00:00Z)".
releasedAt, err = time.Parse(time.RFC3339[:len(opts.ReleasedAt)], opts.ReleasedAt)
if err != nil {
return releaseFailedErr(err, start)
}
}
if opts.Name == "" {
opts.Name = opts.TagName
}
if (resp.StatusCode == http.StatusForbidden || resp.StatusCode == http.StatusNotFound) || release == nil {
createOpts := &gitlab.CreateReleaseOptions{
Name: &opts.Name,
TagName: &opts.TagName,
}
if opts.Notes != "" {
createOpts.Description = &opts.Notes
}
if opts.Ref != "" {
createOpts.Ref = &opts.Ref
}
if opts.TagMessage != "" {
createOpts.TagMessage = &opts.TagMessage
}
if opts.ReleasedAt != "" {
createOpts.ReleasedAt = &releasedAt
}
if len(opts.Milestone) > 0 {
createOpts.Milestones = &opts.Milestone
}
release, _, err = client.Releases.CreateRelease(repo.FullName(), createOpts)
if err != nil {
return releaseFailedErr(err, start)
}
opts.IO.Logf("%s Release created:\t%s=%s\n", color.GreenCheck(),
color.Blue("url"), release.Links.Self)
} else {
if opts.NoUpdate {
return releaseFailedErr(fmt.Errorf("release for tag %q already exists and --no-update flag was specified", opts.TagName), start)
}
updateOpts := &gitlab.UpdateReleaseOptions{
Name: &opts.Name,
}
if opts.Notes != "" {
updateOpts.Description = &opts.Notes
}
if opts.ReleasedAt != "" {
updateOpts.ReleasedAt = &releasedAt
}
if len(opts.Milestone) > 0 {
updateOpts.Milestones = &opts.Milestone
}
release, _, err = client.Releases.UpdateRelease(repo.FullName(), opts.TagName, updateOpts)
if err != nil {
return releaseFailedErr(err, start)
}
opts.IO.Logf("%s Release updated\t%s=%s\n", color.GreenCheck(),
color.Blue("url"), release.Links.Self)
}
// upload files and create asset links
err = releaseutils.CreateReleaseAssets(opts.IO, client, opts.AssetFiles, opts.AssetLinks, repo.FullName(), release.TagName)
if err != nil {
return releaseFailedErr(err, start)
}
if opts.NoCloseMilestone {
opts.IO.Logf("%s Skipping closing milestones\n", color.GreenCheck())
} else {
if len(opts.Milestone) > 0 {
// close all associated milestones
for _, milestone := range opts.Milestone {
opts.IO.StartSpinner("Closing milestone %q", milestone)
err := closeMilestone(opts, milestone)
opts.IO.StopSpinner("")
if err != nil {
opts.IO.Log(color.FailedIcon(), err.Error())
} else {
opts.IO.Logf("%s Closed milestone %q\n", color.GreenCheck(), milestone)
}
}
}
}
opts.IO.Logf(color.Bold("%s Release succeeded after %0.2f seconds.\n"), color.GreenCheck(), time.Since(start).Seconds())
if opts.PublishToCatalog {
err = catalog.Publish(opts.IO, client, repo.FullName(), release.TagName)
if err != nil {
return cmdutils.WrapError(err, "failed to publish the release to the GitLab CI/CD catalog.")
}
}
return nil
}