mirror of
https://github.com/coollabsio/coolify.git
synced 2026-11-06 13:10:37 -04:00
ci: harden workflows (#12424)
This commit is contained in:
@@ -0,0 +1 @@
|
||||
profile: pedantic
|
||||
@@ -0,0 +1,83 @@
|
||||
# This file is machine-generated by `gh actions-lock`.
|
||||
# Do not edit by hand; run `gh actions-lock` to update.
|
||||
# Docs: https://gh.io/actions-lockfile
|
||||
version: 'v0.0.3'
|
||||
workflows:
|
||||
'.github/workflows/build.yaml':
|
||||
- 'actions/checkout@v7.0.1'
|
||||
- 'actions/upload-artifact@v7.0.2'
|
||||
- 'docker/build-push-action@v7.4.0'
|
||||
- 'docker/setup-buildx-action@v4.4.1'
|
||||
'.github/workflows/clean-manifests.yaml':
|
||||
- 'actions/checkout@v7.0.1'
|
||||
- 'actions/upload-artifact@v7.0.2'
|
||||
'.github/workflows/lock-threads.yaml':
|
||||
- 'dessant/lock-threads@v6.0.2'
|
||||
'.github/workflows/main.yaml':
|
||||
- 'actions/checkout@v7.0.1'
|
||||
- 'actions/download-artifact@v8.0.2'
|
||||
- 'docker/login-action@v4.7.0'
|
||||
'.github/workflows/merge-forward.yaml':
|
||||
- 'actions/checkout@v7.0.1'
|
||||
'.github/workflows/nightly.yaml':
|
||||
- 'actions/checkout@v7.0.1'
|
||||
- 'actions/download-artifact@v8.0.2'
|
||||
- 'docker/login-action@v4.7.0'
|
||||
'.github/workflows/pr-quality.yaml':
|
||||
- 'peakoss/anti-slop@v0.3.0'
|
||||
'.github/workflows/pull-request.yaml':
|
||||
- 'actions/download-artifact@v8.0.2'
|
||||
- 'docker/login-action@v4.7.0'
|
||||
'.github/workflows/release.yaml':
|
||||
- 'actions/checkout@v7.0.1'
|
||||
- 'actions/download-artifact@v8.0.2'
|
||||
- 'docker/login-action@v4.7.0'
|
||||
'.github/workflows/request-docs-update.yaml': []
|
||||
'.github/workflows/stale.yaml':
|
||||
- 'actions/stale@v11.0.0'
|
||||
dependencies:
|
||||
'actions/checkout@v7.0.1':
|
||||
ref: 'v7.0.1'
|
||||
commit: 'sha1-3d3c42e5aac5ba805825da76410c181273ba90b1'
|
||||
owner_id: 44036562
|
||||
repo_id: 197814629
|
||||
'actions/download-artifact@v8.0.2':
|
||||
ref: 'v8.0.2'
|
||||
commit: 'sha1-9000827ccba6bdab643e8b6fd33ac0654aef8333'
|
||||
owner_id: 44036562
|
||||
repo_id: 192626254
|
||||
'actions/stale@v11.0.0':
|
||||
ref: 'v11.0.0'
|
||||
commit: 'sha1-4391f3da665fdf50b6810c1a66712fb9ba21aa93'
|
||||
owner_id: 44036562
|
||||
repo_id: 200437066
|
||||
'actions/upload-artifact@v7.0.2':
|
||||
ref: 'v7.0.2'
|
||||
commit: 'sha1-cf430e030ddbb5b0abf93d22962f4752f3646cd9'
|
||||
owner_id: 44036562
|
||||
repo_id: 192625955
|
||||
'dessant/lock-threads@v6.0.2':
|
||||
ref: 'v6.0.2'
|
||||
commit: 'sha1-89ae32b08ed1a541efecbab17912962a5e38981c'
|
||||
owner_id: 7513068
|
||||
repo_id: 113918130
|
||||
'docker/build-push-action@v7.4.0':
|
||||
ref: 'v7.4.0'
|
||||
commit: 'sha1-c3c9e263c25d99ce0380d002d59b67737d91b0dc'
|
||||
owner_id: 5429470
|
||||
repo_id: 241092383
|
||||
'docker/login-action@v4.7.0':
|
||||
ref: 'v4.7.0'
|
||||
commit: 'sha1-81c6f93d4bc991e510b342a00b419b3bb4efc5c6'
|
||||
owner_id: 5429470
|
||||
repo_id: 287743349
|
||||
'docker/setup-buildx-action@v4.4.1':
|
||||
ref: 'v4.4.1'
|
||||
commit: 'sha1-f87e5991a6d7451dcb8d9637bfbc97413f497069'
|
||||
owner_id: 5429470
|
||||
repo_id: 288485773
|
||||
'peakoss/anti-slop@v0.3.0':
|
||||
ref: 'v0.3.0'
|
||||
commit: 'sha1-57858eead489d08b255fab2af45a506c2ca6eab2'
|
||||
owner_id: 227272980
|
||||
repo_id: 1153153658
|
||||
@@ -38,7 +38,7 @@ jobs:
|
||||
coolify: ${{ inputs.coolify || steps.plan.outputs.coolify }}
|
||||
steps:
|
||||
- name: Check out the repository
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # https://github.com/actions/checkout/releases/tag/v7.0.1
|
||||
uses: actions/checkout@v7.0.1
|
||||
with:
|
||||
ref: ${{ inputs.ref }}
|
||||
persist-credentials: false
|
||||
@@ -71,7 +71,7 @@ jobs:
|
||||
runner: ubuntu-26.04-arm
|
||||
steps:
|
||||
- name: Check out the repository
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # https://github.com/actions/checkout/releases/tag/v7.0.1
|
||||
uses: actions/checkout@v7.0.1
|
||||
with:
|
||||
ref: ${{ inputs.ref }}
|
||||
persist-credentials: false
|
||||
@@ -85,12 +85,12 @@ jobs:
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Set up Buildx
|
||||
uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # https://github.com/docker/setup-buildx-action/releases/tag/v4.4.1
|
||||
uses: docker/setup-buildx-action@v4.4.1
|
||||
with:
|
||||
cache-binary: false
|
||||
|
||||
- name: Build the image
|
||||
uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # https://github.com/docker/build-push-action/releases/tag/v7.4.0
|
||||
uses: docker/build-push-action@v7.4.0
|
||||
with:
|
||||
context: .
|
||||
file: docker/production/Dockerfile
|
||||
@@ -103,7 +103,7 @@ jobs:
|
||||
GIT_SHA=${{ steps.args.outputs.sha }}
|
||||
|
||||
- name: Upload the image
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # https://github.com/actions/upload-artifact/releases/tag/v7.0.2
|
||||
uses: actions/upload-artifact@v7.0.2
|
||||
with:
|
||||
name: image-${{ matrix.arch }}
|
||||
path: ${{ runner.temp }}/image
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
name: Lock closed Issues, Discussions, and PRs
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 1 * * *'
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
discussions: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
lock-threads:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Lock threads after 30 days of inactivity
|
||||
uses: dessant/lock-threads@89ae32b08ed1a541efecbab17912962a5e38981c # v6.0.2
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
issue-inactive-days: '30'
|
||||
discussion-inactive-days: '30'
|
||||
pr-inactive-days: '30'
|
||||
@@ -1,182 +0,0 @@
|
||||
name: Manage PR Branch
|
||||
|
||||
# Runs *after* the "PR Quality" workflow finishes. This is required because
|
||||
# PR Quality may close a PR that fails its checks, so we must wait for it to
|
||||
# complete before deciding whether to retarget the PR's base branch.
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: ["PR Quality"]
|
||||
types:
|
||||
- completed
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
|
||||
concurrency:
|
||||
group: manage-pr-branch-${{ github.event.workflow_run.head_sha }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
manage-branch:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Retarget PR base branch based on category
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const run = context.payload.workflow_run;
|
||||
|
||||
// Branch routing based on the "Category" section of the PR body.
|
||||
// Bug fixes and one-click service changes ship in patch releases -> main.
|
||||
// Everything else (features, improvements) -> next.
|
||||
const MAIN_BRANCH = 'main';
|
||||
const NEXT_BRANCH = 'next';
|
||||
|
||||
// Maintainers/collaborators are trusted to pick their own base branch.
|
||||
const EXEMPT_ASSOCIATIONS = new Set(['OWNER', 'MEMBER', 'COLLABORATOR']);
|
||||
|
||||
// Resolve the open PR from the triggering run.
|
||||
//
|
||||
// PR Quality runs on `pull_request_target`, so `run.head_sha` is the
|
||||
// *base* branch tip, not the PR head — a commit-based lookup finds
|
||||
// nothing. Instead match on the source branch (`head_branch`) and its
|
||||
// owner (`head_repository.owner.login`), which uniquely identify the PR
|
||||
// via the `owner:branch` head filter. This also works for forked PRs,
|
||||
// where `workflow_run.pull_requests` is empty.
|
||||
const headOwner = run.head_repository?.owner?.login;
|
||||
const headBranch = run.head_branch;
|
||||
|
||||
let prRef;
|
||||
if (headOwner && headBranch) {
|
||||
const { data: openPrs } = await github.rest.pulls.list({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
state: 'open',
|
||||
head: `${headOwner}:${headBranch}`,
|
||||
per_page: 100,
|
||||
});
|
||||
prRef = openPrs[0];
|
||||
}
|
||||
|
||||
// Fallback: same-repo PRs may also be resolvable by commit association.
|
||||
if (!prRef) {
|
||||
const { data: associated } = await github.rest.repos.listPullRequestsAssociatedWithCommit({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
commit_sha: run.head_sha,
|
||||
});
|
||||
prRef = associated.find(pr => pr.state === 'open');
|
||||
}
|
||||
|
||||
if (!prRef) {
|
||||
core.info('No open PR associated with this run (possibly closed by PR Quality). Skipping.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Fetch the full PR to get an up-to-date body, base ref, and state.
|
||||
const { data: pr } = await github.rest.pulls.get({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
pull_number: prRef.number,
|
||||
});
|
||||
|
||||
if (pr.state !== 'open') {
|
||||
core.info(`PR #${pr.number} is not open. Skipping.`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip PRs opened by owners/members/collaborators — they choose their own base.
|
||||
if (EXEMPT_ASSOCIATIONS.has(pr.author_association)) {
|
||||
core.info(`PR #${pr.number} author association is ${pr.author_association}. Skipping.`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip if a maintainer has already changed the base branch manually.
|
||||
const timeline = await github.paginate(github.rest.issues.listEventsForTimeline, {
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: pr.number,
|
||||
per_page: 100,
|
||||
});
|
||||
|
||||
const baseChanges = timeline.filter(e => e.event === 'base_ref_changed');
|
||||
for (const change of baseChanges) {
|
||||
const actor = change.actor?.login;
|
||||
if (!actor) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
const { data: perm } = await github.rest.repos.getCollaboratorPermissionLevel({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
username: actor,
|
||||
});
|
||||
// admin/maintain/write => trusted maintainer.
|
||||
if (['admin', 'maintain', 'write'].includes(perm.permission)) {
|
||||
core.info(`Base branch was changed manually by ${actor} (${perm.permission}). Skipping.`);
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
core.info(`Could not resolve permission for ${actor}: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse the checked category checkboxes from the PR body.
|
||||
const body = pr.body ?? '';
|
||||
const checked = [];
|
||||
const checkboxRegex = /^\s*-\s*\[([ xX])\]\s*(.+?)\s*$/gm;
|
||||
let match;
|
||||
while ((match = checkboxRegex.exec(body)) !== null) {
|
||||
if (match[1].toLowerCase() === 'x') {
|
||||
checked.push(match[2].toLowerCase());
|
||||
}
|
||||
}
|
||||
|
||||
const includesAny = (labels) => labels.some(label => checked.some(c => c.includes(label)));
|
||||
|
||||
const mainCategories = ['bug fix', 'adding new one click service', 'fixing or updating existing one click service'];
|
||||
const nextCategories = ['improvement', 'new feature'];
|
||||
|
||||
const wantsMain = includesAny(mainCategories);
|
||||
const wantsNext = includesAny(nextCategories);
|
||||
|
||||
if (!wantsMain && !wantsNext) {
|
||||
core.info('No category selected in the PR body. Skipping.');
|
||||
return;
|
||||
}
|
||||
|
||||
// If categories from both groups are checked, prefer next: features and
|
||||
// improvements can only be released from the development branch.
|
||||
const targetBranch = wantsNext ? NEXT_BRANCH : MAIN_BRANCH;
|
||||
|
||||
if (pr.base.ref === targetBranch) {
|
||||
core.info(`PR #${pr.number} already targets ${targetBranch}. Nothing to do.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const previousBranch = pr.base.ref;
|
||||
|
||||
await github.rest.pulls.update({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
pull_number: pr.number,
|
||||
base: targetBranch,
|
||||
});
|
||||
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: pr.number,
|
||||
body: [
|
||||
`Based on the selected category, this PR's base branch was automatically changed from \`${previousBranch}\` to \`${targetBranch}\`.`,
|
||||
'',
|
||||
targetBranch === MAIN_BRANCH
|
||||
? 'Bug fixes and one-click service changes target `main`.'
|
||||
: 'New features and improvements target `next`.',
|
||||
'',
|
||||
'If you believe this is incorrect, please let a maintainer know.',
|
||||
].join('\n'),
|
||||
});
|
||||
|
||||
core.info(`Retargeted PR #${pr.number}: ${previousBranch} -> ${targetBranch}.`);
|
||||
@@ -1,32 +0,0 @@
|
||||
name: Manage Stale Issues and PRs
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 2 * * *'
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
manage-stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Manage stale issues and PRs
|
||||
uses: actions/stale@v9
|
||||
id: stale
|
||||
with:
|
||||
stale-issue-message: 'This issue will be automatically closed in a few days if no response is received. Please provide an update with the requested information.'
|
||||
stale-pr-message: 'This pull request requires attention. If no changes or response is received within the next few days, it will be automatically closed. Please update your PR or leave a comment with the requested information.'
|
||||
close-issue-message: 'This issue has been automatically closed due to inactivity.'
|
||||
close-pr-message: 'Thank you for your contribution. Due to inactivity, this PR was automatically closed. If you would like to continue working on this change in the future, feel free to reopen this PR or submit a new one.'
|
||||
days-before-stale: 14
|
||||
days-before-close: 7
|
||||
stale-issue-label: '⏱︎ Stale'
|
||||
stale-pr-label: '⏱︎ Stale'
|
||||
only-labels: '💤 Waiting for feedback, 💤 Waiting for changes'
|
||||
remove-stale-when-updated: true
|
||||
operations-per-run: 100
|
||||
labels-to-remove-when-unstale: '⏱︎ Stale, 💤 Waiting for feedback, 💤 Waiting for changes'
|
||||
close-issue-reason: 'not_planned'
|
||||
exempt-all-milestones: false
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
- name: Check out the repository
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
uses: actions/checkout@v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
@@ -41,7 +41,7 @@ jobs:
|
||||
|
||||
- name: Upload the list of manifests to delete
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
||||
uses: actions/upload-artifact@v7.0.2
|
||||
with:
|
||||
name: manifests-to-delete
|
||||
path: scripts/manifests-to-delete.tsv
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
name: Cleanup Untagged GHCR Images
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
packages: write
|
||||
|
||||
jobs:
|
||||
cleanup-all-packages:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
package: ['coolify', 'coolify-helper']
|
||||
steps:
|
||||
- name: Delete untagged ${{ matrix.package }} images
|
||||
uses: actions/delete-package-versions@v5
|
||||
with:
|
||||
package-name: ${{ matrix.package }}
|
||||
package-type: 'container'
|
||||
min-versions-to-keep: 0
|
||||
delete-only-untagged-versions: 'true'
|
||||
@@ -0,0 +1,30 @@
|
||||
name: Lock threads
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 1 * * *"
|
||||
|
||||
permissions: {}
|
||||
|
||||
cache-mode: none
|
||||
|
||||
concurrency:
|
||||
group: lock-threads
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
lock:
|
||||
name: Lock threads
|
||||
permissions:
|
||||
issues: write # lock the closed issues
|
||||
discussions: write # lock the closed discussions
|
||||
pull-requests: write # lock the closed pull requests
|
||||
runs-on: ubuntu-26.04 # https://github.com/actions/runner-images
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- name: Lock closed threads that were inactive for the last 30 days
|
||||
uses: dessant/lock-threads@v6.0.2
|
||||
with:
|
||||
issue-inactive-days: 30
|
||||
discussion-inactive-days: 30
|
||||
pr-inactive-days: 30
|
||||
@@ -29,7 +29,7 @@ jobs:
|
||||
build: ${{ steps.plan.outputs.build }}
|
||||
steps:
|
||||
- name: Check out main
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # https://github.com/actions/checkout/releases/tag/v7.0.1
|
||||
uses: actions/checkout@v7.0.1
|
||||
with:
|
||||
ref: main
|
||||
fetch-depth: 0
|
||||
@@ -67,13 +67,13 @@ jobs:
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- name: Download the built images
|
||||
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # https://github.com/actions/download-artifact/releases/tag/v8.0.2
|
||||
uses: actions/download-artifact@v8.0.2
|
||||
with:
|
||||
pattern: image-*
|
||||
path: ${{ runner.temp }}/images
|
||||
|
||||
- name: Log in to ghcr.io
|
||||
uses: docker/login-action@81c6f93d4bc991e510b342a00b419b3bb4efc5c6 # https://github.com/docker/login-action/releases/tag/v4.7.0
|
||||
uses: docker/login-action@v4.7.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- name: Check out the repository
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # https://github.com/actions/checkout/releases/tag/v7.0.1
|
||||
uses: actions/checkout@v7.0.1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
|
||||
@@ -29,7 +29,7 @@ jobs:
|
||||
nightly: ${{ steps.plan.outputs.nightly }}
|
||||
steps:
|
||||
- name: Check out next
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # https://github.com/actions/checkout/releases/tag/v7.0.1
|
||||
uses: actions/checkout@v7.0.1
|
||||
with:
|
||||
ref: next
|
||||
fetch-depth: 0
|
||||
@@ -73,20 +73,20 @@ jobs:
|
||||
line: ${{ fromJSON(needs.plan.outputs.nightly).lines }}
|
||||
steps:
|
||||
- name: Download the built images
|
||||
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # https://github.com/actions/download-artifact/releases/tag/v8.0.2
|
||||
uses: actions/download-artifact@v8.0.2
|
||||
with:
|
||||
pattern: image-*
|
||||
path: ${{ runner.temp }}/images
|
||||
|
||||
- name: Log in to ghcr.io
|
||||
uses: docker/login-action@81c6f93d4bc991e510b342a00b419b3bb4efc5c6 # https://github.com/docker/login-action/releases/tag/v4.7.0
|
||||
uses: docker/login-action@v4.7.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Log in to docker.io
|
||||
uses: docker/login-action@81c6f93d4bc991e510b342a00b419b3bb4efc5c6 # https://github.com/docker/login-action/releases/tag/v4.7.0
|
||||
uses: docker/login-action@v4.7.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
@@ -118,7 +118,7 @@ jobs:
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- name: Check out the nightly
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # https://github.com/actions/checkout/releases/tag/v7.0.1
|
||||
uses: actions/checkout@v7.0.1
|
||||
with:
|
||||
ref: ${{ fromJSON(needs.plan.outputs.nightly).revision }}
|
||||
persist-credentials: false
|
||||
|
||||
@@ -1,19 +1,31 @@
|
||||
name: PR Quality
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
issues: read
|
||||
pull-requests: write
|
||||
name: PR quality
|
||||
|
||||
on:
|
||||
# Checks pull requests from forks too, it checks out and runs no code of the pull request
|
||||
# jactionlint ignore=dangerous-triggers
|
||||
pull_request_target:
|
||||
types: [opened, reopened]
|
||||
|
||||
permissions: {}
|
||||
|
||||
cache-mode: none
|
||||
|
||||
concurrency:
|
||||
group: pr-quality-${{ github.event.pull_request.number }}
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
pr-quality:
|
||||
runs-on: ubuntu-latest
|
||||
check:
|
||||
name: Check pull request
|
||||
permissions:
|
||||
contents: read
|
||||
issues: read # read the linked issues
|
||||
pull-requests: write # comment on, label and close the pull request
|
||||
runs-on: ubuntu-26.04 # https://github.com/actions/runner-images
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: peakoss/anti-slop@v0
|
||||
- name: Check the pull request
|
||||
uses: peakoss/anti-slop@v0.3.0
|
||||
with:
|
||||
# General Settings
|
||||
max-failures: 4
|
||||
@@ -37,7 +49,7 @@ jobs:
|
||||
max-emoji-count: 2
|
||||
max-code-references: 5
|
||||
require-linked-issue: false
|
||||
blocked-terms: |
|
||||
blocked-terms: |
|
||||
STRAWBERRY
|
||||
🤖 Generated with Claude Code
|
||||
Generated with Claude Code
|
||||
|
||||
@@ -61,13 +61,13 @@ jobs:
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- name: Download the built images
|
||||
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # https://github.com/actions/download-artifact/releases/tag/v8.0.2
|
||||
uses: actions/download-artifact@v8.0.2
|
||||
with:
|
||||
pattern: image-*
|
||||
path: ${{ runner.temp }}/images
|
||||
|
||||
- name: Log in to ghcr.io
|
||||
uses: docker/login-action@81c6f93d4bc991e510b342a00b419b3bb4efc5c6 # https://github.com/docker/login-action/releases/tag/v4.7.0
|
||||
uses: docker/login-action@v4.7.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
|
||||
@@ -37,7 +37,7 @@ jobs:
|
||||
releases: ${{ steps.plan.outputs.releases }}
|
||||
steps:
|
||||
- name: Check out the repository
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # https://github.com/actions/checkout/releases/tag/v7.0.1
|
||||
uses: actions/checkout@v7.0.1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
@@ -74,25 +74,25 @@ jobs:
|
||||
release: ${{ fromJSON(needs.plan.outputs.releases) }}
|
||||
steps:
|
||||
- name: Check out the repository
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # https://github.com/actions/checkout/releases/tag/v7.0.1
|
||||
uses: actions/checkout@v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Download the built images
|
||||
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # https://github.com/actions/download-artifact/releases/tag/v8.0.2
|
||||
uses: actions/download-artifact@v8.0.2
|
||||
with:
|
||||
pattern: image-*
|
||||
path: ${{ runner.temp }}/images
|
||||
|
||||
- name: Log in to ghcr.io
|
||||
uses: docker/login-action@81c6f93d4bc991e510b342a00b419b3bb4efc5c6 # https://github.com/docker/login-action/releases/tag/v4.7.0
|
||||
uses: docker/login-action@v4.7.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Log in to docker.io
|
||||
uses: docker/login-action@81c6f93d4bc991e510b342a00b419b3bb4efc5c6 # https://github.com/docker/login-action/releases/tag/v4.7.0
|
||||
uses: docker/login-action@v4.7.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
@@ -136,7 +136,7 @@ jobs:
|
||||
tags: ${{ steps.plan.outputs.tags }}
|
||||
steps:
|
||||
- name: Check out the repository
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # https://github.com/actions/checkout/releases/tag/v7.0.1
|
||||
uses: actions/checkout@v7.0.1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
@@ -148,14 +148,14 @@ jobs:
|
||||
echo "tags=$tags" | tee -a "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Log in to ghcr.io
|
||||
uses: docker/login-action@81c6f93d4bc991e510b342a00b419b3bb4efc5c6 # https://github.com/docker/login-action/releases/tag/v4.7.0
|
||||
uses: docker/login-action@v4.7.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Log in to docker.io
|
||||
uses: docker/login-action@81c6f93d4bc991e510b342a00b419b3bb4efc5c6 # https://github.com/docker/login-action/releases/tag/v4.7.0
|
||||
uses: docker/login-action@v4.7.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
@@ -190,7 +190,7 @@ jobs:
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- name: Check out the repository
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # https://github.com/actions/checkout/releases/tag/v7.0.1
|
||||
uses: actions/checkout@v7.0.1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
|
||||
+29
-19
@@ -1,15 +1,30 @@
|
||||
name: Add comment based on label
|
||||
on:
|
||||
pull_request_target:
|
||||
types:
|
||||
- labeled
|
||||
name: Request docs update
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
on:
|
||||
# Comments on pull requests from forks too, it checks out and runs no code of the pull request
|
||||
# jactionlint ignore=dangerous-triggers
|
||||
pull_request_target:
|
||||
types: [labeled]
|
||||
|
||||
permissions: {}
|
||||
|
||||
cache-mode: none
|
||||
|
||||
concurrency:
|
||||
group: request-docs-update-${{ github.event.pull_request.number }}
|
||||
cancel-in-progress: false
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
add-comment:
|
||||
runs-on: ubuntu-latest
|
||||
comment:
|
||||
name: Request docs update (${{ matrix.label }})
|
||||
permissions:
|
||||
pull-requests: write # comment on the pull request
|
||||
runs-on: ubuntu-26.04 # https://github.com/actions/runner-images
|
||||
timeout-minutes: 10
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
@@ -33,20 +48,15 @@ jobs:
|
||||
|
||||
Coolify Docs Repository: https://github.com/coollabsio/coolify-docs
|
||||
How to Contribute to the Docs: https://coolify.io/docs/get-started/contribute/documentation
|
||||
# - label: "✨ Enhancement"
|
||||
# body: |
|
||||
# It appears to us that you are making an enhancement to Coolify.
|
||||
# We kindly ask you to also review and update the Coolify Documentation to include information about this enhancement if applicable.
|
||||
# This will help ensure that our documentation remains accurate and up-to-date for all users.
|
||||
steps:
|
||||
- name: Add comment
|
||||
- name: Comment on the pull request
|
||||
if: >-
|
||||
(github.event.label.name == matrix.label || github.event.label.name == '📑 Waiting for Docs PR')
|
||||
${{ (github.event.label.name == matrix.label || github.event.label.name == '📑 Waiting for Docs PR')
|
||||
&& contains(github.event.pull_request.labels.*.name, matrix.label)
|
||||
&& contains(github.event.pull_request.labels.*.name, '📑 Waiting for Docs PR')
|
||||
run: gh pr comment "$NUMBER" --body "$BODY"
|
||||
&& contains(github.event.pull_request.labels.*.name, '📑 Waiting for Docs PR') }}
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
GH_REPO: ${{ github.repository }}
|
||||
NUMBER: ${{ github.event.pull_request.number }}
|
||||
BODY: ${{ matrix.body }}
|
||||
run: gh pr comment "$NUMBER" --body "$BODY"
|
||||
@@ -0,0 +1,37 @@
|
||||
name: Stale
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 2 * * *"
|
||||
|
||||
permissions: {}
|
||||
|
||||
cache-mode: none
|
||||
|
||||
concurrency:
|
||||
group: stale
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
name: Close stale issues and pull requests
|
||||
permissions:
|
||||
issues: write # label, comment on and close the stale issues
|
||||
pull-requests: write # label, comment on and close the stale pull requests
|
||||
runs-on: ubuntu-26.04 # https://github.com/actions/runner-images
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- name: Close the issues and pull requests that wait for feedback or changes
|
||||
uses: actions/stale@v11.0.0
|
||||
with:
|
||||
only-labels: "💤 Waiting for feedback, 💤 Waiting for changes"
|
||||
days-before-stale: 14
|
||||
days-before-close: 7
|
||||
stale-issue-label: "⏱︎ Stale"
|
||||
stale-pr-label: "⏱︎ Stale"
|
||||
labels-to-remove-when-unstale: "⏱︎ Stale, 💤 Waiting for feedback, 💤 Waiting for changes"
|
||||
stale-issue-message: This issue will be automatically closed in a few days if no response is received. Please provide an update with the requested information.
|
||||
stale-pr-message: This pull request requires attention. If no changes or response is received within the next few days, it will be automatically closed. Please update your PR or leave a comment with the requested information.
|
||||
close-issue-message: This issue has been automatically closed due to inactivity.
|
||||
close-pr-message: Thank you for your contribution. Due to inactivity, this PR was automatically closed. If you would like to continue working on this change in the future, feel free to reopen this PR or submit a new one.
|
||||
operations-per-run: 100
|
||||
@@ -6,6 +6,20 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Security
|
||||
|
||||
- Refuse to update, force-push or delete the git tag of a release, with a tag protection rule on GitHub
|
||||
- Refuse to delete or force-push `main`, `next`, release and maintenance branches, with branch protection rules on GitHub
|
||||
- Protect archive branches from updates, deletions and force-pushing, with branch protection rules on GitHub
|
||||
- Harden the CI workflows
|
||||
- Require every action to be pinned to a full-length commit SHA
|
||||
- Grant every job the least permissions it needs and state the reason for every write permission
|
||||
- Keep the Docker Hub credentials and the CDN token in the `release` environment, which only the branches that release can use
|
||||
- Keep the tokens that delete images in the `cleanup` environment, which only `main` can use
|
||||
- Lock every action and the actions it calls to a commit in `.github/workflows/actions.lock`, together with the IDs of its owner and repository, which a commit SHA alone does not check
|
||||
- Run without the GitHub Actions cache, layer caches and cached tool binaries, so no run restores what another run wrote
|
||||
- Fix every finding of jactionlint pedantic
|
||||
|
||||
### Added
|
||||
|
||||
- Choose the update channel of an instance on the update page: stable, preview with betas and release candidates, nightly with a warning that breaking changes are possible, or a custom image such as `pr-1234`
|
||||
@@ -48,6 +62,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||
|
||||
### Removed
|
||||
|
||||
- Remove the workflow that deleted every untagged image on ghcr.io, one run would delete the platform images and attestations of every release
|
||||
- Remove the workflow that moved pull requests to `main` or `next` by their category, for now
|
||||
- Remove the Windows support with Docker Desktop, `docker-compose.windows.yml` and `.env.windows-docker-desktop.example`, and the testing host image on Docker Hub, which only it used
|
||||
- Remove the Claude workflow and the temporary workflow and image of the PHP base image
|
||||
- Remove the git-cliff workflow that generated `CHANGELOG.md`, it is written by hand
|
||||
@@ -60,4 +76,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||
|
||||
### Maintenance
|
||||
|
||||
- Add `scripts/clean-manifests.sh` and a workflow that delete the unused manifests from ghcr.io and docker.io, such as the leftovers of the old workflows and the images of closed pull requests, and keep every release, every moving tag, the nightlies of the last 14 days and the images of open pull requests
|
||||
- Give every job a name, a timeout, a fixed runner image and a concurrency group
|
||||
- Bump `actions/stale` to v11, GitHub Actions removed the Node.js 20 it ran on
|
||||
- Describe the new release process in `AGENTS.md`
|
||||
|
||||
Reference in New Issue
Block a user