Merge branch 'master' into ttaylorr/makefile
This commit is contained in:
commit
813fdbdb52
4
.gitignore
vendored
4
.gitignore
vendored
@ -8,7 +8,9 @@ man/*
|
||||
|
||||
*.test
|
||||
tmp
|
||||
test/remote
|
||||
t/remote
|
||||
t/test_count
|
||||
t/test_count.lock
|
||||
|
||||
debian/git-lfs/
|
||||
debian/*.log
|
||||
|
@ -112,7 +112,7 @@ submitting changes, be sure to run the Go tests and the shell integration
|
||||
tests:
|
||||
|
||||
$ make test # runs just the Go tests
|
||||
$ script/integration # runs the shell tests in ./test
|
||||
$ cd t && make test # runs the shell tests in ./test
|
||||
$ script/cibuild # runs everything, with verbose debug output
|
||||
|
||||
## Updating 3rd party packages
|
||||
|
@ -29,8 +29,9 @@ setup and preferences.
|
||||
[PackageCloud](https://packagecloud.io/github/git-lfs/install).
|
||||
* **macOS users**. [Homebrew](https://brew.sh) bottles are distributed, and can
|
||||
be installed via `brew install git-lfs`.
|
||||
* **Windows users**. Chocolatey packages are distributed, and can be installed
|
||||
via `choco install git-lfs`.
|
||||
* **Windows users**. Git LFS is included in the distribution of
|
||||
[Git for Windows](https://gitforwindows.org/). Alternatively, you can
|
||||
install a recent version of Git LFS from the Chocolatey package manager.
|
||||
|
||||
In addition, [binary packages](https://github.com/git-lfs/git-lfs/releases) are
|
||||
available for Linux, macOS, Windows, and FreeBSD. This repository can also be
|
||||
|
@ -1,8 +1,12 @@
|
||||
image: Visual Studio 2017
|
||||
|
||||
skip_branch_with_pr: true
|
||||
|
||||
environment:
|
||||
CYGWIN: "$(CYGWIN) winsymlinks:nativestrict"
|
||||
MSYS: "$(MSYS) winsymlinks:nativestrict"
|
||||
GIT_LFS_NO_TEST_COUNT: 1
|
||||
GIT_LFS_LOCK_ACQUIRE_DISABLED: 1
|
||||
GOPATH: $(HOMEDRIVE)$(HOMEPATH)\go
|
||||
MSYSTEM: MINGW64
|
||||
|
||||
@ -10,8 +14,13 @@ clone_folder: $(GOPATH)\src\github.com\git-lfs\git-lfs
|
||||
|
||||
install:
|
||||
- rd C:\Go /s /q
|
||||
- rd C:\Perl /s /q
|
||||
- refreshenv
|
||||
- cinst golang --version 1.8.3 -y
|
||||
- cinst InnoSetup -y
|
||||
- cinst strawberryperl -y
|
||||
- refreshenv
|
||||
- cinst make
|
||||
- refreshenv
|
||||
- ps: |
|
||||
echo "Go directories in machine PATH environment:"
|
||||
|
@ -1,7 +1,9 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
@ -21,6 +23,10 @@ var (
|
||||
// in the migration.
|
||||
migrateExcludeRefs []string
|
||||
|
||||
// migrateYes indicates that an answer of 'yes' should be presumed
|
||||
// whenever 'git lfs migrate' asks for user input.
|
||||
migrateYes bool
|
||||
|
||||
// migrateSkipFetch assumes that the client has the latest copy of
|
||||
// remote references, and thus should not contact the remote for a set
|
||||
// of updated references.
|
||||
@ -173,13 +179,31 @@ func includeExcludeRefs(l *tasklog.Logger, args []string) (include, exclude []st
|
||||
include = append(include, migrateIncludeRefs...)
|
||||
exclude = append(exclude, migrateExcludeRefs...)
|
||||
} else if migrateEverything {
|
||||
localRefs, err := git.LocalRefs()
|
||||
refs, err := git.AllRefsIn("")
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
for _, ref := range localRefs {
|
||||
for _, ref := range refs {
|
||||
switch ref.Type {
|
||||
case git.RefTypeLocalBranch, git.RefTypeLocalTag,
|
||||
git.RefTypeRemoteBranch, git.RefTypeRemoteTag:
|
||||
|
||||
include = append(include, ref.Refspec())
|
||||
case git.RefTypeOther:
|
||||
parts := strings.SplitN(ref.Refspec(), "/", 3)
|
||||
if len(parts) < 2 {
|
||||
continue
|
||||
}
|
||||
|
||||
switch parts[1] {
|
||||
// The following are GitLab-, GitHub-, VSTS-,
|
||||
// and BitBucket-specific reference naming
|
||||
// conventions.
|
||||
case "merge-requests", "pull", "pull-requests":
|
||||
include = append(include, ref.Refspec())
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
bare, err := git.IsBare()
|
||||
@ -294,6 +318,56 @@ func getHistoryRewriter(cmd *cobra.Command, db *gitobj.ObjectDatabase, l *tasklo
|
||||
githistory.WithFilter(filter), githistory.WithLogger(l))
|
||||
}
|
||||
|
||||
func ensureWorkingCopyClean(in io.Reader, out io.Writer) {
|
||||
dirty, err := git.IsWorkingCopyDirty()
|
||||
if err != nil {
|
||||
ExitWithError(errors.Wrap(err,
|
||||
"fatal: could not determine if working copy is dirty"))
|
||||
}
|
||||
|
||||
if !dirty {
|
||||
return
|
||||
}
|
||||
|
||||
var proceed bool
|
||||
if migrateYes {
|
||||
proceed = true
|
||||
} else {
|
||||
answer := bufio.NewReader(in)
|
||||
L:
|
||||
for {
|
||||
fmt.Fprintf(out, "migrate: override changes in your working copy? [Y/n] ")
|
||||
s, err := answer.ReadString('\n')
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
break L
|
||||
}
|
||||
ExitWithError(errors.Wrap(err,
|
||||
"fatal: could not read answer"))
|
||||
}
|
||||
|
||||
switch strings.TrimSpace(s) {
|
||||
case "n", "N":
|
||||
proceed = false
|
||||
break L
|
||||
case "y", "Y":
|
||||
proceed = true
|
||||
break L
|
||||
}
|
||||
|
||||
if !strings.HasSuffix(s, "\n") {
|
||||
fmt.Fprintf(out, "\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if proceed {
|
||||
fmt.Fprintf(out, "migrate: changes in your working copy will be overridden ...\n")
|
||||
} else {
|
||||
Exit("migrate: working copy must not be dirty")
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
info := NewCommand("info", migrateInfoCommand)
|
||||
info.Flags().IntVar(&migrateInfoTopN, "top", 5, "--top=<n>")
|
||||
@ -321,6 +395,8 @@ func init() {
|
||||
cmd.PersistentFlags().BoolVar(&migrateEverything, "everything", false, "Migrate all local references")
|
||||
cmd.PersistentFlags().BoolVar(&migrateSkipFetch, "skip-fetch", false, "Assume up-to-date remote references.")
|
||||
|
||||
cmd.PersistentFlags().BoolVarP(&migrateYes, "yes", "y", false, "Don't prompt for answers.")
|
||||
|
||||
cmd.AddCommand(exportCmd, importCmd, info)
|
||||
})
|
||||
}
|
||||
|
@ -17,6 +17,8 @@ import (
|
||||
)
|
||||
|
||||
func migrateExportCommand(cmd *cobra.Command, args []string) {
|
||||
ensureWorkingCopyClean(os.Stdin, os.Stderr)
|
||||
|
||||
l := tasklog.NewLogger(os.Stderr)
|
||||
defer l.Close()
|
||||
|
||||
|
@ -22,6 +22,8 @@ import (
|
||||
)
|
||||
|
||||
func migrateImportCommand(cmd *cobra.Command, args []string) {
|
||||
ensureWorkingCopyClean(os.Stdin, os.Stderr)
|
||||
|
||||
l := tasklog.NewLogger(os.Stderr)
|
||||
defer l.Close()
|
||||
|
||||
|
@ -38,7 +38,7 @@ func pushCommand(cmd *cobra.Command, args []string) {
|
||||
requireGitVersion()
|
||||
|
||||
// Remote is first arg
|
||||
if err := cfg.SetValidRemote(args[0]); err != nil {
|
||||
if err := cfg.SetValidPushRemote(args[0]); err != nil {
|
||||
Exit("Invalid remote name %q: %s", args[0], err)
|
||||
}
|
||||
|
||||
|
@ -232,10 +232,22 @@ func (c *Configuration) SetValidRemote(name string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Configuration) SetValidPushRemote(name string) error {
|
||||
if err := git.ValidateRemote(name); err != nil {
|
||||
return err
|
||||
}
|
||||
c.SetPushRemote(name)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Configuration) SetRemote(name string) {
|
||||
c.currentRemote = &name
|
||||
}
|
||||
|
||||
func (c *Configuration) SetPushRemote(name string) {
|
||||
c.pushRemote = &name
|
||||
}
|
||||
|
||||
func (c *Configuration) Remotes() []string {
|
||||
c.loadGitConfig()
|
||||
return c.remotes
|
||||
@ -311,8 +323,8 @@ func (c *Configuration) LocalGitStorageDir() string {
|
||||
return c.Filesystem().GitStorageDir
|
||||
}
|
||||
|
||||
func (c *Configuration) LocalReferenceDir() string {
|
||||
return c.Filesystem().ReferenceDir
|
||||
func (c *Configuration) LocalReferenceDirs() []string {
|
||||
return c.Filesystem().ReferenceDirs
|
||||
}
|
||||
|
||||
func (c *Configuration) LFSStorageDir() string {
|
||||
@ -346,7 +358,12 @@ func (c *Configuration) Filesystem() *fs.Filesystem {
|
||||
|
||||
if c.fs == nil {
|
||||
lfsdir, _ := c.Git.Get("lfs.storage")
|
||||
c.fs = fs.New(c.LocalGitDir(), c.LocalWorkingDir(), lfsdir)
|
||||
c.fs = fs.New(
|
||||
c.Os,
|
||||
c.LocalGitDir(),
|
||||
c.LocalWorkingDir(),
|
||||
lfsdir,
|
||||
)
|
||||
}
|
||||
|
||||
return c.fs
|
||||
|
@ -158,6 +158,7 @@ func keyIsUnsafe(key string) bool {
|
||||
}
|
||||
|
||||
var safeKeys = []string{
|
||||
"lfs.allowincompletepush",
|
||||
"lfs.fetchexclude",
|
||||
"lfs.fetchinclude",
|
||||
"lfs.gitprotocol",
|
||||
|
@ -190,8 +190,8 @@ The following configuration:
|
||||
|
||||
Would, therefore, include commits: F, E, D, C, B, but exclude commit A.
|
||||
|
||||
The presence of flag `--everything` indicates that all local references should be
|
||||
migrated.
|
||||
The presence of flag `--everything` indicates that all local and remote
|
||||
references should be migrated.
|
||||
|
||||
## EXAMPLES
|
||||
|
||||
@ -253,15 +253,19 @@ Note: This will require a force push to any existing Git remotes.
|
||||
|
||||
### Migrate without rewriting local history
|
||||
|
||||
You can also migrate files without modifying the existing history of your respoitory:
|
||||
You can also migrate files without modifying the existing history of your
|
||||
repository:
|
||||
|
||||
Without a specified commit message:
|
||||
|
||||
```
|
||||
git lfs migrate import --no-rewrite test.zip *.mp3 *.psd
|
||||
$ git lfs migrate import --no-rewrite test.zip *.mp3 *.psd
|
||||
```
|
||||
|
||||
With a specified commit message:
|
||||
|
||||
```
|
||||
git lfs migrate import --no-rewrite -m "Import .zip, .mp3, .psd files" \
|
||||
$ git lfs migrate import --no-rewrite -m "Import .zip, .mp3, .psd files" \
|
||||
test.zip *.mpd *.psd
|
||||
```
|
||||
|
||||
|
100
fs/fs.go
100
fs/fs.go
@ -1,6 +1,7 @@
|
||||
package fs
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
@ -12,10 +13,19 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/git-lfs/git-lfs/tools"
|
||||
"github.com/rubyist/tracerx"
|
||||
)
|
||||
|
||||
var oidRE = regexp.MustCompile(`\A[[:alnum:]]{64}`)
|
||||
|
||||
// Environment is a copy of a subset of the interface
|
||||
// github.com/git-lfs/git-lfs/config.Environment.
|
||||
//
|
||||
// For more information, see config/environment.go.
|
||||
type Environment interface {
|
||||
Get(key string) (val string, ok bool)
|
||||
}
|
||||
|
||||
// Object represents a locally stored LFS object.
|
||||
type Object struct {
|
||||
Oid string
|
||||
@ -25,7 +35,7 @@ type Object struct {
|
||||
type Filesystem struct {
|
||||
GitStorageDir string // parent of objects/lfs (may be same as GitDir but may not)
|
||||
LFSStorageDir string // parent of lfs objects and tmp dirs. Default: ".git/lfs"
|
||||
ReferenceDir string // alternative local media dir (relative to clone reference repo)
|
||||
ReferenceDirs []string // alternative local media dirs (relative to clone reference repo)
|
||||
lfsobjdir string
|
||||
tmpdir string
|
||||
logdir string
|
||||
@ -105,12 +115,16 @@ func (f *Filesystem) localObjectDir(oid string) string {
|
||||
return filepath.Join(f.LFSObjectDir(), oid[0:2], oid[2:4])
|
||||
}
|
||||
|
||||
func (f *Filesystem) ObjectReferencePath(oid string) string {
|
||||
if len(f.ReferenceDir) == 0 {
|
||||
return f.ReferenceDir
|
||||
func (f *Filesystem) ObjectReferencePaths(oid string) []string {
|
||||
if len(f.ReferenceDirs) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return filepath.Join(f.ReferenceDir, oid[0:2], oid[2:4], oid)
|
||||
var paths []string
|
||||
for _, ref := range f.ReferenceDirs {
|
||||
paths = append(paths, filepath.Join(ref, oid[0:2], oid[2:4], oid))
|
||||
}
|
||||
return paths
|
||||
}
|
||||
|
||||
func (f *Filesystem) LFSObjectDir() string {
|
||||
@ -159,12 +173,12 @@ func (f *Filesystem) Cleanup() error {
|
||||
// New initializes a new *Filesystem with the given directories. gitdir is the
|
||||
// path to the bare repo, workdir is the path to the repository working
|
||||
// directory, and lfsdir is the optional path to the `.git/lfs` directory.
|
||||
func New(gitdir, workdir, lfsdir string) *Filesystem {
|
||||
func New(env Environment, gitdir, workdir, lfsdir string) *Filesystem {
|
||||
fs := &Filesystem{
|
||||
GitStorageDir: resolveGitStorageDir(gitdir),
|
||||
}
|
||||
|
||||
fs.ReferenceDir = resolveReferenceDir(fs.GitStorageDir)
|
||||
fs.ReferenceDirs = resolveReferenceDirs(env, fs.GitStorageDir)
|
||||
|
||||
if len(lfsdir) == 0 {
|
||||
lfsdir = "lfs"
|
||||
@ -179,19 +193,75 @@ func New(gitdir, workdir, lfsdir string) *Filesystem {
|
||||
return fs
|
||||
}
|
||||
|
||||
func resolveReferenceDir(gitStorageDir string) string {
|
||||
func resolveReferenceDirs(env Environment, gitStorageDir string) []string {
|
||||
var references []string
|
||||
|
||||
envAlternates, ok := env.Get("GIT_ALTERNATE_OBJECT_DIRECTORIES")
|
||||
if ok {
|
||||
splits := strings.Split(envAlternates, string(os.PathListSeparator))
|
||||
for _, split := range splits {
|
||||
if dir, ok := existsAlternate(split); ok {
|
||||
references = append(references, dir)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cloneReferencePath := filepath.Join(gitStorageDir, "objects", "info", "alternates")
|
||||
if tools.FileExists(cloneReferencePath) {
|
||||
buffer, err := ioutil.ReadFile(cloneReferencePath)
|
||||
if err == nil {
|
||||
path := strings.TrimSpace(string(buffer[:]))
|
||||
referenceLfsStoragePath := filepath.Join(filepath.Dir(path), "lfs", "objects")
|
||||
if tools.DirExists(referenceLfsStoragePath) {
|
||||
return referenceLfsStoragePath
|
||||
f, err := os.Open(cloneReferencePath)
|
||||
if err != nil {
|
||||
tracerx.Printf("could not open %s: %s",
|
||||
cloneReferencePath, err)
|
||||
return nil
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
scanner := bufio.NewScanner(f)
|
||||
for scanner.Scan() {
|
||||
text := strings.TrimSpace(scanner.Text())
|
||||
if len(text) == 0 || strings.HasPrefix(text, "#") {
|
||||
continue
|
||||
}
|
||||
|
||||
if dir, ok := existsAlternate(text); ok {
|
||||
references = append(references, dir)
|
||||
}
|
||||
}
|
||||
|
||||
if err := scanner.Err(); err != nil {
|
||||
tracerx.Printf("could not scan %s: %s",
|
||||
cloneReferencePath, err)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
return references
|
||||
}
|
||||
|
||||
// existsAlternate takes an object directory given in "objs" (read as a single,
|
||||
// line from .git/objects/info/alternates). If that is a satisfiable alternates
|
||||
// directory (i.e., it exists), the directory is returned along with "true". If
|
||||
// not, the empty string and false is returned instead.
|
||||
func existsAlternate(objs string) (string, bool) {
|
||||
objs = strings.TrimSpace(objs)
|
||||
if strings.HasPrefix(objs, "\"") {
|
||||
var err error
|
||||
|
||||
unquote := strings.LastIndex(objs, "\"")
|
||||
if unquote == 0 {
|
||||
return "", false
|
||||
}
|
||||
|
||||
objs, err = strconv.Unquote(objs[:unquote+1])
|
||||
if err != nil {
|
||||
return "", false
|
||||
}
|
||||
}
|
||||
|
||||
storage := filepath.Join(filepath.Dir(objs), "lfs", "objects")
|
||||
|
||||
if tools.DirExists(storage) {
|
||||
return storage, true
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
// From a git dir, get the location that objects are to be stored (we will store lfs alongside)
|
||||
|
18
git/git.go
18
git/git.go
@ -1192,3 +1192,21 @@ func IsFileModified(filepath string) (bool, error) {
|
||||
|
||||
return matched, nil
|
||||
}
|
||||
|
||||
// IsWorkingCopyDirty returns true if and only if the working copy in which the
|
||||
// command was executed is dirty as compared to the index.
|
||||
//
|
||||
// If the status of the working copy could not be determined, an error will be
|
||||
// returned instead.
|
||||
func IsWorkingCopyDirty() (bool, error) {
|
||||
bare, err := IsBare()
|
||||
if bare || err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
out, err := gitSimple("status", "--porcelain")
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return len(out) != 0, nil
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ import (
|
||||
"time"
|
||||
|
||||
. "github.com/git-lfs/git-lfs/git"
|
||||
"github.com/git-lfs/git-lfs/test"
|
||||
test "github.com/git-lfs/git-lfs/t/cmd/util"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
@ -16,6 +16,18 @@ import (
|
||||
|
||||
func (f *GitFilter) SmudgeToFile(filename string, ptr *Pointer, download bool, manifest *tq.Manifest, cb tools.CopyCallback) error {
|
||||
os.MkdirAll(filepath.Dir(filename), 0755)
|
||||
|
||||
if stat, _ := os.Stat(filename); stat != nil && stat.Mode()&0200 == 0 {
|
||||
if err := os.Chmod(filename, stat.Mode()|0200); err != nil {
|
||||
return errors.Wrap(err,
|
||||
"Could not restore write permission")
|
||||
}
|
||||
|
||||
// When we're done, return the file back to its normal
|
||||
// permission bits.
|
||||
defer os.Chmod(filename, stat.Mode())
|
||||
}
|
||||
|
||||
file, err := os.Create(filename)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Could not create working directory file: %v", err)
|
||||
|
16
lfs/lfs.go
16
lfs/lfs.go
@ -35,12 +35,14 @@ func Environ(cfg *config.Configuration, manifest *tq.Manifest) []string {
|
||||
|
||||
fetchPruneConfig := NewFetchPruneConfig(cfg.Git)
|
||||
|
||||
references := strings.Join(cfg.LocalReferenceDirs(), ", ")
|
||||
|
||||
env = append(env,
|
||||
fmt.Sprintf("LocalWorkingDir=%s", cfg.LocalWorkingDir()),
|
||||
fmt.Sprintf("LocalGitDir=%s", cfg.LocalGitDir()),
|
||||
fmt.Sprintf("LocalGitStorageDir=%s", cfg.LocalGitStorageDir()),
|
||||
fmt.Sprintf("LocalMediaDir=%s", cfg.LFSObjectDir()),
|
||||
fmt.Sprintf("LocalReferenceDir=%s", cfg.LocalReferenceDir()),
|
||||
fmt.Sprintf("LocalReferenceDirs=%s", references),
|
||||
fmt.Sprintf("TempDir=%s", cfg.TempDir()),
|
||||
fmt.Sprintf("ConcurrentTransfers=%d", api.ConcurrentTransfers),
|
||||
fmt.Sprintf("TusTransfers=%v", cfg.TusTransfersAllowed()),
|
||||
@ -98,13 +100,19 @@ func LinkOrCopyFromReference(cfg *config.Configuration, oid string, size int64)
|
||||
if cfg.LFSObjectExists(oid, size) {
|
||||
return nil
|
||||
}
|
||||
altMediafile := cfg.Filesystem().ObjectReferencePath(oid)
|
||||
altMediafiles := cfg.Filesystem().ObjectReferencePaths(oid)
|
||||
mediafile, err := cfg.Filesystem().ObjectPath(oid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, altMediafile := range altMediafiles {
|
||||
tracerx.Printf("altMediafile: %s", altMediafile)
|
||||
if altMediafile != "" && tools.FileExistsOfSize(altMediafile, size) {
|
||||
return LinkOrCopy(cfg, altMediafile, mediafile)
|
||||
err = LinkOrCopy(cfg, altMediafile, mediafile)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ import (
|
||||
|
||||
"github.com/git-lfs/git-lfs/fs"
|
||||
"github.com/git-lfs/git-lfs/lfs"
|
||||
"github.com/git-lfs/git-lfs/test"
|
||||
test "github.com/git-lfs/git-lfs/t/cmd/util"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
@ -11,7 +11,7 @@ import (
|
||||
"time"
|
||||
|
||||
. "github.com/git-lfs/git-lfs/lfs"
|
||||
"github.com/git-lfs/git-lfs/test"
|
||||
test "github.com/git-lfs/git-lfs/t/cmd/util"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
106
lfsapi/creds.go
106
lfsapi/creds.go
@ -78,6 +78,14 @@ type AskPassCredentialHelper struct {
|
||||
Program string
|
||||
}
|
||||
|
||||
type credValueType int
|
||||
|
||||
const (
|
||||
credValueTypeUnknown credValueType = iota
|
||||
credValueTypeUsername
|
||||
credValueTypePassword
|
||||
)
|
||||
|
||||
// Fill implements fill by running the ASKPASS program and returning its output
|
||||
// as a password encoded in the Creds type given the key "password".
|
||||
//
|
||||
@ -86,60 +94,92 @@ type AskPassCredentialHelper struct {
|
||||
//
|
||||
// If there was an error running the command, it is returned instead of a set of
|
||||
// filled credentials.
|
||||
//
|
||||
// The ASKPASS program is only queried if a credential was not already
|
||||
// provided, i.e. through the git URL
|
||||
func (a *AskPassCredentialHelper) Fill(what Creds) (Creds, error) {
|
||||
var user bytes.Buffer
|
||||
var pass bytes.Buffer
|
||||
var err bytes.Buffer
|
||||
|
||||
u := &url.URL{
|
||||
Scheme: what["protocol"],
|
||||
Host: what["host"],
|
||||
Path: what["path"],
|
||||
}
|
||||
|
||||
// 'ucmd' will run the GIT_ASKPASS (or core.askpass) command prompting
|
||||
// for a username.
|
||||
ucmd := exec.Command(a.Program, a.args(fmt.Sprintf("Username for %q", u))...)
|
||||
ucmd.Stderr = &err
|
||||
ucmd.Stdout = &user
|
||||
creds := make(Creds)
|
||||
|
||||
tracerx.Printf("creds: filling with GIT_ASKPASS: %s", strings.Join(ucmd.Args, " "))
|
||||
if err := ucmd.Run(); err != nil {
|
||||
username, err := a.getValue(what, credValueTypeUsername, u)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
creds["username"] = username
|
||||
|
||||
if err.Len() > 0 {
|
||||
return nil, errors.New(err.String())
|
||||
}
|
||||
|
||||
if username := strings.TrimSpace(user.String()); len(username) > 0 {
|
||||
if len(username) > 0 {
|
||||
// If a non-empty username was given, add it to the URL via func
|
||||
// 'net/url.User()'.
|
||||
u.User = url.User(username)
|
||||
u.User = url.User(creds["username"])
|
||||
}
|
||||
|
||||
// Regardless, create 'pcmd' to run the GIT_ASKPASS (or core.askpass)
|
||||
// command prompting for a password.
|
||||
pcmd := exec.Command(a.Program, a.args(fmt.Sprintf("Password for %q", u))...)
|
||||
pcmd.Stderr = &err
|
||||
pcmd.Stdout = &pass
|
||||
|
||||
tracerx.Printf("creds: filling with GIT_ASKPASS: %s", strings.Join(pcmd.Args, " "))
|
||||
if err := pcmd.Run(); err != nil {
|
||||
password, err := a.getValue(what, credValueTypePassword, u)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
creds["password"] = password
|
||||
|
||||
return creds, nil
|
||||
}
|
||||
|
||||
func (a *AskPassCredentialHelper) getValue(what Creds, valueType credValueType, u *url.URL) (string, error) {
|
||||
var valueString string
|
||||
|
||||
switch valueType {
|
||||
case credValueTypeUsername:
|
||||
valueString = "username"
|
||||
case credValueTypePassword:
|
||||
valueString = "password"
|
||||
default:
|
||||
return "", errors.Errorf("Invalid Credential type queried from AskPass")
|
||||
}
|
||||
|
||||
// Return the existing credential if it was already provided, otherwise
|
||||
// query AskPass for it
|
||||
if given, ok := what[valueString]; ok {
|
||||
return given, nil
|
||||
}
|
||||
return a.getFromProgram(valueType, u)
|
||||
}
|
||||
|
||||
func (a *AskPassCredentialHelper) getFromProgram(valueType credValueType, u *url.URL) (string, error) {
|
||||
var (
|
||||
value bytes.Buffer
|
||||
err bytes.Buffer
|
||||
|
||||
valueString string
|
||||
)
|
||||
|
||||
switch valueType {
|
||||
case credValueTypeUsername:
|
||||
valueString = "Username"
|
||||
case credValueTypePassword:
|
||||
valueString = "Password"
|
||||
default:
|
||||
return "", errors.Errorf("Invalid Credential type queried from AskPass")
|
||||
}
|
||||
|
||||
// 'cmd' will run the GIT_ASKPASS (or core.askpass) command prompting
|
||||
// for the desired valueType (`Username` or `Password`)
|
||||
cmd := exec.Command(a.Program, a.args(fmt.Sprintf("%s for %q", valueString, u))...)
|
||||
cmd.Stderr = &err
|
||||
cmd.Stdout = &value
|
||||
|
||||
tracerx.Printf("creds: filling with GIT_ASKPASS: %s", strings.Join(cmd.Args, " "))
|
||||
if err := cmd.Run(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if err.Len() > 0 {
|
||||
return nil, errors.New(err.String())
|
||||
return "", errors.New(err.String())
|
||||
}
|
||||
|
||||
// Finally, now that we have the username and password information,
|
||||
// store it in the creds instance that we will return to the caller.
|
||||
creds := make(Creds)
|
||||
creds["username"] = strings.TrimSpace(user.String())
|
||||
creds["password"] = strings.TrimSpace(pass.String())
|
||||
|
||||
return creds, nil
|
||||
return strings.TrimSpace(value.String()), nil
|
||||
}
|
||||
|
||||
// Approve implements CredentialHelper.Approve, and returns nil. The ASKPASS
|
||||
|
@ -20,7 +20,7 @@ func TestHttpsProxyFromGitConfig(t *testing.T) {
|
||||
require.Nil(t, err)
|
||||
|
||||
proxyURL, err := proxyFromClient(c)(req)
|
||||
assert.Equal(t, "proxy-from-env:8080", proxyURL.Host)
|
||||
assert.Equal(t, "proxy-from-git-config:8080", proxyURL.Host)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
|
@ -68,7 +68,7 @@ export SKIPAPITESTCOMPILE=1
|
||||
pushd src/github.com/git-lfs/%{name}
|
||||
make test
|
||||
go get github.com/ThomsonReutersEikon/go-ntlm/ntlm
|
||||
./script/integration
|
||||
cd t && make test
|
||||
popd
|
||||
|
||||
rmdir ${GIT_LFS_TEST_DIR}
|
||||
|
@ -1,8 +1,26 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
GOCACHE=off script/bootstrap
|
||||
GOCACHE=off make test
|
||||
|
||||
# re-run test to ensure GIT_TRACE output doesn't leak into the git package
|
||||
GIT_TRACE=1 GOCACHE=off make PKGS=git test
|
||||
|
||||
VERBOSE_LOGS=1 script/integration
|
||||
pushd t >/dev/null
|
||||
UNAME=$(uname -s)
|
||||
X=""
|
||||
if [[ $UNAME == MINGW* || $UNAME == MSYS* || $UNAME == CYGWIN* ]]; then
|
||||
X=".exe"
|
||||
fi
|
||||
|
||||
PROVE="prove"
|
||||
PROVE_EXTRA_ARGS="-j9"
|
||||
if [ -n "$APPVEYOR" ]; then
|
||||
export PATH="/c/Strawberry/perl/bin:.:$PATH"
|
||||
PROVE="prove.bat"
|
||||
PROVE_EXTRA_ARGS="$PROVE_EXTRA_ARGS --exec bash"
|
||||
fi
|
||||
|
||||
VERBOSE_LOGS=1 make X="$X" clean
|
||||
VERBOSE_LOGS=1 make X="$X" PROVE="$PROVE" PROVE_EXTRA_ARGS="$PROVE_EXTRA_ARGS"
|
||||
popd >/dev/null
|
||||
|
@ -1,44 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/testenv.sh"
|
||||
set -e
|
||||
|
||||
SHUTDOWN_LFS=no
|
||||
SHOW_LOGS=yes
|
||||
|
||||
atexit() {
|
||||
res=${1:-$?}
|
||||
SHUTDOWN_LFS=yes
|
||||
if [ "$res" = "0" ]; then
|
||||
SHOW_LOGS=no
|
||||
fi
|
||||
|
||||
if [ "$SHOW_LOGS" = "yes" ] && [ "$VERBOSE_LOGS" = "1" ]; then
|
||||
if [ -s "$REMOTEDIR/gitserver.log" ]; then
|
||||
echo ""
|
||||
echo "gitserver.log:"
|
||||
cat "$REMOTEDIR/gitserver.log"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "env:"
|
||||
env
|
||||
fi
|
||||
|
||||
shutdown
|
||||
exit $res
|
||||
}
|
||||
|
||||
trap "atexit" EXIT
|
||||
|
||||
if [ -s "$LFS_URL_FILE" ]; then
|
||||
SHOW_LOGS=no
|
||||
echo "$LFS_URL_FILE still exists!"
|
||||
echo "Confirm other tests are done, and run:"
|
||||
echo " $ curl $(cat "$LFS_URL_FILE")/shutdown"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
setup
|
||||
|
||||
GO15VENDOREXPERIMENT=1 GIT_LFS_TEST_MAXPROCS=$GIT_LFS_TEST_MAXPROCS GIT_LFS_TEST_DIR="$GIT_LFS_TEST_DIR" SHUTDOWN_LFS="no" go run script/*.go -cmd integration "$@"
|
@ -1,209 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
bashPath string
|
||||
debugging = false
|
||||
erroring = false
|
||||
maxprocs = 4
|
||||
testPattern = regexp.MustCompile(`test[/\\]test-([a-z\-]+)\.sh$`)
|
||||
)
|
||||
|
||||
func mainIntegration() {
|
||||
if len(os.Getenv("DEBUG")) > 0 {
|
||||
debugging = true
|
||||
}
|
||||
|
||||
setBash()
|
||||
|
||||
if max, _ := strconv.Atoi(os.Getenv("GIT_LFS_TEST_MAXPROCS")); max > 0 {
|
||||
maxprocs = max
|
||||
}
|
||||
|
||||
fmt.Println("Running this maxprocs", maxprocs)
|
||||
|
||||
files := testFiles()
|
||||
|
||||
if len(files) == 0 {
|
||||
fmt.Println("no tests to run")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
tests := make(chan string, len(files))
|
||||
output := make(chan string, len(files))
|
||||
|
||||
for _, file := range files {
|
||||
tests <- file
|
||||
}
|
||||
close(tests)
|
||||
|
||||
outputDone := make(chan bool)
|
||||
go func() {
|
||||
for out := range output {
|
||||
fmt.Println(out)
|
||||
}
|
||||
outputDone <- true
|
||||
}()
|
||||
|
||||
for i := 0; i < maxprocs; i++ {
|
||||
wg.Add(1)
|
||||
go worker(tests, output, &wg)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
close(output)
|
||||
<-outputDone
|
||||
|
||||
if erroring {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func runTest(output chan string, testname string) {
|
||||
buf := &bytes.Buffer{}
|
||||
cmd := exec.Command(bashPath, testname)
|
||||
cmd.Stdout = buf
|
||||
cmd.Stderr = buf
|
||||
|
||||
err := cmd.Start()
|
||||
if err != nil {
|
||||
sendTestOutput(output, testname, buf, err)
|
||||
return
|
||||
}
|
||||
|
||||
done := make(chan error)
|
||||
go func() {
|
||||
if err := cmd.Wait(); err != nil {
|
||||
done <- err
|
||||
}
|
||||
close(done)
|
||||
}()
|
||||
|
||||
select {
|
||||
case err = <-done:
|
||||
sendTestOutput(output, testname, buf, err)
|
||||
return
|
||||
case <-time.After(3 * time.Minute):
|
||||
sendTestOutput(output, testname, buf, errors.New("Timed out"))
|
||||
cmd.Process.Kill()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func sendTestOutput(output chan string, testname string, buf *bytes.Buffer, err error) {
|
||||
cli := strings.TrimSpace(buf.String())
|
||||
if len(cli) == 0 {
|
||||
cli = fmt.Sprintf("<no output for %s>", testname)
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
output <- cli
|
||||
} else {
|
||||
basetestname := filepath.Base(testname)
|
||||
if debugging {
|
||||
fmt.Printf("Error on %s: %s\n", basetestname, err)
|
||||
}
|
||||
erroring = true
|
||||
output <- fmt.Sprintf("error: %s => %s\n%s", basetestname, err, cli)
|
||||
}
|
||||
}
|
||||
|
||||
func worker(tests <-chan string, output chan string, wg *sync.WaitGroup) {
|
||||
defer wg.Done()
|
||||
for {
|
||||
select {
|
||||
case testname, ok := <-tests:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
runTest(output, testname)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testFiles() []string {
|
||||
if len(os.Args) < 4 {
|
||||
return allTestFiles()
|
||||
}
|
||||
|
||||
fileMap := make(map[string]bool)
|
||||
for _, file := range allTestFiles() {
|
||||
fileMap[file] = true
|
||||
}
|
||||
|
||||
files := make([]string, 0, len(os.Args)-3)
|
||||
for _, arg := range os.Args {
|
||||
fullname := "test/test-" + arg + ".sh"
|
||||
if fileMap[fullname] {
|
||||
files = append(files, fullname)
|
||||
}
|
||||
}
|
||||
|
||||
return files
|
||||
}
|
||||
|
||||
func allTestFiles() []string {
|
||||
files := make([]string, 0, 100)
|
||||
filepath.Walk("test", func(path string, info os.FileInfo, err error) error {
|
||||
if debugging {
|
||||
fmt.Println("FOUND:", path)
|
||||
}
|
||||
if err != nil || info.IsDir() || !testPattern.MatchString(path) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if debugging {
|
||||
fmt.Println("MATCHING:", path)
|
||||
}
|
||||
files = append(files, path)
|
||||
return nil
|
||||
})
|
||||
return files
|
||||
}
|
||||
|
||||
func setBash() {
|
||||
findcmd := "which"
|
||||
if runtime.GOOS == "windows" {
|
||||
// Can't use paths returned from which even if it's on PATH in Windows
|
||||
// Because our Go binary is a separate Windows app & not MinGW, it
|
||||
// can't understand paths like '/usr/bin/bash', needs Windows version
|
||||
findcmd = "where"
|
||||
}
|
||||
|
||||
out, err := exec.Command(findcmd, "bash").Output()
|
||||
if err != nil {
|
||||
fmt.Println("Unable to find bash:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if len(out) == 0 {
|
||||
fmt.Printf("No output from '%s bash'\n", findcmd)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
bashPath = strings.TrimSpace(strings.Split(string(out), "\n")[0])
|
||||
if debugging {
|
||||
fmt.Println("Using", bashPath)
|
||||
}
|
||||
|
||||
// Test
|
||||
_, err = exec.Command(bashPath, "--version").CombinedOutput()
|
||||
if err != nil {
|
||||
fmt.Println("Error calling bash:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
@ -18,8 +18,6 @@ func main() {
|
||||
switch *SubCommand {
|
||||
case "release":
|
||||
mainRelease()
|
||||
case "integration":
|
||||
mainIntegration()
|
||||
default:
|
||||
log.Fatalln("Unknown command:", *SubCommand)
|
||||
}
|
||||
|
40
t/Makefile
Normal file
40
t/Makefile
Normal file
@ -0,0 +1,40 @@
|
||||
RM ?= rm -f
|
||||
PROVE ?= prove
|
||||
PROVE_EXTRA_ARGS =
|
||||
DEFAULT_TEST_TARGET ?= test
|
||||
|
||||
GO ?= go
|
||||
X =
|
||||
|
||||
TEST_CMDS =
|
||||
|
||||
TEST_CMDS += ../bin/git-credential-lfsnoop$X
|
||||
TEST_CMDS += ../bin/git-credential-lfstest$X
|
||||
TEST_CMDS += ../bin/lfs-askpass$X
|
||||
TEST_CMDS += ../bin/lfs-ssh-echo$X
|
||||
TEST_CMDS += ../bin/lfs-ssh-proxy-test$X
|
||||
TEST_CMDS += ../bin/lfstest-count-tests$X
|
||||
TEST_CMDS += ../bin/lfstest-customadapter$X
|
||||
TEST_CMDS += ../bin/lfstest-gitserver$X
|
||||
TEST_CMDS += ../bin/lfstest-standalonecustomadapter$X
|
||||
TEST_CMDS += ../bin/lfstest-testutils$X
|
||||
|
||||
all : $(DEFAULT_TEST_TARGET)
|
||||
|
||||
test : $(TEST_CMDS)
|
||||
$(RM) -r remote test_count{,.lock}
|
||||
@GIT_LFS_NO_TEST_COUNT= bash -c '. ./testenv.sh && setup'
|
||||
$(PROVE) $(PROVE_EXTRA_ARGS) ./t-*.sh
|
||||
@GIT_LFS_NO_TEST_COUNT= bash -c '. ./testenv.sh && shutdown'
|
||||
|
||||
./t-%.sh : $(TEST_CMDS)
|
||||
$(RM) -r remote test_count{,.lock}
|
||||
$(PROVE) -v $(PROVE_EXTRA_ARGS) $@
|
||||
|
||||
.PHONY : clean
|
||||
clean :
|
||||
$(RM) -r remote
|
||||
$(RM) $(TEST_CMDS)
|
||||
|
||||
../bin/%$X : cmd/%.go
|
||||
go build -o $@ $^
|
117
t/README.md
Normal file
117
t/README.md
Normal file
@ -0,0 +1,117 @@
|
||||
# `t`
|
||||
|
||||
This directory contains one of the two types of tests that the Git LFS project
|
||||
uses to protect against regression. The first, scattered in `*_test.go` files
|
||||
throughout the repository are _unit tests_, and written in Go, designed to
|
||||
uncover failures at the unit level.
|
||||
|
||||
The second kind--and the one contained in this directory--are _integration
|
||||
tests_, which are designed to exercise Git LFS in an end-to-end fashion,
|
||||
running the `git`, and `git-lfs` binaries, along with a mock Git server.
|
||||
|
||||
You can run all tests in this directory with any of the following:
|
||||
|
||||
```ShellSession
|
||||
$ make
|
||||
$ make test
|
||||
$ make PROVE_EXTRA_ARGS=-j9 test
|
||||
```
|
||||
|
||||
Or run a single test (for example, `t-checkout.sh`) by any of the following:
|
||||
|
||||
```ShellSession
|
||||
$ make ./t-checkout.sh
|
||||
$ make PROVE_EXTRA_ARGS=-v ./t-checkout.sh
|
||||
$ ./t-checkout.sh
|
||||
```
|
||||
|
||||
Alternatively, one can run a selection of tests (via explicitly listing them or
|
||||
making use of the built-in shell globbing) by any of the following:
|
||||
|
||||
```ShellSession
|
||||
$ make ./t-*.sh
|
||||
$ make PROVE_EXTRA_ARGS=-j9 ./t-*.sh
|
||||
$ ./t-*.sh
|
||||
```
|
||||
|
||||
## Test File(s)
|
||||
|
||||
There are a few important kinds of files to know about in the `t` directory:
|
||||
|
||||
- `cmd/`: contains the source code of binaries that are useful during test
|
||||
time, like the mocked Git server, or the test counting binary. For more about
|
||||
the contents of this directory, see [test lifecycle](#test-lifecycle) below.
|
||||
|
||||
The file `t/cmd/testutils.go` is automatically linked and included during the
|
||||
build process of each file in `cmd`.
|
||||
|
||||
- `fixtures/`: contains shell scripts that load fixture repositories useful for
|
||||
testing against.
|
||||
|
||||
- `t-*.sh`: file(s) containing zero or more tests, typically related to
|
||||
a similar topic (c.f,. `t/t-push.sh`, `t/t-pull.sh`, etc.)
|
||||
|
||||
- `testenv.sh`: loads environment variables useful during tests. This file is
|
||||
sourced by `testlib.sh`.
|
||||
|
||||
- `testhelpers.sh`: loads shell functions useful during tests, like
|
||||
`setup_remote_repo`, and `clone_repo`.
|
||||
|
||||
- `testlib.sh`: loads the `begin_test`, `end_test`, and similar functions
|
||||
useful for instantiating a particular test.
|
||||
|
||||
## Test Lifecycle
|
||||
|
||||
When a test is run, the following occurs, in order:
|
||||
|
||||
1. Missing test binaries are compiled into the `bin` directory in the
|
||||
repository root. Note: this does _not_ include the `git-lfs` binary, which
|
||||
is re-compiled via `script/boostrap`.
|
||||
|
||||
2. An integration server is started by either (1) the `Makefile` or (2) the
|
||||
`cmd/lfstest-count-test.go` program, which keeps track of the number of
|
||||
running tests and starts an integration server any time the number of active
|
||||
tests goes from `0` to `1`, and stops the server when it goes from `n` to
|
||||
`0`.
|
||||
|
||||
3. After sourcing `t/testlib.sh` (& loading `t/testenv.sh`), each test is run
|
||||
in sequence per file. (In other words, multiple test files can be run in
|
||||
parallel, but the tests in a single file are run in sequence.)
|
||||
|
||||
4. An individual test will finish, and (if running under `prove`) another will
|
||||
be started in its place. Once all tests are done, `t/test_count` will go to
|
||||
`0`, and the test server will be torn down.
|
||||
|
||||
## Test Environment
|
||||
|
||||
There are a few environment variables that you can set to change the test suite
|
||||
behavior:
|
||||
|
||||
* `GIT_LFS_TEST_DIR=path` - This sets the directory that is used as the current
|
||||
working directory of the tests. By default, this will be in your temp dir. It's
|
||||
recommended that this is set to a directory outside of any Git repository.
|
||||
|
||||
* `KEEPTRASH=1` - This will leave the local repository data in a `tmp` directory
|
||||
and the remote repository data in `test/remote`.
|
||||
|
||||
Also ensure that your `noproxy` environment variable contains `127.0.0.1` host,
|
||||
to allow git commands to reach the local Git server `lfstest-gitserver`.
|
||||
|
||||
## Writing new tests
|
||||
|
||||
A new test file should be named `t/t-*.sh`, where `*` is the topic of Git LFS
|
||||
being tested. It should look as follows:
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
begin_test "my test"
|
||||
(
|
||||
set -e
|
||||
|
||||
# ...
|
||||
)
|
||||
end_test
|
||||
```
|
296
t/cmd/lfstest-count-tests.go
Normal file
296
t/cmd/lfstest-count-tests.go
Normal file
@ -0,0 +1,296 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
// countFile is the path to a file (relative to the $LFSTEST_DIR) who's
|
||||
// contents is the number of actively-running integration tests.
|
||||
countFile = "test_count"
|
||||
// lockFile is the path to a file (relative to the $LFSTEST_DIR) who's
|
||||
// presence indicates that another invocation of the lfstest-count-tests
|
||||
// program is modifying the test_count.
|
||||
lockFile = "test_count.lock"
|
||||
|
||||
// lockAcquireTimeout is the maximum amount of time that we will wait
|
||||
// for lockFile to become available (and thus the amount of time that we
|
||||
// will wait in order to acquire the lock).
|
||||
lockAcquireTimeout = 5 * time.Second
|
||||
|
||||
// errCouldNotAcquire indicates that the program could not acquire the
|
||||
// lock needed to modify the test_count. It is a fatal error.
|
||||
errCouldNotAcquire = fmt.Errorf("could not acquire lock, dying")
|
||||
// errNegativeCount indicates that the count in test_count was negative,
|
||||
// which is unexpected and makes this script behave in an undefined
|
||||
// fashion
|
||||
errNegativeCount = fmt.Errorf("unexpected negative count")
|
||||
)
|
||||
|
||||
// countFn is a type signature that all functions who wish to modify the
|
||||
// test_count must inhabit.
|
||||
//
|
||||
// The first and only formal parameter is the current number of running tests
|
||||
// found in test_count after acquiring the lock.
|
||||
//
|
||||
// The returned tuple indicates (1) the new number that should be written to
|
||||
// test_count, and (2) if there was an error in computing that value. If err is
|
||||
// non-nil, the program will exit and test_count will not be updated.
|
||||
type countFn func(int) (int, error)
|
||||
|
||||
func main() {
|
||||
if len(os.Args) > 2 {
|
||||
fmt.Fprintf(os.Stderr,
|
||||
"usage: %s [increment|decrement]\n", os.Args[0])
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(
|
||||
context.Background(), lockAcquireTimeout)
|
||||
defer cancel()
|
||||
|
||||
if err := acquire(ctx); err != nil {
|
||||
fatal(err)
|
||||
}
|
||||
defer release()
|
||||
|
||||
if len(os.Args) == 1 {
|
||||
// Calling with no arguments indicates that we simply want to
|
||||
// read the contents of test_count.
|
||||
callWithCount(func(n int) (int, error) {
|
||||
fmt.Fprintf(os.Stdout, "%d\n", n)
|
||||
return n, nil
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
var err error
|
||||
|
||||
switch strings.ToLower(os.Args[1]) {
|
||||
case "increment":
|
||||
err = callWithCount(func(n int) (int, error) {
|
||||
if n > 0 {
|
||||
// If n>1, it is therefore true that a
|
||||
// lfstest-gitserver invocation is already
|
||||
// running.
|
||||
//
|
||||
// Hence, let's do nothing here other than
|
||||
// increase the count.
|
||||
return n + 1, nil
|
||||
}
|
||||
|
||||
// The lfstest-gitserver invocation (see: below) does
|
||||
// not itself create a gitserver.log in the appropriate
|
||||
// directory. Thus, let's create it ourselves instead.
|
||||
log, err := os.Create(fmt.Sprintf(
|
||||
"%s/gitserver.log", os.Getenv("LFSTEST_DIR")))
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
|
||||
// The executable name depends on the X environment
|
||||
// variable, which is set in script/cibuild.
|
||||
var cmd *exec.Cmd
|
||||
if runtime.GOOS == "windows" {
|
||||
cmd = exec.Command("lfstest-gitserver.exe")
|
||||
} else {
|
||||
cmd = exec.Command("lfstest-gitserver")
|
||||
}
|
||||
|
||||
// The following are ported from the old
|
||||
// test/testhelpers.sh, and comprise the requisite
|
||||
// environment variables needed to run
|
||||
// lfstest-gitserver.
|
||||
cmd.Env = append(os.Environ(),
|
||||
fmt.Sprintf("LFSTEST_URL=%s", os.Getenv("LFSTEST_URL")),
|
||||
fmt.Sprintf("LFSTEST_SSL_URL=%s", os.Getenv("LFSTEST_SSL_URL")),
|
||||
fmt.Sprintf("LFSTEST_CLIENT_CERT_URL=%s", os.Getenv("LFSTEST_CLIENT_CERT_URL")),
|
||||
fmt.Sprintf("LFSTEST_DIR=%s", os.Getenv("LFSTEST_DIR")),
|
||||
fmt.Sprintf("LFSTEST_CERT=%s", os.Getenv("LFSTEST_CERT")),
|
||||
fmt.Sprintf("LFSTEST_CLIENT_CERT=%s", os.Getenv("LFSTEST_CLIENT_CERT")),
|
||||
fmt.Sprintf("LFSTEST_CLIENT_KEY=%s", os.Getenv("LFSTEST_CLIENT_KEY")),
|
||||
)
|
||||
cmd.Stdout = log
|
||||
|
||||
// Start performs a fork/execve, hence we can abandon
|
||||
// this process once it has started.
|
||||
if err := cmd.Start(); err != nil {
|
||||
return n, err
|
||||
}
|
||||
return 1, nil
|
||||
})
|
||||
case "decrement":
|
||||
err = callWithCount(func(n int) (int, error) {
|
||||
if n > 1 {
|
||||
// If there is at least two tests running, we
|
||||
// need not shutdown a lfstest-gitserver
|
||||
// instance.
|
||||
return n - 1, nil
|
||||
}
|
||||
|
||||
// Otherwise, we need to POST to /shutdown, which will
|
||||
// cause the lfstest-gitserver to abort itself.
|
||||
url, err := ioutil.ReadFile(os.Getenv("LFS_URL_FILE"))
|
||||
if err == nil {
|
||||
_, err = http.Post(string(url)+"/shutdown",
|
||||
"application/text",
|
||||
strings.NewReader(time.Now().String()))
|
||||
}
|
||||
|
||||
return 0, nil
|
||||
})
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
// acquireTick is the constant time that one tick (i.e., one attempt at
|
||||
// acquiring the lock) should last.
|
||||
acquireTick = 10 * time.Millisecond
|
||||
)
|
||||
|
||||
// acquire acquires the lock file necessary to perform updates to test_count,
|
||||
// and returns an error if that lock cannot be acquired.
|
||||
func acquire(ctx context.Context) error {
|
||||
if disabled() {
|
||||
return nil
|
||||
}
|
||||
|
||||
path, err := path(lockFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tick := time.NewTicker(acquireTick)
|
||||
defer tick.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-tick.C:
|
||||
// Try every tick of the above ticker before giving up
|
||||
// and trying again.
|
||||
_, err := os.OpenFile(path, os.O_CREATE|os.O_EXCL, 0666)
|
||||
if err == nil || !os.IsExist(err) {
|
||||
return err
|
||||
}
|
||||
case <-ctx.Done():
|
||||
// If the context.Context above has reached its
|
||||
// deadline, we must give up.
|
||||
return errCouldNotAcquire
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// release releases the lock file so that another process can take over, or
|
||||
// returns an error.
|
||||
func release() error {
|
||||
if disabled() {
|
||||
return nil
|
||||
}
|
||||
|
||||
path, err := path(lockFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return os.Remove(path)
|
||||
}
|
||||
|
||||
// callWithCount calls the given countFn with the current count in test_count,
|
||||
// and updates it with what the function returns.
|
||||
//
|
||||
// If the function produced an error, that will be returned instead.
|
||||
func callWithCount(fn countFn) error {
|
||||
path, err := path(countFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f, err := os.OpenFile(path, os.O_CREATE|os.O_RDWR, 0666)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
contents, err := ioutil.ReadAll(f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var n int = 0
|
||||
if len(contents) != 0 {
|
||||
n, err = strconv.Atoi(string(contents))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if n < 0 {
|
||||
return errNegativeCount
|
||||
}
|
||||
}
|
||||
|
||||
after, err := fn(n)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// We want to write over the contents in the file, so "truncate" the
|
||||
// file to a length of 0, and then seek to the beginning of the file to
|
||||
// update the write head.
|
||||
if err := f.Truncate(0); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := f.Seek(0, io.SeekStart); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := fmt.Fprintf(f, "%d", after); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// path returns an absolute path corresponding to any given path relative to the
|
||||
// 't' directory of the current checkout of Git LFS.
|
||||
func path(s string) (string, error) {
|
||||
p := filepath.Join(filepath.Dir(os.Getenv("LFSTEST_DIR")), s)
|
||||
if err := os.MkdirAll(filepath.Dir(p), 0666); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// disabled returns true if and only if the lock acquisition phase is disabled.
|
||||
func disabled() bool {
|
||||
s := os.Getenv("GIT_LFS_LOCK_ACQUIRE_DISABLED")
|
||||
b, err := strconv.ParseBool(s)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// fatal reports the given error (if non-nil), and then dies. If the error was
|
||||
// nil, nothing happens.
|
||||
func fatal(err error) {
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
if err := release(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "fatal: while dying, got: %s\n", err)
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "fatal: %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
@ -101,6 +101,9 @@ func main() {
|
||||
mux.HandleFunc("/storage/", storageHandler)
|
||||
mux.HandleFunc("/verify", verifyHandler)
|
||||
mux.HandleFunc("/redirect307/", redirect307Handler)
|
||||
mux.HandleFunc("/status", func(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintf(w, "%s\n", time.Now().String())
|
||||
})
|
||||
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
id, ok := reqId(w)
|
||||
if !ok {
|
@ -9,7 +9,7 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/git-lfs/git-lfs/test"
|
||||
. "github.com/git-lfs/git-lfs/t/cmd/util"
|
||||
)
|
||||
|
||||
type TestUtilRepoCallback struct{}
|
||||
@ -23,7 +23,7 @@ func (*TestUtilRepoCallback) Errorf(format string, args ...interface{}) {
|
||||
}
|
||||
|
||||
func main() {
|
||||
commandMap := map[string]func(*test.Repo){
|
||||
commandMap := map[string]func(*Repo){
|
||||
"addcommits": AddCommits,
|
||||
}
|
||||
if len(os.Args) < 2 {
|
||||
@ -51,18 +51,18 @@ func main() {
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
repo := test.WrapRepo(&TestUtilRepoCallback{}, wd)
|
||||
repo := WrapRepo(&TestUtilRepoCallback{}, wd)
|
||||
f(repo)
|
||||
}
|
||||
|
||||
func AddCommits(repo *test.Repo) {
|
||||
// Read stdin as JSON []*test.CommitInput
|
||||
func AddCommits(repo *Repo) {
|
||||
// Read stdin as JSON []*CommitInput
|
||||
in, err := ioutil.ReadAll(os.Stdin)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "addcommits: Unable to read input data: %v\n", err)
|
||||
os.Exit(3)
|
||||
}
|
||||
inputs := make([]*test.CommitInput, 0)
|
||||
inputs := make([]*CommitInput, 0)
|
||||
err = json.Unmarshal(in, &inputs)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "addcommits: Unable to unmarshal JSON: %v\n%v\n", string(in), err)
|
@ -1,4 +1,4 @@
|
||||
package test
|
||||
package util
|
||||
|
||||
// Utility functions for more complex go tests
|
||||
// Need to be in a separate test package so they can be imported anywhere
|
@ -178,7 +178,7 @@ setup_single_local_branch_tracked_corrupt() {
|
||||
#
|
||||
# - Commit 'A' has 120, 140 bytes of data in a.txt, and a.md, respectively.
|
||||
#
|
||||
# - Commit 'B' has 30 bytes of data in a.txt, and includes commit 'A' as a
|
||||
# - Commit 'B' has 30 bytes of data in a.md, and includes commit 'A' as a
|
||||
# parent.
|
||||
setup_multiple_local_branches() {
|
||||
set -e
|
||||
@ -218,6 +218,29 @@ setup_multiple_local_branches_with_gitattrs() {
|
||||
git commit -m "add .gitattributes"
|
||||
}
|
||||
|
||||
# setup_multiple_local_branches_non_standard creates a repository as follows:
|
||||
#
|
||||
# refs/pull/1/head
|
||||
# /
|
||||
# |
|
||||
# B
|
||||
# / \
|
||||
# A refs/heads/my-feature
|
||||
# |\
|
||||
# | refs/heads/master
|
||||
# \
|
||||
# refs/pull/1/base
|
||||
#
|
||||
# With the same contents in 'A' and 'B' as setup_multiple_local_branches.
|
||||
setup_multiple_local_branches_non_standard() {
|
||||
set -e
|
||||
|
||||
setup_multiple_local_branches
|
||||
|
||||
git update-ref refs/pull/1/head "$(git rev-parse my-feature)"
|
||||
git update-ref refs/pull/1/base "$(git rev-parse master)"
|
||||
}
|
||||
|
||||
# setup_multiple_local_branches_tracked creates a repo with exactly the same
|
||||
# structure as in setup_multiple_local_branches, but with all files tracked by
|
||||
# Git LFS
|
||||
@ -553,6 +576,28 @@ setup_local_branch_with_symlink() {
|
||||
git commit -m "add symlink"
|
||||
}
|
||||
|
||||
# setup_local_branch_with_dirty_copy creates a repository as follows:
|
||||
#
|
||||
# A
|
||||
# \
|
||||
# refs/heads/master
|
||||
#
|
||||
# - Commit 'A' has the contents "a.txt in a.txt, and marks a.txt as unclean
|
||||
# in the working copy.
|
||||
setup_local_branch_with_dirty_copy() {
|
||||
set -e
|
||||
|
||||
reponame="migrate-single-local-branch-with-dirty-copy"
|
||||
remove_and_create_local_repo "$reponame"
|
||||
|
||||
printf "a.txt" > a.txt
|
||||
|
||||
git add a.txt
|
||||
git commit -m "initial commit"
|
||||
|
||||
printf "2" >> a.txt
|
||||
}
|
||||
|
||||
# make_bare converts the existing full checkout of a repository into a bare one,
|
||||
# and then `cd`'s into it.
|
||||
make_bare() {
|
||||
@ -587,4 +632,6 @@ remove_and_create_remote_repo() {
|
||||
|
||||
setup_remote_repo "$reponame"
|
||||
clone_repo "$reponame" "$reponame"
|
||||
|
||||
rm clone.log
|
||||
}
|
1
t/git-lfs-test-server-api/.gitignore
vendored
Normal file
1
t/git-lfs-test-server-api/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
git-lfs-test-server-api*
|
@ -13,8 +13,8 @@ import (
|
||||
"github.com/git-lfs/git-lfs/errors"
|
||||
"github.com/git-lfs/git-lfs/fs"
|
||||
"github.com/git-lfs/git-lfs/lfsapi"
|
||||
t "github.com/git-lfs/git-lfs/t/cmd/util"
|
||||
"github.com/git-lfs/git-lfs/tasklog"
|
||||
"github.com/git-lfs/git-lfs/test"
|
||||
"github.com/git-lfs/git-lfs/tq"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@ -64,7 +64,7 @@ func testServerApi(cmd *cobra.Command, args []string) {
|
||||
// Use test repo for this to simplify the process of making sure data matches oid
|
||||
// We're not performing a real test at this point (although an upload fail will break it)
|
||||
var callback testDataCallback
|
||||
repo := test.NewRepo(&callback)
|
||||
repo := t.NewRepo(&callback)
|
||||
|
||||
// Force loading of config before we alter it
|
||||
repo.GitEnv().All()
|
||||
@ -137,7 +137,7 @@ func (*testDataCallback) Errorf(format string, args ...interface{}) {
|
||||
fmt.Printf(format, args...)
|
||||
}
|
||||
|
||||
func buildManifest(r *test.Repo) (*tq.Manifest, error) {
|
||||
func buildManifest(r *t.Repo) (*tq.Manifest, error) {
|
||||
// Configure the endpoint manually
|
||||
finder := lfsapi.NewEndpointFinder(r)
|
||||
|
||||
@ -173,7 +173,7 @@ func (c *constantEndpoint) Endpoint(operation, remote string) lfsapi.Endpoint {
|
||||
|
||||
func (c *constantEndpoint) RemoteEndpoint(operation, remote string) lfsapi.Endpoint { return c.e }
|
||||
|
||||
func buildTestData(repo *test.Repo, manifest *tq.Manifest) (oidsExist, oidsMissing []TestObject, err error) {
|
||||
func buildTestData(repo *t.Repo, manifest *tq.Manifest) (oidsExist, oidsMissing []TestObject, err error) {
|
||||
const oidCount = 50
|
||||
oidsExist = make([]TestObject, 0, oidCount)
|
||||
oidsMissing = make([]TestObject, 0, oidCount)
|
||||
@ -183,14 +183,14 @@ func buildTestData(repo *test.Repo, manifest *tq.Manifest) (oidsExist, oidsMissi
|
||||
meter := tq.NewMeter()
|
||||
meter.Logger = meter.LoggerFromEnv(repo.OSEnv())
|
||||
logger.Enqueue(meter)
|
||||
commit := test.CommitInput{CommitterName: "A N Other", CommitterEmail: "noone@somewhere.com"}
|
||||
commit := t.CommitInput{CommitterName: "A N Other", CommitterEmail: "noone@somewhere.com"}
|
||||
for i := 0; i < oidCount; i++ {
|
||||
filename := fmt.Sprintf("file%d.dat", i)
|
||||
sz := int64(rand.Intn(200)) + 50
|
||||
commit.Files = append(commit.Files, &test.FileInput{Filename: filename, Size: sz})
|
||||
commit.Files = append(commit.Files, &t.FileInput{Filename: filename, Size: sz})
|
||||
meter.Add(sz)
|
||||
}
|
||||
outputs := repo.AddCommits([]*test.CommitInput{&commit})
|
||||
outputs := repo.AddCommits([]*t.CommitInput{&commit})
|
||||
|
||||
// now upload
|
||||
uploadQueue := tq.NewTransferQueue(tq.Upload, manifest, "origin", tq.WithProgress(meter))
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
begin_test "askpass: push with GIT_ASKPASS"
|
||||
(
|
||||
@ -102,3 +102,33 @@ begin_test "askpass: push with SSH_ASKPASS"
|
||||
grep "master -> master" push.log
|
||||
)
|
||||
end_test
|
||||
|
||||
begin_test "askpass: defaults to provided credentials"
|
||||
(
|
||||
set -e
|
||||
|
||||
reponame="askpass-provided-creds"
|
||||
setup_remote_repo "$reponame"
|
||||
clone_repo "$reponame" "$reponame"
|
||||
|
||||
git lfs track "*.dat"
|
||||
echo "hello" > a.dat
|
||||
|
||||
git add .gitattributes a.dat
|
||||
git commit -m "initial commit"
|
||||
|
||||
# $password is defined from test/cmd/lfstest-gitserver.go (see: skipIfBadAuth)
|
||||
export LFS_ASKPASS_USERNAME="fakeuser"
|
||||
export LFS_ASKPASS_PASSWORD="fakepass"
|
||||
git config --local "credential.helper" ""
|
||||
|
||||
url=$(git config --get remote.origin.url)
|
||||
newurl=${url/http:\/\//http:\/\/user\:pass@}
|
||||
git remote set-url origin "$newurl"
|
||||
|
||||
GIT_ASKPASS="lfs-askpass" GIT_TRACE=1 GIT_CURL_VERBOSE=1 git push origin master 2>&1 | tee push.log
|
||||
|
||||
[ ! $(grep "filling with GIT_ASKPASS" push.log) ]
|
||||
grep "master -> master" push.log
|
||||
)
|
||||
end_test
|
@ -2,7 +2,7 @@
|
||||
# This is a sample Git LFS test. See test/README.md and testhelpers.sh for
|
||||
# more documentation.
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
begin_test "batch error handling"
|
||||
(
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
begin_test "batch storage upload causes retries"
|
||||
(
|
@ -2,7 +2,7 @@
|
||||
# This is a sample Git LFS test. See test/README.md and testhelpers.sh for
|
||||
# more documentation.
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
begin_test "batch transfer"
|
||||
(
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
begin_test "transfer queue rejects unknown OIDs"
|
||||
(
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
begin_test "checkout"
|
||||
(
|
||||
@ -156,3 +156,29 @@ begin_test "checkout: outside git repository"
|
||||
grep "Not in a git repository" checkout.log
|
||||
)
|
||||
end_test
|
||||
|
||||
begin_test "checkout: write-only file"
|
||||
(
|
||||
set -e
|
||||
|
||||
reponame="checkout-locked"
|
||||
filename="a.txt"
|
||||
|
||||
setup_remote_repo_with_file "$reponame" "$filename"
|
||||
|
||||
pushd "$TRASHDIR" > /dev/null
|
||||
GIT_LFS_SKIP_SMUDGE=1 clone_repo "$reponame" "${reponame}_checkout"
|
||||
|
||||
chmod -w "$filename"
|
||||
|
||||
refute_file_writeable "$filename"
|
||||
assert_pointer "refs/heads/master" "$filename" "$(calc_oid "$filename\n")" 6
|
||||
|
||||
git lfs fetch
|
||||
git lfs checkout "$filename"
|
||||
|
||||
refute_file_writeable "$filename"
|
||||
[ "$filename" = "$(cat "$filename")" ]
|
||||
popd > /dev/null
|
||||
)
|
||||
end_test
|
@ -2,7 +2,7 @@
|
||||
# This is a sample Git LFS test. See test/README.md and testhelpers.sh for
|
||||
# more documentation.
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
begin_test "chunked transfer encoding"
|
||||
(
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
clean_setup () {
|
||||
mkdir "$1"
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
ensure_git_version_isnt $VERSION_LOWER "2.15.0"
|
||||
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
ensure_git_version_isnt $VERSION_LOWER "2.2.0"
|
||||
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
begin_test "commit, delete, then push"
|
||||
(
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
begin_test "default config"
|
||||
(
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
# these tests rely on GIT_TERMINAL_PROMPT to test properly
|
||||
ensure_git_version_isnt $VERSION_LOWER "2.3.0"
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
ensure_git_version_isnt $VERSION_LOWER "2.3.0"
|
||||
|
||||
@ -164,7 +164,7 @@ begin_test "credentials with useHttpPath, with correct password"
|
||||
credcalls="$(grep "creds: git credential" push.log)"
|
||||
[ "0" -eq "$(echo "$credcalls" | grep '", "")' | wc -l)" ]
|
||||
expected="$(echo "$credcalls" | wc -l)"
|
||||
[ "$expected" -eq "$(printf "$credcalls" | grep "test-credentials" | wc -l)" ]
|
||||
[ "$expected" -eq "$(printf "$credcalls" | grep "t-credentials" | wc -l)" ]
|
||||
)
|
||||
end_test
|
||||
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
begin_test "custom-transfer-wrong-path"
|
||||
(
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
begin_test "multiple revs with same OID get pushed once"
|
||||
(
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
envInitConfig='git config filter.lfs.process = "git-lfs filter-process"
|
||||
git config filter.lfs.smudge = "git-lfs smudge -- %f"
|
||||
@ -29,7 +29,7 @@ LocalWorkingDir=%s
|
||||
LocalGitDir=%s
|
||||
LocalGitStorageDir=%s
|
||||
LocalMediaDir=%s
|
||||
LocalReferenceDir=
|
||||
LocalReferenceDirs=
|
||||
TempDir=%s
|
||||
ConcurrentTransfers=3
|
||||
TusTransfers=false
|
||||
@ -81,7 +81,7 @@ LocalWorkingDir=%s
|
||||
LocalGitDir=%s
|
||||
LocalGitStorageDir=%s
|
||||
LocalMediaDir=%s
|
||||
LocalReferenceDir=
|
||||
LocalReferenceDirs=
|
||||
TempDir=%s
|
||||
ConcurrentTransfers=3
|
||||
TusTransfers=false
|
||||
@ -140,7 +140,7 @@ LocalWorkingDir=%s
|
||||
LocalGitDir=%s
|
||||
LocalGitStorageDir=%s
|
||||
LocalMediaDir=%s
|
||||
LocalReferenceDir=
|
||||
LocalReferenceDirs=
|
||||
TempDir=%s
|
||||
ConcurrentTransfers=3
|
||||
TusTransfers=false
|
||||
@ -197,7 +197,7 @@ LocalWorkingDir=%s
|
||||
LocalGitDir=%s
|
||||
LocalGitStorageDir=%s
|
||||
LocalMediaDir=%s
|
||||
LocalReferenceDir=
|
||||
LocalReferenceDirs=
|
||||
TempDir=%s
|
||||
ConcurrentTransfers=3
|
||||
TusTransfers=false
|
||||
@ -256,7 +256,7 @@ LocalWorkingDir=%s
|
||||
LocalGitDir=%s
|
||||
LocalGitStorageDir=%s
|
||||
LocalMediaDir=%s
|
||||
LocalReferenceDir=
|
||||
LocalReferenceDirs=
|
||||
TempDir=%s
|
||||
ConcurrentTransfers=3
|
||||
TusTransfers=false
|
||||
@ -316,7 +316,7 @@ LocalWorkingDir=%s
|
||||
LocalGitDir=%s
|
||||
LocalGitStorageDir=%s
|
||||
LocalMediaDir=%s
|
||||
LocalReferenceDir=
|
||||
LocalReferenceDirs=
|
||||
TempDir=%s
|
||||
ConcurrentTransfers=3
|
||||
TusTransfers=false
|
||||
@ -377,7 +377,7 @@ LocalWorkingDir=%s
|
||||
LocalGitDir=%s
|
||||
LocalGitStorageDir=%s
|
||||
LocalMediaDir=%s
|
||||
LocalReferenceDir=
|
||||
LocalReferenceDirs=
|
||||
TempDir=%s
|
||||
ConcurrentTransfers=5
|
||||
TusTransfers=false
|
||||
@ -445,7 +445,7 @@ LocalWorkingDir=%s
|
||||
LocalGitDir=%s
|
||||
LocalGitStorageDir=%s
|
||||
LocalMediaDir=%s
|
||||
LocalReferenceDir=
|
||||
LocalReferenceDirs=
|
||||
TempDir=%s
|
||||
ConcurrentTransfers=3
|
||||
TusTransfers=false
|
||||
@ -500,7 +500,7 @@ LocalWorkingDir=%s
|
||||
LocalGitDir=%s
|
||||
LocalGitStorageDir=%s
|
||||
LocalMediaDir=%s
|
||||
LocalReferenceDir=
|
||||
LocalReferenceDirs=
|
||||
TempDir=%s
|
||||
ConcurrentTransfers=3
|
||||
TusTransfers=false
|
||||
@ -549,7 +549,7 @@ LocalWorkingDir=%s
|
||||
LocalGitDir=%s
|
||||
LocalGitStorageDir=%s
|
||||
LocalMediaDir=%s
|
||||
LocalReferenceDir=
|
||||
LocalReferenceDirs=
|
||||
TempDir=%s
|
||||
ConcurrentTransfers=3
|
||||
TusTransfers=false
|
||||
@ -582,7 +582,7 @@ LocalWorkingDir=%s
|
||||
LocalGitDir=%s
|
||||
LocalGitStorageDir=%s
|
||||
LocalMediaDir=%s
|
||||
LocalReferenceDir=
|
||||
LocalReferenceDirs=
|
||||
TempDir=%s
|
||||
ConcurrentTransfers=3
|
||||
TusTransfers=false
|
||||
@ -615,7 +615,7 @@ LocalWorkingDir=%s
|
||||
LocalGitDir=%s
|
||||
LocalGitStorageDir=%s
|
||||
LocalMediaDir=%s
|
||||
LocalReferenceDir=
|
||||
LocalReferenceDirs=
|
||||
TempDir=%s
|
||||
ConcurrentTransfers=3
|
||||
TusTransfers=false
|
||||
@ -660,7 +660,7 @@ LocalWorkingDir=
|
||||
LocalGitDir=%s
|
||||
LocalGitStorageDir=%s
|
||||
LocalMediaDir=%s
|
||||
LocalReferenceDir=
|
||||
LocalReferenceDirs=
|
||||
TempDir=%s
|
||||
ConcurrentTransfers=3
|
||||
TusTransfers=false
|
||||
@ -739,7 +739,7 @@ LocalWorkingDir=%s
|
||||
LocalGitDir=%s
|
||||
LocalGitStorageDir=%s
|
||||
LocalMediaDir=%s
|
||||
LocalReferenceDir=
|
||||
LocalReferenceDirs=
|
||||
TempDir=%s
|
||||
ConcurrentTransfers=3
|
||||
TusTransfers=false
|
||||
@ -772,7 +772,7 @@ LocalWorkingDir=%s
|
||||
LocalGitDir=%s
|
||||
LocalGitStorageDir=%s
|
||||
LocalMediaDir=%s
|
||||
LocalReferenceDir=
|
||||
LocalReferenceDirs=
|
||||
TempDir=%s
|
||||
ConcurrentTransfers=3
|
||||
TusTransfers=false
|
||||
@ -838,7 +838,7 @@ LocalWorkingDir=%s
|
||||
LocalGitDir=%s
|
||||
LocalGitStorageDir=%s
|
||||
LocalMediaDir=%s
|
||||
LocalReferenceDir=
|
||||
LocalReferenceDirs=
|
||||
TempDir=%s
|
||||
ConcurrentTransfers=3
|
||||
TusTransfers=true
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
declare -a expiration_types=("absolute" "relative" "both")
|
||||
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
begin_test "ext"
|
||||
(
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
begin_test "http.<url>.extraHeader"
|
||||
(
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
reponame="$(basename "$0" ".sh")"
|
||||
contents="big file"
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
reponame="$(basename "$0" ".sh")"
|
||||
contents="a"
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
reponame="fetch-recent"
|
||||
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
begin_test "fetch with good ref"
|
||||
(
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
contents="a"
|
||||
contents_oid=$(calc_oid "$contents")
|
||||
@ -526,14 +526,14 @@ begin_test "fetch raw remote url"
|
||||
git init
|
||||
git lfs install --local --skip-smudge
|
||||
|
||||
git remote add origin $GITSERVER/test-fetch
|
||||
git remote add origin "$GITSERVER/$reponame"
|
||||
git pull origin master
|
||||
|
||||
# LFS object not downloaded, pointer in working directory
|
||||
refute_local_object "$contents_oid"
|
||||
grep "$content_oid" a.dat
|
||||
|
||||
git lfs fetch "$GITSERVER/test-fetch"
|
||||
git lfs fetch "$GITSERVER/$reponame"
|
||||
|
||||
# LFS object downloaded, pointer still in working directory
|
||||
assert_local_object "$contents_oid" 1
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
begin_test "filter-branch (git-lfs/git-lfs#1773)"
|
||||
(
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
# HACK(taylor): git uses ".g<hash>" in the version name to signal that it is
|
||||
# from the "next" branch, which is the only (current) version of Git that has
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
begin_test "fsck default"
|
||||
(
|
@ -2,7 +2,7 @@
|
||||
# This is a sample Git LFS test. See test/README.md and testhelpers.sh for
|
||||
# more documentation.
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
begin_test "happy path"
|
||||
(
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
# These tests rely on behavior found in Git versions less than 2.9.0 to perform
|
||||
# themselves, specifically:
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
# These tests rely on behavior found in 2.9.0 to perform themselves,
|
||||
# specifically:
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
begin_test "install again"
|
||||
(
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
begin_test "lock with good ref"
|
||||
(
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
begin_test "list a single lock with bad ref"
|
||||
(
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
begin_test "logs"
|
||||
(
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
begin_test "ls-files"
|
||||
(
|
||||
@ -334,16 +334,11 @@ begin_test "ls-files: list/stat files with escaped runes in path before commit"
|
||||
(
|
||||
set -e
|
||||
|
||||
if [ -n "$CIRCLECI" ]; then
|
||||
echo >&2 "info: skipping due to known failure on CircleCI"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
reponame=runes-in-path
|
||||
content="zero"
|
||||
checksum="d3eb539a55"
|
||||
pathWithGermanRunes="german/äöü"
|
||||
fileWithGermanRunes="schüüch.bin"
|
||||
pathWithGermanRunes="german/äöü"
|
||||
fileWithGermanRunes="schüüch.bin"
|
||||
|
||||
mkdir $reponame
|
||||
git init "$reponame"
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
begin_test "malformed pointers"
|
||||
(
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
begin_test "mergetool works with large files"
|
||||
(
|
@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/test-migrate-fixtures.sh"
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/fixtures/migrate.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
begin_test "migrate export (default branch)"
|
||||
(
|
||||
@ -198,7 +198,7 @@ begin_test "migrate export (no filter)"
|
||||
|
||||
setup_multiple_local_branches_tracked
|
||||
|
||||
git lfs migrate export 2>&1 | tee migrate.log
|
||||
git lfs migrate export --yes 2>&1 | tee migrate.log
|
||||
if [ ${PIPESTATUS[0]} -eq 0 ]; then
|
||||
echo >&2 "fatal: expected git lfs migrate export to fail, didn't"
|
||||
exit 1
|
||||
@ -432,7 +432,8 @@ begin_test "migrate export (invalid --remote)"
|
||||
|
||||
setup_single_remote_branch_tracked
|
||||
|
||||
git lfs migrate export --include="*" --remote="zz" 2>&1 | tee migrate.log
|
||||
git lfs migrate export --include="*" --remote="zz" --yes 2>&1 \
|
||||
| tee migrate.log
|
||||
if [ ${PIPESTATUS[0]} -eq 0 ]; then
|
||||
echo >&2 "fatal: expected git lfs migrate export to fail, didn't"
|
||||
exit 1
|
@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/test-migrate-fixtures.sh"
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/fixtures/migrate.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
begin_test "migrate import (--fixup)"
|
||||
(
|
||||
@ -11,7 +11,7 @@ begin_test "migrate import (--fixup)"
|
||||
|
||||
txt_oid="$(calc_oid "$(git cat-file -p :a.txt)")"
|
||||
|
||||
git lfs migrate import --everything --fixup
|
||||
git lfs migrate import --everything --fixup --yes
|
||||
|
||||
assert_pointer "refs/heads/master" "a.txt" "$txt_oid" "120"
|
||||
assert_local_object "$txt_oid" "120"
|
||||
@ -31,7 +31,7 @@ begin_test "migrate import (--fixup, complex nested)"
|
||||
a_oid="$(calc_oid "$(git cat-file -p :a.txt)")"
|
||||
b_oid="$(calc_oid "$(git cat-file -p :dir/b.txt)")"
|
||||
|
||||
git lfs migrate import --everything --fixup
|
||||
git lfs migrate import --everything --fixup --yes
|
||||
|
||||
assert_pointer "refs/heads/master" "a.txt" "$a_oid" "1"
|
||||
refute_pointer "refs/heads/master" "b.txt"
|
||||
@ -53,7 +53,7 @@ begin_test "migrate import (--fixup, --include)"
|
||||
|
||||
setup_single_local_branch_tracked_corrupt
|
||||
|
||||
git lfs migrate import --everything --fixup --include="*.txt" 2>&1 \
|
||||
git lfs migrate import --everything --fixup --yes --include="*.txt" 2>&1 \
|
||||
| tee migrate.log
|
||||
|
||||
if [ "${PIPESTATUS[0]}" -eq 0 ]; then
|
||||
@ -71,7 +71,7 @@ begin_test "migrate import (--fixup, --exclude)"
|
||||
|
||||
setup_single_local_branch_tracked_corrupt
|
||||
|
||||
git lfs migrate import --everything --fixup --exclude="*.txt" 2>&1 \
|
||||
git lfs migrate import --everything --fixup --yes --exclude="*.txt" 2>&1 \
|
||||
| tee migrate.log
|
||||
|
||||
if [ "${PIPESTATUS[0]}" -eq 0 ]; then
|
||||
@ -89,7 +89,7 @@ begin_test "migrate import (--fixup, --no-rewrite)"
|
||||
|
||||
setup_single_local_branch_tracked_corrupt
|
||||
|
||||
git lfs migrate import --everything --fixup --no-rewrite 2>&1 \
|
||||
git lfs migrate import --everything --fixup --yes --no-rewrite 2>&1 \
|
||||
| tee migrate.log
|
||||
|
||||
if [ "${PIPESTATUS[0]}" -eq 0 ]; then
|
@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/test-migrate-fixtures.sh"
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/fixtures/migrate.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
begin_test "migrate import --no-rewrite (default branch)"
|
||||
(
|
||||
@ -12,7 +12,7 @@ begin_test "migrate import --no-rewrite (default branch)"
|
||||
txt_oid="$(calc_oid "$(git cat-file -p :a.txt)")"
|
||||
prev_commit_oid="$(git rev-parse HEAD)"
|
||||
|
||||
git lfs migrate import --no-rewrite *.txt
|
||||
git lfs migrate import --no-rewrite --yes *.txt
|
||||
|
||||
# Ensure our desired files were imported into git-lfs
|
||||
assert_pointer "refs/heads/master" "a.txt" "$txt_oid" "120"
|
||||
@ -46,7 +46,7 @@ begin_test "migrate import --no-rewrite (bare repository)"
|
||||
txt_oid="$(calc_oid "$(git cat-file -p :a.txt)")"
|
||||
md_oid="$(calc_oid "$(git cat-file -p :a.md)")"
|
||||
|
||||
git lfs migrate import --no-rewrite a.txt a.md
|
||||
git lfs migrate import --no-rewrite --yes a.txt a.md
|
||||
|
||||
# Ensure our desired files were imported
|
||||
assert_pointer "refs/heads/master" "a.txt" "$txt_oid" "30"
|
||||
@ -78,7 +78,7 @@ begin_test "migrate import --no-rewrite (multiple branches)"
|
||||
txt_oid="$(calc_oid "$(git cat-file -p :a.txt)")"
|
||||
md_feature_oid="$(calc_oid "$(git cat-file -p my-feature:a.md)")"
|
||||
|
||||
git lfs migrate import --no-rewrite *.txt *.md
|
||||
git lfs migrate import --no-rewrite --yes *.txt *.md
|
||||
|
||||
# Ensure our desired files were imported
|
||||
assert_pointer "refs/heads/master" "a.md" "$md_oid" "140"
|
||||
@ -111,7 +111,7 @@ begin_test "migrate import --no-rewrite (no .gitattributes)"
|
||||
setup_multiple_local_branches
|
||||
|
||||
# Ensure command fails if no .gitattributes files are present
|
||||
git lfs migrate import --no-rewrite *.txt *.md 2>&1 | tee migrate.log
|
||||
git lfs migrate import --no-rewrite --yes *.txt *.md 2>&1 | tee migrate.log
|
||||
if [ ${PIPESTATUS[0]} -eq 0 ]; then
|
||||
echo >&2 "fatal: expected git lfs migrate import --no-rewrite to fail, didn't"
|
||||
exit 1
|
||||
@ -139,7 +139,7 @@ begin_test "migrate import --no-rewrite (nested .gitattributes)"
|
||||
nested_md_oid="$(calc_oid "$(git cat-file -p :b/a.md)")"
|
||||
txt_oid="$(calc_oid "$(git cat-file -p :a.txt)")"
|
||||
|
||||
git lfs migrate import --no-rewrite a.txt b/a.md
|
||||
git lfs migrate import --no-rewrite --yes a.txt b/a.md
|
||||
|
||||
# Ensure a.txt and subtree/a.md were imported, even though *.md only exists in the
|
||||
# nested subtree/.gitattributes file
|
||||
@ -152,7 +152,7 @@ begin_test "migrate import --no-rewrite (nested .gitattributes)"
|
||||
|
||||
# Failure should occur when trying to import a.md as no entry exists in
|
||||
# top-level .gitattributes file
|
||||
git lfs migrate import --no-rewrite a.md 2>&1 | tee migrate.log
|
||||
git lfs migrate import --no-rewrite --yes a.md 2>&1 | tee migrate.log
|
||||
if [ ${PIPESTATUS[0]} -eq 0 ]; then
|
||||
echo >&2 "fatal: expected git lfs migrate import --no-rewrite to fail, didn't"
|
||||
exit 1
|
||||
@ -171,7 +171,7 @@ begin_test "migrate import --no-rewrite (with commit message)"
|
||||
prev_commit_oid="$(git rev-parse HEAD)"
|
||||
expected_commit_msg="run git-lfs migrate import --no-rewrite"
|
||||
|
||||
git lfs migrate import --message "$expected_commit_msg" --no-rewrite *.txt
|
||||
git lfs migrate import --message "$expected_commit_msg" --no-rewrite --yes *.txt
|
||||
|
||||
# Ensure the git history remained the same
|
||||
new_commit_oid="$(git rev-parse HEAD~1)"
|
||||
@ -201,7 +201,7 @@ begin_test "migrate import --no-rewrite (with empty commit message)"
|
||||
|
||||
prev_commit_oid="$(git rev-parse HEAD)"
|
||||
|
||||
git lfs migrate import -m "" --no-rewrite *.txt
|
||||
git lfs migrate import -m "" --no-rewrite --yes *.txt
|
||||
|
||||
# Ensure the git history remained the same
|
||||
new_commit_oid="$(git rev-parse HEAD~1)"
|
@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/test-migrate-fixtures.sh"
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/fixtures/migrate.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
begin_test "migrate import (default branch)"
|
||||
(
|
||||
@ -417,7 +417,7 @@ begin_test "migrate import (existing .gitattributes)"
|
||||
|
||||
txt_master_oid="$(calc_oid "$(git cat-file -p "$master:a.txt")")"
|
||||
|
||||
git lfs migrate import --include-ref=refs/heads/master --include="*.txt"
|
||||
git lfs migrate import --yes --include-ref=refs/heads/master --include="*.txt"
|
||||
|
||||
assert_local_object "$txt_master_oid" "120"
|
||||
|
||||
@ -707,3 +707,85 @@ begin_test "migrate import (multiple remotes)"
|
||||
assert_ref_unmoved "master" "$original_master" "$migrated_master"
|
||||
)
|
||||
end_test
|
||||
|
||||
begin_test "migrate import (dirty copy, negative answer)"
|
||||
(
|
||||
set -e
|
||||
|
||||
setup_local_branch_with_dirty_copy
|
||||
|
||||
original_master="$(git rev-parse master)"
|
||||
|
||||
echo "n" | git lfs migrate import --everything 2>&1 | tee migrate.log
|
||||
grep "migrate: working copy must not be dirty" migrate.log
|
||||
|
||||
migrated_master="$(git rev-parse master)"
|
||||
|
||||
assert_ref_unmoved "master" "$original_master" "$migrated_master"
|
||||
)
|
||||
end_test
|
||||
|
||||
begin_test "migrate import (dirty copy, unknown then negative answer)"
|
||||
(
|
||||
set -e
|
||||
|
||||
setup_local_branch_with_dirty_copy
|
||||
|
||||
original_master="$(git rev-parse master)"
|
||||
|
||||
echo "x\nn" | git lfs migrate import --everything 2>&1 | tee migrate.log
|
||||
|
||||
cat migrate.log
|
||||
|
||||
[ "2" -eq "$(grep -o "override changes in your working copy" migrate.log \
|
||||
| wc -l | awk '{ print $1 }')" ]
|
||||
grep "migrate: working copy must not be dirty" migrate.log
|
||||
|
||||
migrated_master="$(git rev-parse master)"
|
||||
|
||||
assert_ref_unmoved "master" "$original_master" "$migrated_master"
|
||||
)
|
||||
end_test
|
||||
|
||||
begin_test "migrate import (dirty copy, positive answer)"
|
||||
(
|
||||
set -e
|
||||
|
||||
setup_local_branch_with_dirty_copy
|
||||
|
||||
oid="$(calc_oid "$(git cat-file -p :a.txt)")"
|
||||
|
||||
echo "y" | git lfs migrate import --everything 2>&1 | tee migrate.log
|
||||
grep "migrate: changes in your working copy will be overridden ..." \
|
||||
migrate.log
|
||||
|
||||
assert_pointer "refs/heads/master" "a.txt" "$oid" "5"
|
||||
assert_local_object "$oid" "5"
|
||||
)
|
||||
end_test
|
||||
|
||||
begin_test "migrate import (non-standard refs)"
|
||||
(
|
||||
set -e
|
||||
|
||||
setup_multiple_local_branches_non_standard
|
||||
|
||||
md_oid="$(calc_oid "$(git cat-file -p :a.md)")"
|
||||
txt_oid="$(calc_oid "$(git cat-file -p :a.txt)")"
|
||||
md_feature_oid="$(calc_oid "$(git cat-file -p my-feature:a.md)")"
|
||||
|
||||
git lfs migrate import --everything
|
||||
|
||||
assert_pointer "refs/heads/master" "a.md" "$md_oid" "140"
|
||||
assert_pointer "refs/heads/master" "a.txt" "$txt_oid" "120"
|
||||
assert_pointer "refs/pull/1/base" "a.md" "$md_oid" "140"
|
||||
assert_pointer "refs/pull/1/base" "a.txt" "$txt_oid" "120"
|
||||
|
||||
assert_pointer "refs/heads/my-feature" "a.txt" "$txt_oid" "120"
|
||||
assert_pointer "refs/pull/1/head" "a.txt" "$txt_oid" "120"
|
||||
|
||||
assert_local_object "$md_oid" "140"
|
||||
assert_local_object "$txt_oid" "120"
|
||||
assert_local_object "$md_feature_oid" "30"
|
||||
)
|
||||
end_test
|
@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/test-migrate-fixtures.sh"
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/fixtures/migrate.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
begin_test "migrate info (default branch)"
|
||||
(
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
# these tests rely on GIT_TERMINAL_PROMPT to test properly
|
||||
ensure_git_version_isnt $VERSION_LOWER "2.3.0"
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
|
||||
begin_test "pointer --file --stdin"
|
||||
@ -110,6 +110,7 @@ begin_test "pointer --stdin without stdin"
|
||||
|
||||
[ "1" = "$status" ]
|
||||
)
|
||||
end_test
|
||||
|
||||
begin_test "pointer --stdin with bad pointer"
|
||||
(
|
||||
@ -126,6 +127,7 @@ Pointer file error: invalid header"
|
||||
|
||||
[ "1" = "$status" ]
|
||||
)
|
||||
end_test
|
||||
|
||||
begin_test "pointer --file --pointer mismatch"
|
||||
(
|
||||
@ -239,7 +241,7 @@ begin_test "pointer invalid --pointer"
|
||||
|
||||
expected="Pointer from some-pointer
|
||||
|
||||
Pointer file error: invalid header
|
||||
Pointer file error: invalid header"
|
||||
|
||||
diff -u <(printf "$expected") <(printf "$output")
|
||||
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
begin_test "post-checkout"
|
||||
(
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
begin_test "post-commit"
|
||||
(
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
begin_test "post-merge"
|
||||
(
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
begin_test "pre-push with good ref"
|
||||
(
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
begin_test "progress meter displays positive progress"
|
||||
(
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
reponame="$(basename "$0" ".sh")"
|
||||
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
ensure_git_version_isnt $VERSION_LOWER "2.5.0"
|
||||
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
begin_test "prune unreferenced and old"
|
||||
(
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
begin_test "pull"
|
||||
(
|
||||
@ -149,7 +149,7 @@ begin_test "pull without clean filter"
|
||||
(
|
||||
set -e
|
||||
|
||||
GIT_LFS_SKIP_SMUDGE=1 git clone $GITSERVER/test-pull no-clean
|
||||
GIT_LFS_SKIP_SMUDGE=1 git clone $GITSERVER/t-pull no-clean
|
||||
cd no-clean
|
||||
git lfs uninstall
|
||||
git config --list > config.txt
|
||||
@ -198,7 +198,7 @@ begin_test "pull with raw remote url"
|
||||
git init
|
||||
git lfs install --local --skip-smudge
|
||||
|
||||
git remote add origin $GITSERVER/test-pull
|
||||
git remote add origin $GITSERVER/t-pull
|
||||
git pull origin master
|
||||
|
||||
contents="a"
|
||||
@ -208,7 +208,7 @@ begin_test "pull with raw remote url"
|
||||
refute_local_object "$contents_oid"
|
||||
grep "$contents_oid" a.dat
|
||||
|
||||
git lfs pull "$GITSERVER/test-pull"
|
||||
git lfs pull "$GITSERVER/t-pull"
|
||||
echo "pulled!"
|
||||
|
||||
# LFS object downloaded and in working directory
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
ensure_git_version_isnt $VERSION_LOWER "2.3.0"
|
||||
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. "test/testlib.sh"
|
||||
. "$(dirname "$0")/testlib.sh"
|
||||
|
||||
begin_test "push with missing objects (lfs.allowincompletepush true)"
|
||||
(
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user