codeant-ai-for-open-source[bot] commented on code in PR #37906:
URL: https://github.com/apache/superset/pull/37906#discussion_r2799108062


##########
superset-frontend/src/dashboard/components/PropertiesModal/index.tsx:
##########
@@ -240,10 +242,15 @@ const PropertiesModal = ({
     }
   };
 
-  const handleOnChangeOwners = (owners: { value: number; label: string }[]) => 
{
-    const parsedOwners: Owners = ensureIsArray(owners).map(o => ({
+  const handleOnChangeOwners = (
+    owners: { value: number; label: string }[],
+    options: Record<string, unknown>[],
+  ) => {
+    const parsedOwners: Owners = ensureIsArray(owners).map((o, i) => ({
       id: o.value,
-      full_name: o.label,
+      full_name:
+        (options?.[i]?.[OWNER_TEXT_LABEL_PROP] as string) ||
+        (typeof o.label === 'string' ? o.label : ''),
     }));

Review Comment:
   **Suggestion:** When dashboard owners are changed, the updated owners stored 
in state only retain the full name and drop the email/username, so subsequent 
renders of the owners selector lose the secondary username line for those 
owners; the handler should also persist the email from the AsyncSelect options 
into the `owners` state. [logic error]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ⚠️ Owners selector loses username subtitle after editing owners.
   - ⚠️ Harder to distinguish owners with identical names. 
   ```
   </details>
   
   ```suggestion
   import {
     OWNER_TEXT_LABEL_PROP,
     OWNER_EMAIL_PROP,
   } from 'src/features/owners/OwnerSelectLabel';
   import { fetchTags, OBJECT_TYPES } from 'src/features/tags/tags';
   import {
     applyColors,
     getColorNamespace,
     getFreshLabelsColorMapEntries,
   } from 'src/utils/colorScheme';
   import { useDispatch } from 'react-redux';
   import {
     setColorScheme,
     setDashboardMetadata,
   } from 'src/dashboard/actions/dashboardState';
   import { areObjectsEqual } from 'src/reduxUtils';
   import { StandardModal, useModalValidation } from 'src/components/Modal';
   import {
     BasicInfoSection,
     AccessSection,
     StylingSection,
     RefreshSection,
     CertificationSection,
     AdvancedSection,
   } from './sections';
   
   type PropertiesModalProps = {
     dashboardId: number;
     dashboardTitle?: string;
     dashboardInfo?: Record<string, any>;
     show?: boolean;
     onHide?: () => void;
     colorScheme?: string;
     onSubmit?: (params: Record<string, any>) => void;
     addSuccessToast: (message: string) => void;
     addDangerToast: (message: string) => void;
     onlyApply?: boolean;
   };
   
   type Roles = { id: number; name: string }[];
   type Owners = {
     id: number;
     full_name?: string;
     first_name?: string;
     last_name?: string;
     email?: string;
   }[];
   type DashboardInfo = {
     id: number;
     title: string;
     slug: string;
     certifiedBy: string;
     certificationDetails: string;
     isManagedExternally: boolean;
     metadata: Record<string, any>;
     common?: {
       conf?: {
         SUPERSET_DASHBOARD_PERIODICAL_REFRESH_LIMIT?: number;
       };
     };
   };
   
   const PropertiesModal = ({
     addSuccessToast,
     addDangerToast,
     colorScheme: currentColorScheme,
     dashboardId,
     dashboardInfo: currentDashboardInfo,
     dashboardTitle,
     onHide = () => {},
     onlyApply = false,
     onSubmit = () => {},
     show = false,
   }: PropertiesModalProps) => {
     const dispatch = useDispatch();
     const [form] = Form.useForm();
   
     const [isLoading, setIsLoading] = useState(true);
     const [isApplying, setIsApplying] = useState(false);
     const [colorScheme, setCurrentColorScheme] = useState(currentColorScheme);
     const [jsonMetadata, setJsonMetadata] = useState('');
     const [dashboardInfo, setDashboardInfo] = useState<DashboardInfo>();
   
     // JSON validation for metadata
     const jsonAnnotations = useJsonValidation(jsonMetadata, {
       errorPrefix: 'Invalid JSON metadata',
     });
     const [owners, setOwners] = useState<Owners>([]);
     const [roles, setRoles] = useState<Roles>([]);
     const saveLabel = onlyApply ? t('Apply') : t('Save');
     const [tags, setTags] = useState<TagType[]>([]);
     const [customCss, setCustomCss] = useState('');
     const [refreshFrequency, setRefreshFrequency] = useState(0);
     const [selectedThemeId, setSelectedThemeId] = useState<number | 
null>(null);
     const [showChartTimestamps, setShowChartTimestamps] = useState(false);
     const [themes, setThemes] = useState<
       Array<{
         id: number;
         theme_name: string;
       }>
     >([]);
     const categoricalSchemeRegistry = getCategoricalSchemeRegistry();
     const originalDashboardMetadata = useRef<Record<string, any>>({});
   
     const handleErrorResponse = async (response: Response) => {
       const { error, statusText, message } = await 
getClientErrorObject(response);
       let errorText = error || statusText || t('An error has occurred');
       if (
         typeof message === 'object' &&
         'json_metadata' in message &&
         typeof (message as { json_metadata: unknown }).json_metadata === 
'string'
       ) {
         errorText = (message as { json_metadata: string }).json_metadata;
       } else if (typeof message === 'string') {
         errorText = message;
   
         if (message === 'Forbidden') {
           errorText = t('You do not have permission to edit this dashboard');
         }
       }
   
       addDangerToast(String(errorText));
     };
   
     const handleDashboardData = useCallback(
       dashboardData => {
         const {
           id,
           dashboard_title,
           slug,
           certified_by,
           certification_details,
           owners,
           roles,
           metadata,
           is_managed_externally,
           theme,
           css,
         } = dashboardData;
         const dashboardInfo = {
           id,
           title: dashboard_title,
           slug: slug || '',
           certifiedBy: certified_by || '',
           certificationDetails: certification_details || '',
           isManagedExternally: is_managed_externally || false,
           css: css || '',
           metadata,
         };
   
         form.setFieldsValue(dashboardInfo);
         setDashboardInfo(dashboardInfo);
         setOwners(owners);
         setRoles(roles);
         setCustomCss(css || '');
         setCurrentColorScheme(metadata?.color_scheme);
         setSelectedThemeId(theme?.id || null);
   
         const metaDataCopy = omit(metadata, [
           'positions',
           'shared_label_colors',
           'map_label_colors',
           'color_scheme_domain',
           'show_chart_timestamps',
         ]);
   
         setJsonMetadata(metaDataCopy ? jsonStringify(metaDataCopy) : '');
         setRefreshFrequency(metadata?.refresh_frequency || 0);
         setShowChartTimestamps(metadata?.show_chart_timestamps ?? false);
         originalDashboardMetadata.current = metadata;
       },
       [form],
     );
   
     const fetchDashboardDetails = useCallback(() => {
       // We fetch the dashboard details because not all code
       // that renders this component have all the values we need.
       // At some point when we have a more consistent frontend
       // datamodel, the dashboard could probably just be passed as a prop.
       SupersetClient.get({
         endpoint: `/api/v1/dashboard/${dashboardId}`,
       }).then(response => {
         const dashboard = response.json.result;
         const jsonMetadataObj = dashboard.json_metadata?.length
           ? JSON.parse(dashboard.json_metadata)
           : {};
   
         handleDashboardData({
           ...dashboard,
           metadata: jsonMetadataObj,
         });
   
         setIsLoading(false);
       }, handleErrorResponse);
     }, [dashboardId, handleDashboardData]);
   
     const getJsonMetadata = () => {
       try {
         const jsonMetadataObj = jsonMetadata?.length
           ? JSON.parse(jsonMetadata)
           : {};
         return jsonMetadataObj;
       } catch (_) {
         return {};
       }
     };
   
     const handleOnChangeOwners = (
       owners: { value: number; label: string }[],
       options: Record<string, unknown>[],
     ) => {
       const parsedOwners: Owners = ensureIsArray(owners).map((o, i) => {
         const fullName =
           (options?.[i]?.[OWNER_TEXT_LABEL_PROP] as string) ||
           (typeof o.label === 'string' ? o.label : '');
         const email =
           (options?.[i]?.[OWNER_EMAIL_PROP] as string | undefined) || 
undefined;
   
         return {
           id: o.value,
           full_name: fullName,
           email,
         };
       });
   ```
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Open a dashboard and click "Edit dashboard properties" to open 
`PropertiesModal`
   (`superset-frontend/src/dashboard/components/PropertiesModal/index.tsx`), 
which fetches
   data from `/api/v1/dashboard/<id>` and calls `handleDashboardData` around 
lines 88–135,
   setting `owners` state via `setOwners(owners)` with owner objects that 
include `email`.
   
   2. In the modal's "Access & ownership" section rendered by `AccessSection` 
(passed
   `owners` and `onChangeOwners` at the bottom of `index.tsx`), modify the 
owners list (e.g.,
   add or remove an owner) so the owners AsyncSelect triggers the 
`onChangeOwners` callback.
   
   3. The callback `handleOnChangeOwners` at lines ~232–255 receives `(owners, 
options)` and
   maps each selection to `{ id, full_name }`, explicitly omitting the `email` 
field defined
   in the `Owners` type, then calls `setOwners(parsedOwners)`, replacing 
previously
   email-rich owner objects with ones containing only `id` and `full_name`.
   
   4. After this state update, React re-renders `AccessSection` with the 
updated `owners`
   prop that now lacks `email`, so any UI in the owners selector (using 
`OwnerSelectLabel`
   from `src/features/owners/OwnerSelectLabel`) that relies on `owner.email` or 
associated
   option metadata to render the secondary username line no longer has that 
data, and the
   username/secondary text disappears for the modified owners until the modal 
is closed and
   reopened (which reloads full owner data via `handleDashboardData`).
   ```
   </details>
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** 
superset-frontend/src/dashboard/components/PropertiesModal/index.tsx
   **Line:** 41:254
   **Comment:**
        *Logic Error: When dashboard owners are changed, the updated owners 
stored in state only retain the full name and drop the email/username, so 
subsequent renders of the owners selector lose the secondary username line for 
those owners; the handler should also persist the email from the AsyncSelect 
options into the `owners` state.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F37906&comment_hash=be6e720b8acbd98ee108fe57cbdb663199e23fdabe219f536e941189671c596b&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F37906&comment_hash=be6e720b8acbd98ee108fe57cbdb663199e23fdabe219f536e941189671c596b&reaction=dislike'>👎</a>



##########
superset/charts/schemas.py:
##########
@@ -1671,6 +1671,7 @@ class UserSchema(Schema):
     id = fields.Int()
     first_name = fields.String()
     last_name = fields.String()
+    email = fields.String()

Review Comment:
   **Suggestion:** The schema adds an `email` field to the user instead of a 
`username` field, which contradicts the feature intent (showing username) and 
means the API will not provide the data the frontend needs to render usernames, 
while also unnecessarily exposing email addresses. [logic error]
   
   <details>
   <summary><b>Severity Level:</b> Critical 🚨</summary>
   
   ```mdx
   - ❌ Chart detail owners lack username required for new UI.
   - ❌ Email addresses exposed in owners API response.
   - ⚠️ Owner selectors cannot show username as secondary text.
   ```
   </details>
   
   ```suggestion
       username = fields.String()
   ```
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Start the Superset backend including `superset/charts/schemas.py` from 
this PR.
   
   2. Call the chart detail API `GET /api/v1/chart/<id>` which uses 
`ChartGetResponseSchema`
   with `owners = fields.List(fields.Nested(UserSchema))` defined in
   `superset/charts/schemas.py`.
   
   3. Inspect the JSON `owners` array in the response: each owner object 
contains `id`,
   `first_name`, `last_name`, and `email` (from `UserSchema` at
   `superset/charts/schemas.py:1670-1674`), but no `username` field.
   
   4. Open any owner selector (e.g., Chart Properties → Owners) where the UI 
feature is
   specified to show usernames as secondary text; the API does not provide a 
`username`
   field, so the frontend cannot render usernames and instead only has `email`, 
unnecessarily
   exposing email addresses and failing the stated username-based requirement.
   ```
   </details>
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** superset/charts/schemas.py
   **Line:** 1674:1674
   **Comment:**
        *Logic Error: The schema adds an `email` field to the user instead of a 
`username` field, which contradicts the feature intent (showing username) and 
means the API will not provide the data the frontend needs to render usernames, 
while also unnecessarily exposing email addresses.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F37906&comment_hash=a1d7d44cd1d0a304a4c207fb8d13c145d474d0a581e428251fc889401c198b09&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F37906&comment_hash=a1d7d44cd1d0a304a4c207fb8d13c145d474d0a581e428251fc889401c198b09&reaction=dislike'>👎</a>



##########
superset-frontend/src/features/alerts/AlertReportModal.tsx:
##########
@@ -1936,12 +1956,21 @@ const AlertReportModal: 
FunctionComponent<AlertReportModalProps> = ({
               label: (resource.database as DatabaseObject).database_name,
             }
           : undefined,
-        owners: (alert?.owners || []).map(owner => ({
-          value: (owner as MetaObject).value || owner.id,
-          label:
+        owners: (alert?.owners || []).map(owner => {
+          const ownerName =
             (owner as MetaObject).label ||
-            `${(owner as Owner).first_name} ${(owner as Owner).last_name}`,
-        })),
+            `${(owner as Owner).first_name} ${(owner as Owner).last_name}`;
+          return {

Review Comment:
   **Suggestion:** When populating the owners field for an existing alert, the 
code reads from the `alert` prop instead of the freshly fetched `resource`, so 
if the prop does not include owners (or is stale), the modal will show no 
owners and saving will silently drop existing owners for that alert; using 
`resource.owners` ensures the owners list reflects the current server state. 
[logic error]
   
   <details>
   <summary><b>Severity Level:</b> Critical 🚨</summary>
   
   ```mdx
   - ❌ Editing alerts can silently remove all existing owners.
   - ⚠️ Owners field appears empty despite backend having owners.
   - ⚠️ Alert ownership metadata becomes inconsistent with server state.
   ```
   </details>
   
   ```suggestion
           owners: (resource.owners || []).map(owner => {
             const ownerName =
               (owner as MetaObject).label ||
               `${(owner as Owner).first_name} ${(owner as Owner).last_name}`;
             return {
               value: (owner as MetaObject).value || (owner as Owner).id,
   ```
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Open an existing alert/report for editing so `AlertReportModal` mounts 
with a non-null
   `alert` prop containing at least `id` (component `AlertReportModal` in
   `superset-frontend/src/features/alerts/AlertReportModal.tsx`).
   
   2. `useSingleViewResource<AlertObject>('report', ...)` inside 
`AlertReportModal` fetches
   the full alert from `/api/v1/report/<id>` and populates `resource` with the 
canonical
   server state, including `resource.owners` (see hook usage around the top of
   `AlertReportModal`).
   
   3. When `resource` is set, the `useEffect` that depends on `resource` runs 
and calls
   `setCurrentAlert({...resource, owners: (alert?.owners || []).map(...) })` at 
lines
   1946–1973; because this uses `alert?.owners` instead of `resource.owners`, 
if the `alert`
   prop has an empty/missing `owners` array (for example, a lightweight list 
row object),
   `currentAlert.owners` becomes an empty array even though `resource.owners` 
is populated on
   the server.
   
   4. The user clicks "Save" in the modal, which calls `onSave` (same file) and 
serializes
   `owners: (currentAlert?.owners || []).map(owner => (owner as 
MetaObject).value ||
   owner.id)` into the update payload; because `currentAlert.owners` is empty, 
the request
   sent to `/api/v1/report/<id>` removes all owners from the alert, silently 
dropping
   existing owners.
   ```
   </details>
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** superset-frontend/src/features/alerts/AlertReportModal.tsx
   **Line:** 1959:1963
   **Comment:**
        *Logic Error: When populating the owners field for an existing alert, 
the code reads from the `alert` prop instead of the freshly fetched `resource`, 
so if the prop does not include owners (or is stale), the modal will show no 
owners and saving will silently drop existing owners for that alert; using 
`resource.owners` ensures the owners list reflects the current server state.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F37906&comment_hash=36e5246c2a17720e42a6d781803753c92fa086390b92e4da48379ab8918351cc&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F37906&comment_hash=36e5246c2a17720e42a6d781803753c92fa086390b92e4da48379ab8918351cc&reaction=dislike'>👎</a>



##########
superset/reports/api.py:
##########
@@ -152,6 +158,7 @@ def ensure_alert_reports_enabled(self) -> 
Optional[Response]:
         "owners.first_name",
         "owners.id",
         "owners.last_name",
+        "owners.email",

Review Comment:
   **Suggestion:** The report list API is exposing `owners.email` instead of 
`owners.username` in `list_columns`, so list views and owner selectors backed 
by this endpoint will surface email addresses instead of usernames, again 
diverging from the requirement to show usernames as the secondary text. [logic 
error]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ⚠️ Report list endpoint exposes owner email, not username.
   - ⚠️ Owner displays in lists diverge from username-based design.
   ```
   </details>
   
   ```suggestion
           "owners.username",
   ```
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Ensure there is at least one user whose `username` differs from `email`, 
and create
   several report schedules owned by that user.
   
   2. Call `GET /api/v1/report/` (the list endpoint for 
`ReportScheduleRestApi`, exposed via
   `resource_name = \"report\"` in `superset/reports/api.py`).
   
   3. The response items are populated from `list_columns` at
   `superset/reports/api.py:148–166`, which currently include `"owners.email"` 
but not
   `"owners.username"`.
   
   4. Inspect any element in the returned list: owner-related fields expose 
`email` instead
   of `username`, making it impossible for list-based consumers (e.g., report 
list views or
   owner selectors that reuse this payload) to show usernames as the secondary 
text as
   required by the PR description.
   ```
   </details>
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** superset/reports/api.py
   **Line:** 161:161
   **Comment:**
        *Logic Error: The report list API is exposing `owners.email` instead of 
`owners.username` in `list_columns`, so list views and owner selectors backed 
by this endpoint will surface email addresses instead of usernames, again 
diverging from the requirement to show usernames as the secondary text.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F37906&comment_hash=2523eaeb3ce407b7e90d5a216f8627c917380ad21e932130c4ccd96c72240f79&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F37906&comment_hash=2523eaeb3ce407b7e90d5a216f8627c917380ad21e932130c4ccd96c72240f79&reaction=dislike'>👎</a>



##########
superset/reports/api.py:
##########
@@ -113,6 +118,7 @@ def ensure_alert_reports_enabled(self) -> 
Optional[Response]:
         "owners.first_name",
         "owners.id",
         "owners.last_name",
+        "owners.email",
         "recipients.id",

Review Comment:
   **Suggestion:** The report detail API is exposing `owners.email` instead of 
`owners.username` in `show_columns`, which will cause the owner selector and 
detail views to show email addresses rather than usernames, conflicting with 
the intended behavior and potentially confusing users in environments where 
usernames and emails differ. [logic error]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ⚠️ Report detail endpoint cannot supply usernames for owners.
   - ⚠️ Alert/Report modal cannot show usernames as secondary text.
   ```
   </details>
   
   ```suggestion
           "owners.username",
   ```
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Start Superset with this PR code deployed and create a user whose 
`username` differs
   from `email` (via the security/user management UI or API).
   
   2. Create a report schedule owned by that user via `POST /api/v1/report/` 
handled by
   `ReportScheduleRestApi.post` in `superset/reports/api.py` (around lines 
200–250).
   
   3. Fetch the report details with `GET /api/v1/report/<report_id>` (resource 
name is
   `"report"` in `ReportScheduleRestApi`, so FAB exposes `/api/v1/report/<pk>`).
   
   4. Inspect the JSON `result.owners` payload; it contains `first_name`, 
`last_name`, and
   `email` because `show_columns` at `superset/reports/api.py:118–124` includes
   `"owners.email"` but not `"owners.username"`.
   
   5. Any client (including the Alert/Report modal described in the PR) that 
needs to render
   the owner with "secondary text = username" must instead use the exposed 
`email`, so the UI
   will show email addresses where usernames were requested in the feature spec.
   ```
   </details>
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** superset/reports/api.py
   **Line:** 122:122
   **Comment:**
        *Logic Error: The report detail API is exposing `owners.email` instead 
of `owners.username` in `show_columns`, which will cause the owner selector and 
detail views to show email addresses rather than usernames, conflicting with 
the intended behavior and potentially confusing users in environments where 
usernames and emails differ.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F37906&comment_hash=1d0602a19e6036c2deda6ee6163ccb0617a3114e4fae3432d0f52ca846c6ca9d&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F37906&comment_hash=1d0602a19e6036c2deda6ee6163ccb0617a3114e4fae3432d0f52ca846c6ca9d&reaction=dislike'>👎</a>



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to