Skip to content

Commit

Permalink
Merge pull request #43 from rios0rios0/feat/versioning
Browse files Browse the repository at this point in the history
feat(versioning): added the feature to read project names from language config
  • Loading branch information
rios0rios0 authored Jan 24, 2024
2 parents f2b6b57 + 37a2ff9 commit 5767f40
Show file tree
Hide file tree
Showing 14 changed files with 187 additions and 73 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ Exceptions are acceptable depending on the circumstances (critical bug fixes tha

## [Unreleased]

### Added

- added the feature to read project names from the language's configuration file

### Changed

- refactored the project to eliminate warnings from golangci-lint

## [2.11.0] - 2024-01-23

### Added
Expand Down
44 changes: 33 additions & 11 deletions cmd/autobump/azuredevops.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import (
"encoding/base64"
"encoding/json"
"fmt"
"github.com/go-git/go-git/v5"
log "github.com/sirupsen/logrus"
"io"
"io/ioutil"
"net/http"
"strings"

"github.com/go-git/go-git/v5"
log "github.com/sirupsen/logrus"
)

// AzureDevOpsInfo struct to hold organization, project, and repo info
Expand Down Expand Up @@ -48,8 +48,12 @@ func createAzureDevOpsPullRequest(
}

// TODO: refactor to use this library: https://github.com/microsoft/azure-devops-go-api
url := fmt.Sprintf("https://dev.azure.com/%s/%s/_apis/git/repositories/%s/pullrequests?api-version=6.0",
azureInfo.OrganizationName, azureInfo.ProjectName, azureInfo.RepositoryID)
url := fmt.Sprintf(
"https://dev.azure.com/%s/%s/_apis/git/repositories/%s/pullrequests?api-version=6.0",
azureInfo.OrganizationName,
azureInfo.ProjectName,
azureInfo.RepositoryID,
)
prTitle := fmt.Sprintf("chore(bump): bumped version to %s", newVersion)
payload := map[string]interface{}{
"sourceRefName": fmt.Sprintf("refs/heads/%s", sourceBranch),
Expand All @@ -69,7 +73,10 @@ func createAzureDevOpsPullRequest(
}

req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(":"+personalAccessToken)))
req.Header.Set(
"Authorization",
"Basic "+base64.StdEncoding.EncodeToString([]byte(":"+personalAccessToken)),
)

log.Infof("POST %s", url)
resp, err := client.Do(req)
Expand All @@ -80,15 +87,22 @@ func createAzureDevOpsPullRequest(

body, _ := io.ReadAll(resp.Body)
if resp.StatusCode != http.StatusCreated {
return fmt.Errorf("failed to create pull request (status: %d), response body is: %s", resp.StatusCode, body)
return fmt.Errorf(
"failed to create pull request (status: %d), response body is: %s",
resp.StatusCode,
body,
)
}

log.Info("Successfully created Azure DevOps pull request")
return nil
}

// GetAzureDevOpsInfo extracts organization, project, and repo information from the remote URL
func GetAzureDevOpsInfo(repo *git.Repository, personalAccessToken string) (info AzureDevOpsInfo, err error) {
func GetAzureDevOpsInfo(
repo *git.Repository,
personalAccessToken string,
) (info AzureDevOpsInfo, err error) {
remoteURL, err := getRemoteRepoURL(repo)
if err != nil {
return info, err
Expand All @@ -109,14 +123,22 @@ func GetAzureDevOpsInfo(repo *git.Repository, personalAccessToken string) (info
}

// fetch repositoryId using Azure DevOps API
url := fmt.Sprintf("https://dev.azure.com/%s/%s/_apis/git/repositories/%s?api-version=6.0", organizationName, projectName, repositoryName)
url := fmt.Sprintf(
"https://dev.azure.com/%s/%s/_apis/git/repositories/%s?api-version=6.0",
organizationName,
projectName,
repositoryName,
)
client := &http.Client{}
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return info, err
}

req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(":"+personalAccessToken)))
req.Header.Set(
"Authorization",
"Basic "+base64.StdEncoding.EncodeToString([]byte(":"+personalAccessToken)),
)

log.Infof("GET %s", url)
resp, err := client.Do(req)
Expand All @@ -125,7 +147,7 @@ func GetAzureDevOpsInfo(repo *git.Repository, personalAccessToken string) (info
}
defer resp.Body.Close()

bodyBytes, err := ioutil.ReadAll(resp.Body)
bodyBytes, err := io.ReadAll(resp.Body)
if err != nil {
return info, err
}
Expand Down
13 changes: 6 additions & 7 deletions cmd/autobump/changelog.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import (
log "github.com/sirupsen/logrus"
)

const defaultChangelogUrl = "https://raw.githubusercontent.com/rios0rios0/autobump/main/configs/CHANGELOG.template.md"
const defaultChangelogUrl = "https://raw.githubusercontent.com/rios0rios0/" +
"autobump/main/configs/CHANGELOG.template.md"

