Skip to content
Draft
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
8 changes: 8 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
* text=auto eol=lf
*.[cC][mM][dD] text eol=crlf
*.[bB][aA][tT] text eol=crlf
*.css linguist-vendored
*.scss linguist-vendored
*.js linguist-vendored
*.json merge=json
CHANGELOG.md export-ignore
63 changes: 63 additions & 0 deletions .github/instructions/commit.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
---
description: 'Use when writing or reviewing git commit messages, changelogs, or version bumps. Covers Conventional Commits rules, scopes, and types.'
---

<!-- @format -->

## Commit Message Format

Commit message titles must follow [Conventional Commits](https://www.conventionalcommits.org/) rules, enforced by commitlint (`package.json` → `commitlint`).

**Pattern:** `<type>(<scope>): <summary>`

- **Scope is required** — commitlint enforces `scope-enum: always`
- **Summary**: imperative mood, lowercase start, no period at the end (e.g. `add`, not `Added` or `ADDS`)
- **No emoji** in the title — added automatically by devmoji based on type

## Allowed Types

From `@commitlint/config-conventional`:

| Type | When to use | Semver impact |
| ---------- | ------------------------------------------------------------ | ------------- |
| `feat` | New feature or capability visible to users | minor bump |
| `fix` | Bug fix that corrects incorrect behavior | patch bump |
| `perf` | Performance improvement, no behavior change | patch bump |
| `refactor` | Restructuring without adding features or fixing bugs | no bump |
| `test` | Adding or updating tests only | no bump |
| `docs` | Documentation only (README, comments, changelogs) | no bump |
| `style` | Formatting, whitespace, missing semicolons — no logic change | no bump |
| `chore` | Maintenance: tooling, config, dependency bumps | no bump |
| `build` | Build system or script changes | no bump |
| `ci` | CI configuration changes | no bump |
| `revert` | Reverts a previous commit | patch bump |

> Append `!` to type or add `BREAKING CHANGE:` in the footer for breaking changes → major bump.

## Scopes

Scopes are automatically derived from npm workspace package names via `@commitlint/config-workspace-scopes`. Valid scopes are the unscoped part of each package `name` found in the workspace paths defined by `workspaces` in root `package.json` (e.g. `@tomgrv-devcontainer-features/gitutils` → `gitutils`).

To see valid scopes at any time, run:

```bash
npm query .workspace | node -e "const d=require('fs').readFileSync(0,'utf8'); JSON.parse(d).forEach(p => console.log(p.name))"
```

**Rules for choosing a scope:**

- Use the unscoped package name of the affected workspace (strip the `@org/` prefix)
- Use the narrowest scope that accurately describes the change
- When a change spans multiple workspaces equally, pick the primary one

**Examples:**

```
feat(gitutils): add new git alias
fix(githooks): prevent double-run on post-merge
perf(common-utils): reduce script startup time
refactor(gitversion): extract bump logic into shared function
docs(gateway): document SSL setup
chore(githooks): bump @commitlint/cli to latest
feat!(pecl): remove legacy extension installer — breaking change
```
39 changes: 39 additions & 0 deletions .github/skills/feature-githooks/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
name: feature-githooks
description: Git hook automation for commit quality gates, commit message validation, and staged-file linting.
---

<!-- @format -->

# githooks

## Description

Use this feature when an agent needs consistent local Git quality gates and commit workflow automation.

## Commands

- `git commit` - Triggers `pre-commit`, `prepare-commit-msg`, and `commit-msg` hooks.
- `git push` - Triggers `pre-push` validations before remote update.
- `git checkout <branch>` - Triggers `post-checkout` hook operations.
- `git merge` - Triggers `post-merge` hook operations.
- `commitlint --edit <file>` - Validate a commit message against commitlint rules.
- `lint-staged` - Run configured lint/format commands on staged files.

## Use For

- Enforcing commit message standards (`commitlint`, `commitizen`).
- Running pre-commit checks/linting on staged files.
- Validating branch naming and push readiness.
- Keeping dependencies aligned after checkout/merge hooks.

## Do Not Use For

- Repository history rewriting (use `gitutils`).
- Version calculation from history (use `gitversion`).

## Agent Guidance

- Treat hooks as the default guardrails for local commits.
- Update hook-related package snippets/scripts instead of introducing duplicate checks.
- When failures occur, fix the underlying issue and rerun the same hook path.
44 changes: 44 additions & 0 deletions .github/skills/feature-gitutils/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
---
name: feature-gitutils
description: Advanced git aliases and workflows for branch integration, history maintenance, and release flows.
---

<!-- @format -->

# gitutils

## Description

Use this feature for advanced Git operations, interactive repository maintenance, and git-flow shortcuts.

## Commands

- `git align` - Align current branch with its remote tracking branch.
- `git integrate` - Integrate remote modifications into current branch.
- `git fixup [--force|<commit>]` - Amend a target commit and rebase history.
- `git getcommit [--force|<commit>]` - Resolve/select commit target for fixup.
- `git fix date [options] [<commit>]` - Rewrite commit times with scheduling rules.
- `git fix blanks [-d]` - Drop tracked text-file edits made only of blanks and quote/slash swaps.
- `git forall <command>` - Execute a command for repository files.
- `git release-beta` - Start a Git Flow release branch.
- `git release-hotfix` - Start a Git Flow hotfix branch.
- `git release-prod` - Finish release/hotfix flow for production.
- `git unset <prefix> [--local|--global|--system]` - Remove git config keys by prefix.

## Use For

- Branch/rebase alignment and integration tasks.
- Commit cleanup/fixup workflows.
- Release branch shortcuts (`beta`, `hfix`, `prod`).
- Batch repository operations and helper aliases.

## Do Not Use For

- Commit policy enforcement hooks (use `githooks`).
- Semantic version calculation (use `gitversion`).

## Agent Guidance

- Prefer built-in aliases/utilities before crafting raw multi-step Git commands.
- For history-rewrite actions, use explicit/force flags only when requested.
- Keep operations scoped and reversible where possible.
34 changes: 34 additions & 0 deletions .github/workflows/merge-dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# @format

name: 'Dependabot Auto-Merge'

on: pull_request_target

permissions:
pull-requests: write
contents: write

jobs:
dependabot:
runs-on: ubuntu-latest
if: ${{ github.actor == 'dependabot[bot]' }}
steps:
- name: Dependabot metadata
id: metadata
uses: dependabot/fetch-metadata@v2.4.0
with:
github-token: '${{ secrets.GITHUB_TOKEN }}'

- name: Auto-merge Dependabot PRs for semver-minor updates
if: ${{steps.metadata.outputs.update-type == 'version-update:semver-minor'}}
run: gh pr merge --auto --merge "$PR_URL"
env:
PR_URL: ${{github.event.pull_request.html_url}}
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}

