mirror of
https://github.com/lunchcat/sif.git
synced 2026-03-12 21:23:04 -07:00
ci: add pr bot for auto-labeling + rewrite release workflow for semver tags
pr-bot labels PRs by area (scan, nuclei, modules, ci, deps, etc) and size (xs/s/m/l/xl), posts a summary comment with file stats breakdown. release workflow now triggers on v* tags instead of every push to main - extracts version from tag, injects via ldflags, auto-generates changelog from commits since last release, includes install instructions in the release body. prerelease detection for rc/beta tags. Signed-off-by: vmfunc <celeste@linux.com>
This commit is contained in:
44
.github/labeler.yml
vendored
Normal file
44
.github/labeler.yml
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
ci:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ".github/**"
|
||||
|
||||
deps:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- "go.mod"
|
||||
- "go.sum"
|
||||
- "flake.nix"
|
||||
- "flake.lock"
|
||||
|
||||
scan:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: "internal/scan/**"
|
||||
|
||||
nuclei:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: "internal/nuclei/**"
|
||||
|
||||
modules:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- "internal/modules/**"
|
||||
- "internal/scan/builtin/**"
|
||||
- "internal/scan/js/**"
|
||||
- "modules/**"
|
||||
|
||||
docs:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- "**/*.md"
|
||||
- "docs/**"
|
||||
|
||||
tests:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: "**/*_test.go"
|
||||
|
||||
config:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- "internal/config/**"
|
||||
- ".golangci.yml"
|
||||
- ".editorconfig"
|
||||
139
.github/workflows/pr-bot.yml
vendored
Normal file
139
.github/workflows/pr-bot.yml
vendored
Normal file
@@ -0,0 +1,139 @@
|
||||
name: pr bot
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, edited]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
label:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/labeler@v5
|
||||
with:
|
||||
configuration-path: .github/labeler.yml
|
||||
|
||||
size:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: label pr size
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const { data: files } = await github.rest.pulls.listFiles({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
pull_number: context.payload.pull_request.number,
|
||||
per_page: 100,
|
||||
});
|
||||
|
||||
const changes = files.reduce((sum, f) => sum + f.additions + f.deletions, 0);
|
||||
|
||||
let size;
|
||||
if (changes < 10) size = "size/xs";
|
||||
else if (changes < 50) size = "size/s";
|
||||
else if (changes < 200) size = "size/m";
|
||||
else if (changes < 500) size = "size/l";
|
||||
else size = "size/xl";
|
||||
|
||||
const sizeLabels = ["size/xs", "size/s", "size/m", "size/l", "size/xl"];
|
||||
const currentLabels = context.payload.pull_request.labels.map(l => l.name);
|
||||
const toRemove = currentLabels.filter(l => sizeLabels.includes(l) && l !== size);
|
||||
|
||||
for (const label of toRemove) {
|
||||
await github.rest.issues.removeLabel({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: context.payload.pull_request.number,
|
||||
name: label,
|
||||
}).catch(() => {});
|
||||
}
|
||||
|
||||
await github.rest.issues.addLabels({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: context.payload.pull_request.number,
|
||||
labels: [size],
|
||||
});
|
||||
|
||||
ci-summary:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [label, size]
|
||||
if: always()
|
||||
steps:
|
||||
- uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const pr = context.payload.pull_request;
|
||||
const { data: checks } = await github.rest.checks.listForRef({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
ref: pr.head.sha,
|
||||
per_page: 100,
|
||||
});
|
||||
|
||||
const { data: files } = await github.rest.pulls.listFiles({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
pull_number: pr.number,
|
||||
per_page: 100,
|
||||
});
|
||||
|
||||
const additions = files.reduce((sum, f) => sum + f.additions, 0);
|
||||
const deletions = files.reduce((sum, f) => sum + f.deletions, 0);
|
||||
const fileCount = files.length;
|
||||
|
||||
let body = `### pr summary\n\n`;
|
||||
body += `**${fileCount}** files changed (+${additions} -${deletions})\n\n`;
|
||||
|
||||
const goFiles = files.filter(f => f.filename.endsWith('.go')).length;
|
||||
const testFiles = files.filter(f => f.filename.endsWith('_test.go')).length;
|
||||
const ciFiles = files.filter(f => f.filename.startsWith('.github/')).length;
|
||||
const modFiles = files.filter(f => f.filename === 'go.mod' || f.filename === 'go.sum').length;
|
||||
|
||||
if (goFiles > 0 || testFiles > 0 || ciFiles > 0 || modFiles > 0) {
|
||||
body += `| category | files |\n|----------|-------|\n`;
|
||||
if (goFiles > 0) body += `| go source | ${goFiles} |\n`;
|
||||
if (testFiles > 0) body += `| tests | ${testFiles} |\n`;
|
||||
if (ciFiles > 0) body += `| ci/workflows | ${ciFiles} |\n`;
|
||||
if (modFiles > 0) body += `| deps | ${modFiles} |\n`;
|
||||
body += `\n`;
|
||||
}
|
||||
|
||||
// find existing bot comment
|
||||
const { data: comments } = await github.rest.issues.listComments({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: pr.number,
|
||||
});
|
||||
|
||||
const marker = '<!-- sif-pr-bot -->';
|
||||
body = marker + '\n' + body;
|
||||
|
||||
const existing = comments.find(c =>
|
||||
c.user.type === 'Bot' && c.body.includes(marker)
|
||||
);
|
||||
|
||||
if (existing) {
|
||||
await github.rest.issues.updateComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
comment_id: existing.id,
|
||||
body,
|
||||
});
|
||||
} else {
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: pr.number,
|
||||
body,
|
||||
});
|
||||
}
|
||||
103
.github/workflows/release.yml
vendored
103
.github/workflows/release.yml
vendored
@@ -2,7 +2,8 @@ name: release
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
tags:
|
||||
- "v*"
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
@@ -24,21 +25,24 @@ jobs:
|
||||
with:
|
||||
go-version: "1.24"
|
||||
|
||||
- name: extract version
|
||||
run: echo "VERSION=${GITHUB_REF_NAME#v}" >> $GITHUB_ENV
|
||||
|
||||
- name: build for windows
|
||||
run: |
|
||||
GOOS=windows GOARCH=amd64 go build -o sif-windows-amd64.exe ./cmd/sif
|
||||
GOOS=windows GOARCH=386 go build -o sif-windows-386.exe ./cmd/sif
|
||||
GOOS=windows GOARCH=amd64 go build -ldflags="-s -w -X main.version=${{ env.VERSION }}" -o sif-windows-amd64.exe ./cmd/sif
|
||||
GOOS=windows GOARCH=386 go build -ldflags="-s -w -X main.version=${{ env.VERSION }}" -o sif-windows-386.exe ./cmd/sif
|
||||
|
||||
- name: build for macOS
|
||||
run: |
|
||||
GOOS=darwin GOARCH=amd64 go build -o sif-macos-amd64 ./cmd/sif
|
||||
GOOS=darwin GOARCH=arm64 go build -o sif-macos-arm64 ./cmd/sif
|
||||
GOOS=darwin GOARCH=amd64 go build -ldflags="-s -w -X main.version=${{ env.VERSION }}" -o sif-macos-amd64 ./cmd/sif
|
||||
GOOS=darwin GOARCH=arm64 go build -ldflags="-s -w -X main.version=${{ env.VERSION }}" -o sif-macos-arm64 ./cmd/sif
|
||||
|
||||
- name: build for linux
|
||||
run: |
|
||||
GOOS=linux GOARCH=amd64 go build -o sif-linux-amd64 ./cmd/sif
|
||||
GOOS=linux GOARCH=386 go build -o sif-linux-386 ./cmd/sif
|
||||
GOOS=linux GOARCH=arm64 go build -o sif-linux-arm64 ./cmd/sif
|
||||
GOOS=linux GOARCH=amd64 go build -ldflags="-s -w -X main.version=${{ env.VERSION }}" -o sif-linux-amd64 ./cmd/sif
|
||||
GOOS=linux GOARCH=386 go build -ldflags="-s -w -X main.version=${{ env.VERSION }}" -o sif-linux-386 ./cmd/sif
|
||||
GOOS=linux GOARCH=arm64 go build -ldflags="-s -w -X main.version=${{ env.VERSION }}" -o sif-linux-arm64 ./cmd/sif
|
||||
|
||||
- name: package releases with modules
|
||||
run: |
|
||||
@@ -57,8 +61,6 @@ jobs:
|
||||
|
||||
- name: build debian packages
|
||||
run: |
|
||||
VERSION="0.1.0-$(git rev-parse --short HEAD)"
|
||||
|
||||
declare -A arch_map=(
|
||||
["sif-linux-amd64"]="amd64"
|
||||
["sif-linux-386"]="i386"
|
||||
@@ -67,7 +69,7 @@ jobs:
|
||||
|
||||
for binary in sif-linux-amd64 sif-linux-386 sif-linux-arm64; do
|
||||
arch="${arch_map[$binary]}"
|
||||
pkg_dir="sif_${VERSION}_${arch}"
|
||||
pkg_dir="sif_${{ env.VERSION }}_${arch}"
|
||||
|
||||
mkdir -p "${pkg_dir}/DEBIAN"
|
||||
mkdir -p "${pkg_dir}/usr/bin"
|
||||
@@ -79,11 +81,11 @@ jobs:
|
||||
|
||||
cat > "${pkg_dir}/DEBIAN/control" << EOF
|
||||
Package: sif
|
||||
Version: ${VERSION}
|
||||
Version: ${{ env.VERSION }}
|
||||
Section: security
|
||||
Priority: optional
|
||||
Architecture: ${arch}
|
||||
Maintainer: vmfunc <celeste@router.sex>
|
||||
Maintainer: vmfunc <celeste@linux.com>
|
||||
Homepage: https://github.com/vmfunc/sif
|
||||
Description: Modular pentesting toolkit
|
||||
sif is a fast, concurrent, and extensible pentesting toolkit written in Go.
|
||||
@@ -113,41 +115,71 @@ jobs:
|
||||
artifact-name: sbom.spdx.json
|
||||
output-file: sbom.spdx.json
|
||||
|
||||
- name: set release version
|
||||
run: echo "RELEASE_VERSION=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
|
||||
- name: generate changelog
|
||||
id: changelog
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
result-encoding: string
|
||||
script: |
|
||||
const { data: releases } = await github.rest.repos.listReleases({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
per_page: 1,
|
||||
});
|
||||
|
||||
- name: create release and upload assets
|
||||
const prev = releases.length > 0 ? releases[0].tag_name : '';
|
||||
const range = prev ? `${prev}...${context.ref}` : '';
|
||||
|
||||
const { data: commits } = await github.rest.repos.compareCommitsWithBasehead({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
basehead: prev ? `${prev}...${{ github.ref_name }}` : `${{ github.sha }}~10...${{ github.sha }}`,
|
||||
}).catch(() => ({ data: { commits: [] } }));
|
||||
|
||||
let log = '';
|
||||
for (const c of commits.commits || []) {
|
||||
const msg = c.commit.message.split('\n')[0];
|
||||
const sha = c.sha.substring(0, 7);
|
||||
log += `- ${msg} (${sha})\n`;
|
||||
}
|
||||
|
||||
return log || 'initial release';
|
||||
|
||||
- name: create release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: automated-release-${{ env.RELEASE_VERSION }}
|
||||
name: Release ${{ env.RELEASE_VERSION }}
|
||||
name: sif v${{ env.VERSION }}
|
||||
body: |
|
||||
Automated release v${{ env.RELEASE_VERSION }}
|
||||
## what's changed
|
||||
|
||||
## Assets
|
||||
${{ steps.changelog.outputs.result }}
|
||||
|
||||
Each archive contains the sif binary and built-in modules.
|
||||
## install
|
||||
|
||||
- Windows (64-bit): `sif-windows-amd64.zip`
|
||||
- Windows (32-bit): `sif-windows-386.zip`
|
||||
- macOS (64-bit Intel): `sif-macos-amd64.tar.gz`
|
||||
- macOS (64-bit ARM): `sif-macos-arm64.tar.gz`
|
||||
- Linux (64-bit): `sif-linux-amd64.tar.gz`
|
||||
- Linux (32-bit): `sif-linux-386.tar.gz`
|
||||
- Linux (64-bit ARM): `sif-linux-arm64.tar.gz`
|
||||
- Debian/Ubuntu (64-bit): `sif_*_amd64.deb`
|
||||
- Debian/Ubuntu (32-bit): `sif_*_i386.deb`
|
||||
- Debian/Ubuntu (64-bit ARM): `sif_*_arm64.deb`
|
||||
**homebrew / linuxbrew**
|
||||
```bash
|
||||
# coming soon
|
||||
```
|
||||
|
||||
## Verification
|
||||
**debian / ubuntu**
|
||||
```bash
|
||||
sudo dpkg -i sif_${{ env.VERSION }}_amd64.deb
|
||||
```
|
||||
|
||||
**go install**
|
||||
```bash
|
||||
go install github.com/dropalldatabases/sif/cmd/sif@v${{ env.VERSION }}
|
||||
```
|
||||
|
||||
**binary download** - grab the right archive from below.
|
||||
|
||||
## verification
|
||||
|
||||
```bash
|
||||
sha256sum -c checksums-sha256.txt
|
||||
```
|
||||
|
||||
For more details, check the [commit history](https://github.com/${{ github.repository }}/commits/main).
|
||||
draft: false
|
||||
prerelease: false
|
||||
prerelease: ${{ contains(github.ref_name, '-') }}
|
||||
files: |
|
||||
sif-windows-amd64.zip
|
||||
sif-windows-386.zip
|
||||
@@ -165,6 +197,7 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: push to cloudsmith
|
||||
if: ${{ !contains(github.ref_name, '-') }}
|
||||
env:
|
||||
CLOUDSMITH_API_KEY: ${{ secrets.CLOUDSMITH_API_KEY }}
|
||||
run: |
|
||||
|
||||
Reference in New Issue
Block a user