-
Notifications
You must be signed in to change notification settings - Fork 2
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
Allow multiple API tokens and app urls to be specified #499
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
✅ Meticulous spotted zero visual differences across 8 screens tested: view results. Expected differences? Click here. Test suite: public-tests. Last updated for commit 829dde1. This comment will update as new commits are pushed. |
3841435
to
ca83958
Compare
ca83958
to
f7f651c
Compare
const { apiToken: apiTokenInput, appUrl: appUrlInput } = | ||
getInCloudActionInputs(); | ||
const apiTokens = apiTokenInput.split(",").map((token) => token.trim()); | ||
const appUrls = appUrlInput.split(",").map((token) => token.trim()); | ||
while (appUrls.length < apiTokens.length) { | ||
// If the number of app URLs is less than the number of API tokens, the | ||
// last URL will be used for all remaining projects. This allow for | ||
// more concise inputs when one app URL is to be used many times. In | ||
// particular in the common case of one app URL for all projects. | ||
appUrls.push(appUrls[appUrls.length - 1]); | ||
} |
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] Since this is input parsing logic I'd push this down into getInCloudActionInputs to keep it separate from the main code
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.
We should also update the docs here: https://github.com/alwaysmeticulous/report-diffs-action/blob/main/cloud-compute/action.yml.
That said wondering what the best API is for us here? We should work that out before shipping. Some notes here https://www.notion.so/API-for-multi-project-cloud-compute-action-75afd0edf8694bd7be54b305e4a63c30?pvs=4.
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.
Thinking we should do this:
- name: Run Meticulous tests
uses: alwaysmeticulous/report-diffs-action/cloud-compute@v1
with:
# Important: remember to add the '|' character below: GitHub doesn't support complex action inputs, so we're actually passed the sub YAML as a string.
projects_yaml: |
admin_portal:
api_token: ${{ secrets.METICULOUS_ADMIN_PORTAL_API_TOKEN }}
app_url: https://localhost:3000/
skip: ${{ steps.changed-admin-portal-files.outputs.any_changed == 'false' }}
customer_portal:
api_token: ${{ secrets.METICULOUS_CUSTOMER_PORTAL_API_TOKEN }}
app_url: https://localhost:3000/
skip: ${{ steps.changed-customer-portal-files.outputs.any_changed == 'false' }}
One thing I find useful on API design is always to try the API out / write out how user would use it. Much easier to iterate on correct API when looking at example usages across common use cases than by looking at the type definition of the API.
} | ||
}); | ||
if (failureMessage) { | ||
setFailed(failureMessage); |
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.
In the common case of just using one action we should probably keep the failure message as a clean as we can, similar to before e.g.
failures.push({ runNumber: index + 1, message })`
const message = failures.length === 1 ? failures[0].message : ...;
if (result.status === "rejected") { | ||
const message = | ||
result.reason instanceof Error ? result.reason.message : `${error}`; | ||
failureMessage += `Run #${index + 1} failed: ${message}\n`; |
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.
Not sure how often this case would get hit (maybe quite rare?), but it could make sense to give some context.
Also maybe Run
-> Test run
so user doesn't think this is a retry number. And in the common case of just using one action we should probably keep the failure message as a clean as we can, similar to before e.g.
if (apiTokens.length > 1) {
failureMessage += `Test run #${index + 1} against '${appUrls[index]}' with token '${apiTokens.slice(0, 3)}...': ${message}`;
} else {
failureMessage = message;
}
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.
Also, if we're not already logging it, maybe also:
logger.error(`[Test run #${index + 1}]`, result.reason);
const { payload } = context; | ||
const event = getCodeChangeEvent(context.eventName, payload); | ||
const { owner, repo } = context.repo; | ||
const isDebugPRRun = isDebugPullRequestRun(event); | ||
const octokit = getOctokitOrFail(githubToken); | ||
const logger = log.getLogger(METICULOUS_LOGGER_NAME); | ||
const logger = getPrefixedLogger(`Run #${runNumber}`); |
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.
Ah nice!
[nit] Just in case user things this means retries
const logger = getPrefixedLogger(`Run #${runNumber}`); | |
const logger = getPrefixedLogger(`Test run #${runNumber}`); |
).forEach((result, index) => { | ||
if (result.status === "rejected") { | ||
const message = | ||
result.reason instanceof Error ? result.reason.message : `${error}`; |
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.
result.reason instanceof Error ? result.reason.message : `${error}`; | |
result.reason instanceof Error ? result.reason.message : `${result.reason}`; |
(error doesn't exist)
keepTunnelOpenPromise.resolve(); | ||
}, DEBUG_MODE_KEEP_TUNNEL_OPEN_DURAION.as("milliseconds")); | ||
} | ||
testSuiteId: "__meticulous_debug__", |
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.
we should probably tag this comment with the project ID too as this won't work in multi-project setups. Looks like this already doesn't work well on multi-project PRs.
✅ Meticulous spotted zero visual differences across 8 screens tested: view results. Test suite: test Meticulous with deployment url. Last updated for commit 829dde1. This comment will update as new commits are pushed. |
✅ Meticulous spotted zero visual differences across 8 screens tested: view results. Test suite: test Meticulous with app url. Last updated for commit 829dde1. This comment will update as new commits are pushed. |
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.
Nice!
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.
Nice, the new syntax looks good to me! Just a few small nits on your commits @alexivanov 🙂
cloud-compute/action.yml
Outdated
admin: | ||
api-token: {{ secrets.METICULOUS_ADMIN_API_TOKEN }} | ||
app-url: "http://localhost:4000" | ||
skip: {{ secrets.METICULOUS_APP_API_TOKEN }} |
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 guessing this is a bad copy paste? Should probably be an example of using the output from a previous step to determine whether to run it or not?
// This is used to simplify some of the logging and error handling. | ||
const isSingleTestRunExecution = | ||
projectTargetsToRun.length === 1 && | ||
projectTargetsToRun[0].name === "default"; |
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.
Hmm, I think we should use projectTargets
(before the filtering is applied) here. If we have more than one project in the config, I think it's nice to be explicit in the logging about which one the logs are coming from even if a particular run only executed one.
if (!project) { | ||
throw new Error( | ||
`Could not retrieve project data${ | ||
isSingleTestRunExecution ? "" : `for project ${testRunId}` |
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.
isSingleTestRunExecution ? "" : `for project ${testRunId}` | |
isSingleTestRunExecution ? "" : ` for project ${testRunId}` |
src/actions/cloud-compute/consts.ts
Outdated
@@ -0,0 +1,5 @@ | |||
import { Duration } from "luxon"; | |||
|
|||
export const DEBUG_MODE_KEEP_TUNNEL_OPEN_DURAION = Duration.fromObject({ |
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.
export const DEBUG_MODE_KEEP_TUNNEL_OPEN_DURAION = Duration.fromObject({ | |
export const DEBUG_MODE_KEEP_TUNNEL_OPEN_DURATION = Duration.fromObject({ |
74744dc
to
829dde1
Compare
Further follow-up to #499
This hasn't been fully tested yet, but putting it up for review so it can potentially be merged while I'm on holiday if needed.