Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
5fd2e25
feat: add genai-assisted label
pierresisson Jan 5, 2026
7ab8490
feat: add more filters
pierresisson Jan 5, 2026
bd3808b
pattern
pierresisson Jan 5, 2026
d964636
test: point workflow to feature branch for testing
pierresisson Jan 5, 2026
4addaef
fix: make PR body patterns much more permissive
pierresisson Jan 5, 2026
64120c7
feat: remove test
pierresisson Jan 5, 2026
0e47ead
feat: add tests + better pattern
pierresisson Jan 5, 2026
31cabff
test
pierresisson Jan 5, 2026
ee6f171
Apply suggestion from @Copilot
pierresisson Jan 5, 2026
d2a716c
Apply suggestion from @Copilot
pierresisson Jan 5, 2026
827d6c1
Apply suggestions from code review
pierresisson Jan 5, 2026
15b3674
Apply suggestions from code review
pierresisson Jan 5, 2026
383a7a4
feat: add claude hook
pierresisson Jan 6, 2026
993a052
prettier
pierresisson Jan 6, 2026
3836a75
fix eslint
pierresisson Jan 6, 2026
591b408
readibility
pierresisson Jan 6, 2026
ed46503
labels
pierresisson Jan 6, 2026
6a105a1
copilot
pierresisson Jan 6, 2026
2c5de9a
yolo
pierresisson Jan 6, 2026
fb0b047
prettier
pierresisson Jan 6, 2026
45f8569
improve
pierresisson Jan 7, 2026
298f2d8
add patterns
pierresisson Jan 7, 2026
f1f806b
test label
pierresisson Jan 7, 2026
5b43438
test label 2
pierresisson Jan 7, 2026
1b15c55
test label 2
pierresisson Jan 7, 2026
8af5e32
test label 2
pierresisson Jan 7, 2026
67d6465
test label 2
pierresisson Jan 7, 2026
c2bff15
yo
pierresisson Jan 7, 2026
437c978
copilot
pierresisson Jan 7, 2026
dcd3e5f
hook cursor
pierresisson Jan 7, 2026
41b1a0b
test cursor
pierresisson Jan 7, 2026
1168633
rework
pierresisson Jan 8, 2026
7152d71
rework
pierresisson Jan 8, 2026
04a8ff1
test label 2
pierresisson Jan 8, 2026
13238ae
lbl
pierresisson Jan 8, 2026
9313623
yo
pierresisson Jan 8, 2026
8b72856
yo
pierresisson Jan 8, 2026
ef9fc27
docs: readme
pierresisson Jan 8, 2026
dce61ba
copilot review
pierresisson Jan 8, 2026
341624c
copilot review
pierresisson Jan 8, 2026
879a1b2
prettier
pierresisson Jan 8, 2026
744e177
docs: better readme
pierresisson Jan 8, 2026
15033ea
review + prettier + sortpackage
pierresisson Jan 8, 2026
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
14 changes: 14 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "touch .claude-assisted"
}
]
}
]
}
}
10 changes: 10 additions & 0 deletions .cursor/hooks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"version": 1,
"hooks": {
"stop": [
{
"command": "touch .cursor-assisted"
}
]
}
}
Empty file added .genai-assisted
Empty file.
27 changes: 27 additions & 0 deletions .githooks/prepare-commit-msg
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/bin/sh
COMMIT_MSG_FILE=$1
COMMIT_SOURCE=$2

# Skip for merge/squash commits
case "$COMMIT_SOURCE" in
merge|squash) exit 0 ;;
esac

# Check if Co-Authored-By is already present
if grep -qi "co-authored-by:.*\(claude\|cursor\|genai\)" "$COMMIT_MSG_FILE"; then
rm -f .cursor-assisted .claude-assisted
exit 0
fi

# Add Co-Authored-By based on which agent was used
if [ -f ".cursor-assisted" ]; then
echo "" >> "$COMMIT_MSG_FILE"
echo "Co-Authored-By: Cursor" >> "$COMMIT_MSG_FILE"
rm -f .cursor-assisted
fi

if [ -f ".claude-assisted" ]; then
echo "" >> "$COMMIT_MSG_FILE"
echo "Co-Authored-By: Claude" >> "$COMMIT_MSG_FILE"
rm -f .claude-assisted
fi
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ coverage
.LSOverride

# Icon must end with two \r
Icon
Icon

# Thumbnails
._*
Expand Down Expand Up @@ -54,3 +54,7 @@ tags


# End of https://www.toptal.com/developers/gitignore/api/macos,vim

# GenAI marker files (created by agent hooks)
.cursor-assisted
.claude-assisted
43 changes: 30 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,47 @@

