Skip to content

Commit 1a87abe

Browse files
authored
Merge pull request #3 from uddugteam/forking
Forking
2 parents afd7e05 + 29f440b commit 1a87abe

File tree

3 files changed

+127
-34
lines changed

3 files changed

+127
-34
lines changed

.github/workflows/main.yml

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,15 @@ jobs:
6363
tag: ${{ steps.tag_version.outputs.new_tag }}
6464
name: ${{ steps.tag_version.outputs.new_tag }}
6565
body: ${{ steps.tag_version.outputs.changelog }}
66-
token: ${{ secrets.RELEASES_ACTION_GITHUB_TOKEN }}
66+
token: ${{ secrets.RELEASES_ACTION_GITHUB_TOKEN }}
67+
68+
deploy:
69+
needs: build
70+
name: Deploy App on digital ocean
71+
runs-on: ubuntu-latest
72+
steps:
73+
- name: DigitalOcean App Platform deployment
74+
uses: digitalocean/app_action@main
75+
with:
76+
app_name: andskur-gitsec-backend
77+
token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}

internal/models/repo.go

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ type Repo struct {
3535

3636
Metadata string
3737

38+
ForkFrom string
39+
3840
// fileSystem is the filesystem where the repository is stored.
3941
fileSystem billy.Filesystem
4042
// server is the transport server used to handle git sessions.
@@ -46,13 +48,14 @@ type Repo struct {
4648
}
4749

4850
// NewRepo creates a new Repo instance.
49-
func NewRepo(name, description, basePath string, id int, owner common.Address, fs billy.Filesystem) (*Repo, error) {
51+
func NewRepo(name, description, basePath, forkFrom string, id int, owner common.Address, fs billy.Filesystem) (*Repo, error) {
5052
repo := &Repo{
5153
Name: name,
5254
Description: description,
5355
BasePath: basePath,
5456
ID: id,
5557
Owner: owner,
58+
ForkFrom: forkFrom,
5659
}
5760

5861
if err := repo.InitRepo(fs); err != nil {
@@ -92,12 +95,22 @@ func (r *Repo) InitRepo(fs billy.Filesystem) (err error) {
9295
// If the file system does not already exist, a new repository is created.
9396
func (r *Repo) initFileSystem() (err error) {
9497
if !r.isRepoFSExists() {
95-
r.Repocore, err = git.Init(filesystem.NewStorage(r.fileSystem, cache.NewObjectLRU(500)), nil)
96-
if err != nil {
97-
if errors.Is(err, git.ErrRepositoryAlreadyExists) {
98-
return nil
98+
if r.ForkFrom != "" {
99+
r.Repocore, err = git.Clone(filesystem.NewStorage(r.fileSystem, cache.NewObjectLRU(500)), nil, &git.CloneOptions{
100+
URL: r.ForkFrom,
101+
RecurseSubmodules: git.DefaultSubmoduleRecursionDepth,
102+
})
103+
if err != nil {
104+
return fmt.Errorf("failed to clone Repocore on fs: %w", err)
105+
}
106+
} else {
107+
r.Repocore, err = git.Init(filesystem.NewStorage(r.fileSystem, cache.NewObjectLRU(500)), nil)
108+
if err != nil {
109+
if errors.Is(err, git.ErrRepositoryAlreadyExists) {
110+
return nil
111+
}
112+
return fmt.Errorf("failed to create new Repocore on fs: %w", err)
99113
}
100-
return fmt.Errorf("failed to create new Repocore on fs: %w", err)
101114
}
102115
} else {
103116
r.Repocore, err = git.Open(filesystem.NewStorage(r.fileSystem, cache.NewObjectLRU(500)), nil)

internal/service/service.go

Lines changed: 96 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -125,9 +125,51 @@ func NewGitService(cfg *config.Scheme, blockchain *ethclient.Client) (*GitServic
125125
}, nil
126126
}
127127

128+
// TODO move events listeners to separate package
129+
128130
func (g *GitService) StartListener() {
129-
if err := g.ListenRepositoryCreation(); err != nil {
130-
logger.Log().Error(err)
131+
go func() {
132+
if err := g.ListenRepositoryCreation(); err != nil {
133+
logger.Log().Error(err)
134+
}
135+
}()
136+
137+
go func() {
138+
if err := g.ListenRepositoryForks(); err != nil {
139+
logger.Log().Error(err)
140+
}
141+
}()
142+
}
143+
144+
func (g *GitService) ListenRepositoryForks() error {
145+
repos := make(chan *contract.ContractRepositoryForked)
146+
opts := &bind.WatchOpts{Context: context.Background()}
147+
148+
Subscribe:
149+
repositoryForksSubscriptions, err := g.contract.WatchRepositoryForked(opts, repos)
150+
if err != nil {
151+
return fmt.Errorf("failed subscribe to watch transfers event: %w", err)
152+
}
153+
defer repositoryForksSubscriptions.Unsubscribe()
154+
155+
logger.Log().Infof("listen contract repository fork events on %s", g.contractAddress.Hex())
156+
157+
for {
158+
select {
159+
case <-g.stop:
160+
logger.Log().Warning("stop listen contract repository forks events")
161+
close(repos)
162+
return nil
163+
case err := <-repositoryForksSubscriptions.Err():
164+
logger.Log().Error(fmt.Errorf("repository forks subscription error: %w", err))
165+
goto Subscribe
166+
case r := <-repos:
167+
logger.Log().Infof("catch repository forks event: repository %s with ID %d forked from %s created with owner %s", r.RepName, r.RepId, r.Url, r.Owner.Hex())
168+
169+
if err := g.CloneRepo(r.RepName, r.Description, r.Url, int(r.RepId.Int64()), r.Owner); err != nil {
170+
logger.Log().Error(fmt.Errorf("error to fork repository: %w", err))
171+
}
172+
}
131173
}
132174
}
133175

@@ -147,7 +189,7 @@ Subscribe:
147189
for {
148190
select {
149191
case <-g.stop:
150-
logger.Log().Warning("stop listen contract transfers events")
192+
logger.Log().Warning("stop listen contract repository creation events")
151193
close(repos)
152194
return nil
153195
case err := <-repositoryCreationSubscriptions.Err():
@@ -163,12 +205,37 @@ Subscribe:
163205
}
164206
}
165207

208+
func (g *GitService) CloneRepo(name, description, forkFrom string, id int, owner common.Address) error {
209+
repo, err := models.NewRepo(name, description, g.baseGitPath, forkFrom, id, owner, g.fs)
210+
if err != nil {
211+
return fmt.Errorf("failed to create new repo: %w", err)
212+
}
213+
214+
if err := g.processNewRepo(repo); err != nil {
215+
return fmt.Errorf("process new repo: %w", err)
216+
}
217+
218+
if err := g.updateRepositoryMeta(repo); err != nil {
219+
return fmt.Errorf("failed to update repository meta: %w", err)
220+
}
221+
222+
return nil
223+
}
224+
166225
func (g *GitService) CreateRepo(name, description string, id int, owner common.Address) error {
167-
repo, err := models.NewRepo(name, description, g.baseGitPath, id, owner, g.fs)
226+
repo, err := models.NewRepo(name, description, g.baseGitPath, "", id, owner, g.fs)
168227
if err != nil {
169228
return fmt.Errorf("failed to create new repo: %w", err)
170229
}
171230

231+
if err := g.processNewRepo(repo); err != nil {
232+
return fmt.Errorf("process new repo: %w", err)
233+
}
234+
235+
return nil
236+
}
237+
238+
func (g *GitService) processNewRepo(repo *models.Repo) error {
172239
meta, err := repo.GenMeta()
173240
if err != nil {
174241
return fmt.Errorf("failed to generate repository meta: %w", err)
@@ -179,12 +246,12 @@ func (g *GitService) CreateRepo(name, description string, id int, owner common.A
179246
return fmt.Errorf("marshal repository metadata: %w", err)
180247
}
181248

182-
hash, err := g.pinner.Pin(name+"-meta.json", bytes.NewReader(metaJson))
249+
hash, err := g.pinner.Pin(repo.Name+"-meta.json", bytes.NewReader(metaJson))
183250
if err != nil {
184251
return fmt.Errorf("pin repository metadata to ipfs: %w", err)
185252
}
186253

187-
logger.Log().Infof("repository %s metadata %s pinned to IPFS", name, hash)
254+
logger.Log().Infof("repository %s metadata %s pinned to IPFS", repo.Name, hash)
188255

189256
repo.Metadata = hash
190257

@@ -204,13 +271,7 @@ func (g *GitService) CreateRepo(name, description string, id int, owner common.A
204271
return fmt.Errorf("failed to send transaction: %w", err)
205272
}
206273

207-
logger.Log().Infof("transaction %s to update repository %s ID %d metadata %s send to blockchan", tx.Hash().Hex(), name, repo.ID, hash)
208-
209-
rewrewr := &models.Repo{Name: name}
210-
211-
if err := g.repository.GetRepo(rewrewr); err != nil {
212-
return err
213-
}
274+
logger.Log().Infof("transaction %s to update repository %s ID %d metadata %s send to blockchan", tx.Hash().Hex(), repo.Name, repo.ID, hash)
214275

215276
return nil
216277
}
@@ -291,60 +352,68 @@ func (g *GitService) ReceivePack(ctx context.Context, req io.Reader, repositoryN
291352

292353
logger.Log().Infof("recieve pack handled in %s", time.Since(start))
293354

355+
if err := g.updateRepositoryMeta(repo); err != nil {
356+
return nil, fmt.Errorf("failed to update repository meta: %w", err)
357+
}
358+
359+
return res, nil
360+
}
361+
362+
func (g *GitService) updateRepositoryMeta(repo *models.Repo) error {
294363
head, err := repo.Head()
295364
if err != nil {
296-
return nil, fmt.Errorf("failed to get repo head: %w", err)
365+
return fmt.Errorf("failed to get repo head: %w", err)
297366
}
298367

299368
tree, err := repo.Tree(head.Hash())
300369
if err != nil {
301-
return nil, fmt.Errorf("failed to get repo tree: %w", err)
370+
return fmt.Errorf("failed to get repo tree: %w", err)
302371
}
303372

304373
meta, err := repo.GenMeta()
305374
if err != nil {
306-
return nil, fmt.Errorf("failed to generate repository meta: %w", err)
375+
return fmt.Errorf("failed to generate repository meta: %w", err)
307376
}
308377

309378
if err := meta.FillContent(tree); err != nil {
310-
return nil, fmt.Errorf("failed to fill metadata content: %w", err)
379+
return fmt.Errorf("failed to fill metadata content: %w", err)
311380
}
312381

313382
if err := meta.FillCommit(repo); err != nil {
314-
return nil, fmt.Errorf("failed to fill metadata tree commits: %w", err)
383+
return fmt.Errorf("failed to fill metadata tree commits: %w", err)
315384
}
316385

317386
if err := g.StoreMetaTree(meta, repo); err != nil {
318-
return nil, fmt.Errorf("failed to store metadata content: %w", err)
387+
return fmt.Errorf("failed to store metadata content: %w", err)
319388
}
320389

321390
metaBytes, err := json.Marshal(meta)
322391
if err != nil {
323-
return nil, fmt.Errorf("marshal repository metadata: %w", err)
392+
return fmt.Errorf("marshal repository metadata: %w", err)
324393
}
325394

326-
hash, err := g.pinner.Pin(fmt.Sprintf("%s-%d-meta.json", repositoryName, time.Now().Unix()), bytes.NewReader(metaBytes))
395+
hash, err := g.pinner.Pin(fmt.Sprintf("%s-%d-meta.json", repo.Name, time.Now().Unix()), bytes.NewReader(metaBytes))
327396
if err != nil {
328-
return nil, fmt.Errorf("pin repository metadata to ipfs: %w", err)
397+
return fmt.Errorf("pin repository metadata to ipfs: %w", err)
329398
}
330399

331-
logger.Log().Infof("repository %s metadata %s pinned to IPFS", repositoryName, hash)
400+
logger.Log().Infof("repository %s metadata %s pinned to IPFS", repo.Name, hash)
332401

333402
repo.Metadata = hash
334403

335404
sign, err := g.signer.Sign(g.chainId)
336405
if err != nil {
337-
return nil, fmt.Errorf("prepare tx signing: %w", err)
406+
return fmt.Errorf("prepare tx signing: %w", err)
338407
}
339408

340409
tx, err := g.contract.UpdateIPFS(sign, big.NewInt(int64(repo.ID)), hash)
341410
if err != nil {
342-
return nil, fmt.Errorf("failed to send transaction: %w", err)
411+
return fmt.Errorf("failed to send transaction: %w", err)
343412
}
344413

345-
logger.Log().Infof("transaction %s to update repository %s ID %d metadata %s send to blockchan", tx.Hash().Hex(), repositoryName, repo.ID, hash)
414+
logger.Log().Infof("transaction %s to update repository %s ID %d metadata %s send to blockchan", tx.Hash().Hex(), repo.Name, repo.ID, hash)
346415

347-
return res, nil
416+
return nil
348417
}
349418

350419
func (g *GitService) StoreMetaTree(meta *models.RepoMetadata, repo *models.Repo) error {

0 commit comments

Comments
 (0)