func updateChangelogFile(changelogPath string) (*semver.Version, error) {
lines, err := readLines(changelogPath)
Expand Down Expand Up @@ -51,12 +52,12 @@ func getNextVersion(changelogPath string) (*semver.Version, error) {
func createChangelogIfNotExists(changelogPath string) (bool, error) {
if _, err := os.Stat(changelogPath); os.IsNotExist(err) {
log.Warnf("Creating empty CHANGELOG file at '%s'.", changelogPath)
var fileContent, err = downloadFile(defaultChangelogUrl)
fileContent, err := downloadFile(defaultChangelogUrl)
if err != nil {
log.Errorf("It wasn't possible to download the CHANGELOG model file: %v", err)
}

err = os.WriteFile(changelogPath, fileContent, 0644)
err = os.WriteFile(changelogPath, fileContent, 0o644)
if err != nil {
log.Errorf("Error creating CHANGELOG file: %v", err)
return false, err
Expand Down Expand Up @@ -88,7 +89,8 @@ func isChangelogUnreleasedEmpty(changelogPath string) (bool, error) {
}

if unreleased {
if match, _ := regexp.MatchString(`^\s*-\s*[^ ]+`, line); match {
re := regexp.MustCompile(`^\s*-\s*[^ ]+`)
if match := re.MatchString(line); match {
return false, nil
}
}
Expand Down Expand Up @@ -230,17 +232,14 @@ func updateSection(
for i := 0; i < majorChanges; i++ {
nextVersion = nextVersion.IncMajor()
}
break
case minorChanges > 0:
for i := 0; i < minorChanges; i++ {
nextVersion = nextVersion.IncMinor()
}
break
case patchChanges > 0:
for i := 0; i < patchChanges; i++ {
nextVersion = nextVersion.IncPatch()
}
break
}

// Sort the items inside the sections alphabetically
Expand Down
25 changes: 16 additions & 9 deletions cmd/autobump/config.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package main

import (
"errors"
"fmt"
"net/url"
"os"
Expand Down Expand Up @@ -40,9 +39,10 @@ type ProjectConfig struct {
NewVersion string
}

const defaultConfigUrl = "https://raw.githubusercontent.com/rios0rios0/autobump/main/configs/autobump.yaml"
const defaultConfigUrl = "https://raw.githubusercontent.com/rios0rios0/autobump/" +
"main/configs/autobump.yaml"

var missingLanguagesKeyError = errors.New("missing languages key")
var missingLanguagesKeyError = fmt.Errorf("missing languages key")

// readConfig reads the config file and returns a GlobalConfig struct
func readConfig(configPath string) (*GlobalConfig, error) {
Expand Down Expand Up @@ -93,7 +93,10 @@ func readConfig(configPath string) (*GlobalConfig, error) {
if globalConfig.AzureDevOpsAccessToken != "" {
_, err = os.Stat(globalConfig.AzureDevOpsAccessToken)
if !os.IsNotExist(err) {
log.Infof("Reading Azure DevOps access token from file %s", globalConfig.AzureDevOpsAccessToken)
log.Infof(
"Reading Azure DevOps access token from file %s",
globalConfig.AzureDevOpsAccessToken,
)
token, err := os.ReadFile(globalConfig.AzureDevOpsAccessToken)
if err != nil {
return nil, err
Expand Down Expand Up @@ -125,25 +128,26 @@ func decodeConfig(data []byte) (*GlobalConfig, error) {
func validateGlobalConfig(globalConfig *GlobalConfig, batch bool) error {
var missingKeys []string

if batch == true && len(globalConfig.Projects) == 0 {
if batch && len(globalConfig.Projects) == 0 {
missingKeys = append(missingKeys, "projects")
}

for i, projectConfig := range globalConfig.Projects {
if projectConfig.Path == "" {
missingKeys = append(missingKeys, fmt.Sprintf("projects[%d].path", i))
}
if batch == true && globalConfig.GitLabAccessToken == "" &&
if batch && globalConfig.GitLabAccessToken == "" &&
projectConfig.ProjectAccessToken == "" {
log.Error(
"Project access token is required when personal access token is not set in batch mode",
"Project access token is required when personal access token " +
"is not set in batch mode",
)
missingKeys = append(missingKeys, fmt.Sprintf("projects[%d].project_access_token", i))
}
}

if len(missingKeys) > 0 {
return errors.New("missing keys: " + strings.Join(missingKeys, ", "))
return fmt.Errorf("missing keys: " + strings.Join(missingKeys, ", "))
}

if globalConfig.LanguagesConfig == nil {
Expand All @@ -161,7 +165,10 @@ func findConfigOnMissing(configPath string) string {
var err error
configPath, err = findConfig()
if err != nil {
log.Warn("Config file not found in default locations, using the repository configuration as the last resort")
log.Warn(
"Config file not found in default locations, " +
"using the repository configuration as the last resort",
)
configPath = defaultConfigUrl
}

Expand Down
24 changes: 11 additions & 13 deletions cmd/autobump/git.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
package main

import (
"errors"
"fmt"
"github.com/Masterminds/semver/v3"
"github.com/go-git/go-git/v5/plumbing/object"
"github.com/go-git/go-git/v5/plumbing/protocol/packp/capability"
"github.com/go-git/go-git/v5/plumbing/transport"
"os"
"path/filepath"
"strings"
"time"

"github.com/Masterminds/semver/v3"
"github.com/go-git/go-git/v5/plumbing/object"
"github.com/go-git/go-git/v5/plumbing/protocol/packp/capability"
"github.com/go-git/go-git/v5/plumbing/transport"

"github.com/ProtonMail/go-crypto/openpgp"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/config"
Expand Down Expand Up @@ -199,7 +199,6 @@ func getAuthMethods(
Password: globalConfig.GitLabCIJobToken,
})
}
break
case "AzureDevOps":
log.Infof("Using Azure DevOps access token to authenticate")
transport.UnsupportedCapabilities = []capability.Capability{
Expand All @@ -209,15 +208,14 @@ func getAuthMethods(
Username: username,
Password: globalConfig.AzureDevOpsAccessToken,
})
break
default:
log.Errorf("No authentication mechanism implemented for service type '%s'", service)
return nil, errors.New("no authentication mechanism implemented")
return nil, fmt.Errorf("no authentication mechanism implemented")
}

if len(authMethods) == 0 {
log.Error("No authentication credentials found for any authentication method")
return nil, errors.New("no authentication credentials found for any authentication method")
return nil, fmt.Errorf("no authentication credentials found for any authentication method")
}

return authMethods, nil
Expand Down Expand Up @@ -308,14 +306,14 @@ func getLatestTag() (*LatestTag, error) {
}

var latestTag *plumbing.Reference
err = tags.ForEach(func(tag *plumbing.Reference) error {
_ = tags.ForEach(func(tag *plumbing.Reference) error {
latestTag = tag
return nil
})

// get the date time of the tag
commit, err := repo.CommitObject(latestTag.Hash())
var latestTagDate = commit.Committer.When
latestTagDate := commit.Committer.When
if err != nil {
log.Fatal(err)
}
Expand All @@ -325,7 +323,7 @@ func getLatestTag() (*LatestTag, error) {
// if the project is already started with no tags in the history
if commits >= 5 {
log.Warnf("No tags found in Git history, falling back to '%s'", defaultGitTag)
var version, _ = semver.NewVersion(defaultGitTag)
version, _ := semver.NewVersion(defaultGitTag)
return &LatestTag{
Tag: version,
Date: time.Now(),
Expand All @@ -337,7 +335,7 @@ func getLatestTag() (*LatestTag, error) {
}
}

var version, _ = semver.NewVersion(latestTag.Name().Short())
version, _ := semver.NewVersion(latestTag.Name().Short())
return &LatestTag{
Tag: version,
Date: latestTagDate,
Expand Down
11 changes: 7 additions & 4 deletions cmd/autobump/gitlab.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ import (
"github.com/xanzy/go-gitlab"
)

// TODO: this should be better using an Adapter pattern (interface with many providers and implementing the methods)
// TODO: this should be better using an Adapter pattern
//
// (interface with many providers and implementing the methods)
//
// createGitLabMergeRequest creates a new merge request on GitLab
func createGitLabMergeRequest(
globalConfig *GlobalConfig,
Expand Down Expand Up @@ -48,10 +51,10 @@ func createGitLabMergeRequest(
mrTitle := fmt.Sprintf("chore(bump): bumped version to %s", newVersion)

mergeRequestOptions := &gitlab.CreateMergeRequestOptions{
SourceBranch: gitlab.String(sourceBranch),
TargetBranch: gitlab.String("main"),
SourceBranch: gitlab.Ptr(sourceBranch),
TargetBranch: gitlab.Ptr("main"),
Title: &mrTitle,
RemoveSourceBranch: gitlab.Bool(true),
RemoveSourceBranch: gitlab.Ptr(true),
}

_, _, err = gitlabClient.MergeRequests.CreateMergeRequest(projectID, mergeRequestOptions)
Expand Down
14 changes: 14 additions & 0 deletions cmd/autobump/language.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package main

type Language interface {
GetProjectName() (string, error)
}

func getLanguageInterface(projectConfig ProjectConfig) Language {
switch projectConfig.Language {
case "python":
return Python{ProjectConfig: projectConfig}
default:
return nil
}
}
Loading

0 comments on commit 5767f40

Please sign in to comment.