[![NPM](https://github.com/mobsuccess-devops/github-actions-mobsuccess/actions/workflows/npm.yml/badge.svg)](https://github.com/mobsuccess-devops/github-actions-mobsuccess/actions/workflows/npm.yml)

This action validates that the various Mobsuccess policies are enforced when
changes are made to the repository. It checks, for example, the title of the
pull request, the names of the branch…
GitHub Action enforcing Mobsuccess policies on repositories.

# Install the workflow in repository
## Installation

You do not need to make any action to install the GitHub Action workflow,
ms-bot will automatically make PRs on your repository when changes are needed.
No manual setup required - ms-bot automatically creates PRs when changes are needed.

# ACTIONS
## Features

## Changelog
| Action | Description |
| ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `validate-pr` | Validates PR title and branch name conventions, adds branch tag label, detects GenAI-assisted PRs (adds `genai-assisted` label), posts AWS Amplify preview links |
| `changelog` | Generates changelog for the last X releases |

The changelog action allows to generate on a particular repo, a changelog for the last X tags.
## Usage

The "latest tag" corresponds to a tag that has not been pushed as a release. As this action is based on GH releases, it allows to generate the changelog between the last release and the tag being created right now.
### validate-pr

Usage:
```yml
- uses: mobsuccess-devops/github-actions-mobsuccess@master
with:
github-token: ${{ github.token }}
action: validate-pr
```

### changelog

```yml
- uses: mobsuccess-devops/github-actions-mobsuccess@master
with:
github-token: ${{ github.token }}
action: changelog
max-releases: 10 #(optional, default to 10)
unreleased-tag: 0.0.90289303809 # newly created unreleased tag (optional)
max-releases: 10 # optional, default 10
unreleased-tag: 0.0.1 # optional, newly created tag
```

## GenAI Detection

Automatically detects AI-assisted PRs and adds the `genai-assisted` label.

**Detection triggers:** PR author (bot accounts), branch prefix (`cursor/`, `claude/`, `ai/`...), PR body mentions, existing AI labels, commit messages (`Co-Authored-By: Claude`, etc.)

**Supported tools:** Claude, Copilot, ChatGPT, Cursor, Gemini, Windsurf, Codeium, Tabnine, Aider, Devin, Amazon Q, and more.

**Customization:** Edit `lib/genaiPatterns.js` to add patterns.
75 changes: 74 additions & 1 deletion lib/actions/pullRequest.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ const {
isPullRequestTitleValid: isPullRequestTitleValid,
} = require("../pullRequest");
const { getAmplifyURIs } = require("./amplify");
const {
detectGenAI,
GENAI_LABEL,
GENAI_LABEL_COLOR,
GENAI_LABEL_DESCRIPTION,
} = require("../genaiDetection");

exports.validatePR = async function validatePR({ pullRequest, issue }) {
const octokit = getOctokit();
Expand Down Expand Up @@ -59,6 +65,74 @@ exports.validatePR = async function validatePR({ pullRequest, issue }) {
// ignore error
console.log(`Could not apply label: ${e}`);
}

try {
const genaiResult = await detectGenAI(octokit, {
owner,
repo,
pullNumber,
pullRequest,
});

if (genaiResult.detected) {
console.log(`GenAI detected: ${genaiResult.reason}`);
// Ensure label exists with correct color/description
let labelExists = false;
try {
const { data: existingLabel } = await octokit.issues.getLabel({
owner,
repo,
name: GENAI_LABEL,
});
// Update if color or description differs
if (
existingLabel.color !== GENAI_LABEL_COLOR ||
existingLabel.description !== GENAI_LABEL_DESCRIPTION
) {
await octokit.issues.updateLabel({
owner,
repo,
name: GENAI_LABEL,
color: GENAI_LABEL_COLOR,
description: GENAI_LABEL_DESCRIPTION,
});
console.log(`Updated label "${GENAI_LABEL}"`);
}
labelExists = true;
} catch (err) {
if (err.status === 404) {
labelExists = false;
} else {
throw err;
}
}
if (!labelExists) {
await octokit.issues.createLabel({
owner,
repo,
name: GENAI_LABEL,
color: GENAI_LABEL_COLOR,
description: GENAI_LABEL_DESCRIPTION,
});
console.log(
`Created label "${GENAI_LABEL}" with color #${GENAI_LABEL_COLOR}`
);
}
await octokit.issues.addLabels({
owner,
repo,
issue_number: pullNumber,
labels: [GENAI_LABEL],
});
console.log(`Added "${GENAI_LABEL}" label to PR #${pullNumber}`);
} else if (genaiResult.alreadyLabeled) {
console.log(`PR #${pullNumber} already has "${GENAI_LABEL}" label`);
} else {
console.log(`No GenAI assistance detected in PR #${pullNumber}`);
}
} catch (e) {
console.log(`Warning: GenAI detection failed: ${e.message}`);
}
}

// do we have an AWS Amplify URI? If so, make sure that at least one comment
Expand Down Expand Up @@ -139,7 +213,6 @@ exports.validatePR = async function validatePR({ pullRequest, issue }) {
);
}

// delete the bogus comments by the aws-amplify robot
const bogusComments = comments.filter(({ user: { login } }) =>
login.match(/^aws-amplify-/)
);
Expand Down
4 changes: 0 additions & 4 deletions lib/actions/pullRequestMerged.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ const sendRebaseOntoCommentOnSubbranches = async ({
owner: { login: owner },
name: repo,
} = repoObject;
// fetch the pull request from github
const { data: pr } = await octokit.rest.pulls.get({
owner,
repo,
Expand All @@ -22,7 +21,6 @@ const sendRebaseOntoCommentOnSubbranches = async ({
);
return;
}
// find all opened pull requests having the merged PR as base
const { data: subprs } = await octokit.rest.pulls.list({
owner,
repo,
Expand All @@ -49,7 +47,6 @@ git fetch && git rebase --onto origin/master ${lastCommitOfParentPR} && git push
\`\`\`
`;

// post a comment in each subprs
for (const pr of subprs) {
console.log(
`*** PR #${pr.number} is a subpr of #${mergedPrNumber} which has been merged into master`
Expand All @@ -63,7 +60,6 @@ git fetch && git rebase --onto origin/master ${lastCommitOfParentPR} && git push
return comment.body.startsWith(commentToDetectComment);
});
if (comment) {
// if body is different, update body
if (comment.body !== body) {
await octokit.rest.issues.updateComment({
owner,
Expand Down
Loading
Loading