From cafd85d2d0d795a00adfec1d28eb0eb39f7196a8 Mon Sep 17 00:00:00 2001 From: bthos Date: Fri, 13 Feb 2026 21:37:43 +0100 Subject: [PATCH 1/6] Enhance documentation and CI workflows for plugin validation - Update CONTRIBUTING.md and README.md to clarify plugin submission steps and emphasize CI's role in validation and registry building. - Introduce new plugins: Billing, Goals, Pomodoro Timer, and Projects & Tasks, each with metadata and versioning. - Implement GitHub Actions workflows for automatic validation and registry updates upon PR merges. - Adjust validation scripts to improve error handling and streamline the validation process. Signed-off-by: bthos Signed-off-by: bthos --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- .github/workflows/build-registry.yml | 92 +++++++++ .github/workflows/validate-manifest.yml | 8 +- .github/workflows/validate-registry.yml | 50 +---- CONTRIBUTING.md | 259 ++++++++++++++---------- README.md | 162 ++++++++++----- package.json | 2 +- plugins/README.md | 25 ++- registry.json | 100 ++++++++- scripts/validate.js | 6 + 10 files changed, 487 insertions(+), 219 deletions(-) create mode 100644 .github/workflows/build-registry.yml diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 2693e9d..0c9dd4a 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,7 +1,7 @@ ## Plugin Submission Checklist - [ ] Plugin ID follows format: `author.plugin-name` or lowercase-with-hyphens -- [ ] Manifest passes `npm run validate-plugins` (or `npm run validate-all`) +- [ ] Plugin JSON is valid (CI will validate automatically) - [ ] SHA256 checksum verified (if `distribution` with checksums is used) - [ ] Plugin tested locally - [ ] README / docs updated if adding new author or changing structure diff --git a/.github/workflows/build-registry.yml b/.github/workflows/build-registry.yml new file mode 100644 index 0000000..b131a29 --- /dev/null +++ b/.github/workflows/build-registry.yml @@ -0,0 +1,92 @@ +name: Build Registry + +on: + push: + branches: + - main + paths: + - 'plugins/**' + - 'schemas/**' + paths-ignore: + - 'registry.json' + +jobs: + build: + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '18' + + - name: Install dependencies + run: | + npm install + + - name: Validate schema files + run: | + npm run validate-schemas + + - name: Validate individual plugin files + run: | + npm run validate-plugins + + - name: Build registry + run: | + npm run build + + - name: Validate registry + run: | + npm run validate + + - name: Validate repository URLs + run: | + node -e " + const fs = require('fs'); + const registry = JSON.parse(fs.readFileSync('registry.json', 'utf8')); + const https = require('https'); + const http = require('http'); + + async function checkUrl(url) { + return new Promise((resolve) => { + const client = url.startsWith('https') ? https : http; + const req = client.get(url, { timeout: 5000 }, (res) => { + resolve(res.statusCode === 200 || res.statusCode === 301 || res.statusCode === 302); + }); + req.on('error', () => resolve(false)); + req.on('timeout', () => { + req.destroy(); + resolve(false); + }); + }); + } + + (async () => { + for (const plugin of registry.plugins) { + if (plugin.repository) { + const valid = await checkUrl(plugin.repository); + if (!valid) { + console.warn('Warning: Repository URL may be invalid:', plugin.repository); + } + } + } + console.log('Repository URL validation complete'); + })(); + " + + - name: Commit registry.json + run: | + git config --local user.email "action@github.com" + git config --local user.name "GitHub Action" + git add registry.json + if git diff --staged --quiet; then + echo "No changes to registry.json" + else + git commit -m "chore: update registry.json [skip ci]" + git push + fi diff --git a/.github/workflows/validate-manifest.yml b/.github/workflows/validate-manifest.yml index dcc30ff..e905ecf 100644 --- a/.github/workflows/validate-manifest.yml +++ b/.github/workflows/validate-manifest.yml @@ -39,8 +39,6 @@ jobs: - name: Check for duplicates run: npm run check-duplicates - - name: Build registry - run: npm run build - - - name: Validate registry - run: npm run validate + - name: Validate registry (if exists) + run: | + npm run validate || echo "⚠️ registry.json not found, skipping validation" diff --git a/.github/workflows/validate-registry.yml b/.github/workflows/validate-registry.yml index d3890c3..380c92a 100644 --- a/.github/workflows/validate-registry.yml +++ b/.github/workflows/validate-registry.yml @@ -1,13 +1,6 @@ name: Validate Registry on: - push: - branches: - - main - paths: - - 'registry.json' - - 'plugins/**' - - 'schemas/**' pull_request: paths: - 'registry.json' @@ -38,45 +31,6 @@ jobs: run: | npm run validate-plugins - - name: Build registry - run: | - npm run build - - - name: Validate registry - run: | - npm run validate - - - name: Validate repository URLs + - name: Validate registry (if exists) run: | - node -e " - const fs = require('fs'); - const registry = JSON.parse(fs.readFileSync('registry.json', 'utf8')); - const https = require('https'); - const http = require('http'); - - async function checkUrl(url) { - return new Promise((resolve) => { - const client = url.startsWith('https') ? https : http; - const req = client.get(url, { timeout: 5000 }, (res) => { - resolve(res.statusCode === 200 || res.statusCode === 301 || res.statusCode === 302); - }); - req.on('error', () => resolve(false)); - req.on('timeout', () => { - req.destroy(); - resolve(false); - }); - }); - } - - (async () => { - for (const plugin of registry.plugins) { - if (plugin.repository) { - const valid = await checkUrl(plugin.repository); - if (!valid) { - console.warn('Warning: Repository URL may be invalid:', plugin.repository); - } - } - } - console.log('Repository URL validation complete'); - })(); - " + npm run validate || echo "⚠️ registry.json not found, skipping validation" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 31d9161..a80b254 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,88 +2,90 @@ Thank you for your interest in contributing to the Time Tracker Plugins Registry! +## Quick Summary + +Adding a plugin is simple: +1. **Fork** this repository +2. **Create** `plugins/{letter}/{author}/{plugin-id}/{version}/plugin.json` +3. **Submit** a Pull Request + +CI handles validation and registry building automatically. No local setup required (unless you want to use the interactive script). + +πŸ‘‰ **See [FAQ](#frequently-asked-questions-faq) below for common questions.** + ## Developer Certificate of Origin (DCO) -By contributing to this project, you agree to the [Developer Certificate of Origin](https://developercertificate.org/) (DCO). You must sign off your commits to certify that you have the right to submit your contribution. +**What is DCO?** +DCO is a simple way to certify that you have the right to submit your contribution. It's required for all contributions. -To sign off your commits, add the `-s` flag when committing: +**How to sign off:** +Just add `-s` flag when committing: ```bash git commit -s -m "Add plugin: your-plugin-name" ``` -This adds a line like the following to your commit message: +This automatically adds `Signed-off-by: Your Name ` to your commit. -``` -Signed-off-by: Your Name -``` - -All pull requests are checked for DCO sign-off. Commits without sign-off will cause the DCO check to fail. +**⚠️ Important:** All PRs are checked for DCO sign-off. Commits without sign-off will fail the DCO check. ## How to Add a Plugin -### Step 1: Prepare Your Plugin - -Before submitting your plugin to the registry, ensure: +### Prerequisites -1. **Your plugin follows the Plugin Template structure** - - See [Plugin Template](https://github.com/tmtrckr/plugin-template) for details - - Must have a `plugin.toml` manifest file - - Must be hosted on GitHub +Before adding your plugin, make sure: -2. **Your plugin has at least one release** - - Create a GitHub Release with version tag (e.g., `v1.0.0`) - - Release should include compiled binaries for supported platforms - - See Plugin Template for GitHub Actions workflow +βœ… Your plugin is hosted on GitHub +βœ… Your plugin repository has a `plugin.toml` manifest file +βœ… You have at least one GitHub Release with version tag (e.g., `v1.0.0`) +βœ… Your repository includes a README and license file -3. **Your plugin repository includes:** - - Clear README with installation instructions - - License file - - Plugin manifest (`plugin.toml`) +> πŸ’‘ **New to plugin development?** Check out the [Plugin Template](https://github.com/tmtrckr/plugin-template) for a complete example. -### Step 2: Fork the Repository +### Step 1: Fork and Clone -**Important**: Before creating a plugin entry, you must fork this repository: - -1. **Fork this repository** on GitHub -2. **Clone your fork** locally: +1. **Fork this repository** on GitHub (click the "Fork" button) +2. **Clone your fork**: ```bash git clone https://github.com/your-username/plugins-registry.git cd plugins-registry ``` -3. **Install dependencies**: - ```bash - npm install - ``` -### Step 3: Add Plugin Entry +> πŸ’‘ **Tip**: You only need `npm install` if you want to use the interactive script. For manual creation, you can skip it. -**Option A: Use the Interactive Script (Recommended)** +### Step 2: Create Plugin Entry -The easiest way to create a plugin entry is using the interactive script: +**Option A: Interactive Script (Easiest! 🎯)** ```bash +npm install npm run create-plugin ``` -This script will: -- Guide you through all required fields -- Automatically normalize your author name -- Create the correct directory structure -- Generate a properly formatted `plugin.json` file -- Validate the entry format +The script will: +- βœ… Ask you questions about your plugin +- βœ… Automatically normalize your author name +- βœ… Create the correct directory structure +- βœ… Generate a properly formatted `plugin.json` +- βœ… Validate everything for you **Option B: Manual Creation** -1. **Normalize author name**: lowercase, spaces β†’ hyphens, remove special characters (e.g. "John Doe" β†’ "john-doe"). The **first letter** of the normalized name is the partition (e.g. `j`). +If you prefer to create the entry manually: -2. **Create the versioned path**: - ```bash - mkdir -p plugins/j/john-doe/your-plugin-id/1.0.0 - ``` - Use your normalized author, plugin id, and version (semver). +**1. Normalize your author name:** +- Convert to lowercase +- Replace spaces with hyphens +- Remove special characters +- Example: "John Doe" β†’ "john-doe" +- First letter: `j` (this becomes the partition folder) -3. **Create `plugin.json`** in that version directory (e.g. `plugins/j/john-doe/your-plugin-id/1.0.0/plugin.json`): +**2. Create the directory structure:** +```bash +mkdir -p plugins/j/john-doe/your-plugin-id/1.0.0 +``` + +**3. Create `plugin.json`** in that directory: ```json { @@ -105,12 +107,13 @@ This script will: } ``` -**Important**: -- Path must be `plugins/{first-letter}/{normalized-author}/{plugin-id}/{version}/plugin.json` -- `id` must match the plugin directory name; `author` must normalize to the author directory name -- Version directory must be semver (e.g. `1.0.0`) +**⚠️ Important Rules:** +- Path format: `plugins/{first-letter}/{normalized-author}/{plugin-id}/{version}/plugin.json` +- `id` field must match the plugin directory name +- `author` field must normalize to the author directory name +- `latest_version` must match the version directory name -**Field Guidelines:** +**πŸ“– Field Descriptions:** - **id**: Lowercase, alphanumeric with hyphens only (e.g., `calendar-sync`, `jira-integration`) - **name**: Display name (max 100 characters) @@ -139,59 +142,27 @@ This script will: You can compute SHA256 locally with `sha256sum` (Linux/macOS) or `certutil -hashfile file.zip SHA256` (Windows). -### Step 4: Validate Your Entry - -Before submitting, validate your entry: - -1. **Check JSON syntax**: Ensure valid JSON -2. **Validate against schema**: Your entry must match `registry.schema.json` -3. **Verify ID matches directory**: The `id` field must match the plugin directory name -4. **Verify author matches directory**: The `author` field (when normalized) must match the author directory name -5. **Verify author is present**: The `author` field is required and cannot be empty -6. **Verify repository URL**: Ensure the GitHub repository exists and is accessible -7. **Check for duplicates**: Ensure no other plugin has the same `{author}/{id}` combination -8. **Validate your plugin**: Run `npm run validate-plugins` to check your plugin.json file - - CI will automatically build the registry and validate it when you submit a PR - - You can optionally run `npm run validate-all` for a full local check (includes building registry), but it's not required - -### Step 5: Install Git Hooks (Optional but Recommended) +### Step 3: Quick Check Before Submitting -Install pre-commit hooks to automatically validate your changes before committing: - -```bash -npm run install-hooks -``` +Before creating your PR, verify: -This will: -- Install a pre-commit hook that validates plugins before each commit -- Automatically build the registry when plugin files change -- Prevent invalid commits from being made +βœ… `plugin.json` is valid JSON (no syntax errors) +βœ… All required fields are filled in +βœ… `id` matches your plugin directory name +βœ… `author` normalizes to your author directory name +βœ… Repository URL is correct and accessible -### Step 6: Submit Pull Request +> πŸ’‘ **Optional**: If you have Node.js, you can run `npm install && npm run validate-plugins` to check locally. But don't worry - CI will validate everything automatically when you submit your PR! -1. **Validate your plugin:** - ```bash - npm run validate-plugins - ``` - - This checks your plugin.json file. CI will automatically: - - Validate schema files - - Validate all plugin files - - Build the registry from plugins - - Validate the built registry against the schema - - **Optional**: Run `npm run validate-all` for a full local check (builds and validates registry locally), but CI does this automatically. +### Step 4: Submit Pull Request -2. **Commit your changes** (with DCO sign-off): +1. **Commit your changes** (with DCO sign-off): ```bash git add plugins/{letter}/{normalized-author}/{plugin-id}/{version}/plugin.json git commit -s -m "Add plugin: your-plugin-name" ``` - **Important Notes:** - - **Do NOT commit `registry.json`** - CI will automatically regenerate it when your PR is merged - - The build script preserves timestamps when plugins haven't changed, so you won't see unnecessary diffs - - If you installed pre-commit hooks, validation will run automatically and will unstage `registry.json` if only the timestamp changed + **Important**: Do NOT commit `registry.json` - CI will automatically build and commit it after your PR is merged to main. 2. **Push to your fork:** ```bash @@ -204,7 +175,19 @@ This will: - Link to your plugin repository - Screenshots or demo (if applicable) -### Step 6: Review Process +### Step 5: What Happens Next + +**When you submit your PR:** +- βœ… CI automatically validates your plugin +- βœ… Maintainers review your submission +- βœ… Automated checks verify schema compliance and repository URLs + +**After your PR is merged:** +- βœ… CI automatically builds the registry +- βœ… Your plugin appears in `registry.json` +- βœ… Your plugin is available in the Time Tracker Marketplace! + +### Review Process - Registry maintainers will review your submission - Automated validation will check schema compliance @@ -214,12 +197,38 @@ This will: ## Updating an Existing Plugin -To update your plugin entry: +### Updating Plugin Metadata -1. For **metadata changes** (description, tags, etc.): edit `plugin.json` in the version directory (e.g. `plugins/d/developer-name/example-plugin/1.0.0/plugin.json`). -2. For a **new version**: create a new version directory (e.g. `plugins/d/developer-name/example-plugin/1.1.0/`) and add a new `plugin.json` there. -3. Do not change the `author` field or move the plugin to a different author path without coordination. -4. Run `npm run validate-plugins` to check your plugin.json, then commit and submit a pull request. Do **not** commit `registry.json` (CI regenerates it automatically). +To update description, tags, or other metadata: + +1. Edit `plugin.json` in your existing version directory + - Example: `plugins/j/john-doe/jira-integration/1.0.0/plugin.json` +2. Commit and submit a PR + +### Adding a New Version + +To add a new version of your plugin: + +1. Create a new version directory: + ```bash + mkdir -p plugins/j/john-doe/jira-integration/1.1.0 + ``` +2. Create `plugin.json` in the new version directory +3. Update `latest_version` in the new `plugin.json` to match the directory name +4. Commit and submit a PR + +**Example structure for multiple versions:** +``` +plugins/j/john-doe/jira-integration/ +β”œβ”€β”€ 1.0.0/ +β”‚ └── plugin.json +└── 1.1.0/ + └── plugin.json ← New version +``` + +**⚠️ Important:** +- Do NOT change the `author` field or move the plugin to a different author path +- Do NOT commit `registry.json` - CI handles this automatically ## Plugin Verification @@ -269,6 +278,52 @@ Choose the most appropriate category: - Include functionality keywords (e.g., `sync`, `export`, `automation`) - Use lowercase, avoid spaces +## Frequently Asked Questions (FAQ) + +### Do I need to install Node.js to add a plugin? + +**No!** You only need Node.js if you want to use the interactive `create-plugin` script. For manual creation, you can just create the files directly. + +### Do I need to build the registry locally? + +**No!** CI automatically builds `registry.json` after your PR is merged. Just create your `plugin.json` file and submit a PR. + +### What if I make a mistake in my plugin.json? + +Don't worry! CI will validate your plugin when you submit a PR and tell you what's wrong. You can fix it and update your PR. + +### Can I update my plugin later? + +Yes! You can: +- Update metadata by editing the existing `plugin.json` +- Add a new version by creating a new version directory + +### What if my author name has special characters? + +Special characters are removed during normalization. For example: +- "JosΓ© GarcΓ­a" β†’ "jose-garcia" +- "O'Brien" β†’ "obrien" +- "Smith & Co." β†’ "smith-co" + +### Can I have multiple versions of my plugin? + +Yes! Create separate version directories: +``` +plugins/j/john-doe/my-plugin/ +β”œβ”€β”€ 1.0.0/ +β”‚ └── plugin.json +└── 1.1.0/ + └── plugin.json +``` + +### Do I need to commit registry.json? + +**No!** Never commit `registry.json`. CI builds and commits it automatically after your PR is merged. + +### How long does it take for my plugin to appear? + +After your PR is merged, CI automatically builds the registry (usually takes 1-2 minutes). Your plugin will then appear in `registry.json` and be available in the marketplace. + ## Questions? If you have questions about contributing: diff --git a/README.md b/README.md index 7a5fa01..92a698d 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Community-driven registry for Time Tracker application plugins. This repository ## Statistics - **Total Plugins:** See [registry.json](registry.json) for current counts -- **Registry:** [registry.json](registry.json) is built from `plugins/` and validated in CI +- **Registry:** [registry.json](registry.json) is automatically built from `plugins/` by CI after PRs are merged ## Overview @@ -52,7 +52,7 @@ plugins/ - **Version** directory must be semver (e.g. `1.0.0`). Multiple versions per plugin are supported. - The `author` field in `plugin.json` is **required** and must normalize to the author directory name. -The `registry.json` file is built from these plugin files using `npm run build` (latest version per plugin is used). +The `registry.json` file is automatically built from these plugin files by CI (latest version per plugin is used). ### Plugin Metadata Schema @@ -77,47 +77,108 @@ Each plugin's `plugin.json` follows the schema defined in `schemas/manifest.sche ## Adding a Plugin -### Quick Start (Recommended) - -1. **Fork this repository** on GitHub -2. **Clone your fork** locally: - ```bash - git clone https://github.com/your-username/plugins-registry.git - cd plugins-registry - npm install - ``` -3. **Use the interactive script** to create a plugin entry: - ```bash - npm run create-plugin - ``` - This will guide you through all required fields and create the correct structure automatically. -4. **Validate your plugin**: - ```bash - npm run validate-plugins - ``` -5. **Commit and create a Pull Request** (see [CONTRIBUTING.md](CONTRIBUTING.md) for details) - - CI will automatically build and validate the registry when you submit a PR - -### Manual Process - -To add your plugin manually: - -1. **Fork this repository** -2. **Normalize author name**: lowercase, spaces β†’ hyphens, remove special characters (e.g. "John Doe" β†’ "john-doe") -3. **First letter**: use the first character of the normalized author (e.g. "john-doe" β†’ `j`) -4. **Create path**: `plugins/{first-letter}/{normalized-author}/{plugin-id}/{version}/` +### πŸš€ Quick Start (3 Simple Steps) + +**Step 1: Fork and Clone** +```bash +# 1. Fork this repository on GitHub (click "Fork" button) +# 2. Clone your fork: +git clone https://github.com/your-username/plugins-registry.git +cd plugins-registry +``` + +**Step 2: Create Plugin Entry** + +**Option A: Interactive Script (Easiest)** +```bash +npm install +npm run create-plugin +``` +The script will guide you through everything and create the correct structure automatically. + +**Option B: Manual Creation** +1. Create directory: `plugins/{first-letter}/{author}/{plugin-id}/{version}/` - Example: `plugins/j/john-doe/jira-integration/1.0.0/` -5. **Create `plugin.json`** in that version directory with your plugin metadata -6. **Ensure**: - - `id` matches the plugin directory name (e.g. `jira-integration`) - - `author` matches the author directory when normalized (e.g. "John Doe" β†’ "john-doe") - - `latest_version` or directory name is semver (e.g. `1.0.0`) -7. **Validate your plugin**: Run `npm run validate-plugins` to check your plugin.json -8. **Submit a pull request** (CI will automatically build and validate the registry) - -**Example**: Plugin "jira-integration" by "John Doe", version 1.0.0: -- Path: `plugins/j/john-doe/jira-integration/1.0.0/plugin.json` -- In `plugin.json`: `"id": "jira-integration"`, `"author": "John Doe"`, `"latest_version": "1.0.0"` +2. Create `plugin.json` file in that directory (see example below) + +**Step 3: Submit Pull Request** +```bash +git add plugins/j/john-doe/jira-integration/1.0.0/plugin.json +git commit -s -m "Add plugin: jira-integration" +git push origin main +# Then create a Pull Request on GitHub +``` + +That's it! CI will automatically validate your plugin and build the registry after your PR is merged. + +### πŸ“ Example: Adding "Jira Integration" Plugin + +**Author:** John Doe +**Plugin ID:** jira-integration +**Version:** 1.0.0 + +**1. Create the directory:** +```bash +mkdir -p plugins/j/john-doe/jira-integration/1.0.0 +``` + +**2. Create `plugins/j/john-doe/jira-integration/1.0.0/plugin.json`:** +```json +{ + "$schema": "https://github.com/tmtrckr/plugins-registry/schemas/manifest.schema.json", + "id": "jira-integration", + "name": "Jira Integration", + "author": "John Doe", + "repository": "https://github.com/johndoe/jira-integration", + "latest_version": "1.0.0", + "description": "Sync time entries with Jira tickets", + "category": "integration", + "verified": false, + "downloads": 0, + "tags": ["jira", "sync", "integration"], + "license": "MIT", + "min_core_version": "0.3.0", + "max_core_version": "1.0.0", + "api_version": "1.0" +} +``` + +**3. Commit and create PR:** +```bash +git add plugins/j/john-doe/jira-integration/1.0.0/plugin.json +git commit -s -m "Add plugin: jira-integration" +git push +``` + +### πŸ“‹ Understanding the Path Structure + +The path follows this pattern: `plugins/{first-letter}/{author}/{plugin-id}/{version}/` + +**Visual Example:** +``` +plugins/ +└── j/ ← First letter of "john-doe" + └── john-doe/ ← Normalized author name + └── jira-integration/ ← Plugin ID + └── 1.0.0/ ← Version + └── plugin.json ← Your plugin file +``` + +**How to determine each part:** + +| Part | How to Get It | Example | +|------|---------------|---------| +| **First letter** | First character of normalized author | "John Doe" β†’ "john-doe" β†’ `j` | +| **Author** | Normalize: lowercase, spacesβ†’hyphens | "John Doe" β†’ `john-doe` | +| **Plugin ID** | Your plugin identifier (lowercase, hyphens) | `jira-integration` | +| **Version** | Semantic version number | `1.0.0` | + +**⚠️ Important rules:** +- `id` in `plugin.json` must match the plugin directory name +- `author` in `plugin.json` must normalize to the author directory name +- `latest_version` must match the version directory name + +> πŸ’‘ **Need help?** See [CONTRIBUTING.md](CONTRIBUTING.md) for detailed instructions and FAQ. ### Plugin Requirements @@ -199,7 +260,7 @@ The Time Tracker application discovers plugins through: ## Local Development -**Note**: This section covers commands for repository maintainers. Plugin contributors only need `npm run validate-plugins` to check their plugin.json - CI handles the rest automatically. +**Note**: This section covers commands for repository maintainers. Plugin contributors don't need to run any commands locally - CI handles validation and registry building automatically. ### Setup @@ -231,7 +292,7 @@ npm run build ### Validation -**For plugin contributors**: Run `npm run validate-plugins` to check your plugin.json file. CI will handle building and validating the registry automatically. +**For plugin contributors**: CI automatically validates your plugin.json when you submit a PR. No local validation is required. **For repository maintainers**: Full validation commands: @@ -251,13 +312,13 @@ Validate the aggregated registry (requires registry.json to exist - run `npm run npm run validate ``` -Validate everything (schemas, plugins, build registry, and validate registry): +Validate everything (schemas, plugins, and existing registry.json if present): ```bash npm run validate-all ``` -This runs: `validate-schemas` β†’ `validate-plugins` β†’ `build` β†’ `validate` +This runs: `validate-schemas` β†’ `validate-plugins` β†’ `validate` (skips registry validation if registry.json doesn't exist) Check for duplicate plugin IDs: @@ -271,7 +332,7 @@ Format the registry (sorts plugins and updates timestamp): npm run format ``` -### Git Hooks +### Git Hooks (Optional) Install pre-commit hooks to automatically validate plugins before committing: @@ -279,10 +340,7 @@ Install pre-commit hooks to automatically validate plugins before committing: npm run install-hooks ``` -This will: -- Validate plugin files before each commit -- Automatically build the registry when plugin files change -- Prevent invalid commits from being made +This will validate plugin files before each commit. CI handles registry building automatically, so this is optional. ### Example Plugin Entry @@ -308,7 +366,7 @@ Contributions are welcome! Please: ### Ways to Contribute -- **Add a Plugin**: Use `npm run create-plugin` or the [CLI](tools/cli) (`node tools/cli/src/index.js create`) or follow the [manual process](CONTRIBUTING.md) +- **Add a Plugin**: Use `npm run create-plugin` (after `npm install`) or follow the [manual process](CONTRIBUTING.md) - **Request a Plugin**: Create an [issue using the plugin submission template](.github/ISSUE_TEMPLATE/plugin_submission.yml) - **Report Issues**: Open an issue for [bugs](.github/ISSUE_TEMPLATE/bug_report.yml) or [features](.github/ISSUE_TEMPLATE/feature_request.yml) - **Improve Documentation**: Submit PRs to improve docs diff --git a/package.json b/package.json index 83485b8..726c11e 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "validate": "node scripts/validate.js", "validate-plugins": "node scripts/validate-plugins.js", "validate-schemas": "node scripts/validate-schemas.js", - "validate-all": "npm run validate-schemas && npm run validate-plugins && npm run build && npm run validate", + "validate-all": "npm run validate-schemas && npm run validate-plugins && npm run validate", "format": "node scripts/format.js", "check-duplicates": "node scripts/check-duplicates.js", "create-plugin": "node scripts/create-plugin.js", diff --git a/plugins/README.md b/plugins/README.md index 2b99ab3..5e43e8c 100644 --- a/plugins/README.md +++ b/plugins/README.md @@ -32,12 +32,25 @@ plugins/ ## Adding a Plugin -1. Normalize your author name and determine the first letter. -2. Create `plugins/{letter}/{normalized-author}/{plugin-id}/{version}/`. -3. Add `plugin.json` with `id`, `author`, `latest_version` (matching the version directory), and other required fields. -4. Validate your plugin: Run `npm run validate-plugins` from the repository root. - - CI will automatically build and validate the registry when you submit a PR +**Quick steps:** +1. Normalize your author name (lowercase, spaces β†’ hyphens) +2. Create directory: `plugins/{first-letter}/{normalized-author}/{plugin-id}/{version}/` +3. Add `plugin.json` file with required fields +4. Submit a pull request + +**Example:** +- Author: "John Doe" β†’ normalized: "john-doe" β†’ first letter: `j` +- Plugin ID: `jira-integration` +- Version: `1.0.0` +- Path: `plugins/j/john-doe/jira-integration/1.0.0/plugin.json` + +**Important:** +- `id` in `plugin.json` must match the plugin directory name +- `author` in `plugin.json` must normalize to the author directory name +- `latest_version` must match the version directory name + +πŸ‘‰ **For detailed instructions and examples, see [CONTRIBUTING.md](../CONTRIBUTING.md)** ## Example -See `d/developer-name/example-plugin/1.0.0/plugin.json` for a full example. +See `d/developer-name/example-plugin/1.0.0/plugin.json` for a complete example. diff --git a/registry.json b/registry.json index f837bfd..df45596 100644 --- a/registry.json +++ b/registry.json @@ -1,8 +1,29 @@ { "$schema": "https://github.com/tmtrckr/plugins-registry/schemas/registry.schema.json", "version": "1.0.0", - "last_updated": "2026-02-11T20:46:22.116Z", + "last_updated": "2026-02-13T20:30:19.826Z", "plugins": [ + { + "$schema": "https://github.com/tmtrckr/plugins-registry/schemas/manifest.schema.json", + "id": "billing", + "name": "Billing", + "author": "TimeTracker", + "repository": "https://github.com/tmtrckr/plugin-billing", + "latest_version": "1.0.0", + "description": "Billable time tracking plugin for Time Tracker application.", + "category": "other", + "verified": false, + "downloads": 0, + "tags": [], + "license": "MIT", + "min_core_version": "0.3.0", + "max_core_version": "1.0.0", + "api_version": "1.0", + "versions": [ + "1.0.0" + ], + "path": "plugins/t/timetracker/billing" + }, { "$schema": "https://github.com/tmtrckr/plugins-registry/schemas/manifest.schema.json", "id": "example-plugin", @@ -29,11 +50,82 @@ "1.0.0" ], "path": "plugins/d/developer-name/example-plugin" + }, + { + "$schema": "https://github.com/tmtrckr/plugins-registry/schemas/manifest.schema.json", + "id": "goals", + "name": "Goals", + "author": "TimeTracker", + "repository": "https://github.com/tmtrckr/plugin-goals", + "latest_version": "1.0.0", + "description": "Goal tracking plugin for Time Tracker application.", + "category": "productivity", + "verified": false, + "downloads": 0, + "tags": [ + "productivity" + ], + "license": "MIT", + "min_core_version": "0.3.0", + "max_core_version": "1.0.0", + "api_version": "1.0", + "versions": [ + "1.0.0" + ], + "path": "plugins/t/timetracker/goals" + }, + { + "$schema": "https://github.com/tmtrckr/plugins-registry/schemas/manifest.schema.json", + "id": "pomodoro-timer", + "name": "Pomodoro Timer", + "author": "TimeTracker", + "repository": "https://github.com/tmtrckr/plugin-pomodoro", + "latest_version": "1.0.0", + "description": "Pomodoro timer plugin for Time Tracker application", + "category": "productivity", + "verified": false, + "downloads": 0, + "tags": [ + "pomodoro" + ], + "license": "MIT", + "min_core_version": "0.3.0", + "max_core_version": "1.0.0", + "api_version": "1.0", + "versions": [ + "1.0.0" + ], + "path": "plugins/t/timetracker/pomodoro-timer" + }, + { + "$schema": "https://github.com/tmtrckr/plugins-registry/schemas/manifest.schema.json", + "id": "projects-tasks", + "name": "Projects & Tasks", + "author": "TimeTracker", + "repository": "https://github.com/tmtrckr/plugin-projects-tasks", + "latest_version": "1.0.0", + "description": "Project and task management plugin for Time Tracker application.", + "category": "reporting", + "verified": false, + "downloads": 0, + "tags": [ + "projects", + "tasks", + "reporting" + ], + "license": "MIT", + "min_core_version": "0.3.0", + "max_core_version": "1.0.0", + "api_version": "1.0", + "versions": [ + "1.0.0" + ], + "path": "plugins/t/timetracker/projects-tasks" } ], "statistics": { - "total_plugins": 1, - "total_versions": 1, - "total_authors": 1 + "total_plugins": 5, + "total_versions": 5, + "total_authors": 2 } } diff --git a/scripts/validate.js b/scripts/validate.js index 8f06a40..873cf6f 100644 --- a/scripts/validate.js +++ b/scripts/validate.js @@ -15,6 +15,12 @@ const registrySchemaPath = path.join(rootDir, 'schemas', 'registry.schema.json') const manifestSchemaPath = path.join(rootDir, 'schemas', 'manifest.schema.json'); try { + if (!fs.existsSync(registryPath)) { + console.log('⚠️ registry.json not found. Skipping registry validation.'); + console.log(' Run `npm run build` to generate registry.json first.'); + process.exit(0); + } + const registry = JSON.parse(fs.readFileSync(registryPath, 'utf8')); const registrySchema = JSON.parse(fs.readFileSync(registrySchemaPath, 'utf8')); const manifestSchema = JSON.parse(fs.readFileSync(manifestSchemaPath, 'utf8')); From 953f931a2d485073cc01100f8c0b15d78cdd3505 Mon Sep 17 00:00:00 2001 From: bthos <13679349+bthos@users.noreply.github.com> Date: Fri, 13 Feb 2026 21:44:47 +0100 Subject: [PATCH 2/6] Update .github/workflows/validate-registry.yml Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .github/workflows/validate-registry.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/validate-registry.yml b/.github/workflows/validate-registry.yml index 380c92a..23d0cda 100644 --- a/.github/workflows/validate-registry.yml +++ b/.github/workflows/validate-registry.yml @@ -33,4 +33,8 @@ jobs: - name: Validate registry (if exists) run: | - npm run validate || echo "⚠️ registry.json not found, skipping validation" + if [ -f registry.json ]; then + npm run validate + else + echo "⚠️ registry.json not found, skipping validation" + fi From 53d88080b497224937a1ca69471f9b29eb989235 Mon Sep 17 00:00:00 2001 From: bthos <13679349+bthos@users.noreply.github.com> Date: Fri, 13 Feb 2026 21:47:50 +0100 Subject: [PATCH 3/6] Update registry.json Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- registry.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/registry.json b/registry.json index df45596..0fd7c12 100644 --- a/registry.json +++ b/registry.json @@ -11,7 +11,7 @@ "repository": "https://github.com/tmtrckr/plugin-billing", "latest_version": "1.0.0", "description": "Billable time tracking plugin for Time Tracker application.", - "category": "other", + "category": "billing", "verified": false, "downloads": 0, "tags": [], From 9baad5b3becd03cde4495986736efcfd627b66c0 Mon Sep 17 00:00:00 2001 From: bthos <13679349+bthos@users.noreply.github.com> Date: Fri, 13 Feb 2026 21:48:19 +0100 Subject: [PATCH 4/6] Update registry.json Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- registry.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/registry.json b/registry.json index 0fd7c12..e7444da 100644 --- a/registry.json +++ b/registry.json @@ -14,7 +14,13 @@ "category": "billing", "verified": false, "downloads": 0, - "tags": [], + "tags": [ + "billing", + "invoicing", + "finance", + "payments", + "billable-time" + ], "license": "MIT", "min_core_version": "0.3.0", "max_core_version": "1.0.0", From 9e38b2e16bb9f0324b8d25c51c93851e3c677bf0 Mon Sep 17 00:00:00 2001 From: bthos Date: Fri, 13 Feb 2026 21:51:41 +0100 Subject: [PATCH 5/6] Update documentation for DCO requirements and validation commands - Clarify DCO sign-off requirements in CONTRIBUTING.md, emphasizing the need for a valid email address. - Rename validation command in package.json from `validate-all` to `validate-files` for better clarity. - Update README.md to reflect the new validation command and provide additional context on the validation process. - Modify the create plugin script output message to align with the updated validation command. Signed-off-by: bthos Signed-off-by: bthos --- .github/PULL_REQUEST_TEMPLATE.md | 2 ++ CONTRIBUTING.md | 28 +++++++++++++++++++++++++++- README.md | 8 ++++---- package.json | 2 +- tools/cli/src/commands/create.js | 2 +- 5 files changed, 35 insertions(+), 7 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 0c9dd4a..c79bd4f 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -26,3 +26,5 @@ ## DCO By submitting this pull request, I certify that my contributions are made under the terms of the [Developer Certificate of Origin](https://developercertificate.org/). All commits are signed off with `git commit -s`. + +**Note:** DCO requires a valid email address that matches your Git commit author email. See [CONTRIBUTING.md](../CONTRIBUTING.md#developer-certificate-of-origin-dco) for details. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a80b254..d463c85 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -27,7 +27,20 @@ git commit -s -m "Add plugin: your-plugin-name" This automatically adds `Signed-off-by: Your Name ` to your commit. -**⚠️ Important:** All PRs are checked for DCO sign-off. Commits without sign-off will fail the DCO check. +**⚠️ Important:** +- All PRs are checked for DCO sign-off. Commits without sign-off will fail the DCO check. +- **Email is required**: DCO requires a valid email address in the format `Name `. The email must: + - Be a valid email format (you can't use just a username) + - Match your commit author email (the email Git uses when you commit) + +**Setting your Git email:** +If you haven't set your Git email, configure it first: +```bash +git config --global user.email "your.email@example.com" +git config --global user.name "Your Name" +``` + +Then commit with `-s` flag as shown above. ## How to Add a Plugin @@ -320,6 +333,19 @@ plugins/j/john-doe/my-plugin/ **No!** Never commit `registry.json`. CI builds and commits it automatically after your PR is merged. +### What email should I use for DCO sign-off? + +You can use any valid email address. The email in `Signed-off-by:` must: +- Be a valid email format (e.g., `user@example.com`) +- Match your Git commit author email + +**Common options:** +- Your GitHub email (if you have it public) +- Your personal email +- Any valid email address you control + +**Important:** You cannot use just a username - a valid email address is required. + ### How long does it take for my plugin to appear? After your PR is merged, CI automatically builds the registry (usually takes 1-2 minutes). Your plugin will then appear in `registry.json` and be available in the marketplace. diff --git a/README.md b/README.md index 92a698d..bba18d0 100644 --- a/README.md +++ b/README.md @@ -312,13 +312,13 @@ Validate the aggregated registry (requires registry.json to exist - run `npm run npm run validate ``` -Validate everything (schemas, plugins, and existing registry.json if present): +Validate existing files (schemas, plugins, and registry.json if present): ```bash -npm run validate-all +npm run validate-files ``` -This runs: `validate-schemas` β†’ `validate-plugins` β†’ `validate` (skips registry validation if registry.json doesn't exist) +This runs: `validate-schemas` β†’ `validate-plugins` β†’ `validate` (skips registry validation if registry.json doesn't exist). Note: This does not build the registry - run `npm run build` first if you need to generate registry.json. Check for duplicate plugin IDs: @@ -362,7 +362,7 @@ Contributions are welcome! Please: 2. Ensure all URLs are valid 3. Provide clear descriptions 4. Use appropriate categories and tags -5. Sign off commits (DCO): `git commit -s -m "message"` +5. Sign off commits (DCO): `git commit -s -m "message"` (requires valid email - see [CONTRIBUTING.md](CONTRIBUTING.md#developer-certificate-of-origin-dco)) ### Ways to Contribute diff --git a/package.json b/package.json index 726c11e..23a198e 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "validate": "node scripts/validate.js", "validate-plugins": "node scripts/validate-plugins.js", "validate-schemas": "node scripts/validate-schemas.js", - "validate-all": "npm run validate-schemas && npm run validate-plugins && npm run validate", + "validate-files": "npm run validate-schemas && npm run validate-plugins && npm run validate", "format": "node scripts/format.js", "check-duplicates": "node scripts/check-duplicates.js", "create-plugin": "node scripts/create-plugin.js", diff --git a/tools/cli/src/commands/create.js b/tools/cli/src/commands/create.js index 8c6e2ff..b5b7933 100644 --- a/tools/cli/src/commands/create.js +++ b/tools/cli/src/commands/create.js @@ -47,6 +47,6 @@ module.exports = async function create(args) { fs.mkdirSync(pluginDir, { recursive: true }); fs.writeFileSync(pluginPath, JSON.stringify(manifest, null, 2) + '\n', 'utf8'); console.log('Created:', pluginPath); - console.log('Next: npm run validate-all, then submit a PR.'); + console.log('Next: npm run validate-files, then submit a PR.'); return () => {}; }; From ac8cbf36d80284f70d22a147b0595a1c5eac3a0b Mon Sep 17 00:00:00 2001 From: bthos Date: Fri, 13 Feb 2026 21:56:27 +0100 Subject: [PATCH 6/6] Update registry.json to reflect changes in last_updated timestamp, category for the billing plugin, and remove associated tags. Signed-off-by: bthos --- registry.json | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/registry.json b/registry.json index e7444da..079f68c 100644 --- a/registry.json +++ b/registry.json @@ -1,7 +1,7 @@ { "$schema": "https://github.com/tmtrckr/plugins-registry/schemas/registry.schema.json", "version": "1.0.0", - "last_updated": "2026-02-13T20:30:19.826Z", + "last_updated": "2026-02-13T20:55:37.494Z", "plugins": [ { "$schema": "https://github.com/tmtrckr/plugins-registry/schemas/manifest.schema.json", @@ -11,16 +11,10 @@ "repository": "https://github.com/tmtrckr/plugin-billing", "latest_version": "1.0.0", "description": "Billable time tracking plugin for Time Tracker application.", - "category": "billing", + "category": "other", "verified": false, "downloads": 0, - "tags": [ - "billing", - "invoicing", - "finance", - "payments", - "billable-time" - ], + "tags": [], "license": "MIT", "min_core_version": "0.3.0", "max_core_version": "1.0.0",