- name: Auto-merge Dependabot PRs for semver-patch updates
if: ${{steps.metadata.outputs.update-type == 'version-update:semver-patch'}}
run: gh pr merge --auto --merge "$PR_URL"
env:
PR_URL: ${{github.event.pull_request.html_url}}
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
93 changes: 93 additions & 0 deletions .github/workflows/merge-monorepo.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# @format

name: Merge Monorepo

on:
workflow_dispatch:
inputs:
source-branch:
description: Source branch to degit from package repositories. Defaults to the source repository default branch.
required: false
default: ''
type: string
exclude-paths:
description: Comma-separated paths to remove after degit
required: false
default: .github,.devcontainer,.git
type: string

jobs:
list-packages:
name: List packages
runs-on: ubuntu-latest
outputs:
packages: ${{ steps.list.outputs.packages }}
steps:
- name: Checkout
uses: actions/checkout@v6

- name: Set up PHP
uses: tomgrv/actions/setup-php@v0
with:
options: '--no-dev'

- name: Set up Node.js
uses: tomgrv/actions/setup-node@v0

- name: List packages
id: list
uses: tomgrv/actions/list-packages@v0

degit-packages:
name: Degit package
runs-on: ubuntu-latest
needs: list-packages
strategy:
fail-fast: false
matrix:
package: ${{ fromJson(needs.list-packages.outputs.packages) }}
steps:
- name: Checkout monorepo
uses: actions/checkout@v6

- name: Generate a token
id: app-token
uses: actions/create-github-app-token@v3
with:
client-id: ${{ secrets.KLICKSPLIT_CLIENT_ID }}
private-key: ${{ secrets.KLICKSPLIT_APP_KEY }}
owner: ${{ matrix.package.org }}
repositories: ${{ matrix.package.name }}

- name: Configure bot identity
uses: tomgrv/actions/config-bot@v0
with:
github-token: ${{ steps.app-token.outputs.token }}
github-app-slug: ${{ steps.app-token.outputs.app-slug }}

- name: Degit package content
id: degit
uses: tomgrv/actions/degit-package@v0
with:
github-token: ${{ steps.app-token.outputs.token }}
source-organization: ${{ matrix.package.org }}
source-repository: ${{ matrix.package.name }}
target-subdir: ${{ matrix.package.location }}
source-branch: ${{ inputs.source-branch }}
exclude-paths: ${{ inputs.exclude-paths }}

- name: Create or update pull request
if: ${{ steps.degit.outputs.has-changes == 'true' }}
uses: tomgrv/actions/create-pr@v1
with:
github-token: ${{ steps.app-token.outputs.token }}
repository: ${{ matrix.package.org }}/{{ matrix.package.name }}
head-branch: ${{ steps.degit.outputs.degit-branch }}
workdir: ${{ steps.degit.outputs.degit-workdir }}
commit-message: 'sync: degit from ${{ matrix.package.org }}/${{ matrix.package.name }}@${{ steps.degit.outputs.source-branch }}'
pr-title: 'sync: degit from ${{ matrix.package.org }}/${{ matrix.package.name }}'
pr-body: |
### Automated degit sync from [${{ matrix.package.org }}/${{ matrix.package.name }}](${{ matrix.package.repository_url }})

- Source branch: `${{ steps.degit.outputs.source-branch }}`
- Source commit: `${{ steps.degit.outputs.source-sha }}`
28 changes: 28 additions & 0 deletions .github/workflows/rebase-pr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# @format

name: Automatic Rebase
on:
issue_comment:
types: [created]
jobs:
rebase:
name: Rebase
runs-on: ubuntu-latest
if: >-
github.event.issue.pull_request != '' &&
(
contains(github.event.comment.body, '/rebase') ||
contains(github.event.comment.body, '/autosquash')
)
steps:
- name: Checkout the latest code
uses: actions/checkout@v6
with:
token: ${{ secrets.GITHUB_TOKEN }}
fetch-depth: 0 # otherwise, you will fail to push refs to dest repo
- name: Automatic Rebase
uses: cirrus-actions/rebase@1.8
with:
autosquash: ${{ contains(github.event.comment.body, '/autosquash') || contains(github.event.comment.body, '/rebase-autosquash') }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Loading