Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .github/workflows/prune-pull-requests-images-tags.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@ on: # yamllint disable-line rule:truthy
default: "^pr-([0-9]+)(?:-|$)"
type: string
required: false
preserve-tags-filter:
description: |
Optional regular expression to match tags that should be preserved (not deleted).
Tags matching this pattern will never be deleted, even if they are on a package version with PR tags.
Example: "^v.*" to preserve version tags like v1.0.0, v2.1.3, etc.
default: ""
type: string
required: false

permissions: {}

Expand Down Expand Up @@ -105,6 +113,7 @@ jobs:
with:
image: ${{ matrix.image }}
pull-request-tag-filter: ${{ inputs.pull-request-tag-filter }}
preserve-tags-filter: ${{ inputs.preserve-tags-filter }}

- uses: hoverkraft-tech/ci-github-common/actions/local-workflow-actions@b17226e57c8ef31f860719766656ebb6df017218 # 0.31.6
if: always() && steps.local-workflow-actions.outputs.repository
Expand Down
9 changes: 9 additions & 0 deletions actions/docker/prune-pull-requests-image-tags/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ inputs:
pull-request-tag-filter:
description: "The regular expression to match pull request tags. Must have a capture group for the pull request number."
default: "^pr-([0-9]+)(?:-|$)"
preserve-tags-filter:
description: |
Optional regular expression to match tags that should be preserved (not deleted).
Tags matching this pattern will never be deleted, even if they are on a package version with PR tags.
Example: "^v.*" to preserve version tags like v1.0.0, v2.1.3, etc.
required: false
default: ""
github-token:
description: |
GitHub token with the folowing scopes: `pull-requests:read`, `packages:read` and `packages:delete`.
Expand Down Expand Up @@ -73,6 +80,7 @@ runs:

const imageName = `${{ steps.image-name.outputs.image-name }}`;
const isOrganization = `${{ steps.is-organization-or-user.outputs.is-organization }}` === 'true';
const preserveTagsFilter = `${{ inputs.preserve-tags-filter }}`;

const script = require(`${{ github.action_path }}/index.js`)
const tagsToDelete = await script({
Expand All @@ -81,6 +89,7 @@ runs:
core,
imageName,
pullRequestTagFilter,
preserveTagsFilter,
isOrganization,
});

Expand Down
49 changes: 48 additions & 1 deletion actions/docker/prune-pull-requests-image-tags/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ module.exports = async ({
core,
imageName,
pullRequestTagFilter,
preserveTagsFilter,
isOrganization,
}) => {
const repositoryOwner = `${context.repo.owner}`.toLowerCase();
Expand Down Expand Up @@ -33,6 +34,7 @@ module.exports = async ({
context,
core,
pullRequestTagFilter,
preserveTagsFilter,
packageVersion,
}),
),
Expand Down Expand Up @@ -84,6 +86,7 @@ async function getTagsToDeleteFromPackageVersion({
context,
core,
pullRequestTagFilter,
preserveTagsFilter,
packageVersion,
}) {
const tags = packageVersion.metadata.container.tags;
Expand Down Expand Up @@ -123,7 +126,7 @@ async function getTagsToDeleteFromPackageVersion({
return [];
}

return tags;
return filterPreservedTags({ tags, preserveTagsFilter, core });
}

function getPullRequestRelatedTags({ tags, pullRequestTagFilter }) {
Expand All @@ -144,6 +147,50 @@ function getPullRequestRelatedTags({ tags, pullRequestTagFilter }) {
return [...new Set(pullRequestRelatedTags)];
}

function filterPreservedTags({ tags, preserveTagsFilter, core }) {
if (!preserveTagsFilter || preserveTagsFilter.length === 0) {
return tags;
}

let preserveRegex;
try {
preserveRegex = new RegExp(preserveTagsFilter);
} catch (error) {
core.setFailed(
`Invalid preserve tag filter regex "${preserveTagsFilter}". Error: ${error.message}`,
);
throw error;
}

const preservedTags = tags.filter((tag) => {
try {
return preserveRegex.test(tag);
} catch (error) {
core.warning(
`Error while applying preserve tag filter regex "${preserveTagsFilter}" to tag "${tag}". Treating tag as not preserved. Error: ${error.message}`,
);
return false;
}
});

if (preservedTags.length > 0) {
core.debug(
`Preserving tags matching filter ${preserveTagsFilter}: ${preservedTags.join(", ")}`,
);
}

return tags.filter((tag) => {
try {
return !preserveRegex.test(tag);
} catch (error) {
core.warning(
`Error while applying preserve tag filter regex "${preserveTagsFilter}" to tag "${tag}". Keeping tag for safety. Error: ${error.message}`,
);
return true;
}
});
}

const closedPullRequests = new Map();
async function isPullRequestClosed({ github, context, pullRequestNumber }) {
if (!closedPullRequests.has(pullRequestNumber)) {
Expand Down
Loading