-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
306 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
# Docs context provider for OpenCodeGraph | ||
|
||
This is a context provider for [OpenCodeGraph](https://opencodegraph.org) that indexes a documentation corpus and annotates your code with links to relevant documentation pages. | ||
|
||
## Screenshot | ||
|
||
![Screenshot of OpenCodeGraph docs annotations](<TODO(sqs)>) | ||
|
||
_TODO(sqs)_ | ||
|
||
Visit the [OpenCodeGraph playground](https://opencodegraph.org/playground) for a live example. | ||
|
||
## Usage | ||
|
||
Add the following to your settings in any OpenCodeGraph client: | ||
|
||
```json | ||
"opencodegraph.providers": { | ||
// ...other providers... | ||
"https://opencodegraph.org/npm/@opencodegraph/provider-docs": { | ||
// TODO(sqs) | ||
} | ||
}, | ||
``` | ||
|
||
TODO(sqs) | ||
|
||
See "[Configuration](#configuration)" for more. | ||
|
||
Tips: | ||
|
||
- If you're using VS Code, you can put the snippet above in `.vscode/settings.json` in the repository or workspace root to configure per-repository links. | ||
- Play around with the docs provider in realtime on the [OpenCodeGraph playground](https://opencodegraph.org/playground). | ||
|
||
## Configuration | ||
|
||
<!-- Keep in sync with index.ts --> | ||
|
||
```typescript | ||
/** Settings for the docs OpenCodeGraph provider. */ | ||
export interface Settings { | ||
// TODO(sqs) | ||
} | ||
``` | ||
|
||
## Development | ||
|
||
- [Source code](https://sourcegraph.com/github.com/sourcegraph/opencodegraph/-/tree/provider/docs) | ||
- [Docs](https://opencodegraph.org/docs/providers/docs) | ||
- License: Apache 2.0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import { type AnnotationsResult, type CapabilitiesResult } from '@opencodegraph/provider' | ||
import { describe, expect, test } from 'vitest' | ||
import prometheus, { type Settings } from './index' | ||
|
||
describe('prometheus', () => { | ||
const SETTINGS: Settings = { | ||
metricRegistrationPatterns: [ | ||
{ | ||
path: '**/*.go', | ||
pattern: /prometheus\.HistogramOpts{\s*Name:\s*"([^"]+)"/.source, | ||
urlTemplate: 'https://example.com/?q=$1', | ||
}, | ||
], | ||
} | ||
|
||
test('capabilities', async () => { | ||
expect(await prometheus.capabilities({}, SETTINGS)).toStrictEqual<CapabilitiesResult>({ | ||
selector: [{ path: '**/*.go' }], | ||
}) | ||
}) | ||
|
||
test('annotations', () => { | ||
expect( | ||
prometheus.annotations( | ||
{ | ||
file: 'file:///a/b.go', | ||
content: ` | ||
// histogram is a Prometheus metric. | ||
var histogram = promauto.NewHistogram(prometheus.HistogramOpts{ | ||
Name: "random_numbers", | ||
Help: "A histogram of normally distributed random numbers.", | ||
Buckets: prometheus.LinearBuckets(-3, .1, 61), | ||
})`.trim(), | ||
}, | ||
SETTINGS | ||
) | ||
).toEqual<AnnotationsResult>({ | ||
items: [ | ||
{ | ||
id: 'random_numbers', | ||
title: '📟 Prometheus metric: random_numbers', | ||
url: 'https://example.com/?q=random_numbers', | ||
preview: true, | ||
}, | ||
], | ||
annotations: [ | ||
{ | ||
item: { id: 'random_numbers' }, | ||
range: { | ||
start: { line: 2, character: 14 }, | ||
end: { line: 2, character: 28 }, | ||
}, | ||
}, | ||
], | ||
}) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
import { | ||
matchGlob, | ||
type AnnotationsParams, | ||
type AnnotationsResult, | ||
type CapabilitiesParams, | ||
type CapabilitiesResult, | ||
type OpenCodeGraphItem, | ||
type OpenCodeGraphPosition, | ||
type OpenCodeGraphProvider, | ||
type OpenCodeGraphRange, | ||
} from '@opencodegraph/provider' | ||
|
||
/** Settings for the Prometheus OpenCodeGraph provider. */ | ||
export interface Settings { | ||
/** | ||
* Patterns that match metric registrations. | ||
*/ | ||
metricRegistrationPatterns?: MetricRegistrationPattern[] | ||
} | ||
|
||
interface MetricRegistrationPattern { | ||
/** | ||
* Glob pattern matching the file URIs in which to search for this pattern. | ||
*/ | ||
path: string | ||
|
||
/** | ||
* Regexp pattern whose first capture group matches the metric name. | ||
* | ||
* @example `prometheus\\.HistogramOpts{\\s*Name:\\s*"([^"]+)` | ||
* @example `new promClient\\.Histogram\\({\\s*name: '([^']+)` | ||
*/ | ||
pattern: string | ||
|
||
/** | ||
* The URL to view matching metrics on Prometheus, Grafana, or another metrics viewer, with $1 | ||
* replaced by the metric name. | ||
* | ||
* @example https://prometheus.demo.do.prometheus.io/graph?g0.expr=$1&g0.tab=0 | ||
* @example | ||
* https://grafana.example.com/explore?left=%5B%22now-6h%22,%22now%22,%22Prometheus%22,%7B%22expr%22:%22$1%22%7D%5D | ||
*/ | ||
urlTemplate: string | ||
} | ||
|
||
/** | ||
* An [OpenCodeGraph](https://opencodegraph.org) provider that lets you hover over a Prometheus | ||
* metric in your code to see what it's doing in prod and to click through to the live metrics on | ||
* [Prometheus](https://prometheus.io), [Grafana](https://grafana.com/), or another metrics viewer. | ||
* | ||
* These links will be visible in every dev's editor, in code search, on the code host, and in code | ||
* review (assuming all of those tools have OpenCodeGraph support). | ||
* | ||
* - TODO(sqs): Make this find dashboards containing the metric (like | ||
* https://github.com/panodata/grafana-wtf). | ||
* - TODO(sqs): Hit the Prometheus/Grafana APIs to fetch data (eg `curl -XPOST | ||
* 'https://prometheus.demo.do.prometheus.io/api/v1/query?query=go_gc_duration_seconds&timeout=200ms'`). | ||
*/ | ||
const prometheus: OpenCodeGraphProvider<Settings> = { | ||
capabilities(_params: CapabilitiesParams, settings: Settings): CapabilitiesResult { | ||
return { selector: settings.metricRegistrationPatterns?.map(({ path }) => ({ path })) || [] } | ||
}, | ||
|
||
annotations(params: AnnotationsParams, settings: Settings): AnnotationsResult { | ||
const compiledPatterns: | ||
| (Pick<MetricRegistrationPattern, 'urlTemplate'> & { | ||
pattern: RegExp | ||
matchPath: (path: string) => boolean | ||
})[] | ||
| undefined = settings.metricRegistrationPatterns?.map(({ pattern, path, ...other }) => ({ | ||
...other, | ||
pattern: new RegExp(pattern, 'dgs'), | ||
matchPath: matchGlob(path), | ||
})) | ||
|
||
const positionCalculator = createFilePositionCalculator(params.content) | ||
|
||
const result: AnnotationsResult = { | ||
items: [], | ||
annotations: [], | ||
} | ||
const hasItem = (id: string): boolean => result.items.some(item => item.id === id) | ||
|
||
for (const { matchPath, pattern, urlTemplate } of compiledPatterns || []) { | ||
if (!matchPath(new URL(params.file).pathname)) { | ||
continue | ||
} | ||
|
||
const ranges = matchResults(pattern, params.content, positionCalculator) | ||
for (const { range, metricName } of ranges) { | ||
const item: OpenCodeGraphItem = { | ||
id: '', | ||
title: `📟 Prometheus metric: ${metricName}`, | ||
url: urlTemplate.replaceAll('$1', metricName), | ||
preview: true, | ||
} | ||
item.id = metricName | ||
|
||
result.annotations.push({ | ||
item: { id: item.id }, | ||
range, | ||
}) | ||
|
||
if (!hasItem(item.id)) { | ||
result.items.push(item) | ||
} | ||
} | ||
} | ||
|
||
return result | ||
}, | ||
} | ||
|
||
export default prometheus | ||
|
||
interface MatchResult { | ||
range: OpenCodeGraphRange | ||
metricName: string | ||
} | ||
|
||
function matchResults(pattern: RegExp, content: string, pos: PositionCalculator): MatchResult[] { | ||
const results: MatchResult[] = [] | ||
for (const match of content.matchAll(pattern)) { | ||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion | ||
const [start, end] = match.indices![1] | ||
results.push({ | ||
range: { | ||
start: pos(start), | ||
end: pos(end), | ||
}, | ||
metricName: match[1], | ||
}) | ||
break // only add one match per line | ||
} | ||
return results | ||
} | ||
|
||
type PositionCalculator = (offset: number) => OpenCodeGraphPosition | ||
function createFilePositionCalculator(content: string): PositionCalculator { | ||
const lines = content.split('\n') | ||
return (offset: number) => { | ||
let line = 0 | ||
let character = 0 | ||
while (line < lines.length && offset > 0) { | ||
const lineLength = lines[line].length + 1 // +1 for the newline | ||
if (lineLength > offset) { | ||
character = offset | ||
break | ||
} | ||
offset -= lineLength | ||
line += 1 | ||
} | ||
return { line, character } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
{ | ||
"name": "@opencodegraph/provider-prometheus", | ||
"version": "0.0.2", | ||
"description": "Hover over a Prometheus metric to see what it's doing in prod (OpenCodeGraph provider)", | ||
"license": "Apache-2.0", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/sourcegraph/opencodegraph", | ||
"directory": "provider/prometheus" | ||
}, | ||
"type": "module", | ||
"main": "dist/index.js", | ||
"types": "dist/index.d.ts", | ||
"files": [ | ||
"dist", | ||
"index.ts", | ||
"!**/*.test.*", | ||
"README.md" | ||
], | ||
"sideEffects": false, | ||
"scripts": { | ||
"build": "tsc --build", | ||
"test": "vitest" | ||
}, | ||
"dependencies": { | ||
"@opencodegraph/provider": "workspace:*" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
{ | ||
"extends": "../../.config/tsconfig.base.json", | ||
"compilerOptions": { | ||
"module": "ESNext", | ||
"rootDir": ".", | ||
"outDir": "dist", | ||
"lib": ["ESNext"], | ||
}, | ||
"include": ["*.ts"], | ||
"exclude": ["dist", "vitest.config.ts"], | ||
"references": [{ "path": "../../lib/provider" }], | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import { defineConfig } from 'vitest/config' | ||
|
||
export default defineConfig({}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters