Skip to content
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

chore: add new endpoint for backfill #2601

Merged
merged 34 commits into from
Dec 7, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
be99c17
- Modal added for backfilling and disconnecting subscription
krazziekay Dec 5, 2023
150023e
- Fixing eslint in a test case
krazziekay Dec 5, 2023
4dd1eed
- WIP - backfill modal
krazziekay Dec 5, 2023
7377807
- WIP - backfill modal
krazziekay Dec 5, 2023
e5d872b
Merge branch 'main' of github.com:atlassian/github-for-jira into ARC-…
krazziekay Dec 5, 2023
9379076
Merge branch 'main' into ARC-adding-modals-for-backfill-page
krazziekay Dec 5, 2023
e940786
Merge branch 'main' of github.com:atlassian/github-for-jira into ARC-…
krazziekay Dec 5, 2023
54747ff
- WIP - backfill modal
krazziekay Dec 5, 2023
ef67e5a
Merge branch 'main' into ARC-adding-modals-for-backfill-page
krazziekay Dec 6, 2023
85c0ec9
chore: add new endpoint for backfill
kamaksheeAtl Dec 6, 2023
75bf2cd
Merge branch 'main' into ARC-2714-Kamakshee
kamaksheeAtl Dec 6, 2023
b8a0402
chore: add new endpoint for backfill
kamaksheeAtl Dec 6, 2023
d2b2ce1
chore: add new endpoint for backfill
kamaksheeAtl Dec 6, 2023
2a2fcac
chore: add test cases
kamaksheeAtl Dec 6, 2023
8675da7
chore: add test cases
kamaksheeAtl Dec 6, 2023
1ed4f9b
chore: PR comments
kamaksheeAtl Dec 6, 2023
d077876
chore: PR comments
kamaksheeAtl Dec 6, 2023
4da351c
chore: PR comments
kamaksheeAtl Dec 6, 2023
b12fe93
chore: PR comments
kamaksheeAtl Dec 6, 2023
2ea4d5d
chore: PR comments
kamaksheeAtl Dec 6, 2023
ae84f00
chore: PR comments
kamaksheeAtl Dec 6, 2023
0b4d49f
- Using the corrected datepicker
krazziekay Dec 7, 2023
e2bf47a
Merge branch 'ARC-adding-modals-for-backfill-page' into ARC-2714-Kama…
kamaksheeAtl Dec 7, 2023
3726cea
chore: merge main
kamaksheeAtl Dec 7, 2023
a4ea01a
chore: PR comment
kamaksheeAtl Dec 7, 2023
263b5dc
chore: revoke unnecessary changes
kamaksheeAtl Dec 7, 2023
1f6533f
chore: revoke unnecessary changes
kamaksheeAtl Dec 7, 2023
b772dad
Merge branch 'main' into ARC-2714-Kamakshee
kamaksheeAtl Dec 7, 2023
7888cd0
chore: revoke unnecessary changes
kamaksheeAtl Dec 7, 2023
f1a77b2
chore: revoke unnecessary changes
kamaksheeAtl Dec 7, 2023
f478afc
chore: revoke unnecessary changes
kamaksheeAtl Dec 7, 2023
c40b726
chore: revoke unnecessary changes
kamaksheeAtl Dec 7, 2023
93183ab
chore: revoke unnecessary changes
kamaksheeAtl Dec 7, 2023
2519132
chore: revoke unnecessary changes
kamaksheeAtl Dec 7, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion spa/src/api/subscriptions/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import { axiosRest } from "../axiosInstance";

export default {
getSubscriptions: () => axiosRest.get("/rest/subscriptions")
getSubscriptions: () => axiosRest.get("/rest/subscriptions"),
syncSubscriptions: (data: {
kamaksheeAtl marked this conversation as resolved.
Show resolved Hide resolved
installationId: number;
commitsFromDate: string;
source: string;
syncType: string;
}) => axiosRest.post(`/rest/app/cloud/sync`, data),
kamaksheeAtl marked this conversation as resolved.
Show resolved Hide resolved
};
10 changes: 10 additions & 0 deletions src/rest/rest-router.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Router } from "express";
import { JwtHandler } from "./middleware/jwt/jwt-handler";
import { body } from "express-validator";
import { OAuthRouter } from "./routes/oauth";
import { OAuthCallbackHandler, OrgsInstalledHandler, OrgsInstallRequestedHandler } from "./routes/github-callback";
import { GitHubOrgsRouter } from "./routes/github-orgs";
Expand All @@ -10,6 +11,7 @@ import { RestErrorHandler } from "./middleware/error";
import { JiraAdminEnforceMiddleware } from "./middleware/jira-admin/jira-admin-check";
import { AnalyticsProxyHandler } from "./routes/analytics-proxy";
import { SubscriptionsRouter } from "./routes/subscriptions";
import { SyncRouterHandler } from "./routes/sync";
import { DeferredRouter } from "./routes/deferred";

export const RestRouter = Router({ mergeParams: true });
Expand All @@ -27,6 +29,14 @@ RestRouter.use("/subscriptions", JwtHandler, JiraAdminEnforceMiddleware, Subscri
*/
RestRouter.use("/app/:cloudOrUUID", subRouter);

subRouter.post(
kamaksheeAtl marked this conversation as resolved.
Show resolved Hide resolved
"/sync",
body("commitsFromDate").optional().isISO8601(),
JwtHandler,
JiraAdminEnforceMiddleware,
SyncRouterHandler
);

subRouter.get("/github-callback", OAuthCallbackHandler);
subRouter.get("/github-installed", OrgsInstalledHandler);
subRouter.get("/github-requested", OrgsInstallRequestedHandler);
Expand Down
92 changes: 92 additions & 0 deletions src/rest/routes/sync/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { Request, Response, NextFunction } from "express";
import { ParamsDictionary } from "express-serve-static-core";
import { errorWrapper } from "../../helper";
import { Subscription } from "models/subscription";
import { booleanFlag, BooleanFlags } from "config/feature-flags";
import { findOrStartSync } from "~/src/sync/sync-utils";
import { determineSyncTypeAndTargetTasks } from "~/src/util/github-sync-helper";
import { BaseLocals } from "..";
import { InvalidArgumentError } from "~/src/config/errors";

interface RequestBody {
installationId: number;
appId: number;
kamaksheeAtl marked this conversation as resolved.
Show resolved Hide resolved
syncType: string;
source: string;
commitsFromDate: string;
}

const restSyncPost = async (
req: Request<ParamsDictionary, unknown, RequestBody>,
res: Response<unknown, BaseLocals>,
next: NextFunction
) => {
//TODO: We are yet to handle enterprise backfill
// const cloudOrUUID = req.params.cloudOrUUID;
// const gheUUID = cloudOrUUID === "cloud" ? undefined : "some-ghe-uuid";

const {
installationId: gitHubInstallationId,
appId: gitHubAppId,
syncType: syncTypeFromReq,
source
} = req.body;
// A date to start fetching commit history(main and branch) from.
const commitsFromDate = req.body.commitsFromDate
? new Date(req.body.commitsFromDate)
: undefined;

const logAdditionalData = await booleanFlag(
kamaksheeAtl marked this conversation as resolved.
Show resolved Hide resolved
BooleanFlags.VERBOSE_LOGGING,
res.locals.installation.jiraHost
);

logAdditionalData
? req.log.info(
{ gitHubInstallationId },
"verbose logging - Received sync request on rest route")
: req.log.info("Received sync request on rest route");

try {
const subscription = await Subscription.getSingleInstallation(
res.locals.installation.jiraHost,
gitHubInstallationId,
gitHubAppId
);
if (!subscription) {
req.log.info(
{
jiraHost: res.locals.installation.jiraHost,
installationId: gitHubInstallationId
},
"Subscription not found when retrying sync."
);
throw new InvalidArgumentError("Subscription not found, cannot resync.");
kamaksheeAtl marked this conversation as resolved.
Show resolved Hide resolved
}

if (commitsFromDate && commitsFromDate.valueOf() > Date.now()) {
throw new InvalidArgumentError(
"Invalid date value, cannot select a future date!"
);
}

const { syncType, targetTasks } = determineSyncTypeAndTargetTasks(
syncTypeFromReq,
subscription
);
await findOrStartSync(
subscription,
req.log,
syncType,
commitsFromDate || subscription.backfillSince,
targetTasks,
{ source }
);

res.sendStatus(202);
} catch (error: unknown) {
next(new Error("Unauthorized"));
kamaksheeAtl marked this conversation as resolved.
Show resolved Hide resolved
}
};

export const SyncRouterHandler = errorWrapper("AnalyticsProxyHandler",restSyncPost);
29 changes: 3 additions & 26 deletions src/routes/jira/sync/jira-sync-post.ts
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logic for restSyncPost and this endpoint is the same. Would be better to pull this common logic out into another method and reuse it in both places.
As for the analytics, can add an extra attribute spa: true | false.

Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { Subscription, SyncStatus } from "models/subscription";
import { Subscription } from "models/subscription";
import * as Sentry from "@sentry/node";
import { NextFunction, Request, Response } from "express";
import { findOrStartSync } from "~/src/sync/sync-utils";
import { sendAnalytics } from "utils/analytics-client";
import { AnalyticsEventTypes, AnalyticsTrackEventsEnum, AnalyticsTrackSource } from "interfaces/common";
import { TaskType, SyncType } from "~/src/sync/sync.types";
import { booleanFlag, BooleanFlags } from "config/feature-flags";
import { determineSyncTypeAndTargetTasks, getStartTimeInDaysAgo } from "../../../util/github-sync-helper";

export const JiraSyncPost = async (req: Request, res: Response, next: NextFunction): Promise<void> => {
const { installationId: gitHubInstallationId, appId: gitHubAppId, syncType: syncTypeFromReq, source } = req.body;
Expand Down Expand Up @@ -35,7 +35,7 @@ export const JiraSyncPost = async (req: Request, res: Response, next: NextFuncti
return;
}

const { syncType, targetTasks } = await determineSyncTypeAndTargetTasks(syncTypeFromReq, subscription);
const { syncType, targetTasks } = determineSyncTypeAndTargetTasks(syncTypeFromReq, subscription);
await findOrStartSync(subscription, req.log, syncType, commitsFromDate || subscription.backfillSince, targetTasks, { source });

await sendAnalytics(res.locals.jiraHost, AnalyticsEventTypes.TrackEvent, {
Expand Down Expand Up @@ -64,26 +64,3 @@ export const JiraSyncPost = async (req: Request, res: Response, next: NextFuncti
next(new Error("Unauthorized"));
}
};

const MILLISECONDS_IN_ONE_DAY = 24 * 60 * 60 * 1000;
const getStartTimeInDaysAgo = (commitsFromDate: Date | undefined) => {
if (commitsFromDate === undefined) return undefined;
return Math.floor((Date.now() - commitsFromDate?.getTime()) / MILLISECONDS_IN_ONE_DAY);
};

type SyncTypeAndTargetTasks = {
syncType: SyncType,
targetTasks: TaskType[] | undefined,
};

const determineSyncTypeAndTargetTasks = async (syncTypeFromReq: string, subscription: Subscription): Promise<SyncTypeAndTargetTasks> => {
if (syncTypeFromReq === "full") {
return { syncType: "full", targetTasks: undefined };
}

if (subscription.syncStatus === SyncStatus.FAILED) {
return { syncType: "full", targetTasks: undefined };
}

return { syncType: "partial", targetTasks: ["pull", "branch", "commit", "build", "deployment", "dependabotAlert", "secretScanningAlert", "codeScanningAlert"] };
};
26 changes: 26 additions & 0 deletions src/util/github-sync-helper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Subscription, SyncStatus } from "models/subscription";
import { TaskType, SyncType } from "~/src/sync/sync.types";


const MILLISECONDS_IN_ONE_DAY = 24 * 60 * 60 * 1000;
export const getStartTimeInDaysAgo = (commitsFromDate: Date | undefined) => {
if (commitsFromDate === undefined) return undefined;
return Math.floor((Date.now() - commitsFromDate.getTime()) / MILLISECONDS_IN_ONE_DAY);
};

type SyncTypeAndTargetTasks = {
syncType: SyncType,
targetTasks: TaskType[] | undefined,
};

export const determineSyncTypeAndTargetTasks = (syncTypeFromReq: string, subscription: Subscription): SyncTypeAndTargetTasks => {
if (syncTypeFromReq === "full") {
return { syncType: "full", targetTasks: undefined };
}

if (subscription.syncStatus === SyncStatus.FAILED) {
return { syncType: "full", targetTasks: undefined };
}

return { syncType: "partial", targetTasks: ["pull", "branch", "commit", "build", "deployment", "dependabotAlert", "secretScanningAlert", "codeScanningAlert"] };
};
2 changes: 2 additions & 0 deletions test/snapshots/app.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ exports[`app getFrontendApp please review routes and update snapshot when adding
query,expressInit,elapsedTimeMetrics,sentryRequestMiddleware,urlencodedParser,jsonParser,cookieParser,LogMiddleware,serveStatic
:GET ^/?(?=/|$)^/rest/?(?=/|$)^/subscriptions/?(?=/|$)^/?$
query,expressInit,elapsedTimeMetrics,sentryRequestMiddleware,urlencodedParser,jsonParser,cookieParser,LogMiddleware,JwtHandler,jiraAdminEnforceMiddleware,SubscriptionsGet
:POST ^/?(?=/|$)^/rest/?(?=/|$)^/app/(?:([^/]+?))/?(?=/|$)^/sync/?$
query,expressInit,elapsedTimeMetrics,sentryRequestMiddleware,urlencodedParser,jsonParser,cookieParser,LogMiddleware,middleware,JwtHandler,jiraAdminEnforceMiddleware,AnalyticsProxyHandler
:GET ^/?(?=/|$)^/rest/?(?=/|$)^/app/(?:([^/]+?))/?(?=/|$)^/github-callback/?$
query,expressInit,elapsedTimeMetrics,sentryRequestMiddleware,urlencodedParser,jsonParser,cookieParser,LogMiddleware,OAuthCallbackHandler
:GET ^/?(?=/|$)^/rest/?(?=/|$)^/app/(?:([^/]+?))/?(?=/|$)^/github-installed/?$
Expand Down
Loading