Skip to content

Conversation

@Kinin-Code-Offical
Copy link
Owner

@Kinin-Code-Offical Kinin-Code-Offical commented Dec 21, 2025

Closes #14

Summary:

  • Delete existing release assets for a tag before uploading new ones.
  • Skip deletion when no prior release exists.

Tests:

  • npm ci (PASS)
  • npm run lint (PASS)
  • npm test (PASS)
  • npm run build (PASS)
  • npm run package (PASS)
  • npm run smoke:exe (PASS)
  • npm run installer (PASS)
  • npm run stage (PASS)

Rollback:

  • Revert this commit to restore the previous release upload behavior.

Summary by Sourcery

CI:

  • Update release workflow to delete existing assets for a tag via GitHub API before running the release action, skipping deletion when no prior release exists.

Copilot AI review requested due to automatic review settings December 21, 2025 23:36
@sourcery-ai
Copy link

sourcery-ai bot commented Dec 21, 2025

Reviewer's Guide

Adds a pre-release step in the GitHub Actions release workflow to safely delete any existing assets on a release with the same tag prior to creating a new release, while skipping deletion if no prior release exists.

Sequence diagram for deleting existing release assets before republish

sequenceDiagram
    participant GA as GitHubActions_release_workflow
    participant PS as PowerShell_step_Delete_existing_assets
    participant GH as GitHub_REST_API

    GA->>PS: Start delete existing release assets step
    PS->>PS: Extract tag from GITHUB_REF
    PS->>GH: GET /repos/{repo}/releases/tags/{tag}
    alt Release for tag exists
        GH-->>PS: 200 OK with release (includes assets)
        PS->>PS: Check release object
        alt Release has assets
            loop For each asset in release.assets
                PS->>GH: DELETE /repos/{repo}/releases/assets/{asset_id}
                GH-->>PS: 204 No Content
            end
        else No assets in release
            PS->>PS: Log No existing assets to delete
        end
    else Release for tag does not exist
        GH-->>PS: 404 Not Found
        PS->>PS: Log No existing release for tag
        PS-->>GA: Exit step successfully (no deletion)
    end

    PS-->>GA: Deletion step complete
    GA->>GA: Proceed to softprops/action-gh-release@v2 step
Loading

File-Level Changes

Change Details Files
Add a PowerShell step to delete existing assets for a release with the same tag before running the GitHub release action.
  • Derives the tag name from GITHUB_REF by stripping the refs/tags/ prefix.
  • Calls the GitHub Releases API to fetch the release associated with the current tag, handling 404 by exiting early and leaving the workflow green.
  • Guards against missing release data by exiting early without error if no release object is returned.
  • Iterates over existing release assets and deletes each via the GitHub Releases assets API using the provided GITHUB_TOKEN for authentication.
.github/workflows/release.yml

Assessment against linked issues

Issue Objective Addressed Explanation
#14 Allow republishing a release for the same tag by deleting existing release assets for that tag before uploading new ones.
#14 Avoid failures when republishing a tag that does not yet have an existing release (skip deletion gracefully when no prior release exists).

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!

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

Copy link

@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 - I've found 2 issues, and left some high level feedback:

  • The delete-assets step runs unconditionally for the job, whereas the release step is guarded with if: startsWith(github.ref, 'refs/tags/'); consider adding the same condition to avoid invoking the GitHub Releases API for non-tag refs.
  • The 404 handling in the Invoke-RestMethod catch block assumes $_ .Exception.Response.StatusCode is always present; adding a null check around Response (or matching on message/content) would make this more robust to unexpected error shapes.
  • GitHub's REST API typically expects a User-Agent header; adding one to the $headers used by Invoke-RestMethod will make the API calls more standards-compliant and easier to trace.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The delete-assets step runs unconditionally for the job, whereas the release step is guarded with `if: startsWith(github.ref, 'refs/tags/')`; consider adding the same condition to avoid invoking the GitHub Releases API for non-tag refs.
- The 404 handling in the `Invoke-RestMethod` catch block assumes `$_ .Exception.Response.StatusCode` is always present; adding a null check around `Response` (or matching on message/content) would make this more robust to unexpected error shapes.
- GitHub's REST API typically expects a `User-Agent` header; adding one to the `$headers` used by `Invoke-RestMethod` will make the API calls more standards-compliant and easier to trace.

## Individual Comments

