-
Notifications
You must be signed in to change notification settings - Fork 116
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Create External Plugin that reads from disk or url #3114
Conversation
b80b3ae
to
508fc7c
Compare
508fc7c
to
9ba7e51
Compare
Excited to see this moving forward! Initial thoughts: Are users of external plugins expected to generate their own graphs outside of the sourcecred runtime when the other plugin graphs are generated? I was imagining the external plugin wouldn't be a static JSON file but instead a JS file that default exports a class representing the plugin which then gets executed at runtime (e.g. by the |
So really, there is nothing stopping those types of external plugins from being developed right now, they would just have to be registered in our bundledPlugins/bundledDeclarations files. The lift to allow an instance maintainer to import unregistered plugins is likely pretty simple, and I can take a look at knocking that out too this week. This PR introduces some interesting possibilities:
|
@blueridger Makes sense, yea I think this is def a worthwhile primitive to have. I didn't think about the support for remote endpoints, that's actually very powerful and helps a ton for inter-org value graphs. I think the key then becomes to make graph construction as easy as possible via our NPM package. I would say improving the dev experience around that / documenting an example implementation would be more useful than the runtime plugins. |
6659153
to
41fc92f
Compare
Hadn't manual tested the remote case yet. Found and fixed a bug and updated test plan. Seeking reapproval @HammadJ |
Realized, this plugin would be significantly more useful in the library if it could be constructed with a configuration. And also that the 3 files shouldn't need to have the same url root in the remote case. Made these changes. Seeking reapproval @HammadJ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm so excited you're exploring this! I've found some nits, but otherwise I'm feeling quite good about this.
One question I had: What are the implications of moving plugin declarations to async
land? I knew it would have to happen eventually, but do we have to consider adding extra prompts to accommodate longer wait times here?
export async function getPluginDeclaration( | ||
pluginId: PluginId, | ||
storage: DataStorage | ||
): Promise<PluginDeclaration> { | ||
const mapping = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I appreciate this refactoring
pluginId, | ||
storage: new DiskStorage(process.cwd()), | ||
}); | ||
return null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just curious: why not an implicit undefined
return here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will change, probably just a years-old habit from the 1 year in college I spent writing java lol.
fromJSON as declarationFromJSON, | ||
} from "../../analysis/pluginDeclaration"; | ||
import {join as pathJoin} from "path"; | ||
import {type TaskReporter} from "../../util/taskReporter"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
type
should outside the curly brackets here, if only types are in the import.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
accepted all
import {loadJson, loadJsonWithDefault} from "../../util/storage"; | ||
import {merge as mergeWeights} from "../../core/weights"; | ||
import {weightsForDeclaration} from "../../analysis/pluginDeclaration"; | ||
import {type PluginId} from "../../api/pluginId"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here
identityProposalsParser, | ||
} from "../../core/ledger/identityProposal"; | ||
import * as Combo from "../../util/combo"; | ||
import {type DataStorage} from "../../core/storage"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here
type ExternalPluginConfig = {| | ||
+graphUrl: string, | ||
+declarationUrl?: string, | ||
+identityProposalsUrl?: string, | ||
|}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like to see a URL parser created for these, but that can probably be a separate issue, or even a good first issue. I thought we had one, but I can't find it. It'd be really good to "fail fast" on something like this before any network requests are made.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so true. create an issue?
Fair question. I don't anticipate it being a problem, since we actually don't parallelize promises very much in our code, and even over network, it should be a very short fetch time. |
Description
This creates a new special plugin: the External plugin. This is a dynamic plugin that allows 3rd parties to rapidly pipe data into an instance.
The External plugin can be used multiple times, because it simply uses the PluginId pattern "external/X" where X can be any name (but preferably an agreed upon name between the 3rd-party software and the instance maintainer).
The External plugin loads its graph and optionally its declaration and identityProposals from either:
config/plugins/external/X
folder.config.json
file in the instance'sconfig/plugins/external/X
folder with form:{ "graphUrl": "https://www.myhost.com/path/to/file/graph.json" }
Supported files for either method are:
graph.json
/graph.json.gzip
(required) - works whether or not it is compressed using our librarydeclaration.json
(optional) - if omitted, a default declaration with minimal node/edge types is used, but also graphs don't have to adhere to the declaration if they don't desire to be configured using our Weight Configuration UI.identityProposals.json
(optional) - if omitted, no identities are proposedTest Plan
local config graph
output/graphs/sourcecred/github/graph.json.gzip
toconfig/plugins/external/github2/graph.json.gzip
scdev go --no-load
output/graphs/sourcecred/github2/graph.json.gzip
existsalso ended up testing with a non-zipped graph.json
remote url graph
config/plugins/external/github2/config.json
containing{"baseUrl": "https://raw.githubusercontent.com/sourcecred/cred/gh-pages/output/graphs/sourcecred/github/"}
scdev graph
output/graphs/sourcecred/github2/graph.json.gzip
exists