diff --git a/.gitignore b/.gitignore index c795b05..d76b74e 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -build \ No newline at end of file +build +.DS_Store diff --git a/CHANGELOG.md b/CHANGELOG.md index 16ff8d3..51f839e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,19 @@ All notable changes will be documented here. +## [v2.0.0] - 2025-09-08 + +- upgrade gitopia version to v6.0.0 and gitopia-go version to v0.7.0 +- automatic selection of storage provider with the least latency +- add liveness check for storage providers and remove gitserver host from default config +- handle lfs url config using inline configuration removing .lfsconfig dependency +- fix clone of lfs repositories +- minimal logging improvements and redirect git command stdout to stderr to avoid protocol issues +- pass current state of repository packfile in set branch and tag requests +- approve packfile update and lfs object updates in remote helper +- prevent duplicate git hooks calls inside remote helper and improve code to do single push instead of multiple push calls for each ref update +- git push request now goes to storage provider even for delete branch or tag operations + ## [v1.10.0] - 2024-12-02 - upgrade gitopia version to v5.1.0 diff --git a/cmd/git-gitopia/lfs/init.go b/cmd/git-gitopia/lfs/init.go deleted file mode 100644 index ad054be..0000000 --- a/cmd/git-gitopia/lfs/init.go +++ /dev/null @@ -1,98 +0,0 @@ -package lfs - -import ( - "context" - "fmt" - "io/fs" - "os" - "os/exec" - "path" - "strings" - - "github.com/cosmos/cosmos-sdk/codec" - codectypes "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/gitopia/git-remote-gitopia/config" - "github.com/gitopia/git-remote-gitopia/core" - "github.com/gitopia/git-remote-gitopia/core/api" - gitopiatypes "github.com/gitopia/gitopia/v5/x/gitopia/types" - "github.com/pkg/errors" - "github.com/spf13/cobra" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials/insecure" -) - -func InitCommand() *cobra.Command { - cmd := &cobra.Command{ - Use: "init ", - Short: "Initialize the lfsconfig for the gitopia remote", - Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - dir := path.Dir(os.Getenv("GIT_DIR")) - if dir == "" { - return errors.New("not a git repository") - } - - lfsConfigPath := path.Join(dir, ".lfsconfig") - if _, err := os.Stat(lfsConfigPath); !errors.Is(err, fs.ErrNotExist) { - return errors.New(".lfsconfig file already exists") - - } - - c := exec.Command("git", "remote", "get-url", args[0]) - output, err := c.Output() - if err != nil { - return errors.Wrap(err, "error reading the remote url") - } - - remoteURL := strings.TrimSpace(string(output)) - remoteUserId, remoteRepositoryName, err := core.ValidateGitopiaRemoteURL(string(remoteURL)) - if err != nil { - return err - } - - interfaceRegistry := codectypes.NewInterfaceRegistry() - - grpcHost, _ := config.GitConfigGet(config.GitopiaConfigGRPCHostOption) - if grpcHost == "" || !api.CheckGRPCHostLiveness(grpcHost) { - provider := api.GetBestApiProvider() - if err := api.SetConfiguredGRPCHost(provider.GRPCHost); err != nil { - return err - } - } - - grpcConn, err := grpc.Dial(grpcHost, - grpc.WithTransportCredentials(insecure.NewCredentials()), - grpc.WithDefaultCallOptions(grpc.ForceCodec(codec.NewProtoCodec(interfaceRegistry).GRPCCodec())), - ) - if err != nil { - return err - } - defer grpcConn.Close() - - queryClient := gitopiatypes.NewQueryClient(grpcConn) - - // Get RepositoryId - res, err := queryClient.AnyRepository(context.Background(), &gitopiatypes.QueryGetAnyRepositoryRequest{ - Id: remoteUserId, - RepositoryName: remoteRepositoryName, - }) - if err != nil { - return err - } - - remoteRepository := *res.Repository - lfsURL := fmt.Sprintf("%v/%v.git", config.GitServerHost, remoteRepository.Id) - - c = core.GitCommand("git", "config", - fmt.Sprintf("--file=%s", lfsConfigPath), - "lfs.url", - lfsURL) - if err := c.Run(); err != nil { - return errors.Wrap(err, "error creating .lfsconfig") - } - - return nil - }, - } - return cmd -} diff --git a/cmd/git-gitopia/lfs/root.go b/cmd/git-gitopia/lfs/root.go deleted file mode 100644 index fa15109..0000000 --- a/cmd/git-gitopia/lfs/root.go +++ /dev/null @@ -1,18 +0,0 @@ -package lfs - -import ( - "github.com/spf13/cobra" -) - -func Commands() *cobra.Command { - cmd := &cobra.Command{ - Use: "lfs", - Short: "Configure the lfsconfig for the gitopia remote", - CompletionOptions: cobra.CompletionOptions{DisableDefaultCmd: true}, - PersistentPreRun: func(cmd *cobra.Command, _ []string) { - }, - } - cmd.AddCommand(InitCommand()) - - return cmd -} diff --git a/cmd/git-gitopia/root.go b/cmd/git-gitopia/root.go index f5d69c1..18f6137 100644 --- a/cmd/git-gitopia/root.go +++ b/cmd/git-gitopia/root.go @@ -2,7 +2,6 @@ package main import ( "github.com/cosmos/cosmos-sdk/client/keys" - "github.com/gitopia/git-remote-gitopia/cmd/git-gitopia/lfs" "github.com/gitopia/gitopia-go" "github.com/spf13/cobra" ) @@ -16,7 +15,6 @@ func RootCommand() *cobra.Command { }, } cmd.AddCommand(keys.Commands(".")) - cmd.AddCommand(lfs.Commands()) return cmd } diff --git a/cmd/git-remote-gitopia/gitopia.go b/cmd/git-remote-gitopia/gitopia.go index 7d1619b..85f2956 100644 --- a/cmd/git-remote-gitopia/gitopia.go +++ b/cmd/git-remote-gitopia/gitopia.go @@ -20,8 +20,9 @@ import ( core "github.com/gitopia/git-remote-gitopia/core" "github.com/gitopia/git-remote-gitopia/core/api" "github.com/gitopia/git-remote-gitopia/core/wallet" - gitopiatypes "github.com/gitopia/gitopia/v5/x/gitopia/types" - "github.com/gitopia/gitopia/v5/x/gitopia/utils" + gitopiatypes "github.com/gitopia/gitopia/v6/x/gitopia/types" + "github.com/gitopia/gitopia/v6/x/gitopia/utils" + storagetypes "github.com/gitopia/gitopia/v6/x/storage/types" "github.com/go-git/go-git/v5/plumbing" "github.com/pkg/errors" "google.golang.org/grpc" @@ -41,6 +42,7 @@ type GitopiaHandler struct { queryClient gitopiatypes.QueryClient feegrantClient feegrant.QueryClient bankClient banktypes.QueryClient + storageClient storagetypes.QueryClient chainId string remoteUserId string @@ -55,19 +57,43 @@ type GitopiaHandler struct { func (h *GitopiaHandler) Initialize(remote *core.Remote) error { var err error + // Check existing configuration grpcHost, _ := config.GitConfigGet(config.GitopiaConfigGRPCHostOption) tmAddr, _ := config.GitConfigGet(config.GitopiaConfigTmAddrOption) + + // Validate and configure gRPC and RPC hosts + needsReconfiguration := false if grpcHost == "" || tmAddr == "" || !api.CheckGRPCHostLiveness(grpcHost) || !api.CheckRPCHostLiveness(tmAddr) { + needsReconfiguration = true + } + + if needsReconfiguration { + remote.Logger.Printf("Configuring Gitopia hosts...") provider := api.GetBestApiProvider() grpcHost = provider.GRPCHost + tmAddr = provider.TMAddr + if err := api.SetConfiguredGRPCHost(provider.GRPCHost); err != nil { return err } + if err := api.SetConfiguredTmAddr(provider.TMAddr); err != nil { return err } } + // Check and configure Git server host + gitServerHost, _ := config.GitConfigGet(config.GitopiaConfigGitServerHostOption) + + if gitServerHost == "" || !api.CheckGitServerHostLiveness(gitServerHost) { + gitServerHost = api.GetBestGitServerHost(grpcHost) + if gitServerHost != "" { + if err := api.SetConfiguredGitServerHost(gitServerHost); err != nil { + return err + } + } + } + h.grpcConn, err = grpc.Dial(grpcHost, grpc.WithTransportCredentials(insecure.NewCredentials())) if err != nil { return err @@ -81,6 +107,7 @@ func (h *GitopiaHandler) Initialize(remote *core.Remote) error { serviceClient := tmservice.NewServiceClient(h.grpcConn) h.feegrantClient = feegrant.NewQueryClient(h.grpcConn) h.bankClient = banktypes.NewQueryClient(h.grpcConn) + h.storageClient = storagetypes.NewQueryClient(h.grpcConn) nodeInfoRes, err := serviceClient.GetNodeInfo(context.Background(), &tmservice.GetNodeInfoRequest{}) if err != nil { @@ -93,11 +120,19 @@ func (h *GitopiaHandler) Initialize(remote *core.Remote) error { RepositoryName: h.remoteRepositoryName, }) if err != nil { - return err + return errors.Wrap(err, fmt.Sprintf("error getting repository %s/%s", h.remoteUserId, h.remoteRepositoryName)) } h.remoteRepository = *res.Repository + // Configure LFS URL for clone operations to avoid SSH to non-existent "gitopia" hostname + lfsURL := fmt.Sprintf("%v/%v.git", gitServerHost, h.remoteRepository.Id) + cmd := core.GitCommand("git", "config", "--local", "lfs.url", lfsURL) + if err := cmd.Run(); err != nil { + // Log but don't fail if LFS config fails (repo might not have LFS) + remote.Logger.Printf("Warning: could not configure LFS URL: %v", err) + } + return nil } @@ -138,10 +173,16 @@ func (h *GitopiaHandler) List(remote *core.Remote, forPush bool) ([]string, erro } func (h *GitopiaHandler) Fetch(remote *core.Remote, refsToFetch []core.RefToFetch) error { - remoteURL := fmt.Sprintf("%v/%v.git", config.GitServerHost, h.remoteRepository.Id) + gitServerHost, err := config.GitConfigGet(config.GitopiaConfigGitServerHostOption) + if err != nil { + return err + } + remoteURL := fmt.Sprintf("%v/%v.git", gitServerHost, h.remoteRepository.Id) + lfsURL := remoteURL // Use same URL for LFS if !remote.Force { args := []string{ + "-c", fmt.Sprintf("lfs.url=%s", lfsURL), "fetch", "--no-write-fetch-head", remoteURL, @@ -165,6 +206,7 @@ func (h *GitopiaHandler) Fetch(remote *core.Remote, refsToFetch []core.RefToFetc } args := []string{ + "-c", fmt.Sprintf("lfs.url=%s", lfsURL), "fetch", "--no-write-fetch-head", remoteURL, @@ -214,41 +256,102 @@ func (h *GitopiaHandler) Push(remote *core.Remote, refsToPush []core.RefToPush) return nil, fmt.Errorf("fatal: you don't have write permissions to this repository") } - remoteURL := fmt.Sprintf("%v/%v.git", config.GitServerHost, h.remoteRepository.Id) + gitServerHost, err := config.GitConfigGet(config.GitopiaConfigGitServerHostOption) + if err != nil { + return nil, err + } + remoteURL := fmt.Sprintf("%v/%v.git", gitServerHost, h.remoteRepository.Id) + lfsURL := remoteURL // Use same URL for LFS - var newRemoteRefSha string + var allRefspecs []string var setBranches []gitopiatypes.MsgMultiSetBranch_Branch var setTags []gitopiatypes.MsgMultiSetTag_Tag var deleteBranches, deleteTags []string + isForce := false var res []string + var packfileCid string + + packfileRes, err := h.storageClient.RepositoryPackfile(context.Background(), &storagetypes.QueryRepositoryPackfileRequest{ + RepositoryId: h.remoteRepository.Id, + }) + if err == nil { + packfileCid = packfileRes.Packfile.Cid + } + // --- First Pass: Collect all refspecs and metadata --- for _, ref := range refsToPush { - if ref.Local == "" { + if ref.Local == "" { // This is a delete operation + var refNameToDelete string if strings.HasPrefix(ref.Remote, branchPrefix) { - remoteBranchName := strings.TrimPrefix(ref.Remote, branchPrefix) - - // Check if it's the default branch - if remoteBranchName == h.remoteRepository.DefaultBranch { - return nil, fmt.Errorf("fatal: cannot delete default branch, %v", remoteBranchName) - } - - deleteBranches = append(deleteBranches, remoteBranchName) - res = append(res, ref.Remote) - } else if strings.HasPrefix(refsToPush[0].Remote, tagPrefix) { - remoteTagName := strings.TrimPrefix(refsToPush[0].Remote, tagPrefix) - deleteTags = append(deleteTags, remoteTagName) - res = append(res, ref.Remote) + refNameToDelete = strings.TrimPrefix(ref.Remote, branchPrefix) + deleteBranches = append(deleteBranches, refNameToDelete) + } else if strings.HasPrefix(ref.Remote, tagPrefix) { + refNameToDelete = strings.TrimPrefix(ref.Remote, tagPrefix) + deleteTags = append(deleteTags, refNameToDelete) + } else { + continue // Skip unknown ref types } + // Add to the list of commands for the git server + // The syntax for delete is ":" + allRefspecs = append(allRefspecs, ":"+ref.Remote) + res = append(res, ref.Remote) continue } - force := false - if strings.HasPrefix(ref.Local, "+") { - ref.Local = strings.TrimPrefix(ref.Local, "+") - force = true + // This is a create/update operation + localRef := ref.Local + if strings.HasPrefix(localRef, "+") { + localRef = strings.TrimPrefix(localRef, "+") + isForce = true } + // Add to the list of commands for the git server + allRefspecs = append(allRefspecs, fmt.Sprintf("%s:%s", ref.Local, ref.Remote)) + + // Collect metadata for the blockchain transaction + if strings.HasPrefix(localRef, branchPrefix) { + localCommitHash, err := remote.Repo.ResolveRevision(plumbing.Revision(localRef)) + if err != nil { + return nil, fmt.Errorf("fatal: local branch %s doesn't exist", localRef) + } + + remoteBranchName := strings.TrimPrefix(ref.Remote, branchPrefix) + branch := gitopiatypes.MsgMultiSetBranch_Branch{ + Name: remoteBranchName, + Sha: localCommitHash.String(), + } + setBranches = append(setBranches, branch) + res = append(res, ref.Remote) + } else if strings.HasPrefix(localRef, tagPrefix) { + localTagName := strings.TrimPrefix(localRef, tagPrefix) + tagRef, err := remote.Repo.Tag(localTagName) + if err != nil { + // Could be a lightweight tag, resolve revision instead + commitHash, err := remote.Repo.ResolveRevision(plumbing.Revision(localRef)) + if err != nil { + return nil, fmt.Errorf("fatal: invalid tag name or ref, %v", localTagName) + } + tag := gitopiatypes.MsgMultiSetTag_Tag{ + Name: strings.TrimPrefix(ref.Remote, tagPrefix), + Sha: commitHash.String(), + } + setTags = append(setTags, tag) + } else { + // Annotated tag + tag := gitopiatypes.MsgMultiSetTag_Tag{ + Name: strings.TrimPrefix(ref.Remote, tagPrefix), + Sha: tagRef.Hash().String(), + } + setTags = append(setTags, tag) + } + + res = append(res, ref.Remote) + } + } + + // --- Execute a single Git Push if there's anything to do --- + if len(allRefspecs) > 0 { if h.wallet.Type() == wallet.LEDGER { remote.Logger.Println("Please sign the git server request on your ledger device.") } @@ -258,77 +361,69 @@ func (h *GitopiaHandler) Push(remote *core.Remote, refsToPush []core.RefToPush) if err != nil { return nil, errors.Wrap(err, "error signing data") } - credential := fmt.Sprintf("%s:%s", h.wallet.Address(), signature) + args := []string{ - "-c", - fmt.Sprintf("http.extraheader=Authorization: Basic %s", base64.StdEncoding.EncodeToString([]byte(credential))), - "-c", - "credential.helper=", - "-c", - "credential.helper=gitopia", + "-c", fmt.Sprintf("http.extraheader=Authorization: Basic %s", base64.StdEncoding.EncodeToString([]byte(credential))), + "-c", "credential.helper=", + "-c", "credential.helper=gitopia", + "-c", fmt.Sprintf("lfs.url=%s", lfsURL), "push", + "--no-verify", // Keep this to prevent the double-hook call remoteURL, - fmt.Sprintf("%s:%s", ref.Local, ref.Remote), } - if force { + + args = append(args, allRefspecs...) + + if isForce { args = append(args, "--force") } + cmd := core.GitCommand("git", args...) if err := cmd.Run(); err != nil { return nil, errors.Wrap(err, "error pushing to remote repository") } + } - // Update ref on gitopia - if strings.HasPrefix(ref.Local, branchPrefix) { - localCommitHash, err := remote.Repo.ResolveRevision(plumbing.Revision(ref.Local)) - if err != nil { - return nil, fmt.Errorf("fatal: local branch %s doesn't exist", ref.Local) - } - - newRemoteRefSha = localCommitHash.String() - remoteBranchName := strings.TrimPrefix(ref.Remote, branchPrefix) - branch := gitopiatypes.MsgMultiSetBranch_Branch{ - Name: remoteBranchName, - Sha: newRemoteRefSha, - } + var msg []sdk.Msg - setBranches = append(setBranches, branch) - res = append(res, ref.Remote) - } else if strings.HasPrefix(ref.Local, tagPrefix) { - localTagName := strings.TrimPrefix(ref.Local, tagPrefix) - tagRef, err := remote.Repo.Tag(localTagName) - if err != nil { - return nil, fmt.Errorf("fatal: invalid tag name, %v", localTagName) - } + // Only try to approve packfile/LFS updates if we actually pushed something. + if len(allRefspecs) > 0 { + // Approve packfile update + packfileUpdateProposalRes, err := h.storageClient.PackfileUpdateProposal(context.Background(), &storagetypes.QueryPackfileUpdateProposalRequest{ + RepositoryId: h.remoteRepository.Id, + User: h.wallet.Address(), + }) + if err != nil { + return nil, err + } + msg = append(msg, storagetypes.NewMsgApproveRepositoryPackfileUpdate(h.wallet.Address(), packfileUpdateProposalRes.PackfileUpdateProposal.Id)) - newRemoteRefSha = tagRef.Hash().String() - remoteTagName := strings.TrimPrefix(ref.Remote, tagPrefix) - tag := gitopiatypes.MsgMultiSetTag_Tag{ - Name: remoteTagName, - Sha: newRemoteRefSha, - } + lfsObjectUpdateProposalRes, err := h.storageClient.LFSObjectUpdateProposalsByRepositoryId(context.Background(), &storagetypes.QueryLFSObjectUpdateProposalsByRepositoryIdRequest{ + RepositoryId: h.remoteRepository.Id, + User: h.wallet.Address(), + }) + if err != nil { + return nil, err + } - setTags = append(setTags, tag) - res = append(res, ref.Remote) - } else { - return nil, fmt.Errorf("fatal: not a valid branch/tag, %v", ref.Local) + // Approve LFS object update + for _, lfsObjectUpdateProposal := range lfsObjectUpdateProposalRes.LfsObjectProposals { + msg = append(msg, storagetypes.NewMsgApproveLFSObjectUpdate(h.wallet.Address(), lfsObjectUpdateProposal.Id)) } } - var msg []sdk.Msg - if len(setBranches) > 0 { msg = append(msg, gitopiatypes.NewMsgMultiSetBranch(h.wallet.Address(), gitopiatypes.RepositoryId{ Id: h.remoteRepository.Owner.Id, Name: h.remoteRepository.Name, - }, setBranches)) + }, setBranches, packfileCid)) } if len(setTags) > 0 { msg = append(msg, gitopiatypes.NewMsgMultiSetTag(h.wallet.Address(), gitopiatypes.RepositoryId{ Id: h.remoteRepository.Owner.Id, Name: h.remoteRepository.Name, - }, setTags)) + }, setTags, packfileCid)) } if len(deleteBranches) > 0 { msg = append(msg, gitopiatypes.NewMsgMultiDeleteBranch(h.wallet.Address(), gitopiatypes.RepositoryId{ @@ -343,6 +438,12 @@ func (h *GitopiaHandler) Push(remote *core.Remote, refsToPush []core.RefToPush) }, deleteTags)) } + // Make sure we don't send an empty transaction + if len(msg) == 0 { + remote.Logger.Println("Nothing to update on Gitopia.") + return res, nil + } + if h.wallet.Type() == wallet.LEDGER { remote.Logger.Println("Please sign the gitopia transaction on your ledger device.") } @@ -364,7 +465,7 @@ func (h *GitopiaHandler) havePushPermission(walletAddress string) (havePermissio DaoId: h.remoteRepository.Owner.Id, }) if err != nil { - return havePermission, err + return havePermission, errors.Wrap(err, "error querying DAO members") } for _, member := range resp.Members { diff --git a/config/config.go b/config/config.go index 4b9d7b1..bdc50f9 100644 --- a/config/config.go +++ b/config/config.go @@ -36,9 +36,6 @@ func LoadGitConfig() error { if res, err := GitConfigGet(GitopiaConfigChainIdOption); err == nil { ChainId = res } - if res, err := GitConfigGet(GitopiaConfigGitServerHostOption); err == nil { - GitServerHost = res - } if res, err := GitConfigGet(GitopiaConfigGasPricesOption); err == nil { GasPrices = res } diff --git a/config/config_dev.go b/config/config_dev.go index 8408b22..edf90d8 100644 --- a/config/config_dev.go +++ b/config/config_dev.go @@ -4,7 +4,6 @@ package config var ( ChainId = "gitopia" - GitServerHost = "https://server.devnet.gitopia.com" GasPrices = "0.001ulore" FeeGranterAddr = "" Denom = "ulore" diff --git a/config/config_prod.go b/config/config_prod.go index 80e0d88..57107d8 100644 --- a/config/config_prod.go +++ b/config/config_prod.go @@ -4,7 +4,6 @@ package config var ( ChainId = "gitopia" - GitServerHost = "https://server.gitopia.com" GasPrices = "0.001ulore" FeeGranterAddr = "gitopia13ashgc6j5xle4m47kqyn5psavq0u3klmscfxql" Denom = "ulore" diff --git a/config/config_testing.go b/config/config_testing.go index b03757b..f8f4403 100644 --- a/config/config_testing.go +++ b/config/config_testing.go @@ -4,7 +4,6 @@ package config var ( ChainId = "localgitopia" - GitServerHost = "http://localhost:5001" GasPrices = "0.001ulore" FeeGranterAddr = "gitopia12sjhqc3rqgvu3zpg8ekmwl005rp4ys58ekqg89" Denom = "ulore" diff --git a/core/api/gitserver.go b/core/api/gitserver.go new file mode 100644 index 0000000..1855c45 --- /dev/null +++ b/core/api/gitserver.go @@ -0,0 +1,52 @@ +package api + +import ( + "net/http" + "time" + + "github.com/gitopia/git-remote-gitopia/core" +) + +func CheckGitServerHostLiveness(host string) bool { + res, err := http.Get(host + "/healthz") + if err != nil { + return false + } + defer res.Body.Close() + + return res.StatusCode == http.StatusOK +} + +func checkHttpHostLatency(host string) time.Duration { + start := time.Now() + _, err := http.Get(host) + if err != nil { + return time.Hour + } + return time.Since(start) +} + +func GetBestGitServerHost(grpcHost string) string { + providers := GetActiveStorageProviders(grpcHost) + if len(providers) == 0 { + return "" + } + + var bestHost string + bestLatency := time.Hour + + for _, p := range providers { + latency := checkHttpHostLatency(p.ApiUrl) + if latency < bestLatency { + bestHost = p.ApiUrl + bestLatency = latency + } + } + + return bestHost +} + +func SetConfiguredGitServerHost(host string) error { + cmd := core.GitCommand("git", "config", "--global", "gitopia.gitServerHost", host) + return cmd.Run() +} diff --git a/core/api/grpc.go b/core/api/grpc.go index 272d165..4780851 100644 --- a/core/api/grpc.go +++ b/core/api/grpc.go @@ -6,6 +6,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/grpc/tmservice" "github.com/gitopia/git-remote-gitopia/core" + storagetypes "github.com/gitopia/gitopia/v6/x/storage/types" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" ) @@ -50,3 +51,18 @@ func SetConfiguredGRPCHost(host string) error { cmd := core.GitCommand("git", "config", "--global", "gitopia.grpcHost", host) return cmd.Run() } + +func GetActiveStorageProviders(host string) []storagetypes.Provider { + conn, err := grpc.Dial(host, grpc.WithTransportCredentials(insecure.NewCredentials())) + if err != nil { + return nil + } + defer conn.Close() + + client := storagetypes.NewQueryClient(conn) + res, err := client.ActiveProviders(context.Background(), &storagetypes.QueryActiveProvidersRequest{}) + if err != nil { + return nil + } + return res.Providers +} diff --git a/core/util.go b/core/util.go index e3febaf..2d8ea53 100644 --- a/core/util.go +++ b/core/util.go @@ -32,7 +32,8 @@ func GetLocalDir() (string, error) { func GitCommand(name string, args ...string) *exec.Cmd { cmd := exec.Command(name, args...) cmd.Env = os.Environ() - cmd.Stdout = os.Stdout + // Redirect stdout to stderr to avoid protocol communication issues + cmd.Stdout = os.Stderr cmd.Stderr = os.Stderr return cmd diff --git a/core/wallet/gitopia_wallet.go b/core/wallet/gitopia_wallet.go index c33efef..2a9e213 100644 --- a/core/wallet/gitopia_wallet.go +++ b/core/wallet/gitopia_wallet.go @@ -24,8 +24,8 @@ import ( banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/cosmos/cosmos-sdk/x/feegrant" "github.com/gitopia/git-remote-gitopia/config" - gitopia "github.com/gitopia/gitopia/v5/app" - offchaintypes "github.com/gitopia/gitopia/v5/x/offchain/types" + gitopia "github.com/gitopia/gitopia/v6/app" + offchaintypes "github.com/gitopia/gitopia/v6/x/offchain/types" "github.com/pkg/errors" "google.golang.org/grpc" ) diff --git a/core/wallet/ledger.go b/core/wallet/ledger.go index 5b86d34..5ce5d43 100644 --- a/core/wallet/ledger.go +++ b/core/wallet/ledger.go @@ -24,8 +24,8 @@ import ( banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/cosmos/cosmos-sdk/x/feegrant" "github.com/gitopia/git-remote-gitopia/config" - gitopia "github.com/gitopia/gitopia/v5/app" - offchaintypes "github.com/gitopia/gitopia/v5/x/offchain/types" + gitopia "github.com/gitopia/gitopia/v6/app" + offchaintypes "github.com/gitopia/gitopia/v6/x/offchain/types" "github.com/pkg/errors" "google.golang.org/grpc" ) diff --git a/core/wallet/os_keyring.go b/core/wallet/os_keyring.go index 44d2efc..b824088 100644 --- a/core/wallet/os_keyring.go +++ b/core/wallet/os_keyring.go @@ -18,8 +18,8 @@ import ( "github.com/gitopia/git-remote-gitopia/config" glib "github.com/gitopia/gitopia-go" "github.com/gitopia/gitopia-go/logger" - gitopia "github.com/gitopia/gitopia/v5/app" - offchaintypes "github.com/gitopia/gitopia/v5/x/offchain/types" + gitopia "github.com/gitopia/gitopia/v6/app" + offchaintypes "github.com/gitopia/gitopia/v6/x/offchain/types" goGitConfig "github.com/go-git/go-git/v5/config" "github.com/pkg/errors" "github.com/sirupsen/logrus" diff --git a/go.mod b/go.mod index ec07159..066e97c 100644 --- a/go.mod +++ b/go.mod @@ -5,8 +5,8 @@ go 1.21 require ( github.com/cometbft/cometbft v0.37.6 github.com/cosmos/cosmos-sdk v0.47.13 - github.com/gitopia/gitopia-go v0.6.2 - github.com/gitopia/gitopia/v5 v5.1.0 + github.com/gitopia/gitopia-go v0.7.0 + github.com/gitopia/gitopia/v6 v6.0.0 github.com/go-git/go-git/v5 v5.11.0 github.com/pkg/errors v0.9.1 github.com/sirupsen/logrus v1.9.3 @@ -119,6 +119,7 @@ require ( github.com/hashicorp/hcl v1.0.0 // indirect github.com/hdevalence/ed25519consensus v0.1.0 // indirect github.com/huandu/skiplist v1.2.0 // indirect + github.com/iden3/go-iden3-crypto v0.0.16 // indirect github.com/improbable-eng/grpc-web v0.15.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/ipfs/go-cid v0.3.2 // indirect @@ -181,6 +182,7 @@ require ( github.com/tendermint/go-amino v0.16.0 // indirect github.com/tidwall/btree v1.6.0 // indirect github.com/ulikunitz/xz v0.5.11 // indirect + github.com/wealdtech/go-merkletree/v2 v2.6.1 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect github.com/zondax/hid v0.9.2 // indirect github.com/zondax/ledger-go v0.14.3 // indirect diff --git a/go.sum b/go.sum index 05297ed..688bf4f 100644 --- a/go.sum +++ b/go.sum @@ -448,10 +448,10 @@ github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8= github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= -github.com/gitopia/gitopia-go v0.6.2 h1:3Xu090ObJ8TP5FqmRj/blRSX0721ootXojwuOJLHb6Y= -github.com/gitopia/gitopia-go v0.6.2/go.mod h1:UueURx6CKcAl95Y+ldqX1k41TlfjM8fRuBCUNanW6TY= -github.com/gitopia/gitopia/v5 v5.1.0 h1:a/RySnjfpRYJwbkqW76QFmkBW/FihLDJHEpCtbF85Zg= -github.com/gitopia/gitopia/v5 v5.1.0/go.mod h1:t1FjB6j0LlGB2Ka1+Hu+XiARQ4NHhoVx9uKiR8+yhwc= +github.com/gitopia/gitopia-go v0.7.0 h1:HVwr5XoP3g0lWzs8u1CBWj5lCjjkA039+rshNFQPkmI= +github.com/gitopia/gitopia-go v0.7.0/go.mod h1:iD+Gz8hoOZmcLn4vuPby4q4R8S85jZEOe7mAfb+ZFQM= +github.com/gitopia/gitopia/v6 v6.0.0 h1:r3N1L1yhroorGHjU2M4p0Dp36mgCgih+oB1TAGoqMDE= +github.com/gitopia/gitopia/v6 v6.0.0/go.mod h1:HujUCHweDG8AoLctQPt8L7EtL+Eu7L1KpyjVqGVEDr8= github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY= github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= @@ -706,6 +706,8 @@ github.com/huandu/skiplist v1.2.0/go.mod h1:7v3iFjLcSAzO4fN5B8dvebvo/qsfumiLiDXM github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/iden3/go-iden3-crypto v0.0.16 h1:zN867xiz6HgErXVIV/6WyteGcOukE9gybYTorBMEdsk= +github.com/iden3/go-iden3-crypto v0.0.16/go.mod h1:dLpM4vEPJ3nDHzhWFXDjzkn1qHoBeOT/3UEhXsEsP3E= github.com/improbable-eng/grpc-web v0.15.0 h1:BN+7z6uNXZ1tQGcNAuaU1YjsLTApzkjt2tzCixLaUPQ= github.com/improbable-eng/grpc-web v0.15.0/go.mod h1:1sy9HKV4Jt9aEs9JSnkWlRJPuPtwNr0l57L4f878wP8= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= @@ -763,6 +765,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= +github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= @@ -1059,6 +1063,8 @@ github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8= github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/wealdtech/go-merkletree/v2 v2.6.1 h1:EKrzJep7JXHk1bYQAHtEcBvScqW1xgI86aF5y6iPAm0= +github.com/wealdtech/go-merkletree/v2 v2.6.1/go.mod h1:Ooz0/mhs/XF1iYfbowRawrkAI56YYZ+oUl5Dw2Tlnjk= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= diff --git a/readme.md b/readme.md index 370c5b9..04b1468 100644 --- a/readme.md +++ b/readme.md @@ -26,7 +26,7 @@ sudo mv /tmp/tmpinstalldir/git-remote-gitopia /usr/local/bin/ ## Building -Building `git-remote-gitopia` requires [Go 1.18+](https://golang.org/dl/). +Building `git-remote-gitopia` requires [Go 1.21+](https://golang.org/dl/). ``` make install @@ -51,23 +51,10 @@ export GITOPIA_WALLET=/path/to/wallet.json ## Custom Endpoint Configuration Example -### Testnet ``` git config --global gitopia.chainId "gitopia" -git config --global gitopia.grpcHost "localhost:9090" -git config --global gitopia.gitServerHost "http://localhost:5001" -git config --global gitopia.tmAddr "http://localhost:26657" -git config --global gitopia.gasPrices "0.001ulore" -git config --global gitopia.feeGranter "" -git config --global gitopia.denom "ulore" -``` - -### Mainnet -``` -git config --global gitopia.chainId "gitopia" -git config --global gitopia.grpcHost "grpc.gitopia.com:9090" -git config --global gitopia.gitServerHost "https://server.gitopia.com" -git config --global gitopia.tmAddr "https://rpc.gitopia.com:443" +git config --global gitopia.grpcHost "gitopia-grpc.polkachu.com:11390" +git config --global gitopia.tmAddr "https://gitopia-rpc.polkachu.com:443" git config --global gitopia.gasPrices "0.001ulore" git config --global gitopia.feeGranter "gitopia13ashgc6j5xle4m47kqyn5psavq0u3klmscfxql" git config --global gitopia.denom "ulore"