Skip to content
Open
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
5 changes: 5 additions & 0 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,8 @@ jobs:

- name: Validate plugin layout
run: node scripts/validate-devin-plugin.mjs

- name: Validate README has no plugin version
env:
PLUGIN_MANIFEST: .devin-plugin/plugin.json
run: node scripts/validate-readme-no-version.mjs
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

JFrog plugin for [Devin](https://devin.ai/): JFrog Platform skills for artifact management, security scanning, and supply-chain workflows, plus the JFrog Platform MCP server (remote HTTP + OAuth).

> **Current version:** `0.3.0` — skills from [jfrog/jfrog-skills](https://github.com/jfrog/jfrog-skills) (pinned at `v0.25.0`) and a bundled JFrog MCP entry.
> Skills from [jfrog/jfrog-skills](https://github.com/jfrog/jfrog-skills) (pin in [`.github/scripts/sync-skills-vendor.json`](.github/scripts/sync-skills-vendor.json)) and a bundled JFrog MCP entry. Plugin releases are tagged on GitHub — do not duplicate version numbers here.

## Skills

Expand Down Expand Up @@ -44,7 +44,7 @@ The plugin registers this MCP server (declared in `mcp.json` and referenced from
- **Devin CLI** — see [Devin docs](https://docs.devin.ai/)
- **Devin CLI plugins enabled** for your organization (`devin plugins install` must be allowed)
- **`JFROG_PLATFORM_URL`** — JFrog platform host only (no `https://`, no trailing `/`). Required for the bundled MCP entry.
- **Skill runtime** (when using the skills) — `jf` CLI, `jq`, and `curl` on `PATH`, plus a configured JFrog instance (`jf config add`). See [jfrog-skills requirements](https://github.com/jfrog/jfrog-skills/blob/v0.25.0/README.md#requirements).
- **Skill runtime** (when using the skills) — `jf` CLI, `jq`, and `curl` on `PATH`, plus a configured JFrog instance (`jf config add`). See [jfrog-skills requirements](https://github.com/jfrog/jfrog-skills/blob/main/README.md#requirements).

## Installation

Expand Down Expand Up @@ -95,9 +95,9 @@ devin-plugin/
node scripts/validate-devin-plugin.mjs
```

## Versioning
## Releasing

Bump `version` in [`.devin-plugin/plugin.json`](.devin-plugin/plugin.json) when you publish a new release, then tag (for example `v0.3.0`).
Bump `version` in [`.devin-plugin/plugin.json`](.devin-plugin/plugin.json) when you publish a new release, then tag on GitHub. See [`.github/workflows/release.yml`](.github/workflows/release.yml).

## License

Expand Down
78 changes: 78 additions & 0 deletions scripts/validate-readme-no-version.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#!/usr/bin/env node

// Copyright (c) JFrog Ltd. 2026
// Licensed under the Apache License, Version 2.0
// https://www.apache.org/licenses/LICENSE-2.0

import { readFileSync, existsSync } from "node:fs";
import process from "node:process";

const docPaths = (process.env.DOCS || process.env.README_PATH || "README.md")
.split(/\s+/)
.filter(Boolean);

const errors = [];

for (const docPath of docPaths) {
const content = readFileSync(docPath, "utf8");
validateDoc(docPath, content, errors);
}

function validateDoc(docPath, content, errors) {

const bannedPatterns = [
{
re: /current version/i,
msg: 'README must not include a "Current version" callout — use GitHub Releases/tags.',
},
{
re: /^## Versioning\s*$/m,
msg: 'README must not include a "## Versioning" section — versions live in the manifest and GitHub Releases.',
},
{
re: /then tag \(for example `v/i,
msg: "README must not include example release tags.",
},
{
re: /github\.com\/jfrog\/jfrog-skills\/blob\/v\d+\.\d+\.\d+/i,
msg: "README must not pin jfrog-skills doc links to a release tag — use main README or sync-skills-vendor.json.",
},
{
re: /codeload\.github\.com\/jfrog\/jfrog-skills\/(tar\.gz|zip)\/v\d+\.\d+\.\d+/i,
msg: "README must not embed jfrog-skills release tags in download URLs.",
},
];

for (const { re, msg } of bannedPatterns) {
if (re.test(content)) {
errors.push(`${docPath}: ${msg}`);
}
}

const manifestPath = process.env.PLUGIN_MANIFEST;
if (docPath.endsWith("README.md") && manifestPath && existsSync(manifestPath)) {
let version;
if (manifestPath.endsWith(".json")) {
version = JSON.parse(readFileSync(manifestPath, "utf8")).version;
} else if (manifestPath.endsWith("gradle.properties")) {
const match = readFileSync(manifestPath, "utf8").match(/^version\s*=\s*(.+)$/m);
version = match?.[1]?.trim();
}

if (version && content.includes(version)) {
errors.push(
`${docPath}: contains plugin version "${version}" — authoritative source is ${manifestPath}.`
);
}
}
}

if (errors.length > 0) {
console.error("README version validation failed:");
for (const error of errors) {
console.error(`- ${error}`);
}
process.exit(1);
}

console.log("README version validation passed.");
Loading