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

Command to check Rancher dependencies for a RC #286

Merged
merged 29 commits into from
Nov 29, 2023
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
4dfe570
change repo files
johnatasr Oct 14, 2023
e0620ec
func to check all deps and command
johnatasr Oct 17, 2023
54fbdda
add test
johnatasr Oct 17, 2023
ea323c5
last adjusts
johnatasr Oct 19, 2023
0c968b8
improve code
johnatasr Oct 19, 2023
ff54210
merge
johnatasr Oct 19, 2023
df575f1
change requires
johnatasr Oct 19, 2023
98cc14d
remove necessity of repo and org
johnatasr Oct 23, 2023
b2d1773
more improves
johnatasr Oct 26, 2023
b7444fe
more adjusts
johnatasr Oct 27, 2023
e0cf846
removing logrus
johnatasr Oct 27, 2023
b4a2ec2
adjust for message
johnatasr Oct 27, 2023
7fabcf8
adjust for message
johnatasr Oct 27, 2023
81ff6cf
add template tag
johnatasr Oct 30, 2023
f6bd50d
add template
johnatasr Oct 31, 2023
4bcb215
add more changes
johnatasr Nov 1, 2023
2e6bc03
Merge remote-tracking branch 'upstream/master' into feat-racher-relea…
johnatasr Nov 14, 2023
aae5899
using regex for rancher txt files
johnatasr Nov 14, 2023
e3b512e
add docs
johnatasr Nov 15, 2023
9422eac
Update rancher.go
johnatasr Nov 16, 2023
01b8712
remove unsed commit validation
johnatasr Nov 17, 2023
d47811b
split dev deps
johnatasr Nov 17, 2023
9683343
update doc and requires
johnatasr Nov 17, 2023
28b4198
remove unsed api url
johnatasr Nov 17, 2023
1616d52
more fixes
johnatasr Nov 23, 2023
a8d361f
remove func contents
johnatasr Nov 23, 2023
04eb84f
more adjusts
johnatasr Nov 27, 2023
1b965e6
add line and content to min version
johnatasr Nov 28, 2023
0fae92f
add rancher images export in example
johnatasr Nov 28, 2023
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
68 changes: 68 additions & 0 deletions cmd/rancher_release/check_rancher_rc_deps.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package main

import (
"errors"

"github.com/rancher/ecm-distro-tools/release/rancher"
"github.com/sirupsen/logrus"
"github.com/urfave/cli/v2"
)

func checkRancherRCDepsCommand() *cli.Command {
return &cli.Command{
Name: "check-rancher-rc-deps",
Usage: "check if the Rancher version specified by the commit or pre-release title does not contain development dependencies and rc tags",
Flags: []cli.Flag{
&cli.StringFlag{
johnatasr marked this conversation as resolved.
Show resolved Hide resolved
Name: "commit",
Aliases: []string{"c"},
Usage: "last commit for a final rc",
Required: false,
johnatasr marked this conversation as resolved.
Show resolved Hide resolved
},
&cli.StringFlag{
Name: "release-title",
Aliases: []string{"t"},
Usage: "release title from a given release process",
Required: false,
},
&cli.StringFlag{
briandowns marked this conversation as resolved.
Show resolved Hide resolved
johnatasr marked this conversation as resolved.
Show resolved Hide resolved
Name: "org",
Aliases: []string{"o"},
Usage: "organization name",
Required: false,
},
&cli.StringFlag{
Name: "repo",
Aliases: []string{"r"},
Usage: "rancher repository",
Required: false,
},
&cli.StringFlag{
johnatasr marked this conversation as resolved.
Show resolved Hide resolved
Name: "files",
Aliases: []string{"f"},
Usage: "files to be checked",
Required: true,
},
},
Action: checkRancherRCDeps,
}
}

