mirror of
https://github.com/coollabsio/coolify.git
synced 2026-11-04 10:42:23 +00:00
ci: clean up the issue and pull request workflows
- name the files and workflows like the release workflows and every step after what it does - run all workflows without the GitHub Actions cache like the release workflow
This commit is contained in:
1 parent
79fd5a8f7e
commit
c38ce3caef
8 files changed
+91
-287
No files matched your search
@@ -8,16 +8,11 @@ workflows:
|
||||
- 'actions/upload-artifact@v7.0.2'
|
||||
- 'docker/build-push-action@v7.4.0'
|
||||
- 'docker/setup-buildx-action@v4.4.1'
|
||||
'.github/workflows/chore-lock-closed-issues-discussions-and-prs.yml':
|
||||
- 'dessant/lock-threads@v6.0.2'
|
||||
'.github/workflows/chore-manage-pr-branch.yaml':
|
||||
- 'actions/github-script@v9.0.0'
|
||||
'.github/workflows/chore-manage-stale-issues-and-prs.yml':
|
||||
- 'actions/stale@v11.0.0'
|
||||
'.github/workflows/chore-pr-comments.yml': []
|
||||
'.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'
|
||||
@@ -37,6 +32,9 @@ workflows:
|
||||
- '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'
|
||||
@@ -48,11 +46,6 @@ dependencies:
|
||||
commit: 'sha1-9000827ccba6bdab643e8b6fd33ac0654aef8333'
|
||||
owner_id: 44036562
|
||||
repo_id: 192626254
|
||||
'actions/github-script@v9.0.0':
|
||||
ref: 'v9.0.0'
|
||||
commit: 'sha1-3a2844b7e9c422d3c10d287c895573f7108da1b3'
|
||||
owner_id: 44036562
|
||||
repo_id: 205262760
|
||||
'actions/stale@v11.0.0':
|
||||
ref: 'v11.0.0'
|
||||
commit: 'sha1-4391f3da665fdf50b6810c1a66712fb9ba21aa93'
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
name: Lock closed Issues, Discussions, and PRs
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 1 * * *'
|
||||
|
||||
permissions: {}
|
||||
|
||||
concurrency:
|
||||
group: lock-threads
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
lock-threads:
|
||||
name: Lock inactive threads
|
||||
permissions:
|
||||
issues: write # lock the inactive issues
|
||||
discussions: write # lock the inactive discussions
|
||||
pull-requests: write # lock the inactive pull requests
|
||||
runs-on: ubuntu-26.04 # https://github.com/actions/runner-images
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- name: Lock threads after 30 days of inactivity
|
||||
uses: dessant/lock-threads@v6.0.2
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
issue-inactive-days: '30'
|
||||
discussion-inactive-days: '30'
|
||||
pr-inactive-days: '30'
|
||||
@@ -1,187 +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:
|
||||
# Only reads the PR Quality run and the pull request through the API, it checks out and runs no code of the pull request
|
||||
# jactionlint ignore=dangerous-triggers
|
||||
workflow_run:
|
||||
workflows: ["PR Quality"]
|
||||
types:
|
||||
- completed
|
||||
|
||||
permissions: {}
|
||||
|
||||
concurrency:
|
||||
group: manage-pr-branch-${{ github.event.workflow_run.head_sha }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
manage-branch:
|
||||
name: Retarget the pull request
|
||||
permissions:
|
||||
contents: read # read the branches of the repository
|
||||
pull-requests: write # change the base branch of the pull request and comment on it
|
||||
runs-on: ubuntu-26.04 # https://github.com/actions/runner-images
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- name: Retarget PR base branch based on category
|
||||
uses: actions/github-script@v9.0.0
|
||||
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,39 +0,0 @@
|
||||
name: Manage Stale Issues and PRs
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 2 * * *'
|
||||
|
||||
permissions: {}
|
||||
|
||||
concurrency:
|
||||
group: manage-stale
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
manage-stale:
|
||||
name: Manage stale issues and PRs
|
||||
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: Manage stale issues and PRs
|
||||
uses: actions/stale@v11.0.0
|
||||
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
|
||||
@@ -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
|
||||
@@ -1,4 +1,4 @@
|
||||
name: PR Quality
|
||||
name: PR quality
|
||||
|
||||
on:
|
||||
# Checks pull requests from forks too, it checks out and runs no code of the pull request
|
||||
@@ -8,21 +8,24 @@ on:
|
||||
|
||||
permissions: {}
|
||||
|
||||
cache-mode: none
|
||||
|
||||
concurrency:
|
||||
group: pr-quality-${{ github.event.pull_request.number }}
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
pr-quality:
|
||||
name: Check the pull request
|
||||
check:
|
||||
name: Check pull request
|
||||
permissions:
|
||||
contents: read # read the commits and files of the pull request
|
||||
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.3.0
|
||||
- name: Check the pull request
|
||||
uses: peakoss/anti-slop@v0.3.0
|
||||
with:
|
||||
# General Settings
|
||||
max-failures: 4
|
||||
@@ -46,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
|
||||
|
||||
+10
-14
@@ -1,16 +1,17 @@
|
||||
name: Add comment based on label
|
||||
name: Request docs update
|
||||
|
||||
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
|
||||
types: [labeled]
|
||||
|
||||
permissions: {}
|
||||
|
||||
cache-mode: none
|
||||
|
||||
concurrency:
|
||||
group: pr-comments-${{ github.event.pull_request.number }}
|
||||
group: request-docs-update-${{ github.event.pull_request.number }}
|
||||
cancel-in-progress: false
|
||||
|
||||
defaults:
|
||||
@@ -18,8 +19,8 @@ defaults:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
add-comment:
|
||||
name: Ask for the docs of ${{ matrix.label }}
|
||||
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
|
||||
@@ -47,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')
|
||||
&& 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"
|
||||
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
|
||||
Reference in new issue
Block a user