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
Bug 1776069: Uncaught exception in UI when getting webhooks links for buildconfigs #3733
Conversation
@jhadvig: This pull request references Bugzilla bug 1781300, which is invalid:
Comment In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
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.
You should add some types for better type checking. In general, prefer the native Array.map
and Array.find
to the lodash versions (as long as you handle null values).
Looks like you'll have linter errors.
).then(response => { | ||
setWebhookSecrets(response) | ||
}) | ||
}); |
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.
You need to specify dependencies or you'll request the secrets again on every render
@@ -56,7 +56,26 @@ export const WebhookTriggers: React.FC<WebhookTriggersProps> = (props) => { | |||
}); | |||
const tableColumnClasses = getTableColumnClasses(canGetSecret); | |||
const webhooks = _.filter(triggers, (trigger) => webhookTriggers.has(trigger.type)); | |||
if (_.isEmpty(webhooks)) { | |||
const [webhookSecrets, setWebhookSecrets] = React.useState([]) |
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.
const [webhookSecrets, setWebhookSecrets] = React.useState([]) | |
const [webhookSecrets, setWebhookSecrets] = React.useState<K8sResourceKind>([]) |
if (_.isEmpty(webhooks)) { | ||
const [webhookSecrets, setWebhookSecrets] = React.useState([]) | ||
|
||
const webhookNames = _.map(webhooks, (webhook) => { |
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.
const webhookNames = _.map(webhooks, (webhook) => { | |
const webhookNames: string[] = _.map(webhooks, (webhook): string => { |
React.useEffect(() => { | ||
Promise.all( | ||
_.map(webhookNames, (webhookName) => { | ||
return k8sGet(SecretModel, webhookName, namespace).then(res => { |
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.
return k8sGet(SecretModel, webhookName, namespace).then(res => { | |
return k8sGet(SecretModel, webhookName, namespace); |
errorModal({ error }); | ||
}, | ||
); | ||
const webhookSecret = _.find(webhookSecrets, (secret) => { return secret.metadata.name === secretName}) |
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.
const webhookSecret: K8sResourceKind = webhookSecrets.find((secret: K8sReosurceKind) => secret.metadata.name === secretName);
|
||
React.useEffect(() => { | ||
Promise.all( | ||
_.map(webhookNames, (webhookName) => { |
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.
_.map(webhookNames, (webhookName) => { | |
_.map(webhookNames, (webhookName: string): Promise<K8sResourceKind> => { |
@jhadvig: An error was encountered adding this pull request to the external tracker bugs for bug 1776069 on the Bugzilla server at https://bugzilla.redhat.com:
Please contact an administrator to resolve this issue, then request a bug refresh with In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
Manually removing invalid bug since the bot is not working. |
Promise.all( | ||
webhookNames.map( | ||
(webhookName: string): Promise<K8sResourceKind> => { | ||
return k8sGet(SecretModel, webhookName, namespace).catch(() => { |
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.
Had to add the .catch()
block since if there is an error retrieving the secret (eg. user manually edits the BC with a secret that does not exists...) we need to catch the error and return null
, instead of uncaught error in promise
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.
What happens when null
is returned? It would be good to show a warning somewhere if we know the webhook secret doesn't exist and one of the benefits of fetching the secrets ahead. Although we'd need to differentiate between 403 errors and other errors.
@spadgett comments addressed. PTAL |
const webhooks = _.filter(triggers, (trigger) => webhookTriggers.has(trigger.type)); | ||
if (_.isEmpty(webhooks)) { | ||
const [webhookSecrets, setWebhookSecrets] = React.useState<K8sResourceKind[]>([]); | ||
const [isLoaded, setIsLoaded] = React.useState<boolean>(false); |
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 fine, although boolean
in inferred from the default value in this case, so not strictly necessary.
Promise.all( | ||
webhookNames.map( | ||
(webhookName: string): Promise<K8sResourceKind> => { | ||
return k8sGet(SecretModel, webhookName, namespace).catch(() => { |
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.
What happens when null
is returned? It would be good to show a warning somewhere if we know the webhook secret doesn't exist and one of the benefits of fetching the secrets ahead. Although we'd need to differentiate between 403 errors and other errors.
Bug 1776069 correctly targets 4.4. Manually adding the valid bug label since the bot is broken. |
/retest |
/bugzilla refresh |
@eparis: This pull request references Bugzilla bug 1776069, which is valid. The bug has been updated to refer to the pull request using the external bug tracker. In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
@spadget I've updated the PR with additional commit thats handling with the secret request errors. If any error occurs will display it in the If the use will try to copy the webhook error modal will be shown with a generic msg(or maybe just disable the link button?):
Here we can just check the |
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.
Thanks @jhadvig. The nice thing about this approach is we can now show a warning when a webhook secret doesn't exist 👍
(error) => { | ||
errors = _.concat(errors, error.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.
(error) => { | |
errors = _.concat(errors, error.message); | |
({message = `Could not load secret ${webhookName}.`}) => { | |
errors = [...errors, 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.
Would rather keep the error message, since it could differ
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.
Would rather keep the error message, since it could differ
We are keeping the error message, just using es6 syntax instead of _.concat
|
||
React.useEffect(() => { | ||
if (canGetSecret) { | ||
let errors = []; |
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.
let errors = []; | |
let errors: string[] = []; |
const [secretErrors, setSecretErrors] = React.useState<string[]>([]); | ||
const [isLoaded, setIsLoaded] = React.useState(false); | ||
|
||
const webhooks: WebhookTrigger[] = _.filter(triggers, (trigger) => |
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: you can use es6 syntactic sugar
const webhooks: WebhookTrigger[] = _.filter(triggers, (trigger) => | |
const webhooks: WebhookTrigger[] = _.filter(triggers, ({type}) => | |
webhookTriggers.has(type), | |
); |
const webhooks = _.filter(triggers, (trigger) => webhookTriggers.has(trigger.type)); | ||
const [webhookSecrets, setWebhookSecrets] = React.useState<K8sResourceKind[]>([]); | ||
const [secretErrors, setSecretErrors] = React.useState<string[]>([]); | ||
const [isLoaded, setIsLoaded] = React.useState(false); |
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.
const [isLoaded, setIsLoaded] = React.useState(false); | |
const [isLoaded, setLoaded] = React.useState(false); |
); | ||
if (!webhookSecret) { | ||
errorModal({ | ||
error: `Could not get ${secretName} secret`, |
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.
Instead of showing an error, I would just remove the copy link when the secret is missing. We know it won't work.
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 might want to also show the secret name as plain text instead of a link if an error occurred fetching it. Most likely it doesn't exist and will be a broken link. Checking for a 404 status code would tell us for sure.
); | ||
|
||
React.useEffect(() => { | ||
if (canGetSecret) { |
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 suggest an early return here.
if (!canGetSecret) {
return;
}
@spadgett PR updated. Regarding the wording on the error I would rather display the error message to the user. PTAL |
/retest |
const webhookNames: string[] = webhooks.map( | ||
(webhook: WebhookTrigger): string => { | ||
const triggerProperty = getTriggerProperty(webhook); | ||
return _.get(webhook, [triggerProperty, 'secretReference', 'name']); |
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.
Won't this try to fetch secrets for webhooks that don't have a secret reference? You should probably use reduce
to skip webhooks without a secret reference. Consider _.uniq
in case multiple webhooks reference the same secret.
I'd also call the var secretNames
to make it more clear it's the name of the secret itself.
const secretNames: Set<string> = _.uniq(webhooks.reduce((acc: string[], webhook: WebhookTrigger): string[] => {
const triggerProperty = getTriggerProperty(webhook);
const name = _.get(webhook, [triggerProperty, 'secretReference', 'name']);
return name ? [...acc, name] : acc;
}, []));
<ExpandableAlert | ||
variant={AlertVariant.warning} | ||
alerts={_.map(secretErrors, (error, i) => ( | ||
<React.Fragment key={i}>{error}</React.Fragment> |
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.
Should this be a div
so each alert is on its own line?
<React.Fragment key={i}>{error}</React.Fragment> | |
<div className="co-pre-line" key={i}>{error}</div> |
@spadgett PR updated. |
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.
/approve
/lgtm
/retest |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: jhadvig, spadgett The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
/retest Please review the full test history for this PR and help us cut down flakes. |
1 similar comment
/retest Please review the full test history for this PR and help us cut down flakes. |
@jhadvig: All pull requests linked via external trackers have merged. Bugzilla bug 1776069 has been moved to the MODIFIED state. In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
Now we will fetch all the webhook secrets the loading the component.
Solves the clipboard issue in Firefox.
/assign @spadgett