Skip to content
This repository was archived by the owner on Jul 15, 2025. It is now read-only.

fix: delete tags with go backend #216

Merged
merged 10 commits into from
Apr 15, 2025
Merged

fix: delete tags with go backend #216

merged 10 commits into from
Apr 15, 2025

Conversation

kmendell
Copy link
Member

@kmendell kmendell commented Apr 12, 2025

Currently Giving a 500 error

Fixes: #215

Summary by Sourcery

Implement tag deletion functionality across the backend and frontend, allowing users to delete Docker image tags from both the database and container registry

New Features:

  • Add ability to delete Docker image tags with full support in backend and frontend

Bug Fixes:

  • Ensure consistent tag deletion across database and container registry

Enhancements:

  • Implement a robust tag deletion process with database transaction support
  • Add registry manifest deletion capability

Summary by Sourcery

Implement comprehensive tag deletion functionality across backend and frontend, enabling users to delete Docker image tags from both the database and container registry

New Features:

  • Add full-featured tag deletion capability with support for deleting tags from both database and container registry

Bug Fixes:

  • Resolve 500 error when attempting to delete tags
  • Ensure consistent tag deletion across different registry and database systems

Enhancements:

  • Implement robust tag deletion process with database transaction support
  • Add advanced manifest deletion capability with retry and error handling

Copy link
Contributor

sourcery-ai bot commented Apr 12, 2025

Reviewer's Guide by Sourcery

This pull request implements the tag deletion functionality across the backend and frontend. The backend changes include database updates and registry manifest deletion. The frontend changes include adding a delete tag button and implementing the deletion logic. A new API endpoint is exposed for deleting tags.

Sequence diagram for deleting a tag

sequenceDiagram
    actor User
    participant Frontend
    participant Backend API
    participant Tag Repository
    participant Registry Client
    participant Registry

    User->>Frontend: Clicks 'Delete Tag' button
    Frontend->>Backend API: Sends DELETE request to /repositories/{repo}/images/{image}/tags/{tag}
    Backend API->>Tag Repository: Calls DeleteTag(repoName, imageName, tagName)
    Tag Repository->>Tag Repository: Starts database transaction
    Tag Repository->>Tag Repository: Finds tag by repoName, imageName, tagName
    Tag Repository->>Tag Repository: Deletes tag metadata from database
    Tag Repository->>Tag Repository: Deletes tag from database
    Tag Repository->>Tag Repository: Commits database transaction
    Tag Repository->>Registry Client: Calls DeleteManifest(repoPath, digest)
    Registry Client->>Registry: Sends DELETE request to /v2/{repoPath}/manifests/{digest}
    Registry-->>Registry Client: Returns status
    Registry Client->>Tag Repository: Returns result of manifest deletion
    Tag Repository->>Backend API: Returns success or error
    Backend API->>Frontend: Returns success or error
    Frontend->>User: Updates UI with deletion result
Loading

File-Level Changes

Change Details Files
Implements tag deletion functionality in the backend, including database updates and registry manifest deletion.
  • Adds a DeleteTag method to the tagRepository to handle tag deletion from the database and registry.
  • Implements a database transaction to ensure atomicity of tag and metadata deletion.
  • Includes logic to delete the corresponding manifest from the container registry using the registry client.
  • Adds a helper function getManifestDigestForTag to retrieve the manifest digest for a given tag.
  • Adds logic to try multiple digests for deletion, including the tag's primary digest, metadata digests, and the current manifest digest.
  • Adds a DeleteManifest method to the RegistryClient to delete a manifest from the registry by its digest.
  • Adds retry logic to the DeleteManifest method to handle transient errors.
  • Adds logging throughout the deletion process to track progress and errors.
backend/internal/repository/gorm/tag_repository.go
backend/internal/services/registry_client.go
Implements tag deletion functionality in the frontend.
  • Adds a delete tag button to the tag details page.
  • Implements an alert dialog to confirm tag deletion.
  • Adds a form to handle the deletion request.
  • Implements a server action to handle the deletion logic.
  • Adds a method to the TagService to delete a tag.
  • Redirects to the image details page after successful deletion.
