18093: implement review feedback
authorWard Vandewege <ward@curii.com>
Fri, 19 Nov 2021 19:29:39 +0000 (14:29 -0500)
committerWard Vandewege <ward@curii.com>
Fri, 19 Nov 2021 19:53:29 +0000 (14:53 -0500)
Arvados-DCO-1.1-Signed-off-by: Ward Vandewege <ward@curii.com>

cmd/art/TASKS
cmd/art/redmine.go
lib/redmine/projects.go
lib/redmine/releases.go

index 4fdee2cf083dd15e00652bacb076134a53d3b848..9aa1a3b9482bf469dee2411f4b686dc2bac43709 100644 (file)
@@ -1,19 +1,23 @@
 Prepare release branch
+Update the "Upgrading Arvados and Release notes" doc page (main and release branch)
+Ensure that the entire automated testing pipeline is passing on Jenkins
+Manual testing
 Review release branch
 Create next redmine release
-Record git commit
-Build RC packages
-Draft release notes
+Draft release notes and publish them to www-dev
 Review release notes
+Build RC packages
 Test installer
 Deploy RC packages to playground
-Run test pipeline
-Sign off
+Run bam-to-vcf pipeline pipeline
+Approve RC for release
+Build final release packages
 Push packages to stable
 Publish docker image, python and ruby packages
 Publish formula/installer for release
-Publish arvbox image
+Publish arvados/arvbox-demo image
 Tag commits
 Update doc site
-Publish release on arvados.org
+Merge release notes (step 6) form "develop" to "main" and publish release on arvados.org
 Send out release notification
