Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
65 changes: 65 additions & 0 deletions .github/workflows/assign-command.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
name: Assign command

on:
issue_comment:
types: [created]

permissions:
issues: write

jobs:
assign:
if: ${{ !github.event.issue.pull_request && (github.event.comment.body == '/assign' || github.event.comment.body == '/unassign') }}
runs-on: ubuntu-latest
steps:
- name: Handle /assign
if: github.event.comment.body == '/assign'
uses: actions/github-script@v7
with:
script: |
const { owner, repo } = context.repo;
const issue_number = context.issue.number;
const commenter = context.payload.comment.user.login;

const { data: issue } = await github.rest.issues.get({ owner, repo, issue_number });

if (issue.assignees.length > 0) {
const names = issue.assignees.map(a => `@${a.login}`).join(', ');
await github.rest.issues.createComment({
owner, repo, issue_number,
body: `⚠️ This issue is already assigned to ${names}. Ask them to comment \`/unassign\` first if they're no longer working on it.`,
});
return;
}

await github.rest.issues.addAssignees({ owner, repo, issue_number, assignees: [commenter] });
await github.rest.issues.createComment({
owner, repo, issue_number,
body: `✅ Assigned to @${commenter}. Comment \`/unassign\` if you can no longer work on this. Open a PR that includes \`Closes #${issue_number}\` in its description when you're ready for review.`,
});

- name: Handle /unassign
if: github.event.comment.body == '/unassign'
uses: actions/github-script@v7
with:
script: |
const { owner, repo } = context.repo;
const issue_number = context.issue.number;
const commenter = context.payload.comment.user.login;

const { data: issue } = await github.rest.issues.get({ owner, repo, issue_number });
const isAssigned = issue.assignees.some(a => a.login === commenter);

if (!isAssigned) {
await github.rest.issues.createComment({
owner, repo, issue_number,
body: `⚠️ @${commenter}, you're not currently assigned to this issue.`,
});
return;
}

await github.rest.issues.removeAssignees({ owner, repo, issue_number, assignees: [commenter] });
await github.rest.issues.createComment({
owner, repo, issue_number,
body: `Unassigned @${commenter}. This issue is open again — comment \`/assign\` to pick it up.`,
});
48 changes: 48 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Contributing to Modly

Thanks for wanting to help out! You don't need write access to the repository to
pick up a ticket, work on it, and ship a fix — here's how the flow works.

## Finding something to work on

- Browse [open issues](https://github.com/lightningpixel/modly/issues) or the
[project board](https://github.com/users/lightningpixel/projects/1).
- Issues labeled `good first issue` are a good place to start if you're new to
the codebase. See [`CLAUDE.md`](./CLAUDE.md) for an architecture overview.

## Claiming a ticket

Comment **`/assign`** on the issue you want to work on. A bot will assign it to
you automatically — no repo permissions required.

- Only one person can be assigned to an issue at a time. If it's already
assigned, ask the assignee first or wait for them to release it.
- No longer working on it? Comment **`/unassign`** to free it up for someone
else.

This keeps the [project board](https://github.com/users/lightningpixel/projects/1)
honest: an assigned issue moves to **In progress** automatically, so anyone
looking at the board can see what's actively being worked on.

## Submitting your work

1. **Fork** the repository and create a branch for your change.
2. Make your change. Keep it focused — one issue, one PR.
3. Run the checks locally before opening a PR:
```bash
npm run lint
npm run test
```
4. Open a **pull request** against `dev`. Include `Closes #<issue-number>` in
the PR description so it's linked to the ticket and closes it automatically
on merge.

Opening a PR from your fork moves the linked issue to **Ready to review** on
the board. Once a maintainer approves the review, it moves to **Ready to
test**; once merged, it moves to **Done**.

## Getting help

If something in an issue is unclear, ask in a comment on the issue itself
before starting — it's cheaper to clarify scope up front than to redo work
later.
Loading