@@ 447,6 447,23 @@ func (r *mutationResolver) DeleteRepository(ctx context.Context, id int) (*model
var repo model.Repository
if err := database.WithTx(ctx, nil, func(tx *sql.Tx) error {
+ rows, err := tx.QueryContext(ctx,
+ `DELETE FROM artifacts WHERE repo_id = $1 RETURNING filename;`, id)
+ if err != nil {
+ return err
+ }
+ var artifacts []string
+ for rows.Next() {
+ var filename string
+ if err := rows.Scan(&filename); err != nil {
+ return err
+ }
+ artifacts = append(artifacts, filename)
+ }
+ if err := rows.Err(); err != nil {
+ return err
+ }
+
row := tx.QueryRowContext(ctx, `
DELETE FROM repository
WHERE id = $1 AND owner_id = $2
@@ 467,10 484,14 @@ func (r *mutationResolver) DeleteRepository(ctx context.Context, id int) (*model
webhooks.DeliverRepoEvent(ctx, model.WebhookEventRepoDeleted, &repo)
webhooks.DeliverLegacyRepoDeleted(ctx, &repo)
- err := os.RemoveAll(repo.Path)
- if err != nil {
+ if err := os.RemoveAll(repo.Path); err != nil {
return err
}
+
+ if len(artifacts) > 0 {
+ username := auth.ForContext(ctx).Username
+ repos.DeleteArtifacts(ctx, username, repo.Name, artifacts)
+ }
return nil
}); err != nil {
return nil, err
@@ 3,13 3,18 @@ package repos
import (
"context"
"database/sql"
+ "fmt"
"log"
"net/http"
+ "path"
"time"
+ "git.sr.ht/~sircmpwn/core-go/config"
"git.sr.ht/~sircmpwn/core-go/database"
work "git.sr.ht/~sircmpwn/dowork"
"github.com/go-git/go-git/v5"
+ "github.com/minio/minio-go/v7"
+ "github.com/minio/minio-go/v7/pkg/credentials"
)
type contextKey struct {
@@ 69,3 74,41 @@ func Clone(ctx context.Context, repoID int, repo *git.Repository, cloneURL strin
queue.Enqueue(task)
log.Printf("Enqueued clone of %s", cloneURL)
}
+
+// Schedules deletion of artifacts.
+func DeleteArtifacts(ctx context.Context, username, repoName string, filenames []string) {
+ queue, ok := ctx.Value(ctxKey).(*work.Queue)
+ if !ok {
+ panic("No repos worker for this context")
+ }
+ task := work.NewTask(func(ctx context.Context) error {
+ conf := config.ForContext(ctx)
+ upstream, _ := conf.Get("objects", "s3-upstream")
+ accessKey, _ := conf.Get("objects", "s3-access-key")
+ secretKey, _ := conf.Get("objects", "s3-secret-key")
+ bucket, _ := conf.Get("git.sr.ht", "s3-bucket")
+ prefix, _ := conf.Get("git.sr.ht", "s3-prefix")
+
+ if upstream == "" || accessKey == "" || secretKey == "" || bucket == "" {
+ return fmt.Errorf("Object storage is not enabled for this server")
+ }
+
+ mc, err := minio.New(upstream, &minio.Options{
+ Creds: credentials.NewStaticV4(accessKey, secretKey, ""),
+ Secure: true,
+ })
+ if err != nil {
+ panic(err)
+ }
+
+ for _, filename := range filenames {
+ s3path := path.Join(prefix, "artifacts", "~"+username, repoName, filename)
+ if err := mc.RemoveObject(ctx, bucket, s3path, minio.RemoveObjectOptions{}); err != nil {
+ return err
+ }
+ }
+ return nil
+ })
+ queue.Enqueue(task)
+ log.Printf("Enqueued deletion of %d artifacts", len(filenames))
+}