Skip to content

Commit

Permalink
🐛 Add svn support for tags. (#67)
Browse files Browse the repository at this point in the history
Add svn support tags.  Need to support 2 use cases:
1. The user supplies the fully qualified URL including the branch/tag
and directory within the repository for the application.
    - **branch** must be blank.
    - **root** path must be blank.
3. The user supplies the URL to the root of the repository. Must not
include branch or subdir to the application.
- **branch** will be appended to the URL (when specified). Must be fully
qualified path as needed. Ex: `tags/v1.2`. `/trunk` is no longer
assumed.
   - **root** path will be append to the URL (when specified).

Some minor re-organization. Better practice to have exported (public)
methods at the top.

ref: https://issues.redhat.com/browse/MTA-4236

---------

Signed-off-by: Jeff Ortel <jortel@redhat.com>
  • Loading branch information
jortel authored Nov 22, 2024
1 parent 67652f4 commit a87f4c3
Show file tree
Hide file tree
Showing 6 changed files with 184 additions and 81 deletions.
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ require (
github.com/clbanning/mxj v1.8.4
github.com/jortel/go-utils v0.1.2
github.com/konveyor/tackle2-hub v0.5.0-rc.1.0.20240726125502-8bb3c0911660
github.com/onsi/gomega v1.27.6
github.com/swaggo/swag v1.16.1
)

require (
Expand Down Expand Up @@ -36,6 +38,7 @@ require (
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/gnostic v0.5.7-v3refs // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/gofuzz v1.1.0 // indirect
github.com/google/uuid v1.3.0 // indirect
Expand Down
9 changes: 8 additions & 1 deletion go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QX
github.com/go-resty/resty/v2 v2.6.0/go.mod h1:PwvJS6hvaPkjtjNg9ph+VrSD92bi5Zq73w/BIH7cC3Q=
github.com/go-resty/resty/v2 v2.12.0 h1:rsVL8P90LFvkUYq/V5BTVe203WfRIU4gvcf+yfzJzGA=
github.com/go-resty/resty/v2 v2.12.0/go.mod h1:o0yGPrkS3lOe1+eFajk6kBW8ScXzwU3hD69/gt2yB/0=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
Expand Down Expand Up @@ -97,11 +98,13 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
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/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g=
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
Expand Down Expand Up @@ -150,8 +153,9 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo/v2 v2.1.4 h1:GNapqRSid3zijZ9H77KrgVG4/8KqiyRsxcSxe+7ApXY=
github.com/onsi/ginkgo/v2 v2.9.2 h1:BA2GMJOtfGAfagzYtrAlufIP0lq6QERkFmHLMLPwFSU=
github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE=
github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg=
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
Expand Down Expand Up @@ -193,6 +197,8 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/swaggo/swag v1.16.1 h1:fTNRhKstPKxcnoKsytm4sahr8FaYzUcT7i1/3nd/fBg=
github.com/swaggo/swag v1.16.1/go.mod h1:9/LMvHycG3NFHfR6LwvikHv5iFvmPADQ359cKikGxto=
github.com/trivago/tgo v1.0.7 h1:uaWH/XIy9aWYWpjm2CU3RpcqZXmX2ysQ9/Go+d9gyrM=
github.com/trivago/tgo v1.0.7/go.mod h1:w4dpD+3tzNIIiIfkWWa85w5/B77tlvdZckQ+6PkFnhc=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
Expand Down Expand Up @@ -304,6 +310,7 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
Expand Down
6 changes: 4 additions & 2 deletions repository/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ func init() {
HomeDir, _ = os.UserHomeDir()
}

type Remote = api.Repository

// New SCM repository factory.
func New(destDir string, remote *api.Repository, identities []api.Ref) (r SCM, err error) {
func New(destDir string, remote *Remote, identities []api.Ref) (r SCM, err error) {
var insecure bool
switch remote.Kind {
case "subversion":
Expand Down Expand Up @@ -51,7 +53,7 @@ func New(destDir string, remote *api.Repository, identities []api.Ref) (r SCM, e
type SCM interface {
Validate() (err error)
Fetch() (err error)
Branch(name string) (err error)
Branch(ref string) (err error)
Commit(files []string, msg string) (err error)
Head() (commit string, err error)
}
Expand Down
10 changes: 5 additions & 5 deletions repository/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import (
// Git repository.
type Git struct {
Authenticated
Remote api.Repository
Remote Remote
Path string
}

Expand Down Expand Up @@ -86,17 +86,17 @@ func (r *Git) Fetch() (err error) {
}

// Branch creates a branch with the given name if not exist and switch to it.
func (r *Git) Branch(name string) (err error) {
func (r *Git) Branch(ref string) (err error) {
cmd := command.New("/usr/bin/git")
cmd.Dir = r.Path
cmd.Options.Add("checkout", name)
cmd.Options.Add("checkout", ref)
err = cmd.Run()
if err != nil {
cmd = command.New("/usr/bin/git")
cmd.Dir = r.Path
cmd.Options.Add("checkout", "-b", name)
cmd.Options.Add("checkout", "-b", ref)
}
r.Remote.Branch = name
r.Remote.Branch = ref
return cmd.Run()
}

Expand Down
198 changes: 125 additions & 73 deletions repository/subversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,14 @@ import (
// Subversion repository.
type Subversion struct {
Authenticated
Remote api.Repository
Remote Remote
Path string
}

// Validate settings.
func (r *Subversion) Validate() (err error) {
u, err := urllib.Parse(r.Remote.URL)
u := SvnURL{}
err = u.With(r.Remote)
if err != nil {
return
}
Expand All @@ -41,8 +42,8 @@ func (r *Subversion) Validate() (err error) {

// Fetch clones the repository.
func (r *Subversion) Fetch() (err error) {
url := r.URL()
addon.Activity("[SVN] Cloning: %s", url.String())
u := r.URL()
addon.Activity("[SVN] Cloning: %s", u.String())
id, found, err := r.findIdentity("source")
if err != nil {
return
Expand All @@ -64,66 +65,40 @@ func (r *Subversion) Fetch() (err error) {
return
}
agent := ssh.Agent{}
err = agent.Add(id, url.Host)
err = agent.Add(id, u.Host)
if err != nil {
return
}
return r.checkout(r.Remote.Branch)
}

// checkout Checkouts the repository.
func (r *Subversion) checkout(branch string) (err error) {
url := r.URL()
_ = nas.RmDir(r.Path)
cmd := command.New("/usr/bin/svn")
cmd.Options.Add("--non-interactive")
if r.Insecure {
cmd.Options.Add("--trust-server-cert")
}

if branch != "" {
url.Path = pathlib.Join(url.RawPath, "branches", branch)
}
cmd.Options.Add("checkout", url.String(), r.Path)
return cmd.Run()
err = r.checkout()
return
}

func (r *Subversion) Branch(name string) error {
err := r.checkout(name)
if err != nil {
err = r.createBranch(name)
// Branch checks out a branch.
// The branch is created as needed. The `ref` may be either:
// - fully qualified URL (includes branch and root path)
// - branch|tag path. (branches/stable).
func (r *Subversion) Branch(ref string) (err error) {
branch := Subversion{
Authenticated: r.Authenticated,
Remote: r.Remote,
Path: r.Path,
}
_, err = urllib.Parse(ref)
if err == nil {
branch.Remote = Remote{URL: ref}
} else {
branch.Remote.Branch = ref
}
return err
}

// createBranch creates a branch with the given name
func (r *Subversion) createBranch(name string) (err error) {
url := *r.URL()
cmd := command.New("/usr/bin/svn")
cmd.Options.Add("--non-interactive")

branchUrl := url
branchUrl.Path = pathlib.Join(branchUrl.RawPath, "branches", name)

cmd.Options.Add("copy", url.String(), branchUrl.String(), "-m", "Creating branch "+name)
err = cmd.Run()
branch.Remote = Remote{URL: ref}
defer func() {
if err == nil {
r.Remote.URL = branch.Remote.URL
}
}()
err = branch.checkout()
if err != nil {
return err
}
return r.checkout(name)
}

// addFiles adds files to staging area
func (r *Subversion) addFiles(files []string) (err error) {
cmd := command.New("/usr/bin/svn")
cmd.Dir = r.Path
cmd.Options.Add("add")
cmd.Options.Add("--non-interactive")
if r.Insecure {
cmd.Options.Add("--trust-server-cert")
err = branch.createBranch(r.Remote.URL)
}
cmd.Options.Add("--force", files...)
err = cmd.Run()
return
}

Expand All @@ -133,13 +108,9 @@ func (r *Subversion) Commit(files []string, msg string) (err error) {
if err != nil {
return
}
cmd := command.New("/usr/bin/svn")
cmd.Dir = r.Path
cmd := r.svn()
cmd.Dir = r.root()
cmd.Options.Add("commit", "-m", msg)
cmd.Options.Add("--non-interactive")
if r.Insecure {
cmd.Options.Add("--trust-server-cert")
}
err = cmd.Run()
return
}
Expand All @@ -151,15 +122,65 @@ func (r *Subversion) Head() (commit string, err error) {
}

// URL returns the parsed URL.
func (r *Subversion) URL() (u *urllib.URL) {
u, _ = urllib.Parse(r.Remote.URL)
u.RawPath = u.Path
branch := r.Remote.Branch
if branch == "" {
u.Path = pathlib.Join(u.Path, "trunk")
} else {
u.Path = pathlib.Join(u.Path, "branches", branch)
func (r *Subversion) URL() (u *SvnURL) {
u = &SvnURL{}
_ = u.With(r.Remote)
return
}

// svn returns an svn command.
func (r *Subversion) svn() (cmd *command.Command) {
cmd = command.New("/usr/bin/svn")
cmd.Options.Add("--non-interactive")
if r.Insecure {
cmd.Options.Add("--trust-server-cert")
}
return
}

// root returns a path to the cloned repository.
func (r *Subversion) root() (p string) {
p = pathlib.Join(r.Path, r.Remote.Path)
return
}

// checkout the repository.
func (r *Subversion) checkout() (err error) {
root := r.root()
_ = nas.RmDir(r.Path)
_ = nas.MkDir(root, 0777)
u := r.URL()
cmd := r.svn()
cmd.Options.Add("checkout", u.String(), root)
err = cmd.Run()
return
}

// createBranch create and checkout a branch.
func (r *Subversion) createBranch(baseURL string) (err error) {
u := r.URL()
cmd := r.svn()
cmd.Options.Add(
"copy",
baseURL,
u.String(),
"-m",
"Create branch: "+u.String())
err = cmd.Run()
if err != nil {
return
}
err = r.checkout()
return
}

// addFiles adds files to staging area
func (r *Subversion) addFiles(files []string) (err error) {
cmd := r.svn()
cmd.Dir = r.root()
cmd.Options.Add("add")
cmd.Options.Add("--force", files...)
err = cmd.Run()
return
}

Expand Down Expand Up @@ -292,8 +313,8 @@ func (r *Subversion) writePassword(id *api.Identity) (err error) {
// proxy builds the proxy.
func (r *Subversion) proxy() (proxy string, err error) {
kind := ""
url := r.URL()
switch url.Scheme {
u := r.URL()
switch u.Scheme {
case "http":
kind = "http"
case "https",
Expand All @@ -307,7 +328,7 @@ func (r *Subversion) proxy() (proxy string, err error) {
return
}
for _, h := range p.Excluded {
if h == url.Host {
if h == u.Host {
return
}
}
Expand Down Expand Up @@ -336,3 +357,34 @@ func (r *Subversion) proxy() (proxy string, err error) {
strings.Join(p.Excluded, " "))
return
}

// SvnURL subversion URL.
type SvnURL struct {
Raw string
Branch string
RootPath string
Scheme string
Host string
}

// With initializes with a remote.
func (u *SvnURL) With(r Remote) (err error) {
parsed, err := urllib.Parse(r.URL)
if err != nil {
return
}
u.Raw = r.URL
u.Branch = r.Branch
u.RootPath = r.Path
u.Scheme = parsed.Scheme
u.Host = parsed.Host
return
}

// String returns a URL with Branch and RootPath appended.
func (u *SvnURL) String() (s string) {
parsed, _ := urllib.Parse(u.Raw)
parsed.Path = pathlib.Join(parsed.Path, u.Branch, u.RootPath)
s = parsed.String()
return
}
Loading

0 comments on commit a87f4c3

Please sign in to comment.