mirror of
https://github.com/argoproj/argo-cd
synced 2026-04-21 17:07:16 +00:00
* Add support for LFS enabled repositories
This commit is contained in:
parent
6049a49114
commit
8f3a6047b2
23 changed files with 581 additions and 391 deletions
|
|
@ -151,6 +151,15 @@ commands:
|
|||
sudo chmod +x /usr/local/bin/protoc
|
||||
sudo unzip /tmp/dl/protoc.zip include/* -d /usr/local/
|
||||
protoc --version
|
||||
- run:
|
||||
name: Install Git LFS plugin
|
||||
command: |
|
||||
set -x
|
||||
curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | sudo bash
|
||||
sleep 5
|
||||
sudo killall -9 apt-get || true
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y git-lfs openssh-client
|
||||
- save_cache:
|
||||
key: dl-v4
|
||||
paths:
|
||||
|
|
|
|||
|
|
@ -6,11 +6,14 @@ ARG BASE_IMAGE=debian:9.5-slim
|
|||
####################################################################################################
|
||||
FROM golang:1.12.6 as builder
|
||||
|
||||
RUN echo 'deb http://deb.debian.org/debian stretch-backports main' >> /etc/apt/sources.list
|
||||
|
||||
RUN apt-get update && apt-get install -y \
|
||||
openssh-server \
|
||||
nginx \
|
||||
fcgiwrap \
|
||||
git \
|
||||
git-lfs \
|
||||
make \
|
||||
wget \
|
||||
gcc \
|
||||
|
|
@ -101,12 +104,14 @@ FROM $BASE_IMAGE as argocd-base
|
|||
|
||||
USER root
|
||||
|
||||
RUN echo 'deb http://deb.debian.org/debian stretch-backports main' >> /etc/apt/sources.list
|
||||
|
||||
RUN groupadd -g 999 argocd && \
|
||||
useradd -r -u 999 -g argocd argocd && \
|
||||
mkdir -p /home/argocd && \
|
||||
chown argocd:argocd /home/argocd && \
|
||||
apt-get update && \
|
||||
apt-get install -y git && \
|
||||
apt-get install -y git git-lfs && \
|
||||
apt-get clean && \
|
||||
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
||||
|
||||
|
|
|
|||
1
Gopkg.lock
generated
1
Gopkg.lock
generated
|
|
@ -1606,7 +1606,6 @@
|
|||
"github.com/gogo/protobuf/proto",
|
||||
"github.com/gogo/protobuf/protoc-gen-gofast",
|
||||
"github.com/gogo/protobuf/protoc-gen-gogofast",
|
||||
"github.com/gogo/protobuf/sortkeys",
|
||||
"github.com/golang/protobuf/proto",
|
||||
"github.com/golang/protobuf/protoc-gen-go",
|
||||
"github.com/golang/protobuf/ptypes/empty",
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@
|
|||
"ApplicationService"
|
||||
],
|
||||
"summary": "List returns list of applications",
|
||||
"operationId": "ListMixin6",
|
||||
"operationId": "ListMixin1",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
|
|
@ -89,7 +89,7 @@
|
|||
"ApplicationService"
|
||||
],
|
||||
"summary": "Create creates an application",
|
||||
"operationId": "CreateMixin6",
|
||||
"operationId": "CreateMixin1",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "body",
|
||||
|
|
@ -116,7 +116,7 @@
|
|||
"ApplicationService"
|
||||
],
|
||||
"summary": "Update updates an application",
|
||||
"operationId": "UpdateMixin6",
|
||||
"operationId": "UpdateMixin1",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
|
|
@ -197,7 +197,7 @@
|
|||
"ApplicationService"
|
||||
],
|
||||
"summary": "Get returns an application by name",
|
||||
"operationId": "GetMixin6",
|
||||
"operationId": "Get",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
|
|
@ -238,7 +238,7 @@
|
|||
"ApplicationService"
|
||||
],
|
||||
"summary": "Delete deletes an application",
|
||||
"operationId": "DeleteMixin6",
|
||||
"operationId": "DeleteMixin1",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
|
|
@ -852,7 +852,7 @@
|
|||
"ClusterService"
|
||||
],
|
||||
"summary": "List returns list of clusters",
|
||||
"operationId": "List",
|
||||
"operationId": "ListMixin3",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
|
|
@ -874,7 +874,7 @@
|
|||
"ClusterService"
|
||||
],
|
||||
"summary": "Create creates a cluster",
|
||||
"operationId": "Create",
|
||||
"operationId": "CreateMixin3",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "body",
|
||||
|
|
@ -901,7 +901,7 @@
|
|||
"ClusterService"
|
||||
],
|
||||
"summary": "Update updates a cluster",
|
||||
"operationId": "Update",
|
||||
"operationId": "UpdateMixin3",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
|
|
@ -934,7 +934,7 @@
|
|||
"ClusterService"
|
||||
],
|
||||
"summary": "Get returns a cluster by server address",
|
||||
"operationId": "GetMixin1",
|
||||
"operationId": "GetMixin3",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
|
|
@ -957,7 +957,7 @@
|
|||
"ClusterService"
|
||||
],
|
||||
"summary": "Delete deletes a cluster",
|
||||
"operationId": "Delete",
|
||||
"operationId": "DeleteMixin3",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
|
|
@ -1239,7 +1239,7 @@
|
|||
"RepositoryService"
|
||||
],
|
||||
"summary": "List returns list of repos",
|
||||
"operationId": "ListMixin2",
|
||||
"operationId": "List",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
|
|
@ -1261,7 +1261,7 @@
|
|||
"RepositoryService"
|
||||
],
|
||||
"summary": "Create creates a repo",
|
||||
"operationId": "CreateMixin2",
|
||||
"operationId": "Create",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "body",
|
||||
|
|
@ -1288,7 +1288,7 @@
|
|||
"RepositoryService"
|
||||
],
|
||||
"summary": "Update updates a repo",
|
||||
"operationId": "UpdateMixin2",
|
||||
"operationId": "Update",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
|
|
@ -1321,7 +1321,7 @@
|
|||
"RepositoryService"
|
||||
],
|
||||
"summary": "Delete deletes a repo",
|
||||
"operationId": "DeleteMixin2",
|
||||
"operationId": "Delete",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
|
|
@ -1500,7 +1500,7 @@
|
|||
"SettingsService"
|
||||
],
|
||||
"summary": "Get returns Argo CD settings",
|
||||
"operationId": "Get",
|
||||
"operationId": "GetMixin5",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "(empty)",
|
||||
|
|
@ -3255,6 +3255,11 @@
|
|||
"connectionState": {
|
||||
"$ref": "#/definitions/v1alpha1ConnectionState"
|
||||
},
|
||||
"enableLfs": {
|
||||
"type": "boolean",
|
||||
"format": "boolean",
|
||||
"title": "Whether git-lfs support should be enabled for this repo"
|
||||
},
|
||||
"insecure": {
|
||||
"type": "boolean",
|
||||
"format": "boolean",
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ func NewRepoAddCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
|
|||
sshPrivateKeyPath string
|
||||
insecureIgnoreHostKey bool
|
||||
insecureSkipServerVerification bool
|
||||
enableLfs bool
|
||||
)
|
||||
var command = &cobra.Command{
|
||||
Use: "add REPO",
|
||||
|
|
@ -63,6 +64,7 @@ func NewRepoAddCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
|
|||
// InsecureIgnoreHostKey is deprecated and only here for backwards compat
|
||||
repo.InsecureIgnoreHostKey = insecureIgnoreHostKey
|
||||
repo.Insecure = insecureSkipServerVerification
|
||||
repo.EnableLFS = enableLfs
|
||||
|
||||
conn, repoIf := argocdclient.NewClientOrDie(clientOpts).NewRepoClientOrDie()
|
||||
defer util.Close(conn)
|
||||
|
|
@ -100,6 +102,7 @@ func NewRepoAddCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
|
|||
command.Flags().StringVar(&sshPrivateKeyPath, "ssh-private-key-path", "", "path to the private ssh key (e.g. ~/.ssh/id_rsa)")
|
||||
command.Flags().BoolVar(&insecureIgnoreHostKey, "insecure-ignore-host-key", false, "disables SSH strict host key checking (deprecated, use --insecure-skip-server-validation instead)")
|
||||
command.Flags().BoolVar(&insecureSkipServerVerification, "insecure-skip-server-verification", false, "disables server certificate and host key checks")
|
||||
command.Flags().BoolVar(&enableLfs, "enable-lfs", false, "enable git-lfs (Large File Support) on this repository")
|
||||
command.Flags().BoolVar(&upsert, "upsert", false, "Override an existing repository with the same name even if the spec differs")
|
||||
return command
|
||||
}
|
||||
|
|
@ -128,7 +131,7 @@ func NewRepoRemoveCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command
|
|||
// Print table of repo info
|
||||
func printRepoTable(repos []appsv1.Repository) {
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||
fmt.Fprintf(w, "REPO\tINSECURE\tUSER\tSTATUS\tMESSAGE\n")
|
||||
fmt.Fprintf(w, "REPO\tINSECURE\tLFS\tUSER\tSTATUS\tMESSAGE\n")
|
||||
for _, r := range repos {
|
||||
var username string
|
||||
if r.Username == "" {
|
||||
|
|
@ -136,7 +139,7 @@ func printRepoTable(repos []appsv1.Repository) {
|
|||
} else {
|
||||
username = r.Username
|
||||
}
|
||||
fmt.Fprintf(w, "%s\t%v\t%s\t%s\t%s\n", r.Repo, r.Insecure, username, r.ConnectionState.Status, r.ConnectionState.Message)
|
||||
fmt.Fprintf(w, "%s\t%v\t%v\t%s\t%s\t%s\n", r.Repo, r.IsInsecure(), r.EnableLFS, username, r.ConnectionState.Status, r.ConnectionState.Message)
|
||||
}
|
||||
_ = w.Flush()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ API rule violation: names_match,github.com/argoproj/argo-cd/pkg/apis/application
|
|||
API rule violation: names_match,github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1,ConnectionState,ModifiedAt
|
||||
API rule violation: names_match,github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1,JWTToken,ExpiresAt
|
||||
API rule violation: names_match,github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1,JWTToken,IssuedAt
|
||||
API rule violation: names_match,github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1,Repository,EnableLFS
|
||||
API rule violation: names_match,github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1,RepositoryCertificate,CertData
|
||||
API rule violation: names_match,github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1,RepositoryCertificate,CertFingerprint
|
||||
API rule violation: names_match,github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1,RepositoryCertificate,CertSubType
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -503,6 +503,9 @@ message Repository {
|
|||
|
||||
// Whether the repo is insecure
|
||||
optional bool insecure = 7;
|
||||
|
||||
// Whether git-lfs support should be enabled for this repo
|
||||
optional bool enableLfs = 8;
|
||||
}
|
||||
|
||||
// A RepositoryCertificate is either SSH known hosts entry or TLS certificate
|
||||
|
|
|
|||
|
|
@ -1796,6 +1796,13 @@ func schema_pkg_apis_application_v1alpha1_Repository(ref common.ReferenceCallbac
|
|||
Format: "",
|
||||
},
|
||||
},
|
||||
"enableLfs": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Whether git-lfs support should be enabled for this repo",
|
||||
Type: []string{"boolean"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"repo"},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -895,12 +895,18 @@ type Repository struct {
|
|||
InsecureIgnoreHostKey bool `json:"insecureIgnoreHostKey,omitempty" protobuf:"bytes,6,opt,name=insecureIgnoreHostKey"`
|
||||
// Whether the repo is insecure
|
||||
Insecure bool `json:"insecure,omitempty" protobuf:"bytes,7,opt,name=insecure"`
|
||||
// Whether git-lfs support should be enabled for this repo
|
||||
EnableLFS bool `json:"enableLfs,omitempty" protobuf:"bytes,8,opt,name=enableLfs"`
|
||||
}
|
||||
|
||||
func (repo *Repository) IsInsecure() bool {
|
||||
return repo.InsecureIgnoreHostKey || repo.Insecure
|
||||
}
|
||||
|
||||
func (repo *Repository) IsLFSEnabled() bool {
|
||||
return repo.EnableLFS
|
||||
}
|
||||
|
||||
func (m *Repository) HasCredentials() bool {
|
||||
return m.Username != "" || m.Password != "" || m.SSHPrivateKey != "" || m.InsecureIgnoreHostKey
|
||||
}
|
||||
|
|
@ -912,6 +918,7 @@ func (m *Repository) CopyCredentialsFrom(source *Repository) {
|
|||
m.SSHPrivateKey = source.SSHPrivateKey
|
||||
m.InsecureIgnoreHostKey = source.InsecureIgnoreHostKey
|
||||
m.Insecure = source.Insecure
|
||||
m.EnableLFS = source.EnableLFS
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,10 @@ func (w *gitClientWrapper) LsFiles(path string) ([]string, error) {
|
|||
return w.client.LsFiles(path)
|
||||
}
|
||||
|
||||
func (w *gitClientWrapper) LsLargeFiles() ([]string, error) {
|
||||
return w.client.LsLargeFiles()
|
||||
}
|
||||
|
||||
func (w *gitClientWrapper) Checkout(revision string) error {
|
||||
return w.client.Checkout(revision)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,8 +53,8 @@ func (m *MetricsServer) IncGitRequest(repo string, requestType GitRequestType) {
|
|||
m.gitRequestCounter.WithLabelValues(repo, string(requestType)).Inc()
|
||||
}
|
||||
|
||||
func (m *MetricsServer) NewClient(repoURL string, path string, creds git.Creds, insecureIgnoreHostKey bool) (git.Client, error) {
|
||||
client, err := m.gitClientFactory.NewClient(repoURL, path, creds, insecureIgnoreHostKey)
|
||||
func (m *MetricsServer) NewClient(repoURL string, path string, creds git.Creds, insecureIgnoreHostKey bool, lfsEnabled bool) (git.Client, error) {
|
||||
client, err := m.gitClientFactory.NewClient(repoURL, path, creds, insecureIgnoreHostKey, lfsEnabled)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -526,7 +526,7 @@ func (s *Service) newClientResolveRevision(repo *v1alpha1.Repository, revision s
|
|||
|
||||
func (s *Service) newClient(repo *v1alpha1.Repository) (git.Client, error) {
|
||||
appPath := tempRepoPath(git.NormalizeGitURL(repo.Repo))
|
||||
return s.gitFactory.NewClient(repo.Repo, appPath, argo.GetRepoCreds(repo), repo.IsInsecure())
|
||||
return s.gitFactory.NewClient(repo.Repo, appPath, argo.GetRepoCreds(repo), repo.IsInsecure(), repo.EnableLFS)
|
||||
}
|
||||
|
||||
func runCommand(command v1alpha1.Command, path string, env []string) (string, error) {
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ type fakeGitClientFactory struct {
|
|||
revisionMetadata *git.RevisionMetadata
|
||||
}
|
||||
|
||||
func (f *fakeGitClientFactory) NewClient(repoURL string, path string, creds git.Creds, insecureIgnoreHostKey bool) (git.Client, error) {
|
||||
func (f *fakeGitClientFactory) NewClient(repoURL string, path string, creds git.Creds, insecureIgnoreHostKey bool, enableLfs bool) (git.Client, error) {
|
||||
mockClient := gitmocks.Client{}
|
||||
root := "./testdata"
|
||||
if f.root != "" {
|
||||
|
|
|
|||
|
|
@ -962,7 +962,7 @@ func (s *Server) resolveRevision(ctx context.Context, app *appv1.Application, sy
|
|||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
gitClient, err := s.gitFactory.NewClient(repo.Repo, "", argoutil.GetRepoCreds(repo), repo.IsInsecure())
|
||||
gitClient, err := s.gitFactory.NewClient(repo.Repo, "", argoutil.GetRepoCreds(repo), repo.IsInsecure(), repo.IsLFSEnabled())
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ func (s *Server) getConnectionState(ctx context.Context, url string) appsv1.Conn
|
|||
}
|
||||
repo, err := s.db.GetRepository(ctx, url)
|
||||
if err == nil {
|
||||
err = git.TestRepo(repo.Repo, argo.GetRepoCreds(repo), repo.IsInsecure())
|
||||
err = git.TestRepo(repo.Repo, argo.GetRepoCreds(repo), repo.IsInsecure(), repo.EnableLFS)
|
||||
}
|
||||
if err != nil {
|
||||
connectionState.Status = appsv1.ConnectionStatusFailed
|
||||
|
|
@ -86,7 +86,12 @@ func (s *Server) List(ctx context.Context, q *repositorypkg.RepoQuery) (*appsv1.
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, appsv1.Repository{Repo: url, Insecure: repo.IsInsecure(), Username: repo.Username})
|
||||
items = append(items, appsv1.Repository{
|
||||
Repo: url,
|
||||
Username: repo.Username,
|
||||
Insecure: repo.IsInsecure(),
|
||||
EnableLFS: repo.EnableLFS,
|
||||
})
|
||||
}
|
||||
}
|
||||
err = util.RunAllAsync(len(items), func(i int) error {
|
||||
|
|
@ -228,7 +233,7 @@ func (s *Server) Create(ctx context.Context, q *repositorypkg.RepoCreateRequest)
|
|||
return nil, err
|
||||
}
|
||||
r := q.Repo
|
||||
err := git.TestRepo(r.Repo, argo.GetRepoCreds(r), r.IsInsecure())
|
||||
err := git.TestRepo(r.Repo, argo.GetRepoCreds(r), r.IsInsecure(), r.EnableLFS)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -287,7 +292,7 @@ func (s *Server) ValidateAccess(ctx context.Context, q *repositorypkg.RepoAccess
|
|||
}
|
||||
|
||||
repo := &appsv1.Repository{Username: q.Username, Password: q.Password, SSHPrivateKey: q.SshPrivateKey, Insecure: q.Insecure}
|
||||
err := git.TestRepo(q.Repo, argo.GetRepoCreds(repo), q.Insecure)
|
||||
err := git.TestRepo(q.Repo, argo.GetRepoCreds(repo), q.Insecure, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -179,7 +179,7 @@ func ValidateRepo(ctx context.Context, spec *argoappv1.ApplicationSpec, repoClie
|
|||
return nil, "", err
|
||||
}
|
||||
|
||||
err = git.TestRepo(repoRes.Repo, GetRepoCreds(repoRes), repoRes.IsInsecure())
|
||||
err = git.TestRepo(repoRes.Repo, GetRepoCreds(repoRes), repoRes.IsInsecure(), repoRes.EnableLFS)
|
||||
if err != nil {
|
||||
conditions = append(conditions, argoappv1.ApplicationCondition{
|
||||
Type: argoappv1.ApplicationConditionInvalidSpecError,
|
||||
|
|
|
|||
|
|
@ -64,8 +64,9 @@ func (db *db) CreateRepository(ctx context.Context, r *appsv1.Repository) (*apps
|
|||
|
||||
repoInfo := settings.RepoCredentials{
|
||||
URL: r.Repo,
|
||||
InsecureIgnoreHostKey: (r.InsecureIgnoreHostKey || r.Insecure),
|
||||
Insecure: (r.InsecureIgnoreHostKey || r.Insecure),
|
||||
InsecureIgnoreHostKey: r.IsInsecure(),
|
||||
Insecure: r.IsInsecure(),
|
||||
EnableLFS: r.EnableLFS,
|
||||
}
|
||||
err = db.updateSecrets(&repoInfo, r)
|
||||
if err != nil {
|
||||
|
|
@ -123,6 +124,7 @@ func (db *db) credentialsToRepository(repoInfo settings.RepoCredentials) (*appsv
|
|||
Repo: repoInfo.URL,
|
||||
InsecureIgnoreHostKey: repoInfo.InsecureIgnoreHostKey,
|
||||
Insecure: repoInfo.Insecure,
|
||||
EnableLFS: repoInfo.EnableLFS,
|
||||
}
|
||||
err := db.unmarshalFromSecretsStr(map[*string]*apiv1.SecretKeySelector{
|
||||
&repo.Username: repoInfo.UsernameSecret,
|
||||
|
|
@ -150,6 +152,12 @@ func (db *db) UpdateRepository(ctx context.Context, r *appsv1.Repository) (*apps
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Update boolean settings
|
||||
repoInfo.InsecureIgnoreHostKey = r.IsInsecure()
|
||||
repoInfo.Insecure = r.IsInsecure()
|
||||
repoInfo.EnableLFS = r.EnableLFS
|
||||
|
||||
repos[index] = repoInfo
|
||||
err = db.settingsMgr.SaveRepositories(repos)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ type Client interface {
|
|||
Checkout(revision string) error
|
||||
LsRemote(revision string) (string, error)
|
||||
LsFiles(path string) ([]string, error)
|
||||
LsLargeFiles() ([]string, error)
|
||||
CommitSHA() (string, error)
|
||||
RevisionMetadata(revision string) (*RevisionMetadata, error)
|
||||
}
|
||||
|
|
@ -48,7 +49,7 @@ type Client interface {
|
|||
// ClientFactory is a factory of Git Clients
|
||||
// Primarily used to support creation of mock git clients during unit testing
|
||||
type ClientFactory interface {
|
||||
NewClient(rawRepoURL string, path string, creds Creds, insecure bool) (Client, error)
|
||||
NewClient(rawRepoURL string, path string, creds Creds, insecure bool, enableLfs bool) (Client, error)
|
||||
}
|
||||
|
||||
// nativeGitClient implements Client interface using git CLI
|
||||
|
|
@ -61,6 +62,8 @@ type nativeGitClient struct {
|
|||
creds Creds
|
||||
// Whether to connect insecurely to repository, e.g. don't verify certificate
|
||||
insecure bool
|
||||
// Whether the repository is LFS enabled
|
||||
enableLfs bool
|
||||
}
|
||||
|
||||
type factory struct{}
|
||||
|
|
@ -69,20 +72,13 @@ func NewFactory() ClientFactory {
|
|||
return &factory{}
|
||||
}
|
||||
|
||||
func (f *factory) NewClient(rawRepoURL string, path string, creds Creds, insecure bool) (Client, error) {
|
||||
// We need a custom HTTP client for go-git when we want to skip validation
|
||||
// of the server's TLS certificate (--insecure-ignore-server-cert). Since
|
||||
// this change is permanent to go-git Client during runtime, we need to
|
||||
// explicitly replace it with default client for repositories without the
|
||||
// insecure flag set.
|
||||
//if IsHTTPSURL(rawRepoURL) {
|
||||
// gitclient.InstallProtocol("https", githttp.NewClient(getRepoHTTPClient(rawRepoURL, insecure)))
|
||||
//}
|
||||
func (f *factory) NewClient(rawRepoURL string, path string, creds Creds, insecure bool, enableLfs bool) (Client, error) {
|
||||
client := nativeGitClient{
|
||||
repoURL: rawRepoURL,
|
||||
root: path,
|
||||
creds: creds,
|
||||
insecure: insecure,
|
||||
repoURL: rawRepoURL,
|
||||
root: path,
|
||||
creds: creds,
|
||||
insecure: insecure,
|
||||
enableLfs: enableLfs,
|
||||
}
|
||||
return &client, nil
|
||||
}
|
||||
|
|
@ -200,9 +196,24 @@ func (m *nativeGitClient) Init() error {
|
|||
return err
|
||||
}
|
||||
|
||||
// Returns true if the repository is LFS enabled
|
||||
func (m *nativeGitClient) IsLFSEnabled() bool {
|
||||
return m.enableLfs
|
||||
}
|
||||
|
||||
// Fetch fetches latest updates from origin
|
||||
func (m *nativeGitClient) Fetch() error {
|
||||
_, err := m.runCredentialedCmd("git", "fetch", "origin", "--tags", "--force")
|
||||
// When we have LFS support enabled, check for large files and fetch them too.
|
||||
if err == nil && m.IsLFSEnabled() {
|
||||
largeFiles, err := m.LsLargeFiles()
|
||||
if err == nil && len(largeFiles) > 0 {
|
||||
_, err = m.runCredentialedCmd("git", "lfs", "fetch", "--all")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
@ -217,6 +228,16 @@ func (m *nativeGitClient) LsFiles(path string) ([]string, error) {
|
|||
return ss[:len(ss)-1], nil
|
||||
}
|
||||
|
||||
// LsLargeFiles lists all files that have references to LFS storage
|
||||
func (m *nativeGitClient) LsLargeFiles() ([]string, error) {
|
||||
out, err := m.runCmd("lfs", "ls-files", "-n")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ss := strings.Split(out, "\n")
|
||||
return ss, nil
|
||||
}
|
||||
|
||||
// Checkout checkout specified git sha
|
||||
func (m *nativeGitClient) Checkout(revision string) error {
|
||||
if revision == "" || revision == "HEAD" {
|
||||
|
|
@ -225,6 +246,19 @@ func (m *nativeGitClient) Checkout(revision string) error {
|
|||
if _, err := m.runCmd("checkout", "--force", revision); err != nil {
|
||||
return err
|
||||
}
|
||||
// We must populate LFS content by using lfs checkout, if we have at least
|
||||
// one LFS reference in the current revision.
|
||||
if m.IsLFSEnabled() {
|
||||
if largeFiles, err := m.LsLargeFiles(); err == nil {
|
||||
if len(largeFiles) > 0 {
|
||||
if _, err := m.runCmd("lfs", "checkout"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if _, err := m.runCmd("clean", "-fdx"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -361,9 +395,12 @@ func (m *nativeGitClient) runCredentialedCmd(command string, args ...string) (st
|
|||
func (m *nativeGitClient) runCmdOutput(cmd *exec.Cmd) (string, error) {
|
||||
cmd.Dir = m.root
|
||||
cmd.Env = append(cmd.Env, os.Environ()...)
|
||||
// Set $HOME to nowhere, so we can be execute Git regardless of any external
|
||||
// authentication keys (e.g. in ~/.ssh) -- this is especially important for
|
||||
// running tests on local machines and/or CircleCI.
|
||||
cmd.Env = append(cmd.Env, "HOME=/dev/null")
|
||||
cmd.Env = append(cmd.Env, "GIT_CONFIG_NOSYSTEM=true")
|
||||
cmd.Env = append(cmd.Env, "GIT_CONFIG_NOGLOBAL=true")
|
||||
// Skip LFS for most Git operations except when explicitly requested
|
||||
cmd.Env = append(cmd.Env, "GIT_LFS_SKIP_SMUDGE=1")
|
||||
log.Debug(strings.Join(cmd.Args, " "))
|
||||
return argoexec.RunCommandExt(cmd, argoconfig.CmdOpts())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,8 +78,8 @@ func IsHTTPSURL(url string) bool {
|
|||
}
|
||||
|
||||
// TestRepo tests if a repo exists and is accessible with the given credentials
|
||||
func TestRepo(repo string, creds Creds, insecure bool) error {
|
||||
clnt, err := NewFactory().NewClient(repo, "", creds, insecure)
|
||||
func TestRepo(repo string, creds Creds, insecure bool, enableLfs bool) error {
|
||||
clnt, err := NewFactory().NewClient(repo, "", creds, insecure, enableLfs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package git
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
|
@ -107,7 +108,7 @@ func TestSameURL(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestLsRemote(t *testing.T) {
|
||||
clnt, err := NewFactory().NewClient("https://github.com/argoproj/argo-cd.git", "/tmp", NopCreds{}, false)
|
||||
clnt, err := NewFactory().NewClient("https://github.com/argoproj/argo-cd.git", "/tmp", NopCreds{}, false, false)
|
||||
assert.NoError(t, err)
|
||||
xpass := []string{
|
||||
"HEAD",
|
||||
|
|
@ -139,6 +140,46 @@ func TestLsRemote(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// Running this test requires git-lfs to be installed on your machine.
|
||||
func TestLFSClient(t *testing.T) {
|
||||
tempDir, err := ioutil.TempDir("", "git-client-lfs-test-")
|
||||
assert.NoError(t, err)
|
||||
if err == nil {
|
||||
defer func() { _ = os.RemoveAll(tempDir) }()
|
||||
}
|
||||
|
||||
client, err := NewFactory().NewClient("https://github.com/argoproj-labs/argocd-testrepo-lfs", tempDir, NopCreds{}, false, true)
|
||||
assert.NoError(t, err)
|
||||
|
||||
commitSHA, err := client.LsRemote("HEAD")
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, "", commitSHA)
|
||||
|
||||
err = client.Init()
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = client.Fetch()
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = client.Checkout(commitSHA)
|
||||
assert.NoError(t, err)
|
||||
|
||||
largeFiles, err := client.LsLargeFiles()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 3, len(largeFiles))
|
||||
|
||||
fileHandle, err := os.Open(fmt.Sprintf("%s/test3.yaml", tempDir))
|
||||
assert.NoError(t, err)
|
||||
if err == nil {
|
||||
defer fileHandle.Close()
|
||||
text, err := ioutil.ReadAll(fileHandle)
|
||||
assert.NoError(t, err)
|
||||
if err == nil {
|
||||
assert.Equal(t, "This is not a YAML, sorry.\n", string(text))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewFactory(t *testing.T) {
|
||||
addBinDirToPath := path.NewBinDirToPath()
|
||||
defer addBinDirToPath.Close()
|
||||
|
|
@ -166,7 +207,7 @@ func TestNewFactory(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
defer func() { _ = os.RemoveAll(dirName) }()
|
||||
|
||||
client, err := NewFactory().NewClient(tt.args.url, dirName, NopCreds{}, tt.args.insecureIgnoreHostKey)
|
||||
client, err := NewFactory().NewClient(tt.args.url, dirName, NopCreds{}, tt.args.insecureIgnoreHostKey, false)
|
||||
assert.NoError(t, err)
|
||||
commitSHA, err := client.LsRemote("HEAD")
|
||||
assert.NoError(t, err)
|
||||
|
|
|
|||
|
|
@ -96,6 +96,29 @@ func (_m *Client) LsFiles(path string) ([]string, error) {
|
|||
return r0, r1
|
||||
}
|
||||
|
||||
// LsLargeFiles provides a mock function with given fields:
|
||||
func (_m *Client) LsLargeFiles() ([]string, error) {
|
||||
ret := _m.Called()
|
||||
|
||||
var r0 []string
|
||||
if rf, ok := ret.Get(0).(func() []string); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]string)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func() error); ok {
|
||||
r1 = rf()
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// LsRemote provides a mock function with given fields: revision
|
||||
func (_m *Client) LsRemote(revision string) (string, error) {
|
||||
ret := _m.Called(revision)
|
||||
|
|
|
|||
|
|
@ -94,6 +94,8 @@ type RepoCredentials struct {
|
|||
InsecureIgnoreHostKey bool `json:"insecureIgnoreHostKey,omitempty"`
|
||||
// Whether to connect the repository in an insecure way
|
||||
Insecure bool `json:"insecure,omitempty"`
|
||||
// Whether the repo is git-lfs enabled
|
||||
EnableLFS bool `json:"enableLfs,omitempty"`
|
||||
}
|
||||
|
||||
type HelmRepoCredentials struct {
|
||||
|
|
|
|||
Loading…
Reference in a new issue