func checkRancherRCDeps(c *cli.Context) error {
rcReleaseTitle := c.String("release-title")
rcCommit := c.String("commit")
rcOrg := c.String("org")
rcRepo := c.String("repo")
rcFiles := c.String("files")

if rcCommit == "" && rcReleaseTitle == "" {
return errors.New("'commit' or 'release-title' are required")
}
if rcFiles == "" {
return errors.New("'files' is required, e.g, --files Dockerfile.dapper,go.mod")
}
logrus.Debugf("organization: %s, repository: %s, commit: %s, release title: %s, files: %s",
rcOrg, rcRepo, rcCommit, rcReleaseTitle, rcFiles)

return rancher.CheckRancherFinalRCDeps(rcOrg, rcRepo, rcCommit, rcReleaseTitle, rcFiles)
}
1 change: 1 addition & 0 deletions cmd/rancher_release/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ func main() {
checkRancherImageCommand(),
setKDMBranchReferencesCommand(),
setChartsBranchReferencesCommand(),
checkRancherRCDepsCommand(),
labelIssuesCommand(),
}
app.Flags = rootFlags
Expand Down
93 changes: 90 additions & 3 deletions release/rancher/rancher.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import (
"bufio"
"context"
"errors"
"fmt"
"io"
"net/http"
"regexp"
"strconv"
"strings"
"time"
Expand Down Expand Up @@ -91,6 +93,11 @@ if [ "${DRY_RUN}" = false ]; then
fi`
)

const (
rancherRepo = "rancher"
rancherOrg = rancherRepo
)

type SetBranchReferencesArgs struct {
RancherRepoPath string
CurrentBranch string
Expand Down Expand Up @@ -263,8 +270,7 @@ func SetChartBranchReferences(ctx context.Context, forkPath, rancherBaseBranch,
}

func createPRFromRancher(ctx context.Context, rancherBaseBranch, title, branchName, forkOwner string, ghClient *github.Client) error {
const repo = "rancher"
org, err := repository.OrgFromRepo(repo)
org, err := repository.OrgFromRepo(rancherRepo)
if err != nil {
return err
}
Expand All @@ -274,7 +280,88 @@ func createPRFromRancher(ctx context.Context, rancherBaseBranch, title, branchNa
Head: github.String(forkOwner + ":" + branchName),
MaintainerCanModify: github.Bool(true),
}
_, _, err = ghClient.PullRequests.Create(ctx, org, repo, pull)
_, _, err = ghClient.PullRequests.Create(ctx, org, rancherRepo, pull)

return err
}

func CheckRancherFinalRCDeps(org, repo, commitHash, releaseTitle, files string) error {
const (
releaseTitleRegex = `^Pre-release v2\.7\.[0-9]{1,100}-rc[1-9][0-9]{0,1}$`
partialFinalRCCommitMessage = "last commit for final rc"
)
var (
matchCommitMessage bool
existsReleaseTitle bool
badFiles bool
)

devDependencyPattern := regexp.MustCompile(`dev-v[0-9]+\.[0-9]+`)
rcTagPattern := regexp.MustCompile(`-rc[0-9]+`)

httpClient := ecmHTTP.NewClient(time.Second * 15)

if repo == "" {
repo = rancherRepo
}
if org == "" {
org = rancherOrg
}
if commitHash != "" {
commitData, err := repository.CommitInfo(org, repo, commitHash, &httpClient)
if err != nil {
return err
}
matchCommitMessage = strings.Contains(commitData.Message, partialFinalRCCommitMessage)

}
if releaseTitle != "" {
innerExistsReleaseTitle, err := regexp.MatchString(releaseTitleRegex, releaseTitle)
if err != nil {
return err
}
existsReleaseTitle = innerExistsReleaseTitle
}

if matchCommitMessage || existsReleaseTitle {
for _, filePath := range strings.Split(files, ",") {
content, err := repository.ContentByFileNameAndCommit(org, repo, commitHash, filePath, &httpClient)
if err != nil {
return err
}

scanner := bufio.NewScanner(strings.NewReader(string(content)))
lineNum := 1

for scanner.Scan() {
line := scanner.Text()
lineByte := []byte(line)

if devDependencyPattern.Match(lineByte) {
badFiles = true
logMessage := fmt.Sprintf("error: %s contains dev dependencies (line %d) - %s", filePath, lineNum, line)
logrus.Info(logMessage)
}
if rcTagPattern.Match(lineByte) {
badFiles = true
logMessage := fmt.Sprintf("error: %s contains rc tags (line %d) - %s", filePath, lineNum, line)
logrus.Info(logMessage)
}

lineNum++
}
if err := scanner.Err(); err != nil {
return err
}
}
if badFiles {
return errors.New("check failed, some files don't match the expected dependencies for a final release candidate")
}

logrus.Info("check completed successfully")
return nil
}

logrus.Info("skipped check")
return nil
}
79 changes: 79 additions & 0 deletions repository/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,22 @@ package repository

import (
"context"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net/http"
"os"
"os/exec"
"strconv"
"strings"
"time"

"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing"
"github.com/google/go-github/v39/github"
"github.com/rancher/ecm-distro-tools/types"
"github.com/sirupsen/logrus"
"golang.org/x/oauth2"
)

Expand All @@ -21,6 +26,8 @@ const (
emptyReleaseNote = "```release-note\r\n\r\n```"
noneReleaseNote = "```release-note\r\nNONE\r\n```"
httpTimeout = time.Second * 10
ghContentURL = "https://raw.githubusercontent.com"
baseURLGHApi = "https://api.github.com"
johnatasr marked this conversation as resolved.
Show resolved Hide resolved
)

// repoToOrg associates repo to org.
Expand Down Expand Up @@ -457,3 +464,75 @@ To find more information on specific steps, please see documentation [here](http
- [ ] QA: Final validation of above PR and tracked through the linked ticket
- [ ] PJM: Close the milestone in GitHub.
`

type Author struct {
Name string `json:"name"`
Email string `json:"email"`
Date string `json:"date"`
}

type Commit struct {
Author Author `json:"author"`
Committer Author `json:"committer"`
Message string `json:"message"`
URL string `json:"url"`
}

type CommitResponse struct {
SHA string `json:"sha"`
NodeID string `json:"node_id"`
Commit Commit `json:"commit"`
URL string `json:"url"`
HTMLURL string `json:"html_url"`
CommentsURL string `json:"comments_url"`
}

func CommitInfo(owner, repo, commitHash string, httpClient *http.Client) (*Commit, error) {
johnatasr marked this conversation as resolved.
Show resolved Hide resolved
apiUrl := fmt.Sprintf(baseURLGHApi+"/repos/%s/%s/commits/%s", owner, repo, commitHash)

response, err := httpClient.Get(apiUrl)
if err != nil {
logrus.Debug("Error making request:", err)
return nil, err
}
defer response.Body.Close()
if response.StatusCode != http.StatusOK {
return nil, errors.New("failed to fetch commit information. status code: " + strconv.Itoa(response.StatusCode))
}
data, err := ioutil.ReadAll(response.Body)
johnatasr marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
logrus.Debug("error reading response body:", err)
return nil, err
}

var commitResponse CommitResponse

err = json.Unmarshal([]byte(data), &commitResponse)
johnatasr marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
logrus.Debug("error unmarshaling JSON:", err)
return nil, err
}

return &commitResponse.Commit, nil
}

func ContentByFileNameAndCommit(owner, repo, commitHash, filePath string, httpClient *http.Client) ([]byte, error) {
johnatasr marked this conversation as resolved.
Show resolved Hide resolved
rawURL := fmt.Sprintf(ghContentURL+"/%s/%s/%s/%s", owner, repo, commitHash, filePath)

response, err := http.Get(rawURL)
if err != nil {
logrus.Debug("error fetching raw file:", err)
johnatasr marked this conversation as resolved.
Show resolved Hide resolved
return nil, err
}
defer response.Body.Close()
if response.StatusCode != http.StatusOK {
return nil, errors.New("failed to fetch raw file. status code: " + strconv.Itoa(response.StatusCode))
}
data, err := ioutil.ReadAll(response.Body)
if err != nil {
logrus.Debug("error reading response body:", err)
return nil, err
}

return data, nil
}