Skip to content

!refactor: rename <Comark> components to <Markdown> and more #57

!refactor: rename <Comark> components to <Markdown> and more

!refactor: rename <Comark> components to <Markdown> and more #57

name: commit-signature
on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
permissions:
contents: read
pull-requests: write
jobs:
check:
name: signed commits
runs-on: ubuntu-latest
# Skip draft PRs — only enforce when ready for review
if: github.event.pull_request.draft == false
steps:
- name: Check commit signatures
uses: actions/github-script@v7
with:
script: |
const { owner, repo } = context.repo
const pr = context.payload.pull_request
const prNumber = pr.number
const author = pr.user.login
const baseSha = pr.base.sha
const headSha = pr.head.sha
const marker = '<!-- commit-signature-check -->'
// Fetch all commits on the PR (paginated)
const commits = await github.paginate(github.rest.pulls.listCommits, {
owner,
repo,
pull_number: prNumber,
per_page: 100,
})
const unsigned = []
for (const commit of commits) {
const verified = commit.commit?.verification?.verified === true
if (!verified) {
unsigned.push({
sha: commit.sha,
short: commit.sha.slice(0, 7),
message: (commit.commit?.message || '').split('\n')[0],
author: commit.author?.login || commit.commit?.author?.name || 'unknown',
reason: commit.commit?.verification?.reason || 'unsigned',
})
}
}
// Find an existing bot comment so we can update or remove it
const comments = await github.paginate(github.rest.issues.listComments, {
owner,
repo,
issue_number: prNumber,
per_page: 100,
})
const existing = comments.find(
(c) => c.user?.type === 'Bot' && c.body?.includes(marker)
)
if (unsigned.length === 0) {
core.info(`All ${commits.length} commit(s) are signed.`)
if (existing) {
await github.rest.issues.deleteComment({
owner,
repo,
comment_id: existing.id,
})
}
return
}
const list = unsigned
.map(
(c) =>
`- \`${c.short}\` — ${c.message} _(by @${c.author}, reason: \`${c.reason}\`)`
)
.join('\n')
const body = [
marker,
'## ✍️ Unsigned commit(s) detected',
'',
`@${author} one or more commits on this PR are **not signed**. Please sign them and update the PR.`,
'',
'### Unsigned commits',
'',
list,
'',
'### How to fix',
'',
'Sign your commits with GPG or SSH, then force-push the updated history:',
'',
'```bash',
'# Configure signing once (GPG example)',
'git config --global commit.gpgsign true',
'# or SSH: git config --global gpg.format ssh && git config --global user.signingkey ~/.ssh/id_ed25519.pub',
'',
'# Re-sign all commits on this branch (from the merge base)',
`git rebase --exec 'git commit --amend --no-edit -S' ${baseSha}`,
'',
'# Push the rewritten history',
'git push --force-with-lease',
'```',
'',
'If you only need to re-sign the tip commit:',
'',
'```bash',
'git commit --amend --no-edit -S',
'git push --force-with-lease',
'```',
'',
'See GitHub\'s guide: [About commit signature verification](https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification).',
].join('\n')
if (existing) {
await github.rest.issues.updateComment({
owner,
repo,
comment_id: existing.id,
body,
})
} else {
await github.rest.issues.createComment({
owner,
repo,
issue_number: prNumber,
body,
})
}
core.setFailed(
`${unsigned.length} unsigned commit(s) found. @${author} please sign and update the commits.`
)