### Comment 1
<location> `.github/workflows/release.yml:66-68` </location>
<code_context>
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+        run: |
+          $tag = $env:GITHUB_REF -replace 'refs/tags/', ''
+          $headers = @{
+            Authorization = "Bearer $env:GITHUB_TOKEN"
+            Accept = "application/vnd.github+json"
+          }
+          try {
</code_context>

<issue_to_address>
**issue (bug_risk):** GitHub REST calls are missing a User-Agent header, which can cause API requests to be rejected.

Please add a required `User-Agent` header to `$headers` (for example, `User-Agent = "github-actions/$env:GITHUB_REPOSITORY"`) so these GitHub REST requests aren’t rejected or throttled intermittently.
</issue_to_address>

### Comment 2
<location> `.github/workflows/release.yml:72-78` </location>
<code_context>
+          }
+          try {
+            $release = Invoke-RestMethod -Method Get -Uri "https://api.github.com/repos/$env:GITHUB_REPOSITORY/releases/tags/$tag" -Headers $headers
+          } catch {
+            if ($_.Exception.Response.StatusCode.value__ -eq 404) {
+              Write-Host "No existing release for $tag"
+              exit 0
</code_context>

<issue_to_address>
**suggestion (bug_risk):** The 404 handling assumes Response is non-null and may throw if the exception shape differs.

In some failure cases (e.g., network errors), `$_` may not have `.Exception.Response` or `.StatusCode`, causing this catch block to throw. Please add a null check (e.g. `if ($_.Exception.Response -and $_.Exception.Response.StatusCode.value__ -eq 404)`) or use null-propagation to ensure the 404 handling is safe for all error types.

```suggestion
          } catch {
            if ($_.Exception.Response -and $_.Exception.Response.StatusCode.value__ -eq 404) {
              Write-Host "No existing release for $tag"
              exit 0
            }
            throw
          }
```
</issue_to_address>

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.

Comment on lines +66 to +68
$headers = @{
Authorization = "Bearer $env:GITHUB_TOKEN"
Accept = "application/vnd.github+json"
Copy link

Choose a reason for hiding this comment

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

issue (bug_risk): GitHub REST calls are missing a User-Agent header, which can cause API requests to be rejected.

Please add a required User-Agent header to $headers (for example, User-Agent = "github-actions/$env:GITHUB_REPOSITORY") so these GitHub REST requests aren’t rejected or throttled intermittently.

Comment on lines +72 to +78
} catch {
if ($_.Exception.Response.StatusCode.value__ -eq 404) {
Write-Host "No existing release for $tag"
exit 0
}
throw
}
Copy link

Choose a reason for hiding this comment

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

suggestion (bug_risk): The 404 handling assumes Response is non-null and may throw if the exception shape differs.

In some failure cases (e.g., network errors), $_ may not have .Exception.Response or .StatusCode, causing this catch block to throw. Please add a null check (e.g. if ($_.Exception.Response -and $_.Exception.Response.StatusCode.value__ -eq 404)) or use null-propagation to ensure the 404 handling is safe for all error types.

Suggested change
} catch {
if ($_.Exception.Response.StatusCode.value__ -eq 404) {
Write-Host "No existing release for $tag"
exit 0
}
throw
}
} catch {
if ($_.Exception.Response -and $_.Exception.Response.StatusCode.value__ -eq 404) {
Write-Host "No existing release for $tag"
exit 0
}
throw
}

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR implements functionality to safely republish releases with the same tag by deleting existing release assets before uploading new ones. This addresses issue #14 and enables clobber behavior for release assets.

Key Changes:

  • Adds a new workflow step that queries the GitHub API to check for existing releases
  • Deletes all assets from an existing release before the new release upload
  • Gracefully handles cases where no prior release exists (404 responses)

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +80 to +84
if (-not $release) {
Write-Host "No existing release data for $tag"
exit 0
}
Copy link

Copilot AI Dec 21, 2025

Choose a reason for hiding this comment

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

This null check is redundant. If the Invoke-RestMethod call on line 71 succeeds, it will always return a response object. The 404 case is already handled in the catch block above. This check can never be true after a successful API call, making these lines unreachable code.

Suggested change
if (-not $release) {
Write-Host "No existing release data for $tag"
exit 0
}

Copilot uses AI. Check for mistakes.
foreach ($asset in $release.assets) {
Write-Host "Deleting asset $($asset.name)"
Invoke-RestMethod -Method Delete -Uri "https://api.github.com/repos/$env:GITHUB_REPOSITORY/releases/assets/$($asset.id)" -Headers $headers
Copy link

Copilot AI Dec 21, 2025

Choose a reason for hiding this comment

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

The asset deletion loop lacks error handling. If deletion of any asset fails (e.g., due to network issues or API rate limits), the script will throw an exception and halt, potentially leaving the release in an inconsistent state with some assets deleted and others remaining. Consider adding try-catch blocks within the loop to handle individual asset deletion failures gracefully, or at minimum, add logging to identify which asset failed.

Suggested change
Invoke-RestMethod -Method Delete -Uri "https://api.github.com/repos/$env:GITHUB_REPOSITORY/releases/assets/$($asset.id)" -Headers $headers
try {
Invoke-RestMethod -Method Delete -Uri "https://api.github.com/repos/$env:GITHUB_REPOSITORY/releases/assets/$($asset.id)" -Headers $headers
} catch {
Write-Warning "Failed to delete asset '$($asset.name)' (ID: $($asset.id)): $($_.Exception.Message)"
}

Copilot uses AI. Check for mistakes.
@Kinin-Code-Offical Kinin-Code-Offical merged commit bd4d44b into main Dec 21, 2025
11 checks passed
@Kinin-Code-Offical Kinin-Code-Offical deleted the p0/release-republish-clobber branch December 21, 2025 23:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

P0: Release republish same tag (clobber existing assets safely)

2 participants