Skip to content

Commit

Permalink
feat: add github release command
Browse files Browse the repository at this point in the history
  • Loading branch information
corang committed Oct 16, 2024
1 parent 151c93d commit f6db7a5
Show file tree
Hide file tree
Showing 7 changed files with 197 additions and 9 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ uds-releaser release <flavor>

When running `uds-releaser release gitlab <flavor>` you are expected to have an environment variable set to a GitLab token that has write permissions for your current project. This defaults to `GITLAB_RELEASE_TOKEN` but can be changed with the `--token-var-name` flag.

### GitHub

When running `uds-releaser release github <flavor>` you are expected to have an environment variable set to a GitHub token that has write permissions for your current project. This defaults to `GITHUB_TOKEN` but can be changed with the `--token-var-name` flag.

## Configuration

UDS-Releaser can be configured using a YAML file named uds-releaser.yaml in your project's root directory.
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ require (
github.com/defenseunicorns/uds-cli v0.16.0
github.com/go-git/go-git/v5 v5.12.0
github.com/goccy/go-yaml v1.12.0
github.com/google/go-github/v66 v66.0.0
github.com/spf13/cobra v1.8.1
github.com/stretchr/testify v1.9.0
github.com/xanzy/go-gitlab v0.109.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4er
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-github/v66 v66.0.0 h1:ADJsaXj9UotwdgK8/iFZtv7MLc8E8WBl62WLd/D/9+M=
github.com/google/go-github/v66 v66.0.0/go.mod h1:+4SO9Zkuyf8ytMj0csN1NR/5OTR+MfqPp8P8dVlcvY4=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
Expand Down
25 changes: 25 additions & 0 deletions src/cmd/release.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ limitations under the License.
package cmd

import (
"github.com/defenseunicorns/uds-releaser/src/github"
"github.com/defenseunicorns/uds-releaser/src/gitlab"
"github.com/defenseunicorns/uds-releaser/src/utils"
"github.com/spf13/cobra"
Expand Down Expand Up @@ -45,6 +46,28 @@ var gitlabCmd = &cobra.Command{
},
}

// githubCmd represents the github command
var githubCmd = &cobra.Command{
Use: "github flavor",
Short: "Create a tag and release on GitHub based on flavor",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
releaserConfig, err := utils.LoadReleaserConfig(releaserDir)
if err != nil {
return err
}

currentFlavor, err := utils.GetFlavorConfig(args[0], releaserConfig)
if err != nil {
return err
}

rootCmd.SilenceUsage = true

return github.TagAndRelease(currentFlavor, tokenVarName)
},
}