+Major releases only: Copy "run-tests" jobs in jenkins
index 27c14e0d2d999f907a508641b0c8a2cff3e99f6f..e02bb473e9119b55beb1abe5dac077030788d396 100644 (file)
@@ -6,6 +6,7 @@ package main
 
 import (
        "bufio"
+       "encoding/json"
        "fmt"
        "log"
        "os"
@@ -28,6 +29,7 @@ import (
 func init() {
        rootCmd.AddCommand(redmineCmd)
        redmineCmd.AddCommand(issuesCmd)
+       redmineCmd.AddCommand(releasesCmd)
 
        associateIssueCmd.Flags().IntP("release", "r", 0, "Redmine release ID")
        err := associateIssueCmd.MarkFlagRequired("release")
@@ -70,12 +72,19 @@ func init() {
        if err != nil {
                log.Fatalf(err.Error())
        }
-       createReleaseIssueCmd.Flags().IntP("project", "p", 0, "Redmine project ID")
+       createReleaseIssueCmd.Flags().StringP("project", "p", "", "Redmine project name")
        err = createReleaseIssueCmd.MarkFlagRequired("project")
        if err != nil {
                log.Fatalf(err.Error())
        }
        issuesCmd.AddCommand(createReleaseIssueCmd)
+
+       getReleaseCmd.Flags().IntP("release", "r", 0, "ID of the redmine release")
+       err = getReleaseCmd.MarkFlagRequired("release")
+       if err != nil {
+               log.Fatalf(err.Error())
+       }
+       releasesCmd.AddCommand(getReleaseCmd)
 }
 
 var redmineCmd = &cobra.Command{
@@ -359,18 +368,18 @@ var createReleaseIssueCmd = &cobra.Command{
                        log.Fatal(fmt.Errorf("[error] can not convert Redmine sprint (version) ID to integer: %s", err))
                        return
                }
-               projectID, err := cmd.Flags().GetInt("project")
+               projectName, err := cmd.Flags().GetString("project")
                if err != nil {
-                       log.Fatal(fmt.Errorf("[error] can not convert Redmine project ID to integer: %s", err))
+                       log.Fatal(fmt.Errorf("[error] can not get Redmine project name: %s", err))
                        return
                }
 
                r := redmine.NewClient(conf.Endpoint, conf.Apikey)
 
                // Does this project exist?
-               project, err := r.GetProject(projectID)
+               project, err := r.GetProjectByName(projectName)
                if err != nil {
-                       log.Fatalf("[error] can not find project with id %d: %s", projectID, err)
+                       log.Fatalf("[error] can not find project with name %s: %s", projectName, err)
                }
 
                // Is the sprint (aka "version" in redmine) in the correct state?
@@ -382,7 +391,7 @@ var createReleaseIssueCmd = &cobra.Command{
                        log.Fatal(fmt.Errorf("[error] the sprint must be open; the status of the sprint with id %d is '%s'", v.ID, v.Status))
                }
 
-               i, err := r.FindOrCreateIssue("Release Arvados "+newReleaseVersion, 0, v.ID, projectID)
+               i, err := r.FindOrCreateIssue("Release Arvados "+newReleaseVersion, 0, v.ID, project.ID)
                if err != nil {
                        log.Fatal(err)
                }
@@ -400,10 +409,10 @@ var createReleaseIssueCmd = &cobra.Command{
                defer tasks.Close()
 
                scanner := bufio.NewScanner(tasks)
-               count := 0
+               count := 1
                for scanner.Scan() {
                        task := scanner.Text()
-                       taskIssue, err := r.FindOrCreateIssue(fmt.Sprintf("%d. %s", count, task), i.ID, v.ID, projectID)
+                       taskIssue, err := r.FindOrCreateIssue(fmt.Sprintf("%d. %s", count, task), i.ID, v.ID, project.ID)
                        fmt.Printf("[ok] #%d: %d. %s\n", taskIssue.ID, count, task)
                        count++
                        if err != nil {
@@ -431,7 +440,7 @@ var createReleaseIssueCmd = &cobra.Command{
                        release.Sharing = "hierarchy"
                        release.ReleaseStartDate = time.Now().AddDate(0, 0, 7*1).Format("2006-01-02") // arbitrary choice, 1 week from today
                        release.ReleaseEndDate = time.Now().AddDate(0, 0, 7*5).Format("2006-01-02")   // also arbitrary, 5 weeks from today
-                       release.ProjectID = projectID
+                       release.ProjectID = project.ID
                        release.Status = "open"
                        // Populate Project
                        tmp, err := r.GetProject(release.ProjectID)
@@ -440,12 +449,47 @@ var createReleaseIssueCmd = &cobra.Command{
                        }
                        release.Project = &redmine.IDName{ID: release.ProjectID, Name: tmp.Name}
 
-                       tmpRelease, err := r.CreateRelease(*release)
+                       release, err = r.CreateRelease(*release)
                        if err != nil {
                                log.Fatalf("Unable to create release: %s", err)
                        }
-                       release = tmpRelease
                }
                fmt.Printf("[ok] the redmine release object for the next release is '%s' (%s/rb/release/%d)\n", release.Name, conf.Endpoint, release.ID)
        },
 }
+
+var releasesCmd = &cobra.Command{
+       Use:   "releases",
+       Short: "Manage Redmine releases",
+       Long: "Manage Redmine releases.\n" +
+               "\nThe REDMINE_ENDPOINT environment variable must be set to the base URL of your redmine server." +
+               "\nThe REDMINE_APIKEY environment variable must be set to your redmine API key.",
+}
+
+var getReleaseCmd = &cobra.Command{
+       Use:   "get",
+       Short: "get a release",
+       Long: "Get a release.\n" +
+               "\nThe REDMINE_ENDPOINT environment variable must be set to the base URL of your redmine server." +
+               "\nThe REDMINE_APIKEY environment variable must be set to your redmine API key.",
+       Run: func(cmd *cobra.Command, args []string) {
+               releaseID, err := cmd.Flags().GetInt("release")
+               if err != nil {
+                       fmt.Printf("Error converting Redmine release ID to integer: %s", err)
+                       os.Exit(1)
+               }
+
+               r := redmine.NewClient(conf.Endpoint, conf.Apikey)
+
+               release, err := r.GetRelease(releaseID)
+               if err != nil {
+                       log.Fatalf("Error finding release with id %d: %s", releaseID, err)
+               }
+               releaseStr, err := json.MarshalIndent(release, "", "  ")
+               if err != nil {
+                       log.Fatalf("Error decoding release with id %d: %s", releaseID, err)
+               }
+               fmt.Println(string(releaseStr))
+
+       },
+}
index f942c13944894e7fdedc037a30e820a7776f96c9..4d4b5df9094551369978566ffecbc30bd6e1dbd6 100644 (file)
@@ -42,3 +42,18 @@ func (c *Client) GetProject(id int) (*Project, error) {
        }
        return &r.Project, nil
 }
+
+func (c *Client) GetProjectByName(name string) (*Project, error) {
+       res, err := c.Get("/projects/" + name + ".json")
+       if err != nil {
+               return nil, err
+       }
+       defer res.Body.Close()
+
+       var r projectWrapper
+       err = responseHelper(res, &r, 200)
+       if err != nil {
+               return nil, err
+       }
+       return &r.Project, nil
+}
index 4a13e3fd643c0ac039c7350d995c5b51d160e45f..d9308fb17f756a654528dac941030433e29b7492 100644 (file)
@@ -8,20 +8,35 @@ import (
        "encoding/json"
        "fmt"
        "net/url"
+       "strconv"
        "strings"
 )
 
+//map[string]interface {}{
+/*  "release":map[string]interface {}{
+       "description":interface {}(nil),
+       "id":64,
+       "name":"Arvados 2.3.7",
+       "planned_velocity":interface {}(nil),
+       "project":map[string]interface {}{
+               "id":36,
+               "name":"Arvados"},
+       "release_end_date":"2021-12-24",
+       "release_start_date":"2021-11-26",
+       "sharing":"hierarchy",
+       "status":"open"}
+} */
 type Release struct {
-       ID               int     `json:"id"`
-       Name             string  `json:"name"`
-       Description      string  `json:"description"`
-       Sharing          string  `json:"sharing"`
-       ReleaseStartDate string  `json:"release_start_date"`
-       ReleaseEndDate   string  `json:"release_end_date"`
-       PlannedVelocity  string  `json:"planned_velocity"`
-       Status           string  `json:"status"`
-       ProjectID        int     `json:"-"`
-       Project          *IDName `json:"-"`
+       ID               int     `json:"id,omitempty"`
+       Name             string  `json:"name,omitempty"`
+       Description      string  `json:"description,omitempty"`
+       Sharing          string  `json:"sharing,omitempty"`
+       ReleaseStartDate string  `json:"release_start_date,omitempty"`
+       ReleaseEndDate   string  `json:"release_end_date,omitempty"`
+       PlannedVelocity  string  `json:"planned_velocity,omitempty"`
+       Status           string  `json:"status,omitempty"`
+       ProjectID        int     `json:"project_id,omitempty"`
+       Project          *IDName `json:"project,omitempty"`
 }
 
 type releaseWrapper struct {
@@ -51,6 +66,29 @@ func (c *Client) FindReleaseByName(project, name string) (*Release, error) {
        return &r.Release, nil
 }
 
+// FindReleaseByName retrieves a redmine Release object by name
+func (c *Client) GetRelease(ID int) (*Release, error) {
+       // This api call only returns the first matching release object. There is no unique index on release names.
+       res, err := c.Get("/rb/release/" + strconv.Itoa(ID) + ".json")
+       if err != nil {
+               return nil, err
+       }
+       defer res.Body.Close()
+
+       if res.StatusCode == 404 {
+               return nil, fmt.Errorf("Not found")
+       }
+       var r releaseWrapper
+       err = responseHelper(res, &r, 200)
+       if err != nil {
+               return nil, err
+       }
+       if r.Release.ID == 0 {
+               return nil, nil
+       }
+       return &r.Release, nil
+}
+
 func (c *Client) CreateRelease(release Release) (*Release, error) {
        var rr releaseWrapper
        rr.Release = release
@@ -65,7 +103,7 @@ func (c *Client) CreateRelease(release Release) (*Release, error) {
        defer res.Body.Close()
 
        var r releaseWrapper
-       err = responseHelper(res, r, 200)
+       err = responseHelper(res, &r, 201)
        if err != nil {
                return nil, err
        }