-
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
Implement Grain Integration functionality in the CLI #3085
Conversation
44cce43
to
a7046cf
Compare
e766631
to
8fbffa7
Compare
3714583
to
4ca7e28
Compare
packages/sourcecred/src/cli/grain.js
Outdated
const integrationCurrency = grainInput.currencyDetails.integrationCurrency; | ||
const grainIntegration = grainInput.grainConfig.integration; | ||
if (integrationCurrency && grainIntegration) { | ||
distributions.forEach((distribution) => { | ||
const result = executeGrainIntegration( | ||
ledger, | ||
grainIntegration.function, | ||
distribution, | ||
integrationCurrency, | ||
false | ||
); | ||
if (result.grainIntegrationOutput) | ||
instance.writeGrainIntegrationOutput( | ||
result.grainIntegrationOutput, | ||
distribution | ||
); | ||
}); | ||
} |
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.
Shouldn't this go in the grain API instead of the grain CLI since it is business logic?
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.
good point. I'll separate the business logic from the I/O
39b467e
to
2f68004
Compare
4ca7e28
to
3fa71ac
Compare
if (integrationCurrency && grainIntegration) { | ||
distributions.forEach((distribution) => { | ||
const result = executeGrainIntegration( | ||
ledger, | ||
grainIntegration.function, | ||
distribution, | ||
integrationCurrency, | ||
false | ||
); | ||
results.push(result); | ||
}); | ||
} | ||
return results; | ||
} |
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.
Seems strange for this to return an array of objects that each contain the same ledger, and that in the CLI we encode the assumption that the ledger we passed in is going to be mutated and so we can ignore the ledgers that come out. What about a refactor that looks more like:
if (integrationCurrency && grainIntegration) { | |
distributions.forEach((distribution) => { | |
const result = executeGrainIntegration( | |
ledger, | |
grainIntegration.function, | |
distribution, | |
integrationCurrency, | |
false | |
); | |
results.push(result); | |
}); | |
} | |
return results; | |
} | |
if (integrationCurrency && grainIntegration) { | |
let ledgerResult = ledger; | |
distributions.forEach((distribution) => { | |
const {ledger: newLedger, output, distributionCredTimestamp} = executeGrainIntegration( | |
ledger, | |
grainIntegration.function, | |
distribution, | |
integrationCurrency, | |
false | |
); | |
results.push({output, distributionCredTimestamp}); | |
ledgerResult = newLedger; | |
}); | |
} | |
return {ledger: ledgerResult, results}; | |
} |
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.
yeah good catch. We don't ever want to assume it's safe to mutate the same ledger reference across multiple function calls.
packages/sourcecred/src/cli/grain.js
Outdated
const {distributions, ledger} = await grain(grainInput); | ||
|
||
const grainIntegrationResults = executeGrainIntegrationsFromGrainInput( | ||
grainInput, | ||
ledger, | ||
distributions | ||
); |
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.
This is related to my other comment.
const {distributions, ledger} = await grain(grainInput); | |
const grainIntegrationResults = executeGrainIntegrationsFromGrainInput( | |
grainInput, | |
ledger, | |
distributions | |
); | |
const {distributions, ledger: ledgerBeforeIntegrations} = await grain(grainInput); | |
const {ledger, results: grainIntegrationResults} = executeGrainIntegrationsFromGrainInput( | |
grainInput, | |
ledgerBeforeIntegrations, | |
distributions | |
); |
This officially hooks up grain integrations into something accessible! All we need to use it is a way to easily set payout addresses for participants. These changes also contain a semantic change for the grain integration typing. The function exported by a grain integration is now named `GrainIntegrationFunction` The original `GrainIntegration` type which used to represent the function is now as follows: ```js type GrainIntegration = {| function: GrainIntegrationFunction, name: string |} ``` This will allow core to utilize the configured grain integration name internally, if desired. Merge Plan: Merge after #3079 Test Plan: 0. `scdev build` 1. from repo root: `cd packages/sourcecred/sharness/__snapshots__/test-instance` 2. scdev grain -f 3. open the new file in the output/grainIntegration and observe 2 lines of csv output. The first column containing payout addresses, the second column containing payout amounts in bigint form.
Business Logic should be agnostic of I/O so it can be utilized elsewhere. This also lead to a minor API cleanup: Each distribution's credtimestamp is now included in the integration result, so integration results now have all the identifying details needed to make them unique.
d480be8
to
db1cd4d
Compare
db1cd4d
to
dab95f0
Compare
results.push(result); | ||
}); | ||
} | ||
return {ledger: ledgerResult, results}; |
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.
Still seems weird / too heavy that we are returning a bunch of ledgers in results right here. Is there a reason for it, or can we slim down and toss the extra references to garbage collection?
@@ -24,8 +25,15 @@ export type GrainOutput = {| | |||
+ledger: Ledger, | |||
|}; | |||
|
|||
// Similar to GrainIntegrationResult but excludes the ledger | |||
// since only the most recent ledger is relevant | |||
export type GrainIntegrationMultiResult = {| |
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.
nit: Why multi? Makes me think it's going to be an array. Not sure I have a better suggestion, I'm all turned around on the namings in this epic lol. timeStampedGrainIntegrationOutput? nah the output is optional... idk. you can keep it.
@@ -47,5 +47,7 @@ export interface Instance extends ReadOnlyInstance { | |||
writeLedger(ledger: Ledger): Promise<void>; | |||
|
|||
/** writes grain integration output */ | |||
writeGrainIntegrationOutput(result: GrainIntegrationResult): Promise<void>; | |||
writeGrainIntegrationOutput( | |||
result: $Shape<GrainIntegrationMultiResult> |
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.
why shape? seems unnecessary since the GrainIntegrationOutput attribute is optional already
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 wanted to be unopinionated enough to accept the GrainIntegrationResult
type.
Details
This officially hooks up grain integrations into something accessible via the CLI!
I'm open to setting up a CLI flag in addition to allowing the invocation of
grain integrations at the config level as well.
These changes also contain a semantic change for the grain integration
typing. The function exported by a grain integration is now named
GrainIntegrationFunction
The original
GrainIntegration
type which used to represent thefunction is now as follows:
Merge Plan
Merge after #3079
Test Plan
yarn build
cd packages/sourcecred/sharness/__snapshots__/test-instance
scdev grain -f
of csv output. The first column containing payout addresses, the
second column containing payout amounts in BigInt form.
Next Steps
All we need to use it is a way to easily set payout addresses for
participants. This was done by hand in a NodeJS repl in order to
enable the above test case.