// releaseCmd represents the release command
var releaseCmd = &cobra.Command{
Use: "release platform",
Expand All @@ -54,5 +77,7 @@ var releaseCmd = &cobra.Command{
func init() {
rootCmd.AddCommand(releaseCmd)
releaseCmd.AddCommand(gitlabCmd)
releaseCmd.AddCommand(githubCmd)
gitlabCmd.Flags().StringVarP(&tokenVarName, "token-var-name", "t", "GITLAB_RELEASE_TOKEN", "Environment variable name for GitLab token")
githubCmd.Flags().StringVarP(&tokenVarName, "token-var-name", "t", "GITHUB_TOKEN", "Environment variable name for GitHub token")
}
120 changes: 120 additions & 0 deletions src/github/release.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package github

import (
"context"
"fmt"
"os"
"regexp"
"time"

"github.com/defenseunicorns/uds-releaser/src/types"
"github.com/defenseunicorns/uds-releaser/src/utils"
github "github.com/google/go-github/v66/github"
)

func TagAndRelease(flavor types.Flavor, tokenVarName string) error {
repo, err := utils.OpenRepo()
if err != nil {
return err
}

remote, err := repo.Remote("origin")
if err != nil {
return err
}

// Get the default branch of the current repository
ref, err := repo.Head()
if err != nil {
return err
}

// Create a new GitHub client
githubClient := github.NewClient(nil)

// Set the authentication token
githubClient = githubClient.WithAuthToken(os.Getenv(tokenVarName))

// Get the repository owner and name

remoteURL := remote.Config().URLs[0]

owner, repoName, err := getGithubOwnerAndRepo(remoteURL)
if err != nil {
return err
}

// Create the tag
zarfPackageName, err := utils.GetPackageName()
if err != nil {
return err
}

tagName := fmt.Sprintf("%s-%s", flavor.Version, flavor.Name)
releaseName := fmt.Sprintf("%s %s", zarfPackageName, tagName)

tag := createGitHubTag(tagName, releaseName, ref.Hash().String())

createdTag, _, err := githubClient.Git.CreateTag(context.Background(), owner, repoName, tag)
if err != nil {
return err
}

// Create a reference for the tag
tagRef := &github.Reference{
Ref: github.String("refs/tags/" + tagName),
Object: &github.GitObject{
SHA: createdTag.SHA,
},
}

_, _, err = githubClient.Git.CreateRef(context.Background(), owner, repoName, tagRef)
if err != nil {
return err
}

// Create the release
release := &github.RepositoryRelease{
TagName: github.String(tagName),
Name: github.String(releaseName),
Body: github.String(releaseName), //TODO @corang release notes
GenerateReleaseNotes: github.Bool(true),
}

_, _, err = githubClient.Repositories.CreateRelease(context.Background(), owner, repoName, release)
if err != nil {
return err
}
return nil
}

func createGitHubTag(tagName string, releaseName string, hash string) *github.Tag {
tag := &github.Tag{
Tag: github.String(tagName),
Message: github.String(releaseName),
Object: &github.GitObject{
SHA: github.String(hash),
Type: github.String("commit"),
},
Tagger: &github.CommitAuthor{
Name: github.String(os.Getenv("GITHUB_ACTOR")),
Email: github.String(os.Getenv("GITHUB_ACTOR") + "@users.noreply.github.com"),
Date: &github.Timestamp{Time: time.Now()},
},
}
return tag
}

func getGithubOwnerAndRepo(remoteURL string) (string, string, error) {
// Parse the GitHub owner and repository name from the remote URL
ownerRepoRegex := regexp.MustCompile(`github.com[:/](.*)/(.*).git`)

Check failure

Code scanning / CodeQL

Incomplete regular expression for hostnames High

This regular expression has an unescaped dot before 'com', so it might match more hosts than expected when
the regular expression is used
.
matches := ownerRepoRegex.FindStringSubmatch(remoteURL)
if len(matches) != 3 {
return "", "", fmt.Errorf("could not parse GitHub owner and repository name from remote URL: %s", remoteURL)
}

owner := matches[1]
repo := matches[2]

return owner, repo, nil
}
42 changes: 42 additions & 0 deletions src/github/release_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package github

import (
"testing"

"github.com/stretchr/testify/assert"
)

func testCreateGitHubTag(t *testing.T) {
// Create a new tag
tagName := "v1.0.0-uds.0-unicorn"
releaseName := "testing-package v1.0.0-uds.0-unicorn"
hash := "1234567890"

tag := createGitHubTag(tagName, releaseName, hash)

assert.Equal(t, tagName, *tag.Tag)
assert.Equal(t, releaseName, *tag.Message)
assert.Equal(t, hash, *tag.Object.SHA)
}

func testgetGithubOwnerAndRepo(t *testing.T) {
// Get the owner and repo from a remote URL
httpsRemoteURL := "https://github.com/defenseunicorns/uds-releaser.git"
sshRemoteURL := "git@github.com:defenseunicorns/uds-releaser.git"

owner, repo, err := getGithubOwnerAndRepo(httpsRemoteURL)
assert.NoError(t, err)
assert.Equal(t, "defenseunicorns", owner)
assert.Equal(t, "uds-releaser", repo)

owner, repo, err = getGithubOwnerAndRepo(sshRemoteURL)
assert.NoError(t, err)
assert.Equal(t, "defenseunicorns", owner)
assert.Equal(t, "uds-releaser", repo)

gitlabRemoteURL := "https://gitlab.com/defenseunicorns/uds-releaser.git"
owner, repo, err = getGithubOwnerAndRepo(gitlabRemoteURL)
assert.Error(t, err)
assert.Empty(t, owner)
assert.Empty(t, repo)
}
12 changes: 3 additions & 9 deletions src/gitlab/release.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,8 @@ import (
gitlab "github.com/xanzy/go-gitlab"
)

var newGitlabClient = gitlab.NewClient

var openRepo = utils.OpenRepo

var getPackageName = utils.GetPackageName

func TagAndRelease(flavor types.Flavor, tokenVarName string) error {
repo, err := openRepo()
repo, err := utils.OpenRepo()
if err != nil {
return err
}
Expand Down Expand Up @@ -47,12 +41,12 @@ func TagAndRelease(flavor types.Flavor, tokenVarName string) error {
fmt.Printf("Default branch: %s\n", defaultBranch)

// Create a new GitLab client
gitlabClient, err := newGitlabClient(os.Getenv(tokenVarName), gitlab.WithBaseURL(gitlabBaseURL))
gitlabClient, err := gitlab.NewClient(os.Getenv(tokenVarName), gitlab.WithBaseURL(gitlabBaseURL))
if err != nil {
return err
}

zarfPackageName, err := getPackageName()
zarfPackageName, err := utils.GetPackageName()
if err != nil {
return err
}
Expand Down

0 comments on commit f6db7a5

Please sign in to comment.