frontend/src/routes/details/[repo]/[image]/[tag]/+page.svelte
frontend/src/routes/details/[repo]/[image]/[tag]/+page.server.ts
frontend/src/lib/services/tag-service.ts
Exposes a new API endpoint for deleting tags.
  • Adds a DeleteTag handler to the TagHandler.
  • Sets up a new route for deleting tags in routes.go.
backend/internal/api/handlers/tags.go
backend/internal/api/routes/routes.go

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!
  • Generate a plan of action for an issue: Comment @sourcery-ai plan on
    an issue to generate a plan of action for it.

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@kmendell kmendell marked this pull request as ready for review April 15, 2025 00:01
Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @kmendell - I've reviewed your changes - here's some feedback:

Overall Comments:

  • Consider adding a unique constraint to the database to prevent duplicate tags.
  • The registry client should be injected into the tag repository instead of creating it within the delete function.
Here's what I looked at during the review
  • 🟢 General issues: all looks good
  • 🟢 Security: all looks good
  • 🟢 Testing: all looks good
  • 🟡 Complexity: 1 issue found
  • 🟢 Documentation: all looks good

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@@ -117,8 +124,134 @@ func (r *tagRepository) UpdateTag(ctx context.Context, tag *models.Tag) error {
}

func (r *tagRepository) DeleteTag(ctx context.Context, repoName, imageName, tagName string) error {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (complexity): Consider extracting the registry deletion logic into a separate service layer to improve testability and maintainability by separating concerns related to database transactions and registry operations within the DeleteTag function.

The updated DeleteTag function now mixes database transaction management with digest extraction and registry deletion logic, resulting in a single multi-responsibility function. Consider extracting the registry deletion logic (including digest lookup) into its own service layer. This would make the code easier to test and maintain while keeping the database logic isolated.

Actionable steps:

  1. Create a new function in a registry service:
    Move all registry-related operations including manifest retrieval and deletion into a separate function, e.g., DeleteRegistryTag.

  2. Simplify DeleteTag:
    Let DeleteTag handle only the database operations and then call the new registry service function.

Example changes:

Extract registry deletion logic:

// In services/registry.go
func (s *RegistryService) DeleteRegistryTag(ctx context.Context, repository, tagName string, possibleDigests []string) error {
    for _, digest := range possibleDigests {
        log.Printf("Attempting to delete manifest using digest: %s", digest)
        if err := s.client.DeleteManifest(ctx, repository, digest); err == nil {
            log.Printf("Successfully deleted manifest with digest: %s", digest)
            return nil
        } else {
            log.Printf("Failed to delete manifest with digest %s: %v", digest, err)
        }
    }
    return errors.New("failed to delete registry tag with any digest")
}

Simplify DeleteTag:

func (r *tagRepository) DeleteTag(ctx context.Context, repoName, imageName, tagName string) error {
    tx := r.db.Begin()
    // Find tag and manage transaction...
    // [database deletion logic remains unchanged]

    if err := tx.Commit().Error; err != nil {
        return err
    }
    log.Printf("Successfully deleted tag %s from database", tagName)

    // Construct registry path
    registryPath := imageName
    if repoName != "library" {
        registryPath = fmt.Sprintf("%s/%s", repoName, imageName)
    }

    // Retrieve possible digests
    possibleDigests := extractDigests(tag) // refactor digest extraction into its own helper

    // Delegate registry deletion to the new service
    registryService := services.NewRegistryService(os.Getenv("PUBLIC_REGISTRY_URL"), 
                                                     os.Getenv("REGISTRY_USERNAME"), 
                                                     os.Getenv("REGISTRY_PASSWORD"))
    if err := registryService.DeleteRegistryTag(ctx, registryPath, tagName, possibleDigests); err != nil {
        log.Printf("Warning: Registry cleanup failed: %v", err)
    }
    return nil
}

By splitting the concerns, each function becomes focused on a single responsibility, making your code easier to test, maintain, and debug without reverting functionality.

kmendell and others added 5 commits April 14, 2025 19:04
…m user input

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
…m user input

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
@kmendell kmendell merged commit c28e3b1 into main Apr 15, 2025
7 checks passed
@kmendell kmendell deleted the fix/delete-tags-go branch April 15, 2025 00:22
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Bug: Deleting Tags not working with GoLang backend
1 participant