add the ability to specify repository ref (#80)
closes #75 Reviewed-on: #80 Co-authored-by: Maxim Slipenko <no-reply@maxim.slipenko.com> Co-committed-by: Maxim Slipenko <no-reply@maxim.slipenko.com>
This commit is contained in:
@ -11,7 +11,7 @@
|
|||||||
<g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11">
|
<g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11">
|
||||||
<text x="33.5" y="15" fill="#010101" fill-opacity=".3">coverage</text>
|
<text x="33.5" y="15" fill="#010101" fill-opacity=".3">coverage</text>
|
||||||
<text x="33.5" y="14">coverage</text>
|
<text x="33.5" y="14">coverage</text>
|
||||||
<text x="86" y="15" fill="#010101" fill-opacity=".3">16.4%</text>
|
<text x="86" y="15" fill="#010101" fill-opacity=".3">17.0%</text>
|
||||||
<text x="86" y="14">16.4%</text>
|
<text x="86" y="14">17.0%</text>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 926 B After Width: | Height: | Size: 926 B |
62
e2e-tests/issue_75_ref_specify_test.go
Normal file
62
e2e-tests/issue_75_ref_specify_test.go
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
// ALR - Any Linux Repository
|
||||||
|
// Copyright (C) 2025 The ALR Authors
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//go:build e2e
|
||||||
|
|
||||||
|
package e2etests_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/alecthomas/assert/v2"
|
||||||
|
"github.com/efficientgo/e2e"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestE2EIssue75InstallWithDeps(t *testing.T) {
|
||||||
|
dockerMultipleRun(
|
||||||
|
t,
|
||||||
|
"issue-75-ref-specify",
|
||||||
|
COMMON_SYSTEMS,
|
||||||
|
func(t *testing.T, r e2e.Runnable) {
|
||||||
|
err := r.Exec(e2e.NewCommand(
|
||||||
|
"sudo",
|
||||||
|
"alr",
|
||||||
|
"addrepo",
|
||||||
|
"--name",
|
||||||
|
"alr-repo",
|
||||||
|
"--url",
|
||||||
|
"https://gitea.plemya-x.ru/Maks1mS/repo-for-tests.git",
|
||||||
|
))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = r.Exec(e2e.NewCommand(
|
||||||
|
"sudo", "alr", "ref",
|
||||||
|
))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// TODO: replace with alr command when it be added
|
||||||
|
err = r.Exec(e2e.NewCommand(
|
||||||
|
"sudo", "sh", "-c", "sed -i 's/ref = .*/ref = \"bd26236cd7\"/' /etc/alr/alr.toml",
|
||||||
|
))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = r.Exec(e2e.NewCommand(
|
||||||
|
"sh", "-c", "test $(alr list | wc -l) -eq 2 || exit 1",
|
||||||
|
))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
@ -413,19 +413,19 @@ msgstr ""
|
|||||||
msgid "Executing %s()"
|
msgid "Executing %s()"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: pkg/repos/pull.go:79
|
#: pkg/repos/pull.go:80
|
||||||
msgid "Pulling repository"
|
msgid "Pulling repository"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: pkg/repos/pull.go:103
|
#: pkg/repos/pull.go:116
|
||||||
msgid "Repository up to date"
|
msgid "Repository up to date"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: pkg/repos/pull.go:160
|
#: pkg/repos/pull.go:207
|
||||||
msgid "Git repository does not appear to be a valid ALR repo"
|
msgid "Git repository does not appear to be a valid ALR repo"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: pkg/repos/pull.go:176
|
#: pkg/repos/pull.go:223
|
||||||
msgid ""
|
msgid ""
|
||||||
"ALR repo's minimum ALR version is greater than the current version. Try "
|
"ALR repo's minimum ALR version is greater than the current version. Try "
|
||||||
"updating ALR if something doesn't work."
|
"updating ALR if something doesn't work."
|
||||||
|
@ -425,19 +425,19 @@ msgstr "Выполнение build()"
|
|||||||
msgid "Executing %s()"
|
msgid "Executing %s()"
|
||||||
msgstr "Выполнение %s()"
|
msgstr "Выполнение %s()"
|
||||||
|
|
||||||
#: pkg/repos/pull.go:79
|
#: pkg/repos/pull.go:80
|
||||||
msgid "Pulling repository"
|
msgid "Pulling repository"
|
||||||
msgstr "Скачивание репозитория"
|
msgstr "Скачивание репозитория"
|
||||||
|
|
||||||
#: pkg/repos/pull.go:103
|
#: pkg/repos/pull.go:116
|
||||||
msgid "Repository up to date"
|
msgid "Repository up to date"
|
||||||
msgstr "Репозиторий уже обновлён"
|
msgstr "Репозиторий уже обновлён"
|
||||||
|
|
||||||
#: pkg/repos/pull.go:160
|
#: pkg/repos/pull.go:207
|
||||||
msgid "Git repository does not appear to be a valid ALR repo"
|
msgid "Git repository does not appear to be a valid ALR repo"
|
||||||
msgstr "Репозиторий Git не поддерживается репозиторием ALR"
|
msgstr "Репозиторий Git не поддерживается репозиторием ALR"
|
||||||
|
|
||||||
#: pkg/repos/pull.go:176
|
#: pkg/repos/pull.go:223
|
||||||
msgid ""
|
msgid ""
|
||||||
"ALR repo's minimum ALR version is greater than the current version. Try "
|
"ALR repo's minimum ALR version is greater than the current version. Try "
|
||||||
"updating ALR if something doesn't work."
|
"updating ALR if something doesn't work."
|
||||||
|
@ -34,4 +34,5 @@ type Config struct {
|
|||||||
type Repo struct {
|
type Repo struct {
|
||||||
Name string `toml:"name"`
|
Name string `toml:"name"`
|
||||||
URL string `toml:"url"`
|
URL string `toml:"url"`
|
||||||
|
Ref string `toml:"ref"`
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,7 @@ import (
|
|||||||
"github.com/go-git/go-billy/v5"
|
"github.com/go-git/go-billy/v5"
|
||||||
"github.com/go-git/go-billy/v5/osfs"
|
"github.com/go-git/go-billy/v5/osfs"
|
||||||
"github.com/go-git/go-git/v5"
|
"github.com/go-git/go-git/v5"
|
||||||
|
gitConfig "github.com/go-git/go-git/v5/config"
|
||||||
"github.com/go-git/go-git/v5/plumbing"
|
"github.com/go-git/go-git/v5/plumbing"
|
||||||
"github.com/leonelquinteros/gotext"
|
"github.com/leonelquinteros/gotext"
|
||||||
"github.com/pelletier/go-toml/v2"
|
"github.com/pelletier/go-toml/v2"
|
||||||
@ -88,6 +89,14 @@ func (rs *Repos) Pull(ctx context.Context, repos []types.Repo) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = r.FetchContext(ctx, &git.FetchOptions{
|
||||||
|
Progress: os.Stderr,
|
||||||
|
Force: true,
|
||||||
|
})
|
||||||
|
if err != nil && !errors.Is(err, git.NoErrAlreadyUpToDate) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
w, err := r.Worktree()
|
w, err := r.Worktree()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -98,16 +107,24 @@ func (rs *Repos) Pull(ctx context.Context, repos []types.Repo) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = w.PullContext(ctx, &git.PullOptions{Progress: os.Stderr})
|
revHash, err := resolveHash(r, repo.Ref)
|
||||||
if errors.Is(err, git.NoErrAlreadyUpToDate) {
|
if err != nil {
|
||||||
|
return fmt.Errorf("error resolving hash: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if old.Hash() == *revHash {
|
||||||
slog.Info(gotext.Get("Repository up to date"), "name", repo.Name)
|
slog.Info(gotext.Get("Repository up to date"), "name", repo.Name)
|
||||||
} else if err != nil {
|
}
|
||||||
|
|
||||||
|
err = w.Checkout(&git.CheckoutOptions{
|
||||||
|
Hash: plumbing.NewHash(revHash.String()),
|
||||||
|
Force: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
repoFS = w.Filesystem
|
repoFS = w.Filesystem
|
||||||
|
|
||||||
// Make sure the DB is created even if the repo is up to date
|
|
||||||
if !errors.Is(err, git.NoErrAlreadyUpToDate) || rs.db.IsEmpty(ctx) {
|
|
||||||
new, err := r.Head()
|
new, err := r.Head()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -127,7 +144,6 @@ func (rs *Repos) Pull(ctx context.Context, repos []types.Repo) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
err = os.RemoveAll(repoDir)
|
err = os.RemoveAll(repoDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -139,9 +155,40 @@ func (rs *Repos) Pull(ctx context.Context, repos []types.Repo) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = git.PlainCloneContext(ctx, repoDir, false, &git.CloneOptions{
|
r, err := git.PlainInit(repoDir, false)
|
||||||
URL: repoURL.String(),
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = r.CreateRemote(&gitConfig.RemoteConfig{
|
||||||
|
Name: git.DefaultRemoteName,
|
||||||
|
URLs: []string{repoURL.String()},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = r.FetchContext(ctx, &git.FetchOptions{
|
||||||
Progress: os.Stderr,
|
Progress: os.Stderr,
|
||||||
|
Force: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
w, err := r.Worktree()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
revHash, err := resolveHash(r, repo.Ref)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error resolving hash: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = w.Checkout(&git.CheckoutOptions{
|
||||||
|
Hash: plumbing.NewHash(revHash.String()),
|
||||||
|
Force: true,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -268,7 +315,8 @@ func (rs *Repos) processRepoChangesRunner(repoDir, scriptDir string) (*interp.Ru
|
|||||||
interp.StatHandler(handlers.RestrictedStat(repoDir)),
|
interp.StatHandler(handlers.RestrictedStat(repoDir)),
|
||||||
interp.OpenHandler(handlers.RestrictedOpen(repoDir)),
|
interp.OpenHandler(handlers.RestrictedOpen(repoDir)),
|
||||||
interp.StdIO(handlers.NopRWC{}, handlers.NopRWC{}, handlers.NopRWC{}),
|
interp.StdIO(handlers.NopRWC{}, handlers.NopRWC{}, handlers.NopRWC{}),
|
||||||
interp.Dir(scriptDir),
|
// Use temp dir instead script dir because runner may be for deleted file
|
||||||
|
interp.Dir(os.TempDir()),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -285,7 +333,7 @@ func (rs *Repos) processRepoChanges(ctx context.Context, repo types.Repo, r *git
|
|||||||
|
|
||||||
patch, err := oldCommit.Patch(newCommit)
|
patch, err := oldCommit.Patch(newCommit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return fmt.Errorf("error to create patch: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var actions []action
|
var actions []action
|
||||||
@ -319,6 +367,7 @@ func (rs *Repos) processRepoChanges(ctx context.Context, repo types.Repo, r *git
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
default:
|
default:
|
||||||
|
slog.Debug("unexpected, but I'll try to do")
|
||||||
actions = append(actions, action{
|
actions = append(actions, action{
|
||||||
Type: actionUpdate,
|
Type: actionUpdate,
|
||||||
File: to.Path(),
|
File: to.Path(),
|
||||||
@ -332,7 +381,7 @@ func (rs *Repos) processRepoChanges(ctx context.Context, repo types.Repo, r *git
|
|||||||
for _, action := range actions {
|
for _, action := range actions {
|
||||||
runner, err := rs.processRepoChangesRunner(repoDir, filepath.Dir(filepath.Join(repoDir, action.File)))
|
runner, err := rs.processRepoChangesRunner(repoDir, filepath.Dir(filepath.Join(repoDir, action.File)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return fmt.Errorf("error creating process repo changes runner: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch action.Type {
|
switch action.Type {
|
||||||
@ -340,7 +389,6 @@ func (rs *Repos) processRepoChanges(ctx context.Context, repo types.Repo, r *git
|
|||||||
if filepath.Base(action.File) != "alr.sh" {
|
if filepath.Base(action.File) != "alr.sh" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
scriptFl, err := oldCommit.File(action.File)
|
scriptFl, err := oldCommit.File(action.File)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
@ -378,7 +426,7 @@ func (rs *Repos) processRepoChanges(ctx context.Context, repo types.Repo, r *git
|
|||||||
|
|
||||||
err = rs.updatePkg(ctx, repo, runner, r)
|
err = rs.updatePkg(ctx, repo, runner, r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return fmt.Errorf("error updatePkg: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,12 +18,18 @@ package repos
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/go-git/go-git/v5"
|
||||||
|
"github.com/go-git/go-git/v5/plumbing"
|
||||||
"github.com/go-git/go-git/v5/plumbing/format/diff"
|
"github.com/go-git/go-git/v5/plumbing/format/diff"
|
||||||
|
"github.com/go-git/go-git/v5/plumbing/transport"
|
||||||
|
"github.com/go-git/go-git/v5/plumbing/transport/client"
|
||||||
|
|
||||||
"mvdan.cc/sh/v3/interp"
|
"mvdan.cc/sh/v3/interp"
|
||||||
"mvdan.cc/sh/v3/syntax"
|
"mvdan.cc/sh/v3/syntax"
|
||||||
|
|
||||||
@ -137,3 +143,59 @@ func resolveOverrides(runner *interp.Runner, pkg *db.Package) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getHeadReference(r *git.Repository) (plumbing.ReferenceName, error) {
|
||||||
|
remote, err := r.Remote(git.DefaultRemoteName)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
endpoint, err := transport.NewEndpoint(remote.Config().URLs[0])
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
gitClient, err := client.NewClient(endpoint)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
session, err := gitClient.NewUploadPackSession(endpoint, nil)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
info, err := session.AdvertisedReferences()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
refs, err := info.AllReferences()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return refs["HEAD"].Target(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resolveHash(r *git.Repository, ref string) (*plumbing.Hash, error) {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if ref == "" {
|
||||||
|
reference, err := getHeadReference(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get head reference %w", err)
|
||||||
|
}
|
||||||
|
ref = reference.Short()
|
||||||
|
}
|
||||||
|
|
||||||
|
hsh, err := r.ResolveRevision(git.DefaultRemoteName + "/" + plumbing.Revision(ref))
|
||||||
|
if err != nil {
|
||||||
|
hsh, err = r.ResolveRevision(plumbing.Revision(ref))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return hsh, nil
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user