Merge pull request #34124 from appsmithorg/release
10/06 Daily Promotion
This commit is contained in:
commit
f0b3147d9f
|
|
@ -30,10 +30,10 @@ COPY ./app/client/build editor/
|
||||||
# Add RTS - Application Layer
|
# Add RTS - Application Layer
|
||||||
COPY ./app/client/packages/rts/dist rts/
|
COPY ./app/client/packages/rts/dist rts/
|
||||||
|
|
||||||
ENV PATH /opt/appsmith/utils/node_modules/.bin:/opt/java/bin:/opt/node/bin:$PATH
|
ENV PATH /opt/bin:/opt/appsmith/utils/node_modules/.bin:/opt/java/bin:/opt/node/bin:$PATH
|
||||||
|
|
||||||
RUN cd ./utils && npm install --only=prod && npm install --only=prod -g . && cd - \
|
RUN cd ./utils && npm install --only=prod && npm install --only=prod -g . && cd - \
|
||||||
&& chmod +x *.sh /watchtower-hooks/*.sh \
|
&& chmod +x /opt/bin/* *.sh /watchtower-hooks/*.sh \
|
||||||
# Disable setuid/setgid bits for the files inside container.
|
# Disable setuid/setgid bits for the files inside container.
|
||||||
&& find / \( -path /proc -prune \) -o \( \( -perm -2000 -o -perm -4000 \) -print -exec chmod -s '{}' + \) || true \
|
&& find / \( -path /proc -prune \) -o \( \( -perm -2000 -o -perm -4000 \) -print -exec chmod -s '{}' + \) || true \
|
||||||
&& mkdir -p /.mongodb/mongosh /appsmith-stacks \
|
&& mkdir -p /.mongodb/mongosh /appsmith-stacks \
|
||||||
|
|
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
import { WIDGET } from "../../../../locators/WidgetLocators";
|
|
||||||
import { ObjectsRegistry } from "../../../../support/Objects/Registry";
|
|
||||||
import EditorNavigation, {
|
|
||||||
EntityType,
|
|
||||||
} from "../../../../support/Pages/EditorNavigation";
|
|
||||||
import PageList from "../../../../support/Pages/PageList";
|
|
||||||
|
|
||||||
const { CommonLocators: locators, EntityExplorer: ee } = ObjectsRegistry;
|
|
||||||
|
|
||||||
describe("Empty canvas ctas", () => {
|
|
||||||
it("1. Ctas validations", () => {
|
|
||||||
cy.wait(3000); // for page to load, failing in CI
|
|
||||||
//Ctas should not be shown in the second page
|
|
||||||
cy.get(locators._emptyCanvasCta).should("be.visible");
|
|
||||||
PageList.AddNewPage();
|
|
||||||
cy.get(locators._emptyCanvasCta).should("not.exist");
|
|
||||||
EditorNavigation.SelectEntityByName("Page1", EntityType.Page);
|
|
||||||
|
|
||||||
//Ctas should continue to show on refresh
|
|
||||||
cy.get(locators._emptyCanvasCta).should("be.visible");
|
|
||||||
cy.reload();
|
|
||||||
cy.get(locators._emptyCanvasCta).should("be.visible");
|
|
||||||
|
|
||||||
//Hide cta on adding a widget
|
|
||||||
cy.get(locators._emptyCanvasCta).should("be.visible");
|
|
||||||
ee.DragDropWidgetNVerify(WIDGET.BUTTON, 200, 200);
|
|
||||||
cy.get(locators._emptyCanvasCta).should("not.exist");
|
|
||||||
PageList.AddNewPage();
|
|
||||||
cy.get(locators._emptyCanvasCta).should("not.exist");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import homePage from "../../../../locators/HomePage";
|
import homePage from "../../../../locators/HomePage";
|
||||||
import * as _ from "../../../../support/Objects/ObjectsCore";
|
import * as _ from "../../../../support/Objects/ObjectsCore";
|
||||||
|
import PageList from "../../../../support/Pages/PageList";
|
||||||
|
|
||||||
describe("Visual regression tests", { tags: ["@tag.Visual"] }, () => {
|
describe("Visual regression tests", { tags: ["@tag.Visual"] }, () => {
|
||||||
// for any changes in UI, update the screenshot in snapshot folder, to do so:
|
// for any changes in UI, update the screenshot in snapshot folder, to do so:
|
||||||
|
|
@ -18,7 +19,7 @@ describe("Visual regression tests", { tags: ["@tag.Visual"] }, () => {
|
||||||
cy.get("#root").matchImageSnapshot("apppage");
|
cy.get("#root").matchImageSnapshot("apppage");
|
||||||
|
|
||||||
//Layout validation for Quick page wizard
|
//Layout validation for Quick page wizard
|
||||||
cy.get("[data-testid='generate-app']").click();
|
PageList.AddNewPage(Cypress.env("MESSAGES").GENERATE_PAGE_ACTION_TITLE());
|
||||||
cy.wait(2000);
|
cy.wait(2000);
|
||||||
// taking screenshot of generate crud page
|
// taking screenshot of generate crud page
|
||||||
cy.get("#root").matchImageSnapshot("quickPageWizard");
|
cy.get("#root").matchImageSnapshot("quickPageWizard");
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
{
|
{
|
||||||
"generateCRUDPageActionCard": "[data-testid='generate-app']",
|
|
||||||
"selectDatasourceDropdown": "[data-testid=t--datasource-dropdown]",
|
"selectDatasourceDropdown": "[data-testid=t--datasource-dropdown]",
|
||||||
"datasourceDropdownOption": "[data-testid=t--datasource-dropdown-option]",
|
"datasourceDropdownOption": "[data-testid=t--datasource-dropdown-option]",
|
||||||
"selectTableDropdown": "[data-testid=t--table-dropdown]",
|
"selectTableDropdown": "[data-testid=t--table-dropdown]",
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,6 @@ export class HomePage {
|
||||||
_applicationName = ".t--application-name";
|
_applicationName = ".t--application-name";
|
||||||
private _editAppName = "bp3-editable-text-editing";
|
private _editAppName = "bp3-editable-text-editing";
|
||||||
private _appMenu = ".ads-v2-menu__menu-item-children";
|
private _appMenu = ".ads-v2-menu__menu-item-children";
|
||||||
_buildFromDataTableActionCard = "[data-testid='generate-app']";
|
|
||||||
private _selectRole = "//span[text()='Select a role']/ancestor::div";
|
private _selectRole = "//span[text()='Select a role']/ancestor::div";
|
||||||
private _searchInput = "input[type='text']";
|
private _searchInput = "input[type='text']";
|
||||||
_appHoverIcon = (action: string) => ".t--application-" + action + "-link";
|
_appHoverIcon = (action: string) => ".t--application-" + action + "-link";
|
||||||
|
|
|
||||||
|
|
@ -37,9 +37,7 @@ export class Table {
|
||||||
private assertHelper = ObjectsRegistry.AssertHelper;
|
private assertHelper = ObjectsRegistry.AssertHelper;
|
||||||
|
|
||||||
private _tableWrap = "//div[contains(@class,'tableWrap')]";
|
private _tableWrap = "//div[contains(@class,'tableWrap')]";
|
||||||
private _tableHeader =
|
private _tableHeader = ".thead div[role=columnheader]";
|
||||||
this._tableWrap +
|
|
||||||
"//div[contains(@class,'thead')]//div[contains(@class,'tr')][1]";
|
|
||||||
private _columnHeader = (columnName: string) =>
|
private _columnHeader = (columnName: string) =>
|
||||||
this._tableWrap +
|
this._tableWrap +
|
||||||
"//div[contains(@class,'thead')]//div[contains(@class,'tr')][1]//div[@role='columnheader']//div[contains(text(),'" +
|
"//div[contains(@class,'thead')]//div[contains(@class,'tr')][1]//div[@role='columnheader']//div[contains(text(),'" +
|
||||||
|
|
@ -258,7 +256,7 @@ export class Table {
|
||||||
}
|
}
|
||||||
|
|
||||||
public AssertTableHeaderOrder(expectedOrder: string) {
|
public AssertTableHeaderOrder(expectedOrder: string) {
|
||||||
cy.xpath(this._tableHeader)
|
cy.get(this._tableHeader)
|
||||||
.invoke("text")
|
.invoke("text")
|
||||||
.then((x) => {
|
.then((x) => {
|
||||||
expect(x).to.eq(expectedOrder);
|
expect(x).to.eq(expectedOrder);
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@ export function Link(props: LinkProps) {
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Text color="accent" {...rest}>
|
|
||||||
<HeadlessLink
|
<HeadlessLink
|
||||||
className={styles.link}
|
className={styles.link}
|
||||||
download={download}
|
download={download}
|
||||||
|
|
@ -28,8 +27,9 @@ export function Link(props: LinkProps) {
|
||||||
rel={rel}
|
rel={rel}
|
||||||
target={target}
|
target={target}
|
||||||
>
|
>
|
||||||
|
<Text color="accent" {...rest}>
|
||||||
{children}
|
{children}
|
||||||
</HeadlessLink>
|
|
||||||
</Text>
|
</Text>
|
||||||
|
</HeadlessLink>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,19 @@
|
||||||
.link {
|
.link {
|
||||||
|
position: relative;
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
text-decoration-color: currentColor;
|
|
||||||
text-underline-offset: 2px;
|
text-underline-offset: 2px;
|
||||||
color: currentColor;
|
color: currentColor;
|
||||||
|
text-decoration-color: var(--color-bd-accent);
|
||||||
|
text-decoration-thickness: 0.5px;
|
||||||
|
|
||||||
&:hover {
|
&[data-hovered] {
|
||||||
color: currentColor;
|
text-decoration: none;
|
||||||
text-decoration-color: currentColor;
|
}
|
||||||
|
|
||||||
|
&[data-focus-visible] {
|
||||||
|
border-radius: var(--border-radius-elevation-3);
|
||||||
|
outline: 2px solid var(--color-bd-focus);
|
||||||
|
outline-offset: 4px;
|
||||||
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,9 @@ import { matchBuilderPath, matchViewerPath } from "constants/routes";
|
||||||
|
|
||||||
const GENERATOR_TRACE = "generator-tracer";
|
const GENERATOR_TRACE = "generator-tracer";
|
||||||
|
|
||||||
|
export type OtlpSpan = Span;
|
||||||
|
export type SpanAttributes = Attributes;
|
||||||
|
|
||||||
const getCommonTelemetryAttributes = () => {
|
const getCommonTelemetryAttributes = () => {
|
||||||
const pathname = window.location.pathname;
|
const pathname = window.location.pathname;
|
||||||
const isEditorUrl = matchBuilderPath(pathname);
|
const isEditorUrl = matchBuilderPath(pathname);
|
||||||
|
|
@ -33,16 +36,13 @@ const getCommonTelemetryAttributes = () => {
|
||||||
|
|
||||||
export function startRootSpan(
|
export function startRootSpan(
|
||||||
spanName: string,
|
spanName: string,
|
||||||
spanAttributes: Attributes = {},
|
spanAttributes: SpanAttributes = {},
|
||||||
startTime?: TimeInput,
|
startTime?: TimeInput,
|
||||||
) {
|
) {
|
||||||
const tracer = trace.getTracer(GENERATOR_TRACE);
|
const tracer = trace.getTracer(GENERATOR_TRACE);
|
||||||
if (!spanName) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const commonAttributes = getCommonTelemetryAttributes();
|
const commonAttributes = getCommonTelemetryAttributes();
|
||||||
|
|
||||||
return tracer?.startSpan(spanName, {
|
return tracer.startSpan(spanName, {
|
||||||
kind: SpanKind.CLIENT,
|
kind: SpanKind.CLIENT,
|
||||||
attributes: {
|
attributes: {
|
||||||
...commonAttributes,
|
...commonAttributes,
|
||||||
|
|
@ -56,15 +56,10 @@ export const generateContext = (span: Span) => {
|
||||||
};
|
};
|
||||||
export function startNestedSpan(
|
export function startNestedSpan(
|
||||||
spanName: string,
|
spanName: string,
|
||||||
parentSpan?: Span,
|
parentSpan: Span,
|
||||||
spanAttributes: Attributes = {},
|
spanAttributes: SpanAttributes = {},
|
||||||
startTime?: TimeInput,
|
startTime?: TimeInput,
|
||||||
) {
|
) {
|
||||||
if (!spanName || !parentSpan) {
|
|
||||||
// do not generate nested span without parentSpan..we cannot generate context out of it
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const parentContext = generateContext(parentSpan);
|
const parentContext = generateContext(parentSpan);
|
||||||
|
|
||||||
const generatorTrace = trace.getTracer(GENERATOR_TRACE);
|
const generatorTrace = trace.getTracer(GENERATOR_TRACE);
|
||||||
|
|
@ -81,14 +76,14 @@ export function startNestedSpan(
|
||||||
return generatorTrace.startSpan(spanName, spanOptions, parentContext);
|
return generatorTrace.startSpan(spanName, spanOptions, parentContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function endSpan(span?: Span) {
|
export function endSpan(span: Span) {
|
||||||
span?.end();
|
span.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setAttributesToSpan(span: Span, spanAttributes: Attributes) {
|
export function setAttributesToSpan(
|
||||||
if (!span) {
|
span: Span,
|
||||||
return;
|
spanAttributes: SpanAttributes,
|
||||||
}
|
) {
|
||||||
span.setAttributes(spanAttributes);
|
span.setAttributes(spanAttributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -96,5 +91,3 @@ export function wrapFnWithParentTraceContext(parentSpan: Span, fn: () => any) {
|
||||||
const parentContext = trace.setSpan(context.active(), parentSpan);
|
const parentContext = trace.setSpan(context.active(), parentSpan);
|
||||||
return context.with(parentContext, fn);
|
return context.with(parentContext, fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
export type OtlpSpan = Span;
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
|
import type { OtlpSpan, SpanAttributes } from "./generateTraces";
|
||||||
import { startNestedSpan } from "./generateTraces";
|
import { startNestedSpan } from "./generateTraces";
|
||||||
import type { TimeInput, Attributes, Span } from "@opentelemetry/api";
|
import type { TimeInput } from "@opentelemetry/api";
|
||||||
|
|
||||||
export interface WebworkerSpanData {
|
export interface WebworkerSpanData {
|
||||||
attributes: Attributes;
|
attributes: SpanAttributes;
|
||||||
spanName: string;
|
spanName: string;
|
||||||
startTime: TimeInput;
|
startTime: TimeInput;
|
||||||
endTime: TimeInput;
|
endTime: TimeInput;
|
||||||
|
|
@ -13,7 +14,7 @@ export interface WebworkerSpanData {
|
||||||
//to regular otlp telemetry data and subsequently exported to our telemetry collector
|
//to regular otlp telemetry data and subsequently exported to our telemetry collector
|
||||||
export const newWebWorkerSpanData = (
|
export const newWebWorkerSpanData = (
|
||||||
spanName: string,
|
spanName: string,
|
||||||
attributes: Attributes,
|
attributes: SpanAttributes,
|
||||||
): WebworkerSpanData => {
|
): WebworkerSpanData => {
|
||||||
return {
|
return {
|
||||||
attributes,
|
attributes,
|
||||||
|
|
@ -29,8 +30,8 @@ const addEndTimeForWebWorkerSpanData = (span: WebworkerSpanData) => {
|
||||||
|
|
||||||
export const profileFn = (
|
export const profileFn = (
|
||||||
spanName: string,
|
spanName: string,
|
||||||
attributes: Attributes = {},
|
attributes: SpanAttributes = {},
|
||||||
allSpans: Record<string, WebworkerSpanData>,
|
allSpans: Record<string, WebworkerSpanData | SpanAttributes>,
|
||||||
fn: (...args: any[]) => any,
|
fn: (...args: any[]) => any,
|
||||||
) => {
|
) => {
|
||||||
const span = newWebWorkerSpanData(spanName, attributes);
|
const span = newWebWorkerSpanData(spanName, attributes);
|
||||||
|
|
@ -42,7 +43,7 @@ export const profileFn = (
|
||||||
|
|
||||||
//convert webworker spans to OTLP spans
|
//convert webworker spans to OTLP spans
|
||||||
export const convertWebworkerSpansToRegularSpans = (
|
export const convertWebworkerSpansToRegularSpans = (
|
||||||
parentSpan: Span,
|
parentSpan: OtlpSpan,
|
||||||
allSpans: Record<string, WebworkerSpanData> = {},
|
allSpans: Record<string, WebworkerSpanData> = {},
|
||||||
) => {
|
) => {
|
||||||
Object.values(allSpans)
|
Object.values(allSpans)
|
||||||
|
|
@ -53,3 +54,14 @@ export const convertWebworkerSpansToRegularSpans = (
|
||||||
span?.end(endTime);
|
span?.end(endTime);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const filterSpanData = (
|
||||||
|
spanData: Record<string, WebworkerSpanData | SpanAttributes>,
|
||||||
|
): Record<string, WebworkerSpanData> => {
|
||||||
|
return Object.keys(spanData)
|
||||||
|
.filter((key) => !key.startsWith("__"))
|
||||||
|
.reduce<Record<string, WebworkerSpanData>>((obj, key) => {
|
||||||
|
obj[key] = spanData[key] as WebworkerSpanData;
|
||||||
|
return obj;
|
||||||
|
}, {});
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,10 @@ import {
|
||||||
ReduxActionErrorTypes,
|
ReduxActionErrorTypes,
|
||||||
ReduxActionTypes,
|
ReduxActionTypes,
|
||||||
} from "@appsmith/constants/ReduxActionConstants";
|
} from "@appsmith/constants/ReduxActionConstants";
|
||||||
import type { ConnectToGitPayload } from "api/GitSyncAPI";
|
import type {
|
||||||
|
ConnectToGitPayload,
|
||||||
|
GitAutocommitProgressResponse,
|
||||||
|
} from "api/GitSyncAPI";
|
||||||
import type { GitConfig, GitSyncModalTab, MergeStatus } from "entities/GitSync";
|
import type { GitConfig, GitSyncModalTab, MergeStatus } from "entities/GitSync";
|
||||||
import type { GitApplicationMetadata } from "@appsmith/api/ApplicationApi";
|
import type { GitApplicationMetadata } from "@appsmith/api/ApplicationApi";
|
||||||
import {
|
import {
|
||||||
|
|
@ -480,6 +483,7 @@ export const setShowBranchPopupAction = (show: boolean) => {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// START autocommit
|
||||||
export const toggleAutocommitEnabledInit = () => ({
|
export const toggleAutocommitEnabledInit = () => ({
|
||||||
type: ReduxActionTypes.GIT_TOGGLE_AUTOCOMMIT_ENABLED_INIT,
|
type: ReduxActionTypes.GIT_TOGGLE_AUTOCOMMIT_ENABLED_INIT,
|
||||||
});
|
});
|
||||||
|
|
@ -489,14 +493,60 @@ export const setIsAutocommitModalOpen = (isAutocommitModalOpen: boolean) => ({
|
||||||
payload: { isAutocommitModalOpen },
|
payload: { isAutocommitModalOpen },
|
||||||
});
|
});
|
||||||
|
|
||||||
export const startAutocommitProgressPolling = () => ({
|
export const triggerAutocommitInitAction = () => ({
|
||||||
type: ReduxActionTypes.GIT_AUTOCOMMIT_INITIATE_PROGRESS_POLLING,
|
type: ReduxActionTypes.GIT_AUTOCOMMIT_TRIGGER_INIT,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const stopAutocommitProgressPolling = () => ({
|
export const triggerAutocommitSuccessAction = () => ({
|
||||||
|
type: ReduxActionTypes.GIT_AUTOCOMMIT_TRIGGER_SUCCESS,
|
||||||
|
});
|
||||||
|
|
||||||
|
export interface TriggerAutocommitErrorActionPayload {
|
||||||
|
error: any;
|
||||||
|
show: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const triggerAutocommitErrorAction = (
|
||||||
|
payload: TriggerAutocommitErrorActionPayload,
|
||||||
|
) => ({
|
||||||
|
type: ReduxActionErrorTypes.GIT_AUTOCOMMIT_TRIGGER_ERROR,
|
||||||
|
payload,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const startAutocommitProgressPollingAction = () => ({
|
||||||
|
type: ReduxActionTypes.GIT_AUTOCOMMIT_START_PROGRESS_POLLING,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const stopAutocommitProgressPollingAction = () => ({
|
||||||
type: ReduxActionTypes.GIT_AUTOCOMMIT_STOP_PROGRESS_POLLING,
|
type: ReduxActionTypes.GIT_AUTOCOMMIT_STOP_PROGRESS_POLLING,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export type SetAutocommitActionPayload = GitAutocommitProgressResponse;
|
||||||
|
|
||||||
|
export const setAutocommitProgressAction = (
|
||||||
|
payload: SetAutocommitActionPayload,
|
||||||
|
) => ({
|
||||||
|
type: ReduxActionTypes.GIT_SET_AUTOCOMMIT_PROGRESS,
|
||||||
|
payload,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const resetAutocommitProgressAction = () => ({
|
||||||
|
type: ReduxActionTypes.GIT_RESET_AUTOCOMMIT_PROGRESS,
|
||||||
|
});
|
||||||
|
|
||||||
|
export interface AutocommitProgressErrorActionPayload {
|
||||||
|
error: any;
|
||||||
|
show: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const autoCommitProgressErrorAction = (
|
||||||
|
payload: AutocommitProgressErrorActionPayload,
|
||||||
|
) => ({
|
||||||
|
type: ReduxActionErrorTypes.GIT_AUTOCOMMIT_PROGRESS_POLLING_ERROR,
|
||||||
|
payload,
|
||||||
|
});
|
||||||
|
// END autocommit
|
||||||
|
|
||||||
export const getGitMetadataInitAction = () => ({
|
export const getGitMetadataInitAction = () => ({
|
||||||
type: ReduxActionTypes.GIT_GET_METADATA_INIT,
|
type: ReduxActionTypes.GIT_GET_METADATA_INIT,
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,27 @@ interface GitRemoteStatusParam {
|
||||||
branch: string;
|
branch: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum AutocommitResponseEnum {
|
||||||
|
IN_PROGRESS = "IN_PROGRESS",
|
||||||
|
LOCKED = "LOCKED",
|
||||||
|
PUBLISHED = "PUBLISHED",
|
||||||
|
IDLE = "IDLE",
|
||||||
|
NOT_REQUIRED = "NOT_REQUIRED",
|
||||||
|
NON_GIT_APP = "NON_GIT_APP",
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GitAutocommitProgressResponse {
|
||||||
|
autoCommitResponse: AutocommitResponseEnum;
|
||||||
|
progress: number;
|
||||||
|
branchName: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GitTriggerAutocommitResponse {
|
||||||
|
autoCommitResponse: AutocommitResponseEnum;
|
||||||
|
progress: number;
|
||||||
|
branchName: string;
|
||||||
|
}
|
||||||
|
|
||||||
class GitSyncAPI extends Api {
|
class GitSyncAPI extends Api {
|
||||||
static baseURL = `/v1/git`;
|
static baseURL = `/v1/git`;
|
||||||
|
|
||||||
|
|
@ -227,6 +248,12 @@ class GitSyncAPI extends Api {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async triggerAutocommit(applicationId: string, branchName: string) {
|
||||||
|
return Api.post(
|
||||||
|
`${GitSyncAPI.baseURL}/auto-commit/app/${applicationId}?branchName=${branchName}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
static async getAutocommitProgress(applicationId: string) {
|
static async getAutocommitProgress(applicationId: string) {
|
||||||
return Api.get(
|
return Api.get(
|
||||||
`${GitSyncAPI.baseURL}/auto-commit/progress/app/${applicationId}`,
|
`${GitSyncAPI.baseURL}/auto-commit/progress/app/${applicationId}`,
|
||||||
|
|
|
||||||
|
|
@ -131,8 +131,8 @@ const ActionTypes = {
|
||||||
GIT_TOGGLE_AUTOCOMMIT_ENABLED_INIT: "GIT_TOGGLE_AUTOCOMMIT_ENABLED_INIT",
|
GIT_TOGGLE_AUTOCOMMIT_ENABLED_INIT: "GIT_TOGGLE_AUTOCOMMIT_ENABLED_INIT",
|
||||||
GIT_TOGGLE_AUTOCOMMIT_ENABLED_SUCCESS:
|
GIT_TOGGLE_AUTOCOMMIT_ENABLED_SUCCESS:
|
||||||
"GIT_TOGGLE_AUTOCOMMIT_ENABLED_SUCCESS",
|
"GIT_TOGGLE_AUTOCOMMIT_ENABLED_SUCCESS",
|
||||||
GIT_AUTOCOMMIT_INITIATE_PROGRESS_POLLING:
|
GIT_AUTOCOMMIT_TRIGGER_INIT: "GIT_AUTOCOMMIT_TRIGGER_INIT",
|
||||||
"GIT_AUTOCOMMIT_INITIATE_PROGRESS_POLLING",
|
GIT_AUTOCOMMIT_TRIGGER_SUCCESS: "GIT_AUTOCOMMIT_TRIGGER_SUCCESS",
|
||||||
GIT_AUTOCOMMIT_START_PROGRESS_POLLING:
|
GIT_AUTOCOMMIT_START_PROGRESS_POLLING:
|
||||||
"GIT_AUTOCOMMIT_START_PROGRESS_POLLING",
|
"GIT_AUTOCOMMIT_START_PROGRESS_POLLING",
|
||||||
GIT_AUTOCOMMIT_STOP_PROGRESS_POLLING: "GIT_AUTOCOMMIT_STOP_PROGRESS_POLLING",
|
GIT_AUTOCOMMIT_STOP_PROGRESS_POLLING: "GIT_AUTOCOMMIT_STOP_PROGRESS_POLLING",
|
||||||
|
|
@ -962,6 +962,7 @@ export const ReduxActionErrorTypes = {
|
||||||
GIT_TOGGLE_AUTOCOMMIT_ENABLED_ERROR: "GIT_TOGGLE_AUTOCOMMIT_ENABLED_ERROR",
|
GIT_TOGGLE_AUTOCOMMIT_ENABLED_ERROR: "GIT_TOGGLE_AUTOCOMMIT_ENABLED_ERROR",
|
||||||
GIT_AUTOCOMMIT_PROGRESS_POLLING_ERROR:
|
GIT_AUTOCOMMIT_PROGRESS_POLLING_ERROR:
|
||||||
"GIT_AUTOCOMMIT_PROGRESS_POLLING_ERROR",
|
"GIT_AUTOCOMMIT_PROGRESS_POLLING_ERROR",
|
||||||
|
GIT_AUTOCOMMIT_TRIGGER_ERROR: "GIT_AUTOCOMMIT_TRIGGER_ERROR",
|
||||||
GIT_GET_METADATA_ERROR: "GIT_GET_METADATA_ERROR",
|
GIT_GET_METADATA_ERROR: "GIT_GET_METADATA_ERROR",
|
||||||
FETCH_FEATURE_FLAGS_ERROR: "FETCH_FEATURE_FLAGS_ERROR",
|
FETCH_FEATURE_FLAGS_ERROR: "FETCH_FEATURE_FLAGS_ERROR",
|
||||||
FETCH_NOTIFICATIONS_ERROR: "FETCH_NOTIFICATIONS_ERROR",
|
FETCH_NOTIFICATIONS_ERROR: "FETCH_NOTIFICATIONS_ERROR",
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,119 @@
|
||||||
|
import "@testing-library/jest-dom/extend-expect";
|
||||||
|
import React from "react";
|
||||||
|
import { render, screen } from "@testing-library/react";
|
||||||
|
import { Provider } from "react-redux";
|
||||||
|
import configureStore from "redux-mock-store";
|
||||||
|
import { lightTheme } from "selectors/themeSelectors";
|
||||||
|
import { ThemeProvider } from "styled-components";
|
||||||
|
import CreateNewAppsOption from "./CreateNewAppsOption";
|
||||||
|
import { BrowserRouter as Router } from "react-router-dom";
|
||||||
|
import { unitTestBaseMockStore } from "layoutSystems/common/dropTarget/unitTestUtils";
|
||||||
|
|
||||||
|
const defaultStoreState = {
|
||||||
|
...unitTestBaseMockStore,
|
||||||
|
tenant: {
|
||||||
|
tenantConfiguration: {},
|
||||||
|
},
|
||||||
|
entities: {
|
||||||
|
...unitTestBaseMockStore.entities,
|
||||||
|
plugins: {
|
||||||
|
list: [],
|
||||||
|
},
|
||||||
|
datasources: {
|
||||||
|
list: [],
|
||||||
|
mockDatasourceList: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ui: {
|
||||||
|
...unitTestBaseMockStore.ui,
|
||||||
|
selectedWorkspace: {
|
||||||
|
...unitTestBaseMockStore.ui.selectedWorkspace,
|
||||||
|
applications: [unitTestBaseMockStore.ui.applications.currentApplication],
|
||||||
|
},
|
||||||
|
debugger: {
|
||||||
|
isOpen: false,
|
||||||
|
},
|
||||||
|
editor: {
|
||||||
|
loadingStates: {},
|
||||||
|
isProtectedMode: true,
|
||||||
|
zoomLevel: 1,
|
||||||
|
},
|
||||||
|
gitSync: {
|
||||||
|
globalGitConfig: {},
|
||||||
|
branches: [],
|
||||||
|
localGitConfig: {},
|
||||||
|
disconnectingGitApp: {},
|
||||||
|
},
|
||||||
|
users: {
|
||||||
|
loadingStates: {},
|
||||||
|
list: [],
|
||||||
|
users: [],
|
||||||
|
error: "",
|
||||||
|
currentUser: {},
|
||||||
|
featureFlag: {
|
||||||
|
data: {},
|
||||||
|
isFetched: true,
|
||||||
|
overriddenFlags: {},
|
||||||
|
},
|
||||||
|
productAlert: {
|
||||||
|
config: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
apiPane: {
|
||||||
|
isCreating: false,
|
||||||
|
isRunning: {},
|
||||||
|
isSaving: {},
|
||||||
|
isDeleting: {},
|
||||||
|
isDirty: {},
|
||||||
|
extraformData: {},
|
||||||
|
selectedConfigTabIndex: 0,
|
||||||
|
debugger: {
|
||||||
|
open: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const mockStore = configureStore([]);
|
||||||
|
describe("CreateNewAppsOption", () => {
|
||||||
|
let store: any;
|
||||||
|
it("Should not render skip button if no application is present", () => {
|
||||||
|
store = mockStore(defaultStoreState);
|
||||||
|
|
||||||
|
render(
|
||||||
|
<Provider store={store}>
|
||||||
|
<ThemeProvider theme={lightTheme}>
|
||||||
|
<Router>
|
||||||
|
<CreateNewAppsOption currentApplicationIdForCreateNewApp="test" />
|
||||||
|
</Router>
|
||||||
|
</ThemeProvider>
|
||||||
|
</Provider>,
|
||||||
|
);
|
||||||
|
|
||||||
|
const button = screen.queryAllByTestId("t--create-new-app-option-skip");
|
||||||
|
|
||||||
|
// Check that the skip button to be absent in the document
|
||||||
|
expect(button).toHaveLength(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should render skip button if application is present", () => {
|
||||||
|
render(
|
||||||
|
<Provider store={store}>
|
||||||
|
<ThemeProvider theme={lightTheme}>
|
||||||
|
<Router>
|
||||||
|
<CreateNewAppsOption currentApplicationIdForCreateNewApp="659d2e15d0cbfb0c5e0a7428" />
|
||||||
|
</Router>
|
||||||
|
</ThemeProvider>
|
||||||
|
</Provider>,
|
||||||
|
);
|
||||||
|
|
||||||
|
const button = screen.queryAllByTestId("t--create-new-app-option-skip");
|
||||||
|
|
||||||
|
// Check that the skip button to be present in the document
|
||||||
|
expect(button).toHaveLength(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
store.clearActions();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -140,14 +140,14 @@ const CreateNewAppsOption = ({
|
||||||
};
|
};
|
||||||
|
|
||||||
const onClickSkipButton = () => {
|
const onClickSkipButton = () => {
|
||||||
if (application) {
|
const applicationObject = application!;
|
||||||
urlBuilder.updateURLParams(
|
urlBuilder.updateURLParams(
|
||||||
{
|
{
|
||||||
applicationSlug: application.slug,
|
applicationSlug: applicationObject.slug,
|
||||||
applicationVersion: application.applicationVersion,
|
applicationVersion: applicationObject.applicationVersion,
|
||||||
applicationId: application.id,
|
applicationId: applicationObject.id,
|
||||||
},
|
},
|
||||||
application.pages.map((page) => ({
|
applicationObject.pages.map((page) => ({
|
||||||
pageSlug: page.slug,
|
pageSlug: page.slug,
|
||||||
customSlug: page.customSlug,
|
customSlug: page.customSlug,
|
||||||
pageId: page.id,
|
pageId: page.id,
|
||||||
|
|
@ -155,10 +155,9 @@ const CreateNewAppsOption = ({
|
||||||
);
|
);
|
||||||
history.push(
|
history.push(
|
||||||
builderURL({
|
builderURL({
|
||||||
pageId: application.pages[0].id,
|
pageId: applicationObject.pages[0].id,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
addAnalyticEventsForSkip();
|
addAnalyticEventsForSkip();
|
||||||
};
|
};
|
||||||
|
|
@ -214,7 +213,7 @@ const CreateNewAppsOption = ({
|
||||||
>
|
>
|
||||||
{createMessage(GO_BACK)}
|
{createMessage(GO_BACK)}
|
||||||
</LinkWrapper>
|
</LinkWrapper>
|
||||||
|
{application && (
|
||||||
<LinkWrapper
|
<LinkWrapper
|
||||||
className="t--create-new-app-option-skip"
|
className="t--create-new-app-option-skip"
|
||||||
data-testid="t--create-new-app-option-skip"
|
data-testid="t--create-new-app-option-skip"
|
||||||
|
|
@ -223,6 +222,7 @@ const CreateNewAppsOption = ({
|
||||||
>
|
>
|
||||||
{createMessage(SKIP_START_WITH_USE_CASE_TEMPLATES)}
|
{createMessage(SKIP_START_WITH_USE_CASE_TEMPLATES)}
|
||||||
</LinkWrapper>
|
</LinkWrapper>
|
||||||
|
)}
|
||||||
</BackWrapper>
|
</BackWrapper>
|
||||||
<Flex flexDirection="column" pl="spaces-3" pr="spaces-3">
|
<Flex flexDirection="column" pl="spaces-3" pr="spaces-3">
|
||||||
<Header
|
<Header
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import type { WebworkerSpanData } from "UITelemetry/generateWebWorkerTraces";
|
import type { WebworkerSpanData } from "UITelemetry/generateWebWorkerTraces";
|
||||||
|
import type { SpanAttributes } from "UITelemetry/generateTraces";
|
||||||
|
|
||||||
export enum AppsmithWorkers {
|
export enum AppsmithWorkers {
|
||||||
LINT_WORKER = "LINT_WORKER",
|
LINT_WORKER = "LINT_WORKER",
|
||||||
|
|
@ -12,5 +13,5 @@ export enum WorkerErrorTypes {
|
||||||
export interface WorkerRequest<TData, TActions> {
|
export interface WorkerRequest<TData, TActions> {
|
||||||
method: TActions;
|
method: TActions;
|
||||||
data: TData;
|
data: TData;
|
||||||
webworkerTelemetry: Record<string, WebworkerSpanData>;
|
webworkerTelemetry: Record<string, WebworkerSpanData | SpanAttributes>;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import {
|
||||||
remoteUrlInputValue,
|
remoteUrlInputValue,
|
||||||
resetPullMergeStatus,
|
resetPullMergeStatus,
|
||||||
fetchBranchesInit,
|
fetchBranchesInit,
|
||||||
startAutocommitProgressPolling,
|
triggerAutocommitInitAction,
|
||||||
getGitMetadataInitAction,
|
getGitMetadataInitAction,
|
||||||
} from "actions/gitSyncActions";
|
} from "actions/gitSyncActions";
|
||||||
import { restoreRecentEntitiesRequest } from "actions/globalSearchActions";
|
import { restoreRecentEntitiesRequest } from "actions/globalSearchActions";
|
||||||
|
|
@ -296,10 +296,8 @@ export default class AppEditorEngine extends AppEngine {
|
||||||
yield put(fetchGitProtectedBranchesInit());
|
yield put(fetchGitProtectedBranchesInit());
|
||||||
yield put(fetchGitProtectedBranchesInit());
|
yield put(fetchGitProtectedBranchesInit());
|
||||||
yield put(getGitMetadataInitAction());
|
yield put(getGitMetadataInitAction());
|
||||||
|
yield put(triggerAutocommitInitAction());
|
||||||
yield put(fetchGitStatusInit({ compareRemote: true }));
|
yield put(fetchGitStatusInit({ compareRemote: true }));
|
||||||
|
|
||||||
yield put(startAutocommitProgressPolling());
|
|
||||||
yield put(resetPullMergeStatus());
|
yield put(resetPullMergeStatus());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@ import { getCurrentAppGitMetaData } from "@appsmith/selectors/applicationSelecto
|
||||||
import BranchList from "../components/BranchList";
|
import BranchList from "../components/BranchList";
|
||||||
import {
|
import {
|
||||||
getGitStatus,
|
getGitStatus,
|
||||||
|
getIsPollingAutocommit,
|
||||||
|
getIsTriggeringAutocommit,
|
||||||
protectedModeSelector,
|
protectedModeSelector,
|
||||||
showBranchPopupSelector,
|
showBranchPopupSelector,
|
||||||
} from "selectors/gitSyncSelectors";
|
} from "selectors/gitSyncSelectors";
|
||||||
|
|
@ -28,6 +30,10 @@ const ButtonContainer = styled(Button)`
|
||||||
margin: 0 ${(props) => props.theme.spaces[4]}px;
|
margin: 0 ${(props) => props.theme.spaces[4]}px;
|
||||||
max-width: 122px;
|
max-width: 122px;
|
||||||
min-width: unset !important;
|
min-width: unset !important;
|
||||||
|
|
||||||
|
:active {
|
||||||
|
border: 1px solid var(--ads-v2-color-border-muted);
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
function BranchButton() {
|
function BranchButton() {
|
||||||
|
|
@ -38,6 +44,9 @@ function BranchButton() {
|
||||||
const labelTarget = useRef<HTMLSpanElement>(null);
|
const labelTarget = useRef<HTMLSpanElement>(null);
|
||||||
const status = useSelector(getGitStatus);
|
const status = useSelector(getGitStatus);
|
||||||
const isOpen = useSelector(showBranchPopupSelector);
|
const isOpen = useSelector(showBranchPopupSelector);
|
||||||
|
const triggeringAutocommit = useSelector(getIsTriggeringAutocommit);
|
||||||
|
const pollingAutocommit = useSelector(getIsPollingAutocommit);
|
||||||
|
const isBranchChangeDisabled = triggeringAutocommit || pollingAutocommit;
|
||||||
|
|
||||||
const setIsOpen = (isOpen: boolean) => {
|
const setIsOpen = (isOpen: boolean) => {
|
||||||
dispatch(setShowBranchPopupAction(isOpen));
|
dispatch(setShowBranchPopupAction(isOpen));
|
||||||
|
|
@ -47,6 +56,7 @@ function BranchButton() {
|
||||||
<Popover2
|
<Popover2
|
||||||
content={<BranchList setIsPopupOpen={setIsOpen} />}
|
content={<BranchList setIsPopupOpen={setIsOpen} />}
|
||||||
data-testid={"t--git-branch-button-popover"}
|
data-testid={"t--git-branch-button-popover"}
|
||||||
|
disabled={isBranchChangeDisabled}
|
||||||
hasBackdrop
|
hasBackdrop
|
||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
minimal
|
minimal
|
||||||
|
|
@ -69,6 +79,7 @@ function BranchButton() {
|
||||||
<ButtonContainer
|
<ButtonContainer
|
||||||
className="t--branch-button"
|
className="t--branch-button"
|
||||||
data-testid={"t--branch-button-currentBranch"}
|
data-testid={"t--branch-button-currentBranch"}
|
||||||
|
isDisabled={isBranchChangeDisabled}
|
||||||
kind="secondary"
|
kind="secondary"
|
||||||
>
|
>
|
||||||
{isProtectedMode ? (
|
{isProtectedMode ? (
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,7 @@ const initialState: GitSyncReducerState = {
|
||||||
|
|
||||||
isAutocommitModalOpen: false,
|
isAutocommitModalOpen: false,
|
||||||
togglingAutocommit: false,
|
togglingAutocommit: false,
|
||||||
|
triggeringAutocommit: false,
|
||||||
pollingAutocommitStatus: false,
|
pollingAutocommitStatus: false,
|
||||||
|
|
||||||
gitMetadata: null,
|
gitMetadata: null,
|
||||||
|
|
@ -619,6 +620,18 @@ const gitSyncReducer = createReducer(initialState, {
|
||||||
...state,
|
...state,
|
||||||
togglingAutocommit: false,
|
togglingAutocommit: false,
|
||||||
}),
|
}),
|
||||||
|
[ReduxActionTypes.GIT_AUTOCOMMIT_TRIGGER_INIT]: (state) => ({
|
||||||
|
...state,
|
||||||
|
triggeringAutocommit: true,
|
||||||
|
}),
|
||||||
|
[ReduxActionTypes.GIT_AUTOCOMMIT_TRIGGER_SUCCESS]: (state) => ({
|
||||||
|
...state,
|
||||||
|
triggeringAutocommit: false,
|
||||||
|
}),
|
||||||
|
[ReduxActionErrorTypes.GIT_AUTOCOMMIT_TRIGGER_ERROR]: (state) => ({
|
||||||
|
...state,
|
||||||
|
triggeringAutocommit: false,
|
||||||
|
}),
|
||||||
[ReduxActionTypes.GIT_AUTOCOMMIT_START_PROGRESS_POLLING]: (state) => ({
|
[ReduxActionTypes.GIT_AUTOCOMMIT_START_PROGRESS_POLLING]: (state) => ({
|
||||||
...state,
|
...state,
|
||||||
pollingAutocommitStatus: true,
|
pollingAutocommitStatus: true,
|
||||||
|
|
@ -833,6 +846,7 @@ export type GitSyncReducerState = GitBranchDeleteState & {
|
||||||
|
|
||||||
isAutocommitModalOpen: boolean;
|
isAutocommitModalOpen: boolean;
|
||||||
togglingAutocommit: boolean;
|
togglingAutocommit: boolean;
|
||||||
|
triggeringAutocommit: boolean;
|
||||||
pollingAutocommitStatus: boolean;
|
pollingAutocommitStatus: boolean;
|
||||||
|
|
||||||
gitMetadata: GitMetadata | null;
|
gitMetadata: GitMetadata | null;
|
||||||
|
|
|
||||||
|
|
@ -1662,8 +1662,10 @@ function* handleUpdateActionData(
|
||||||
EVAL_WORKER_ACTIONS.UPDATE_ACTION_DATA,
|
EVAL_WORKER_ACTIONS.UPDATE_ACTION_DATA,
|
||||||
actionDataPayload,
|
actionDataPayload,
|
||||||
);
|
);
|
||||||
|
if (parentSpan) {
|
||||||
endSpan(parentSpan);
|
endSpan(parentSpan);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function* watchPluginActionExecutionSagas() {
|
export function* watchPluginActionExecutionSagas() {
|
||||||
yield all([
|
yield all([
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,13 @@ import {
|
||||||
takeLatest,
|
takeLatest,
|
||||||
} from "redux-saga/effects";
|
} from "redux-saga/effects";
|
||||||
import type { TakeableChannel } from "@redux-saga/core";
|
import type { TakeableChannel } from "@redux-saga/core";
|
||||||
import type { MergeBranchPayload, MergeStatusPayload } from "api/GitSyncAPI";
|
import type {
|
||||||
import GitSyncAPI from "api/GitSyncAPI";
|
GitAutocommitProgressResponse,
|
||||||
|
GitTriggerAutocommitResponse,
|
||||||
|
MergeBranchPayload,
|
||||||
|
MergeStatusPayload,
|
||||||
|
} from "api/GitSyncAPI";
|
||||||
|
import GitSyncAPI, { AutocommitResponseEnum } from "api/GitSyncAPI";
|
||||||
import {
|
import {
|
||||||
getCurrentApplicationId,
|
getCurrentApplicationId,
|
||||||
getCurrentPageId,
|
getCurrentPageId,
|
||||||
|
|
@ -40,6 +45,13 @@ import {
|
||||||
updateGitProtectedBranchesInit,
|
updateGitProtectedBranchesInit,
|
||||||
clearCommitSuccessfulState,
|
clearCommitSuccessfulState,
|
||||||
setShowBranchPopupAction,
|
setShowBranchPopupAction,
|
||||||
|
stopAutocommitProgressPollingAction,
|
||||||
|
startAutocommitProgressPollingAction,
|
||||||
|
setAutocommitProgressAction,
|
||||||
|
autoCommitProgressErrorAction,
|
||||||
|
resetAutocommitProgressAction,
|
||||||
|
triggerAutocommitErrorAction,
|
||||||
|
triggerAutocommitSuccessAction,
|
||||||
} from "actions/gitSyncActions";
|
} from "actions/gitSyncActions";
|
||||||
import {
|
import {
|
||||||
commitToRepoSuccess,
|
commitToRepoSuccess,
|
||||||
|
|
@ -103,6 +115,7 @@ import { addBranchParam, GIT_BRANCH_QUERY_KEY } from "constants/routes";
|
||||||
import {
|
import {
|
||||||
getCurrentGitBranch,
|
getCurrentGitBranch,
|
||||||
getDisconnectingGitApplication,
|
getDisconnectingGitApplication,
|
||||||
|
getGitMetadataSelector,
|
||||||
} from "selectors/gitSyncSelectors";
|
} from "selectors/gitSyncSelectors";
|
||||||
import { initEditor } from "actions/initActions";
|
import { initEditor } from "actions/initActions";
|
||||||
import { fetchPage } from "actions/pageActions";
|
import { fetchPage } from "actions/pageActions";
|
||||||
|
|
@ -113,7 +126,10 @@ import { log } from "loglevel";
|
||||||
import GIT_ERROR_CODES from "constants/GitErrorCodes";
|
import GIT_ERROR_CODES from "constants/GitErrorCodes";
|
||||||
import { builderURL } from "@appsmith/RouteBuilder";
|
import { builderURL } from "@appsmith/RouteBuilder";
|
||||||
import { APP_MODE } from "entities/App";
|
import { APP_MODE } from "entities/App";
|
||||||
import type { GitDiscardResponse } from "reducers/uiReducers/gitSyncReducer";
|
import type {
|
||||||
|
GitDiscardResponse,
|
||||||
|
GitMetadata,
|
||||||
|
} from "reducers/uiReducers/gitSyncReducer";
|
||||||
import { FocusEntity, identifyEntityFromPath } from "navigation/FocusEntity";
|
import { FocusEntity, identifyEntityFromPath } from "navigation/FocusEntity";
|
||||||
import {
|
import {
|
||||||
getActions,
|
getActions,
|
||||||
|
|
@ -123,6 +139,8 @@ import type { Action } from "entities/Action";
|
||||||
import type { JSCollectionDataState } from "@appsmith/reducers/entityReducers/jsActionsReducer";
|
import type { JSCollectionDataState } from "@appsmith/reducers/entityReducers/jsActionsReducer";
|
||||||
import { toast } from "design-system";
|
import { toast } from "design-system";
|
||||||
import { gitExtendedSagas } from "@appsmith/sagas/GitExtendedSagas";
|
import { gitExtendedSagas } from "@appsmith/sagas/GitExtendedSagas";
|
||||||
|
import { selectFeatureFlagCheck } from "@appsmith/selectors/featureFlagsSelectors";
|
||||||
|
import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag";
|
||||||
|
|
||||||
export function* handleRepoLimitReachedError(response?: ApiResponse) {
|
export function* handleRepoLimitReachedError(response?: ApiResponse) {
|
||||||
const { responseMeta } = response || {};
|
const { responseMeta } = response || {};
|
||||||
|
|
@ -1159,78 +1177,110 @@ function* getGitMetadataSaga() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isAutocommitHappening(
|
||||||
|
response:
|
||||||
|
| GitTriggerAutocommitResponse
|
||||||
|
| GitAutocommitProgressResponse
|
||||||
|
| undefined,
|
||||||
|
): boolean {
|
||||||
|
return (
|
||||||
|
!!response &&
|
||||||
|
!!(
|
||||||
|
response.autoCommitResponse === AutocommitResponseEnum.PUBLISHED ||
|
||||||
|
response.autoCommitResponse === AutocommitResponseEnum.IN_PROGRESS ||
|
||||||
|
response.autoCommitResponse === AutocommitResponseEnum.LOCKED
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function* pollAutocommitProgressSaga(): any {
|
function* pollAutocommitProgressSaga(): any {
|
||||||
const applicationId: string = yield select(getCurrentApplicationId);
|
const applicationId: string = yield select(getCurrentApplicationId);
|
||||||
|
const branchName: string = yield select(getCurrentGitBranch);
|
||||||
|
|
||||||
|
let triggerResponse: ApiResponse<GitTriggerAutocommitResponse> | undefined;
|
||||||
try {
|
try {
|
||||||
const response: ApiResponse<any> = yield call(
|
const res = yield call(
|
||||||
GitSyncAPI.getAutocommitProgress,
|
GitSyncAPI.triggerAutocommit,
|
||||||
applicationId,
|
applicationId,
|
||||||
|
branchName,
|
||||||
);
|
);
|
||||||
const isValidResponse: boolean = yield validateResponse(
|
const isValidResponse: boolean = yield validateResponse(
|
||||||
response,
|
res,
|
||||||
false,
|
false,
|
||||||
getLogToSentryFromResponse(response),
|
getLogToSentryFromResponse(res),
|
||||||
);
|
|
||||||
if (isValidResponse && response?.data?.isRunning) {
|
|
||||||
yield put({
|
|
||||||
type: ReduxActionTypes.GIT_AUTOCOMMIT_START_PROGRESS_POLLING,
|
|
||||||
});
|
|
||||||
while (true) {
|
|
||||||
const response: ApiResponse<any> = yield call(
|
|
||||||
GitSyncAPI.getAutocommitProgress,
|
|
||||||
applicationId,
|
|
||||||
);
|
|
||||||
const isValidResponse: boolean = yield validateResponse(
|
|
||||||
response,
|
|
||||||
false,
|
|
||||||
getLogToSentryFromResponse(response),
|
|
||||||
);
|
);
|
||||||
if (isValidResponse) {
|
if (isValidResponse) {
|
||||||
yield put({
|
triggerResponse = res;
|
||||||
type: ReduxActionTypes.GIT_SET_AUTOCOMMIT_PROGRESS,
|
yield put(triggerAutocommitSuccessAction());
|
||||||
payload: response.data,
|
} else {
|
||||||
});
|
yield put(
|
||||||
if (!response?.data?.isRunning) {
|
triggerAutocommitErrorAction({
|
||||||
yield put({
|
error: res?.responseMeta?.error?.message,
|
||||||
type: ReduxActionTypes.GIT_AUTOCOMMIT_STOP_PROGRESS_POLLING,
|
show: true,
|
||||||
});
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
yield put(triggerAutocommitErrorAction({ error: err, show: false }));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (isAutocommitHappening(triggerResponse?.data)) {
|
||||||
|
yield put(startAutocommitProgressPollingAction());
|
||||||
|
while (true) {
|
||||||
|
const progressResponse: ApiResponse<GitAutocommitProgressResponse> =
|
||||||
|
yield call(GitSyncAPI.getAutocommitProgress, applicationId);
|
||||||
|
const isValidResponse: boolean = yield validateResponse(
|
||||||
|
progressResponse,
|
||||||
|
false,
|
||||||
|
getLogToSentryFromResponse(progressResponse),
|
||||||
|
);
|
||||||
|
if (isValidResponse) {
|
||||||
|
yield put(setAutocommitProgressAction(progressResponse.data));
|
||||||
|
if (!isAutocommitHappening(progressResponse?.data)) {
|
||||||
|
yield put(stopAutocommitProgressPollingAction());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
yield put({
|
yield put(stopAutocommitProgressPollingAction());
|
||||||
type: ReduxActionTypes.GIT_AUTOCOMMIT_STOP_PROGRESS_POLLING,
|
yield put(
|
||||||
});
|
autoCommitProgressErrorAction({
|
||||||
yield put({
|
error: progressResponse?.responseMeta?.error?.message,
|
||||||
type: ReduxActionErrorTypes.GIT_AUTOCOMMIT_PROGRESS_POLLING_ERROR,
|
|
||||||
payload: {
|
|
||||||
error: response?.responseMeta?.error?.message,
|
|
||||||
show: true,
|
show: true,
|
||||||
},
|
}),
|
||||||
});
|
);
|
||||||
}
|
}
|
||||||
yield delay(1000);
|
yield delay(1000);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
yield put({
|
yield put(stopAutocommitProgressPollingAction());
|
||||||
type: ReduxActionTypes.GIT_AUTOCOMMIT_STOP_PROGRESS_POLLING,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
yield put({
|
yield put(stopAutocommitProgressPollingAction());
|
||||||
type: ReduxActionTypes.GIT_AUTOCOMMIT_STOP_PROGRESS_POLLING,
|
yield put(autoCommitProgressErrorAction({ error, show: false }));
|
||||||
});
|
|
||||||
yield put({
|
|
||||||
type: ReduxActionErrorTypes.GIT_AUTOCOMMIT_PROGRESS_POLLING_ERROR,
|
|
||||||
payload: { error },
|
|
||||||
});
|
|
||||||
} finally {
|
} finally {
|
||||||
if (yield cancelled()) {
|
if (yield cancelled()) {
|
||||||
yield put({
|
yield put(resetAutocommitProgressAction());
|
||||||
type: ReduxActionTypes.GIT_RESET_AUTOCOMMIT_PROGRESS,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function* triggerAutocommitSaga() {
|
||||||
|
const isAutocommitFeatureEnabled: boolean = yield select(
|
||||||
|
selectFeatureFlagCheck,
|
||||||
|
FEATURE_FLAG.release_git_autocommit_feature_enabled,
|
||||||
|
);
|
||||||
|
const gitMetadata: GitMetadata = yield select(getGitMetadataSelector);
|
||||||
|
const isAutocommitEnabled: boolean = !!gitMetadata?.autoCommitConfig?.enabled;
|
||||||
|
if (isAutocommitFeatureEnabled && isAutocommitEnabled) {
|
||||||
|
/* @ts-expect-error: not sure how to do typings of this */
|
||||||
|
const pollTask = yield fork(pollAutocommitProgressSaga);
|
||||||
|
yield take(ReduxActionTypes.GIT_AUTOCOMMIT_STOP_PROGRESS_POLLING);
|
||||||
|
yield cancel(pollTask);
|
||||||
|
} else {
|
||||||
|
yield put(triggerAutocommitSuccessAction());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const gitRequestBlockingActions: Record<
|
const gitRequestBlockingActions: Record<
|
||||||
(typeof ReduxActionTypes)[keyof typeof ReduxActionTypes],
|
(typeof ReduxActionTypes)[keyof typeof ReduxActionTypes],
|
||||||
(...args: any[]) => any
|
(...args: any[]) => any
|
||||||
|
|
@ -1252,6 +1302,9 @@ const gitRequestBlockingActions: Record<
|
||||||
[ReduxActionTypes.GIT_DISCARD_CHANGES]: discardChanges,
|
[ReduxActionTypes.GIT_DISCARD_CHANGES]: discardChanges,
|
||||||
[ReduxActionTypes.GIT_UPDATE_PROTECTED_BRANCHES_INIT]:
|
[ReduxActionTypes.GIT_UPDATE_PROTECTED_BRANCHES_INIT]:
|
||||||
updateGitProtectedBranchesSaga,
|
updateGitProtectedBranchesSaga,
|
||||||
|
[ReduxActionTypes.GIT_AUTOCOMMIT_TRIGGER_INIT]: triggerAutocommitSaga,
|
||||||
|
[ReduxActionTypes.FETCH_GIT_STATUS_INIT]: fetchGitStatusSaga,
|
||||||
|
[ReduxActionTypes.GIT_GET_METADATA_INIT]: getGitMetadataSaga,
|
||||||
};
|
};
|
||||||
|
|
||||||
const gitRequestNonBlockingActions: Record<
|
const gitRequestNonBlockingActions: Record<
|
||||||
|
|
@ -1261,13 +1314,11 @@ const gitRequestNonBlockingActions: Record<
|
||||||
...gitExtendedSagas,
|
...gitExtendedSagas,
|
||||||
[ReduxActionTypes.FETCH_GLOBAL_GIT_CONFIG_INIT]: fetchGlobalGitConfig,
|
[ReduxActionTypes.FETCH_GLOBAL_GIT_CONFIG_INIT]: fetchGlobalGitConfig,
|
||||||
[ReduxActionTypes.FETCH_LOCAL_GIT_CONFIG_INIT]: fetchLocalGitConfig,
|
[ReduxActionTypes.FETCH_LOCAL_GIT_CONFIG_INIT]: fetchLocalGitConfig,
|
||||||
[ReduxActionTypes.FETCH_GIT_STATUS_INIT]: fetchGitStatusSaga,
|
|
||||||
[ReduxActionTypes.SHOW_CONNECT_GIT_MODAL]: showConnectGitModal,
|
[ReduxActionTypes.SHOW_CONNECT_GIT_MODAL]: showConnectGitModal,
|
||||||
[ReduxActionTypes.FETCH_SSH_KEY_PAIR_INIT]: getSSHKeyPairSaga,
|
[ReduxActionTypes.FETCH_SSH_KEY_PAIR_INIT]: getSSHKeyPairSaga,
|
||||||
[ReduxActionTypes.GIT_FETCH_PROTECTED_BRANCHES_INIT]:
|
[ReduxActionTypes.GIT_FETCH_PROTECTED_BRANCHES_INIT]:
|
||||||
fetchGitProtectedBranchesSaga,
|
fetchGitProtectedBranchesSaga,
|
||||||
[ReduxActionTypes.GIT_TOGGLE_AUTOCOMMIT_ENABLED_INIT]: toggleAutocommitSaga,
|
[ReduxActionTypes.GIT_TOGGLE_AUTOCOMMIT_ENABLED_INIT]: toggleAutocommitSaga,
|
||||||
[ReduxActionTypes.GIT_GET_METADATA_INIT]: getGitMetadataSaga,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1298,18 +1349,7 @@ function* watchGitNonBlockingRequests() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function* watchGitAutocommitPolling() {
|
|
||||||
while (true) {
|
|
||||||
yield take(ReduxActionTypes.GIT_AUTOCOMMIT_INITIATE_PROGRESS_POLLING);
|
|
||||||
/* @ts-expect-error: not sure how to do typings of this */
|
|
||||||
const pollTask = yield fork(pollAutocommitProgressSaga);
|
|
||||||
yield take(ReduxActionTypes.GIT_AUTOCOMMIT_STOP_PROGRESS_POLLING);
|
|
||||||
yield cancel(pollTask);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function* gitSyncSagas() {
|
export default function* gitSyncSagas() {
|
||||||
yield fork(watchGitNonBlockingRequests);
|
yield fork(watchGitNonBlockingRequests);
|
||||||
yield fork(watchGitBlockingRequests);
|
yield fork(watchGitBlockingRequests);
|
||||||
yield fork(watchGitAutocommitPolling);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -257,6 +257,9 @@ export const getIsAutocommitToggling = (state: AppState) =>
|
||||||
export const getIsAutocommitModalOpen = (state: AppState) =>
|
export const getIsAutocommitModalOpen = (state: AppState) =>
|
||||||
state.ui.gitSync.isAutocommitModalOpen;
|
state.ui.gitSync.isAutocommitModalOpen;
|
||||||
|
|
||||||
|
export const getIsTriggeringAutocommit = (state: AppState) =>
|
||||||
|
state.ui.gitSync.triggeringAutocommit;
|
||||||
|
|
||||||
export const getIsPollingAutocommit = (state: AppState) =>
|
export const getIsPollingAutocommit = (state: AppState) =>
|
||||||
state.ui.gitSync.pollingAutocommitStatus;
|
state.ui.gitSync.pollingAutocommitStatus;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,16 @@ import { uniqueId } from "lodash";
|
||||||
import log from "loglevel";
|
import log from "loglevel";
|
||||||
import type { TMessage } from "./MessageUtil";
|
import type { TMessage } from "./MessageUtil";
|
||||||
import { MessageType, sendMessage } from "./MessageUtil";
|
import { MessageType, sendMessage } from "./MessageUtil";
|
||||||
import type { OtlpSpan } from "UITelemetry/generateTraces";
|
import type { OtlpSpan, SpanAttributes } from "UITelemetry/generateTraces";
|
||||||
import { endSpan, startRootSpan } from "UITelemetry/generateTraces";
|
import {
|
||||||
|
endSpan,
|
||||||
|
setAttributesToSpan,
|
||||||
|
startRootSpan,
|
||||||
|
} from "UITelemetry/generateTraces";
|
||||||
import type { WebworkerSpanData } from "UITelemetry/generateWebWorkerTraces";
|
import type { WebworkerSpanData } from "UITelemetry/generateWebWorkerTraces";
|
||||||
import {
|
import {
|
||||||
convertWebworkerSpansToRegularSpans,
|
convertWebworkerSpansToRegularSpans,
|
||||||
|
filterSpanData,
|
||||||
newWebWorkerSpanData,
|
newWebWorkerSpanData,
|
||||||
} from "UITelemetry/generateWebWorkerTraces";
|
} from "UITelemetry/generateWebWorkerTraces";
|
||||||
|
|
||||||
|
|
@ -156,33 +161,35 @@ export class GracefulWorkerService {
|
||||||
startTime,
|
startTime,
|
||||||
webworkerTelemetry,
|
webworkerTelemetry,
|
||||||
}: {
|
}: {
|
||||||
webworkerTelemetry: Record<string, WebworkerSpanData>;
|
webworkerTelemetry:
|
||||||
|
| Record<string, WebworkerSpanData | SpanAttributes>
|
||||||
|
| undefined;
|
||||||
rootSpan: OtlpSpan | undefined;
|
rootSpan: OtlpSpan | undefined;
|
||||||
method: string;
|
method: string;
|
||||||
startTime: number;
|
startTime: number;
|
||||||
endTime: number;
|
endTime: number;
|
||||||
}) {
|
}) {
|
||||||
const webworkerTelemetryResponse = webworkerTelemetry as Record<
|
if (!webworkerTelemetry) {
|
||||||
string,
|
return;
|
||||||
WebworkerSpanData
|
}
|
||||||
>;
|
|
||||||
|
|
||||||
if (webworkerTelemetryResponse) {
|
const { transferDataToMainThread } = webworkerTelemetry;
|
||||||
const { transferDataToMainThread } = webworkerTelemetryResponse;
|
|
||||||
if (transferDataToMainThread) {
|
if (transferDataToMainThread) {
|
||||||
transferDataToMainThread.endTime = Date.now();
|
transferDataToMainThread.endTime = Date.now();
|
||||||
}
|
}
|
||||||
/// Add the completeWebworkerComputation span to the root span
|
/// Add the completeWebworkerComputation span to the root span
|
||||||
webworkerTelemetryResponse["completeWebworkerComputation"] = {
|
webworkerTelemetry["completeWebworkerComputation"] = {
|
||||||
startTime,
|
startTime,
|
||||||
endTime,
|
endTime,
|
||||||
attributes: {},
|
attributes: {},
|
||||||
spanName: "completeWebworkerComputation",
|
spanName: "completeWebworkerComputation",
|
||||||
};
|
};
|
||||||
}
|
|
||||||
//we are attaching the child spans to the root span over here
|
//we are attaching the child spans to the root span over here
|
||||||
rootSpan &&
|
rootSpan &&
|
||||||
convertWebworkerSpansToRegularSpans(rootSpan, webworkerTelemetryResponse);
|
convertWebworkerSpansToRegularSpans(
|
||||||
|
rootSpan,
|
||||||
|
filterSpanData(webworkerTelemetry),
|
||||||
|
);
|
||||||
|
|
||||||
//genereate separate completeWebworkerComputationRoot root span
|
//genereate separate completeWebworkerComputationRoot root span
|
||||||
// this span does not contain any child spans, it just captures the webworker computation alone
|
// this span does not contain any child spans, it just captures the webworker computation alone
|
||||||
|
|
@ -218,11 +225,15 @@ export class GracefulWorkerService {
|
||||||
let timeTaken;
|
let timeTaken;
|
||||||
const rootSpan = startRootSpan(method);
|
const rootSpan = startRootSpan(method);
|
||||||
|
|
||||||
const webworkerTelemetryData: Record<string, WebworkerSpanData> = {
|
const webworkerTelemetryData: Record<
|
||||||
|
string,
|
||||||
|
WebworkerSpanData | SpanAttributes
|
||||||
|
> = {
|
||||||
transferDataToWorkerThread: newWebWorkerSpanData(
|
transferDataToWorkerThread: newWebWorkerSpanData(
|
||||||
"transferDataToWorkerThread",
|
"transferDataToWorkerThread",
|
||||||
{},
|
{},
|
||||||
),
|
),
|
||||||
|
__spanAttributes: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
const body = {
|
const body = {
|
||||||
|
|
@ -231,6 +242,11 @@ export class GracefulWorkerService {
|
||||||
webworkerTelemetry: webworkerTelemetryData,
|
webworkerTelemetry: webworkerTelemetryData,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let webworkerTelemetryResponse: Record<
|
||||||
|
string,
|
||||||
|
WebworkerSpanData | SpanAttributes
|
||||||
|
> = {};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
sendMessage.call(this._Worker, {
|
sendMessage.call(this._Worker, {
|
||||||
messageType: MessageType.REQUEST,
|
messageType: MessageType.REQUEST,
|
||||||
|
|
@ -241,9 +257,10 @@ export class GracefulWorkerService {
|
||||||
// The `this._broker` method is listening to events and will pass response to us over this channel.
|
// The `this._broker` method is listening to events and will pass response to us over this channel.
|
||||||
const response = yield take(ch);
|
const response = yield take(ch);
|
||||||
const { data, endTime, startTime } = response;
|
const { data, endTime, startTime } = response;
|
||||||
const { webworkerTelemetry } = data;
|
webworkerTelemetryResponse = data.webworkerTelemetry;
|
||||||
|
|
||||||
this.addChildSpansToRootSpan({
|
this.addChildSpansToRootSpan({
|
||||||
webworkerTelemetry,
|
webworkerTelemetry: webworkerTelemetryResponse,
|
||||||
rootSpan,
|
rootSpan,
|
||||||
method,
|
method,
|
||||||
startTime,
|
startTime,
|
||||||
|
|
@ -268,6 +285,14 @@ export class GracefulWorkerService {
|
||||||
log.debug(` Worker ${method} took ${timeTaken}ms`);
|
log.debug(` Worker ${method} took ${timeTaken}ms`);
|
||||||
log.debug(` Transfer ${method} took ${transferTime}ms`);
|
log.debug(` Transfer ${method} took ${transferTime}ms`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (webworkerTelemetryResponse) {
|
||||||
|
setAttributesToSpan(
|
||||||
|
rootSpan,
|
||||||
|
webworkerTelemetryResponse.__spanAttributes as SpanAttributes,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
endSpan(rootSpan);
|
endSpan(rootSpan);
|
||||||
// Cleanup
|
// Cleanup
|
||||||
ch.close();
|
ch.close();
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ import {
|
||||||
profileFn,
|
profileFn,
|
||||||
newWebWorkerSpanData,
|
newWebWorkerSpanData,
|
||||||
} from "UITelemetry/generateWebWorkerTraces";
|
} from "UITelemetry/generateWebWorkerTraces";
|
||||||
|
import type { SpanAttributes } from "UITelemetry/generateTraces";
|
||||||
import type { CanvasWidgetsReduxState } from "reducers/entityReducers/canvasWidgetsReducer";
|
import type { CanvasWidgetsReduxState } from "reducers/entityReducers/canvasWidgetsReducer";
|
||||||
import type { MetaWidgetsReduxState } from "reducers/entityReducers/metaWidgetsReducer";
|
import type { MetaWidgetsReduxState } from "reducers/entityReducers/metaWidgetsReducer";
|
||||||
|
|
||||||
|
|
@ -85,6 +86,9 @@ export function evalTree(request: EvalWorkerSyncRequest) {
|
||||||
let isNewTree = false;
|
let isNewTree = false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
(webworkerTelemetry.__spanAttributes as SpanAttributes)["firstEvaluation"] =
|
||||||
|
!dataTreeEvaluator;
|
||||||
|
|
||||||
if (!dataTreeEvaluator) {
|
if (!dataTreeEvaluator) {
|
||||||
isCreateFirstTree = true;
|
isCreateFirstTree = true;
|
||||||
replayMap = replayMap || {};
|
replayMap = replayMap || {};
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import type { WorkerRequest } from "@appsmith/workers/common/types";
|
||||||
import type { DataTreeDiff } from "@appsmith/workers/Evaluation/evaluationUtils";
|
import type { DataTreeDiff } from "@appsmith/workers/Evaluation/evaluationUtils";
|
||||||
import type { APP_MODE } from "entities/App";
|
import type { APP_MODE } from "entities/App";
|
||||||
import type { WebworkerSpanData } from "UITelemetry/generateWebWorkerTraces";
|
import type { WebworkerSpanData } from "UITelemetry/generateWebWorkerTraces";
|
||||||
|
import type { SpanAttributes } from "UITelemetry/generateTraces";
|
||||||
import type { AffectedJSObjects } from "sagas/EvaluationsSagaUtils";
|
import type { AffectedJSObjects } from "sagas/EvaluationsSagaUtils";
|
||||||
|
|
||||||
export type EvalWorkerSyncRequest<T = any> = WorkerRequest<
|
export type EvalWorkerSyncRequest<T = any> = WorkerRequest<
|
||||||
|
|
@ -59,6 +60,6 @@ export interface EvalTreeResponseData {
|
||||||
isNewWidgetAdded: boolean;
|
isNewWidgetAdded: boolean;
|
||||||
undefinedEvalValuesMap: Record<string, boolean>;
|
undefinedEvalValuesMap: Record<string, boolean>;
|
||||||
jsVarsCreatedEvent?: { path: string; type: string }[];
|
jsVarsCreatedEvent?: { path: string; type: string }[];
|
||||||
webworkerTelemetry?: Record<string, WebworkerSpanData>;
|
webworkerTelemetry?: Record<string, WebworkerSpanData | SpanAttributes>;
|
||||||
updates: string;
|
updates: string;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -137,6 +137,7 @@ import {
|
||||||
profileFn,
|
profileFn,
|
||||||
type WebworkerSpanData,
|
type WebworkerSpanData,
|
||||||
} from "UITelemetry/generateWebWorkerTraces";
|
} from "UITelemetry/generateWebWorkerTraces";
|
||||||
|
import type { SpanAttributes } from "UITelemetry/generateTraces";
|
||||||
import type { AffectedJSObjects } from "sagas/EvaluationsSagaUtils";
|
import type { AffectedJSObjects } from "sagas/EvaluationsSagaUtils";
|
||||||
import generateOverrideContext from "@appsmith/workers/Evaluation/generateOverrideContext";
|
import generateOverrideContext from "@appsmith/workers/Evaluation/generateOverrideContext";
|
||||||
|
|
||||||
|
|
@ -233,7 +234,7 @@ export default class DataTreeEvaluator {
|
||||||
setupFirstTree(
|
setupFirstTree(
|
||||||
unEvalTree: any,
|
unEvalTree: any,
|
||||||
configTree: ConfigTree,
|
configTree: ConfigTree,
|
||||||
webworkerTelemetry: Record<string, WebworkerSpanData> = {},
|
webworkerTelemetry: Record<string, WebworkerSpanData | SpanAttributes> = {},
|
||||||
): {
|
): {
|
||||||
jsUpdates: Record<string, JSUpdate>;
|
jsUpdates: Record<string, JSUpdate>;
|
||||||
evalOrder: string[];
|
evalOrder: string[];
|
||||||
|
|
@ -489,7 +490,7 @@ export default class DataTreeEvaluator {
|
||||||
setupUpdateTree(
|
setupUpdateTree(
|
||||||
unEvalTree: any,
|
unEvalTree: any,
|
||||||
configTree: ConfigTree,
|
configTree: ConfigTree,
|
||||||
webworkerTelemetry: Record<string, WebworkerSpanData> = {},
|
webworkerTelemetry: Record<string, WebworkerSpanData | SpanAttributes> = {},
|
||||||
affectedJSObjects: AffectedJSObjects = { isAllAffected: false, ids: [] },
|
affectedJSObjects: AffectedJSObjects = { isAllAffected: false, ids: [] },
|
||||||
): {
|
): {
|
||||||
unEvalUpdates: DataTreeDiff[];
|
unEvalUpdates: DataTreeDiff[];
|
||||||
|
|
|
||||||
|
|
@ -288,8 +288,10 @@ public class FileUtilsCEImpl implements FileInterface {
|
||||||
|
|
||||||
// Save JS Libs if there's at least one change
|
// Save JS Libs if there's at least one change
|
||||||
if (modifiedResources != null
|
if (modifiedResources != null
|
||||||
&& !CollectionUtils.isEmpty(
|
&& (modifiedResources.isAllModified()
|
||||||
modifiedResources.getModifiedResourceMap().get(CUSTOM_JS_LIB_LIST))) {
|
|| !CollectionUtils.isEmpty(
|
||||||
|
modifiedResources.getModifiedResourceMap().get(CUSTOM_JS_LIB_LIST)))) {
|
||||||
|
|
||||||
Path jsLibDirectory = baseRepo.resolve(JS_LIB_DIRECTORY);
|
Path jsLibDirectory = baseRepo.resolve(JS_LIB_DIRECTORY);
|
||||||
Set<Map.Entry<String, Object>> jsLibEntries =
|
Set<Map.Entry<String, Object>> jsLibEntries =
|
||||||
applicationGitReference.getJsLibraries().entrySet();
|
applicationGitReference.getJsLibraries().entrySet();
|
||||||
|
|
@ -953,16 +955,23 @@ public class FileUtilsCEImpl implements FileInterface {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<Object> reconstructMetadataFromGitRepo(
|
public Mono<Object> reconstructMetadataFromGitRepo(
|
||||||
String workspaceId, String defaultArtifactId, String repoName, String branchName, Path baseRepoSuffix) {
|
String workspaceId,
|
||||||
|
String defaultArtifactId,
|
||||||
|
String repoName,
|
||||||
|
String branchName,
|
||||||
|
Path baseRepoSuffix,
|
||||||
|
Boolean isResetToLastCommitRequired) {
|
||||||
Mono<Object> metadataMono;
|
Mono<Object> metadataMono;
|
||||||
try {
|
try {
|
||||||
|
Mono<Boolean> gitResetMono = Mono.just(Boolean.TRUE);
|
||||||
|
if (Boolean.TRUE.equals(isResetToLastCommitRequired)) {
|
||||||
// instead of checking out to last branch we are first cleaning the git repo,
|
// instead of checking out to last branch we are first cleaning the git repo,
|
||||||
// then checking out to the desired branch
|
// then checking out to the desired branch
|
||||||
metadataMono = gitExecutor
|
gitResetMono = gitExecutor.resetToLastCommit(baseRepoSuffix, branchName);
|
||||||
.resetToLastCommit(baseRepoSuffix, branchName)
|
}
|
||||||
.map(isSwitched -> {
|
|
||||||
Path baseRepoPath =
|
metadataMono = gitResetMono.map(isSwitched -> {
|
||||||
Paths.get(gitServiceConfig.getGitRootPath()).resolve(baseRepoSuffix);
|
Path baseRepoPath = Paths.get(gitServiceConfig.getGitRootPath()).resolve(baseRepoSuffix);
|
||||||
Object metadata = fileOperations.readFile(
|
Object metadata = fileOperations.readFile(
|
||||||
baseRepoPath.resolve(CommonConstants.METADATA + CommonConstants.JSON_EXTENSION));
|
baseRepoPath.resolve(CommonConstants.METADATA + CommonConstants.JSON_EXTENSION));
|
||||||
return metadata;
|
return metadata;
|
||||||
|
|
@ -973,4 +982,35 @@ public class FileUtilsCEImpl implements FileInterface {
|
||||||
|
|
||||||
return metadataMono.subscribeOn(scheduler);
|
return metadataMono.subscribeOn(scheduler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Mono<Object> reconstructPageFromGitRepo(
|
||||||
|
String pageName, String branchName, Path baseRepoSuffixPath, Boolean resetToLastCommitRequired) {
|
||||||
|
Mono<Object> pageObjectMono;
|
||||||
|
try {
|
||||||
|
Mono<Boolean> resetToLastCommit = Mono.just(Boolean.TRUE);
|
||||||
|
|
||||||
|
if (Boolean.TRUE.equals(resetToLastCommitRequired)) {
|
||||||
|
// instead of checking out to last branch we are first cleaning the git repo,
|
||||||
|
// then checking out to the desired branch
|
||||||
|
resetToLastCommit = gitExecutor.resetToLastCommit(baseRepoSuffixPath, branchName);
|
||||||
|
}
|
||||||
|
|
||||||
|
pageObjectMono = resetToLastCommit.map(isSwitched -> {
|
||||||
|
Path pageSuffix = Paths.get(PAGE_DIRECTORY, pageName);
|
||||||
|
Path repoPath = Paths.get(gitServiceConfig.getGitRootPath())
|
||||||
|
.resolve(baseRepoSuffixPath)
|
||||||
|
.resolve(pageSuffix);
|
||||||
|
|
||||||
|
Object pageObject =
|
||||||
|
fileOperations.readFile(repoPath.resolve(pageName + CommonConstants.JSON_EXTENSION));
|
||||||
|
|
||||||
|
return pageObject;
|
||||||
|
});
|
||||||
|
} catch (GitAPIException | IOException exception) {
|
||||||
|
pageObjectMono = Mono.error(exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
return pageObjectMono.subscribeOn(scheduler);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ public class FileOperationsCEv2Impl extends FileOperationsCEImpl implements File
|
||||||
this.observationHelper = observationHelper;
|
this.observationHelper = observationHelper;
|
||||||
}
|
}
|
||||||
|
|
||||||
@FeatureFlagged(featureFlagName = FeatureFlagEnum.release_git_cleanup_feature_enabled)
|
@FeatureFlagged(featureFlagName = FeatureFlagEnum.release_git_autocommit_feature_enabled)
|
||||||
@Override
|
@Override
|
||||||
public void saveMetadataResource(ApplicationGitReference applicationGitReference, Path baseRepo) {
|
public void saveMetadataResource(ApplicationGitReference applicationGitReference, Path baseRepo) {
|
||||||
ObjectNode metadata = objectMapper.valueToTree(applicationGitReference.getMetadata());
|
ObjectNode metadata = objectMapper.valueToTree(applicationGitReference.getMetadata());
|
||||||
|
|
@ -78,7 +78,7 @@ public class FileOperationsCEv2Impl extends FileOperationsCEImpl implements File
|
||||||
saveResource(metadata, baseRepo.resolve(CommonConstants.METADATA + CommonConstants.JSON_EXTENSION));
|
saveResource(metadata, baseRepo.resolve(CommonConstants.METADATA + CommonConstants.JSON_EXTENSION));
|
||||||
}
|
}
|
||||||
|
|
||||||
@FeatureFlagged(featureFlagName = FeatureFlagEnum.release_git_cleanup_feature_enabled)
|
@FeatureFlagged(featureFlagName = FeatureFlagEnum.release_git_autocommit_feature_enabled)
|
||||||
@Override
|
@Override
|
||||||
public void saveWidgets(JSONObject sourceEntity, String resourceName, Path path) {
|
public void saveWidgets(JSONObject sourceEntity, String resourceName, Path path) {
|
||||||
Span span = observationHelper.createSpan(GitSpan.FILE_WRITE);
|
Span span = observationHelper.createSpan(GitSpan.FILE_WRITE);
|
||||||
|
|
@ -98,7 +98,7 @@ public class FileOperationsCEv2Impl extends FileOperationsCEImpl implements File
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@FeatureFlagged(featureFlagName = FeatureFlagEnum.release_git_cleanup_feature_enabled)
|
@FeatureFlagged(featureFlagName = FeatureFlagEnum.release_git_autocommit_feature_enabled)
|
||||||
@Override
|
@Override
|
||||||
public boolean writeToFile(Object sourceEntity, Path path) throws IOException {
|
public boolean writeToFile(Object sourceEntity, Path path) throws IOException {
|
||||||
Span span = observationHelper.createSpan(GitSpan.FILE_WRITE);
|
Span span = observationHelper.createSpan(GitSpan.FILE_WRITE);
|
||||||
|
|
@ -123,7 +123,7 @@ public class FileOperationsCEv2Impl extends FileOperationsCEImpl implements File
|
||||||
* @param filePath file on which the read operation will be performed
|
* @param filePath file on which the read operation will be performed
|
||||||
* @return resource stored in the JSON file
|
* @return resource stored in the JSON file
|
||||||
*/
|
*/
|
||||||
@FeatureFlagged(featureFlagName = FeatureFlagEnum.release_git_cleanup_feature_enabled)
|
@FeatureFlagged(featureFlagName = FeatureFlagEnum.release_git_autocommit_feature_enabled)
|
||||||
@Override
|
@Override
|
||||||
public Object readFile(Path filePath) {
|
public Object readFile(Path filePath) {
|
||||||
Span span = observationHelper.createSpan(GitSpan.FILE_READ);
|
Span span = observationHelper.createSpan(GitSpan.FILE_READ);
|
||||||
|
|
@ -147,7 +147,7 @@ public class FileOperationsCEv2Impl extends FileOperationsCEImpl implements File
|
||||||
* @param directoryPath directory path for files on which read operation will be performed
|
* @param directoryPath directory path for files on which read operation will be performed
|
||||||
* @return resources stored in the directory
|
* @return resources stored in the directory
|
||||||
*/
|
*/
|
||||||
@FeatureFlagged(featureFlagName = FeatureFlagEnum.release_git_cleanup_feature_enabled)
|
@FeatureFlagged(featureFlagName = FeatureFlagEnum.release_git_autocommit_feature_enabled)
|
||||||
@Override
|
@Override
|
||||||
public Map<String, Object> readFiles(Path directoryPath, String keySuffix) {
|
public Map<String, Object> readFiles(Path directoryPath, String keySuffix) {
|
||||||
Map<String, Object> resource = new HashMap<>();
|
Map<String, Object> resource = new HashMap<>();
|
||||||
|
|
@ -168,7 +168,7 @@ public class FileOperationsCEv2Impl extends FileOperationsCEImpl implements File
|
||||||
return resource;
|
return resource;
|
||||||
}
|
}
|
||||||
|
|
||||||
@FeatureFlagged(featureFlagName = FeatureFlagEnum.release_git_cleanup_feature_enabled)
|
@FeatureFlagged(featureFlagName = FeatureFlagEnum.release_git_autocommit_feature_enabled)
|
||||||
@Override
|
@Override
|
||||||
public Integer getFileFormatVersion(Object metadata) {
|
public Integer getFileFormatVersion(Object metadata) {
|
||||||
if (metadata == null) {
|
if (metadata == null) {
|
||||||
|
|
@ -179,7 +179,7 @@ public class FileOperationsCEv2Impl extends FileOperationsCEImpl implements File
|
||||||
return fileFormatVersion;
|
return fileFormatVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
@FeatureFlagged(featureFlagName = FeatureFlagEnum.release_git_cleanup_feature_enabled)
|
@FeatureFlagged(featureFlagName = FeatureFlagEnum.release_git_autocommit_feature_enabled)
|
||||||
@Override
|
@Override
|
||||||
public JSONObject getMainContainer(Object pageJson) {
|
public JSONObject getMainContainer(Object pageJson) {
|
||||||
JsonNode pageJSON = objectMapper.valueToTree(pageJson);
|
JsonNode pageJSON = objectMapper.valueToTree(pageJson);
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,15 @@ public enum FeatureFlagEnum {
|
||||||
release_embed_hide_share_settings_enabled,
|
release_embed_hide_share_settings_enabled,
|
||||||
rollout_datasource_test_rate_limit_enabled,
|
rollout_datasource_test_rate_limit_enabled,
|
||||||
release_git_autocommit_feature_enabled,
|
release_git_autocommit_feature_enabled,
|
||||||
release_git_cleanup_feature_enabled,
|
/**
|
||||||
release_git_server_autocommit_feature_enabled,
|
* Since checking eligibility for autocommit is an expensive operation,
|
||||||
|
* We want to roll out this feature on cloud in a controlled manner.
|
||||||
|
* We could have used the autocommit flag itself, however it is on tenant level,
|
||||||
|
* and it can't be moved to user level due to its usage on non-reactive code paths.
|
||||||
|
* We would keep the main autocommit flag false on production for the version <= testing versions,
|
||||||
|
* and turn it to true for later versions
|
||||||
|
* We would remove this feature flag once the testing is complete.
|
||||||
|
*/
|
||||||
|
release_git_autocommit_eligibility_enabled,
|
||||||
// Add EE flags below this line, to avoid conflicts.
|
// Add EE flags below this line, to avoid conflicts.
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,10 +54,19 @@ public interface FileInterface {
|
||||||
* @param repoName
|
* @param repoName
|
||||||
* @param branchName
|
* @param branchName
|
||||||
* @param repoSuffixPath
|
* @param repoSuffixPath
|
||||||
|
* @param isResetToLastCommitRequired
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
Mono<Object> reconstructMetadataFromGitRepo(
|
Mono<Object> reconstructMetadataFromGitRepo(
|
||||||
String workspaceId, String defaultApplicationId, String repoName, String branchName, Path repoSuffixPath);
|
String workspaceId,
|
||||||
|
String defaultApplicationId,
|
||||||
|
String repoName,
|
||||||
|
String branchName,
|
||||||
|
Path repoSuffixPath,
|
||||||
|
Boolean isResetToLastCommitRequired);
|
||||||
|
|
||||||
|
Mono<Object> reconstructPageFromGitRepo(
|
||||||
|
String pageName, String branchName, Path repoSuffixPath, Boolean checkoutRequired);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Once the user connects the existing application to a remote repo, we will initialize the repo with Readme.md -
|
* Once the user connects the existing application to a remote repo, we will initialize the repo with Readme.md -
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,8 @@ public class GitConstantsCE {
|
||||||
public static final String GIT_PROFILE_ERROR = "Unable to find git author configuration for logged-in user. You can"
|
public static final String GIT_PROFILE_ERROR = "Unable to find git author configuration for logged-in user. You can"
|
||||||
+ " set up a git profile from the user profile section.";
|
+ " set up a git profile from the user profile section.";
|
||||||
|
|
||||||
|
public static final String RECONSTRUCT_PAGE = "reconstruct page";
|
||||||
|
|
||||||
public class GitMetricConstantsCE {
|
public class GitMetricConstantsCE {
|
||||||
public static final String CHECKOUT_REMOTE = "checkout-remote";
|
public static final String CHECKOUT_REMOTE = "checkout-remote";
|
||||||
public static final String HARD_RESET = "hard-reset";
|
public static final String HARD_RESET = "hard-reset";
|
||||||
|
|
@ -47,5 +49,7 @@ public class GitConstantsCE {
|
||||||
public static final String MERGE_BRANCH = "mergeBranch";
|
public static final String MERGE_BRANCH = "mergeBranch";
|
||||||
public static final String DELETE = "delete";
|
public static final String DELETE = "delete";
|
||||||
public static final String DISCARD = "discard";
|
public static final String DISCARD = "discard";
|
||||||
|
public static final String PAGE_DSL_VERSION = "pageDslVersion";
|
||||||
|
public static final String AUTO_COMMIT_ELIGIBILITY = "autoCommitEligibility";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,10 @@ package com.appsmith.server.controllers;
|
||||||
|
|
||||||
import com.appsmith.server.constants.Url;
|
import com.appsmith.server.constants.Url;
|
||||||
import com.appsmith.server.controllers.ce.GitControllerCE;
|
import com.appsmith.server.controllers.ce.GitControllerCE;
|
||||||
|
import com.appsmith.server.git.autocommit.AutoCommitService;
|
||||||
import com.appsmith.server.git.common.CommonGitService;
|
import com.appsmith.server.git.common.CommonGitService;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
|
@ -12,7 +14,8 @@ import org.springframework.web.bind.annotation.RestController;
|
||||||
@RequestMapping(Url.GIT_URL)
|
@RequestMapping(Url.GIT_URL)
|
||||||
public class GitController extends GitControllerCE {
|
public class GitController extends GitControllerCE {
|
||||||
|
|
||||||
public GitController(CommonGitService service) {
|
@Autowired
|
||||||
super(service);
|
public GitController(CommonGitService service, AutoCommitService autoCommitService) {
|
||||||
|
super(service, autoCommitService);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ import com.appsmith.server.domains.GitArtifactMetadata;
|
||||||
import com.appsmith.server.domains.GitAuth;
|
import com.appsmith.server.domains.GitAuth;
|
||||||
import com.appsmith.server.domains.GitProfile;
|
import com.appsmith.server.domains.GitProfile;
|
||||||
import com.appsmith.server.dtos.ApplicationImportDTO;
|
import com.appsmith.server.dtos.ApplicationImportDTO;
|
||||||
import com.appsmith.server.dtos.AutoCommitProgressDTO;
|
import com.appsmith.server.dtos.AutoCommitResponseDTO;
|
||||||
import com.appsmith.server.dtos.BranchProtectionRequestDTO;
|
import com.appsmith.server.dtos.BranchProtectionRequestDTO;
|
||||||
import com.appsmith.server.dtos.GitCommitDTO;
|
import com.appsmith.server.dtos.GitCommitDTO;
|
||||||
import com.appsmith.server.dtos.GitConnectDTO;
|
import com.appsmith.server.dtos.GitConnectDTO;
|
||||||
|
|
@ -22,6 +22,7 @@ import com.appsmith.server.dtos.GitDocsDTO;
|
||||||
import com.appsmith.server.dtos.GitMergeDTO;
|
import com.appsmith.server.dtos.GitMergeDTO;
|
||||||
import com.appsmith.server.dtos.GitPullDTO;
|
import com.appsmith.server.dtos.GitPullDTO;
|
||||||
import com.appsmith.server.dtos.ResponseDTO;
|
import com.appsmith.server.dtos.ResponseDTO;
|
||||||
|
import com.appsmith.server.git.autocommit.AutoCommitService;
|
||||||
import com.appsmith.server.git.common.CommonGitService;
|
import com.appsmith.server.git.common.CommonGitService;
|
||||||
import com.appsmith.server.helpers.GitDeployKeyGenerator;
|
import com.appsmith.server.helpers.GitDeployKeyGenerator;
|
||||||
import com.fasterxml.jackson.annotation.JsonView;
|
import com.fasterxml.jackson.annotation.JsonView;
|
||||||
|
|
@ -53,6 +54,7 @@ import java.util.Map;
|
||||||
public class GitControllerCE {
|
public class GitControllerCE {
|
||||||
|
|
||||||
private final CommonGitService service;
|
private final CommonGitService service;
|
||||||
|
private final AutoCommitService autoCommitService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* applicationId is the defaultApplicationId
|
* applicationId is the defaultApplicationId
|
||||||
|
|
@ -333,16 +335,18 @@ public class GitControllerCE {
|
||||||
|
|
||||||
@JsonView(Views.Public.class)
|
@JsonView(Views.Public.class)
|
||||||
@PostMapping("/auto-commit/app/{defaultApplicationId}")
|
@PostMapping("/auto-commit/app/{defaultApplicationId}")
|
||||||
public Mono<ResponseDTO<Boolean>> autoCommit(
|
public Mono<ResponseDTO<AutoCommitResponseDTO>> autoCommitApplication(
|
||||||
@PathVariable String defaultApplicationId, @RequestParam String branchName) {
|
@PathVariable String defaultApplicationId, @RequestHeader(name = FieldName.BRANCH_NAME) String branchName) {
|
||||||
return service.autoCommitApplication(defaultApplicationId, branchName, ArtifactType.APPLICATION)
|
return autoCommitService
|
||||||
|
.autoCommitApplication(defaultApplicationId, branchName)
|
||||||
.map(data -> new ResponseDTO<>(HttpStatus.OK.value(), data, null));
|
.map(data -> new ResponseDTO<>(HttpStatus.OK.value(), data, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonView(Views.Public.class)
|
@JsonView(Views.Public.class)
|
||||||
@GetMapping("/auto-commit/progress/app/{defaultApplicationId}")
|
@GetMapping("/auto-commit/progress/app/{defaultApplicationId}")
|
||||||
public Mono<ResponseDTO<AutoCommitProgressDTO>> getAutoCommitProgress(@PathVariable String defaultApplicationId) {
|
public Mono<ResponseDTO<AutoCommitResponseDTO>> getAutoCommitProgress(
|
||||||
return service.getAutoCommitProgress(defaultApplicationId, ArtifactType.APPLICATION)
|
@PathVariable String defaultApplicationId, @RequestHeader(name = FieldName.BRANCH_NAME) String branchName) {
|
||||||
|
return service.getAutoCommitProgress(defaultApplicationId, branchName, ArtifactType.APPLICATION)
|
||||||
.map(data -> new ResponseDTO<>(HttpStatus.OK.value(), data, null));
|
.map(data -> new ResponseDTO<>(HttpStatus.OK.value(), data, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ import com.appsmith.external.views.Git;
|
||||||
import com.appsmith.external.views.Views;
|
import com.appsmith.external.views.Views;
|
||||||
import com.appsmith.server.helpers.CollectionUtils;
|
import com.appsmith.server.helpers.CollectionUtils;
|
||||||
import com.appsmith.server.helpers.CompareDslActionDTO;
|
import com.appsmith.server.helpers.CompareDslActionDTO;
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonView;
|
import com.fasterxml.jackson.annotation.JsonView;
|
||||||
import lombok.AccessLevel;
|
import lombok.AccessLevel;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
@ -50,7 +49,6 @@ public class Layout {
|
||||||
|
|
||||||
// this attribute will be used to display errors caused white calculating allOnLoadAction
|
// this attribute will be used to display errors caused white calculating allOnLoadAction
|
||||||
// PageLoadActionsUtilCEImpl.java
|
// PageLoadActionsUtilCEImpl.java
|
||||||
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
|
|
||||||
@JsonView({Views.Public.class, Views.Export.class})
|
@JsonView({Views.Public.class, Views.Export.class})
|
||||||
List<ErrorDTO> layoutOnLoadActionErrors;
|
List<ErrorDTO> layoutOnLoadActionErrors;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -50,8 +50,11 @@ public class NewPage extends BranchAwareDomain implements Context {
|
||||||
@JsonView(Views.Internal.class)
|
@JsonView(Views.Internal.class)
|
||||||
@Override
|
@Override
|
||||||
public Layout getLayout() {
|
public Layout getLayout() {
|
||||||
|
if (this.getUnpublishedPage() == null || this.getUnpublishedPage().getLayouts() == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
List<Layout> layouts = this.getUnpublishedPage().getLayouts();
|
List<Layout> layouts = this.getUnpublishedPage().getLayouts();
|
||||||
return (layouts != null && !layouts.isEmpty()) ? layouts.get(0) : null;
|
return !layouts.isEmpty() ? layouts.get(0) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Fields extends BranchAwareDomain.Fields {
|
public static class Fields extends BranchAwareDomain.Fields {
|
||||||
|
|
|
||||||
|
|
@ -38,13 +38,13 @@ public class Theme extends BaseDomain {
|
||||||
@JsonView(Views.Public.class)
|
@JsonView(Views.Public.class)
|
||||||
String workspaceId;
|
String workspaceId;
|
||||||
|
|
||||||
@JsonView(Views.Public.class)
|
@JsonView({Views.Public.class, Git.class})
|
||||||
private Object config;
|
private Object config;
|
||||||
|
|
||||||
@JsonView(Views.Public.class)
|
@JsonView({Views.Public.class, Git.class})
|
||||||
private Object properties;
|
private Object properties;
|
||||||
|
|
||||||
@JsonView(Views.Public.class)
|
@JsonView({Views.Public.class, Git.class})
|
||||||
private Map<String, Object> stylesheet;
|
private Map<String, Object> stylesheet;
|
||||||
|
|
||||||
@JsonProperty("isSystemTheme") // manually setting property name to make sure it's compatible with Gson
|
@JsonProperty("isSystemTheme") // manually setting property name to make sure it's compatible with Gson
|
||||||
|
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
package com.appsmith.server.dtos;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
import lombok.NonNull;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
@NoArgsConstructor
|
|
||||||
public class AutoCommitProgressDTO {
|
|
||||||
@NonNull private Boolean isRunning;
|
|
||||||
|
|
||||||
// using primitive type int instead of Integer because we want to 0 as default value. Integer have default null
|
|
||||||
private int progress;
|
|
||||||
private String branchName;
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
package com.appsmith.server.dtos;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class AutoCommitResponseDTO {
|
||||||
|
|
||||||
|
public enum AutoCommitResponse {
|
||||||
|
/**
|
||||||
|
* This enum is used when an autocommit is in progress for a different branch from the branch on which
|
||||||
|
* the autocommit is requested.
|
||||||
|
*/
|
||||||
|
LOCKED,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This enum is used when an autocommit has been published.
|
||||||
|
*/
|
||||||
|
PUBLISHED,
|
||||||
|
/**
|
||||||
|
* This enum is used when an autocommit is in progress for the branch from which
|
||||||
|
* the autocommit is requested.
|
||||||
|
*/
|
||||||
|
IN_PROGRESS,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This enum is used when an autocommit has been requested however it did not fulfil the pre-requisite.
|
||||||
|
*/
|
||||||
|
REQUIRED,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This enum is used when an autocommit is requested however it's not required.
|
||||||
|
*/
|
||||||
|
IDLE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This enum is used when the app on which the autocommit is requested is a non git app.
|
||||||
|
*/
|
||||||
|
NON_GIT_APP
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enum to denote the current state of autocommit
|
||||||
|
*/
|
||||||
|
private AutoCommitResponse autoCommitResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* progress of the already-running auto-commit.
|
||||||
|
*/
|
||||||
|
private int progress;
|
||||||
|
|
||||||
|
private String branchName;
|
||||||
|
|
||||||
|
public AutoCommitResponseDTO(AutoCommitResponse autoCommitResponse) {
|
||||||
|
this.autoCommitResponse = autoCommitResponse;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,22 +1,34 @@
|
||||||
package com.appsmith.server.dtos;
|
package com.appsmith.server.dtos;
|
||||||
|
|
||||||
|
import com.appsmith.external.dtos.DslExecutableDTO;
|
||||||
import com.appsmith.server.domains.Layout;
|
import com.appsmith.server.domains.Layout;
|
||||||
import com.appsmith.server.meta.validations.FileName;
|
import com.appsmith.server.meta.validations.FileName;
|
||||||
import jakarta.validation.constraints.NotEmpty;
|
import jakarta.validation.constraints.NotEmpty;
|
||||||
import jakarta.validation.constraints.Size;
|
import jakarta.validation.constraints.Size;
|
||||||
|
import net.minidev.json.JSONObject;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
public record PageCreationDTO(
|
public record PageCreationDTO(
|
||||||
@FileName(message = "Page names must be valid file names", isNullValid = false) @Size(max = 30) String name,
|
@FileName(message = "Page names must be valid file names", isNullValid = false) @Size(max = 30) String name,
|
||||||
@NotEmpty @Size(min = 24, max = 50) String applicationId,
|
@NotEmpty @Size(min = 24, max = 50) String applicationId,
|
||||||
@NotEmpty List<Layout> layouts) {
|
@NotEmpty List<LayoutDTO> layouts) {
|
||||||
|
|
||||||
|
public record LayoutDTO(JSONObject dsl, List<Set<DslExecutableDTO>> layoutOnLoadActions) {}
|
||||||
|
|
||||||
public PageDTO toPageDTO() {
|
public PageDTO toPageDTO() {
|
||||||
final PageDTO page = new PageDTO();
|
final PageDTO page = new PageDTO();
|
||||||
page.setName(name.trim());
|
page.setName(name.trim());
|
||||||
page.setApplicationId(applicationId);
|
page.setApplicationId(applicationId);
|
||||||
page.setLayouts(layouts);
|
page.setLayouts(layouts.stream()
|
||||||
|
.map(layoutDto -> {
|
||||||
|
final Layout l = new Layout();
|
||||||
|
l.setDsl(layoutDto.dsl);
|
||||||
|
l.setLayoutOnLoadActions(layoutDto.layoutOnLoadActions);
|
||||||
|
return l;
|
||||||
|
})
|
||||||
|
.toList());
|
||||||
return page;
|
return page;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
package com.appsmith.server.dtos;
|
package com.appsmith.server.dtos;
|
||||||
|
|
||||||
import com.appsmith.server.domains.Layout;
|
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
import net.minidev.json.JSONObject;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|
@ -22,6 +22,8 @@ public class UpdateMultiplePageLayoutDTO {
|
||||||
|
|
||||||
@NotNull private String layoutId;
|
@NotNull private String layoutId;
|
||||||
|
|
||||||
private Layout layout;
|
private LayoutDTO layout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public record LayoutDTO(JSONObject dsl) {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
package com.appsmith.server.git;
|
package com.appsmith.server.git.autocommit;
|
||||||
|
|
||||||
public interface AutoCommitEventHandler extends AutoCommitEventHandlerCE {}
|
public interface AutoCommitEventHandler extends AutoCommitEventHandlerCE {}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package com.appsmith.server.git;
|
package com.appsmith.server.git.autocommit;
|
||||||
|
|
||||||
import com.appsmith.server.events.AutoCommitEvent;
|
import com.appsmith.server.events.AutoCommitEvent;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package com.appsmith.server.git;
|
package com.appsmith.server.git.autocommit;
|
||||||
|
|
||||||
import com.appsmith.external.constants.AnalyticsEvents;
|
import com.appsmith.external.constants.AnalyticsEvents;
|
||||||
import com.appsmith.external.dtos.ModifiedResources;
|
import com.appsmith.external.dtos.ModifiedResources;
|
||||||
|
|
@ -13,6 +13,7 @@ import com.appsmith.server.dtos.ApplicationJson;
|
||||||
import com.appsmith.server.events.AutoCommitEvent;
|
import com.appsmith.server.events.AutoCommitEvent;
|
||||||
import com.appsmith.server.exceptions.AppsmithError;
|
import com.appsmith.server.exceptions.AppsmithError;
|
||||||
import com.appsmith.server.exceptions.AppsmithException;
|
import com.appsmith.server.exceptions.AppsmithException;
|
||||||
|
import com.appsmith.server.git.GitRedisUtils;
|
||||||
import com.appsmith.server.helpers.CollectionUtils;
|
import com.appsmith.server.helpers.CollectionUtils;
|
||||||
import com.appsmith.server.helpers.CommonGitFileUtils;
|
import com.appsmith.server.helpers.CommonGitFileUtils;
|
||||||
import com.appsmith.server.helpers.DSLMigrationUtils;
|
import com.appsmith.server.helpers.DSLMigrationUtils;
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
package com.appsmith.server.git;
|
package com.appsmith.server.git.autocommit;
|
||||||
|
|
||||||
import com.appsmith.external.git.GitExecutor;
|
import com.appsmith.external.git.GitExecutor;
|
||||||
import com.appsmith.server.configurations.ProjectProperties;
|
import com.appsmith.server.configurations.ProjectProperties;
|
||||||
|
import com.appsmith.server.git.GitRedisUtils;
|
||||||
import com.appsmith.server.helpers.CommonGitFileUtils;
|
import com.appsmith.server.helpers.CommonGitFileUtils;
|
||||||
import com.appsmith.server.helpers.DSLMigrationUtils;
|
import com.appsmith.server.helpers.DSLMigrationUtils;
|
||||||
import com.appsmith.server.helpers.RedisUtils;
|
import com.appsmith.server.helpers.RedisUtils;
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
package com.appsmith.server.git.autocommit;
|
||||||
|
|
||||||
|
public interface AutoCommitService extends AutoCommitServiceCE {}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
package com.appsmith.server.git.autocommit;
|
||||||
|
|
||||||
|
import com.appsmith.server.dtos.AutoCommitResponseDTO;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
public interface AutoCommitServiceCE {
|
||||||
|
|
||||||
|
Mono<AutoCommitResponseDTO> autoCommitApplication(String defaultApplicationId, String branchName);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,147 @@
|
||||||
|
package com.appsmith.server.git.autocommit;
|
||||||
|
|
||||||
|
import com.appsmith.server.applications.base.ApplicationService;
|
||||||
|
import com.appsmith.server.constants.FieldName;
|
||||||
|
import com.appsmith.server.domains.Application;
|
||||||
|
import com.appsmith.server.domains.ApplicationMode;
|
||||||
|
import com.appsmith.server.domains.GitArtifactMetadata;
|
||||||
|
import com.appsmith.server.dtos.AutoCommitResponseDTO;
|
||||||
|
import com.appsmith.server.dtos.AutoCommitTriggerDTO;
|
||||||
|
import com.appsmith.server.dtos.PageDTO;
|
||||||
|
import com.appsmith.server.exceptions.AppsmithError;
|
||||||
|
import com.appsmith.server.exceptions.AppsmithException;
|
||||||
|
import com.appsmith.server.git.autocommit.helpers.AutoCommitEligibilityHelper;
|
||||||
|
import com.appsmith.server.git.autocommit.helpers.GitAutoCommitHelperImpl;
|
||||||
|
import com.appsmith.server.newpages.base.NewPageService;
|
||||||
|
import com.appsmith.server.solutions.ApplicationPermission;
|
||||||
|
import com.appsmith.server.solutions.PagePermission;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static com.appsmith.server.dtos.AutoCommitResponseDTO.AutoCommitResponse.IDLE;
|
||||||
|
import static com.appsmith.server.dtos.AutoCommitResponseDTO.AutoCommitResponse.IN_PROGRESS;
|
||||||
|
import static com.appsmith.server.dtos.AutoCommitResponseDTO.AutoCommitResponse.LOCKED;
|
||||||
|
import static com.appsmith.server.dtos.AutoCommitResponseDTO.AutoCommitResponse.NON_GIT_APP;
|
||||||
|
import static com.appsmith.server.dtos.AutoCommitResponseDTO.AutoCommitResponse.PUBLISHED;
|
||||||
|
import static com.appsmith.server.dtos.AutoCommitResponseDTO.AutoCommitResponse.REQUIRED;
|
||||||
|
import static java.lang.Boolean.TRUE;
|
||||||
|
import static org.springframework.util.StringUtils.hasText;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class AutoCommitServiceCEImpl implements AutoCommitServiceCE {
|
||||||
|
|
||||||
|
private final ApplicationService applicationService;
|
||||||
|
private final ApplicationPermission applicationPermission;
|
||||||
|
|
||||||
|
private final NewPageService newPageService;
|
||||||
|
private final PagePermission pagePermission;
|
||||||
|
|
||||||
|
private final AutoCommitEligibilityHelper autoCommitEligibilityHelper;
|
||||||
|
private final GitAutoCommitHelperImpl gitAutoCommitHelper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Mono<AutoCommitResponseDTO> autoCommitApplication(String defaultApplicationId, String branchName) {
|
||||||
|
|
||||||
|
if (!hasText(defaultApplicationId)) {
|
||||||
|
return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.APPLICATION_ID));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasText(branchName)) {
|
||||||
|
return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.BRANCH_NAME));
|
||||||
|
}
|
||||||
|
|
||||||
|
Mono<Application> applicationMonoCached = applicationService
|
||||||
|
.findByBranchNameAndDefaultApplicationId(
|
||||||
|
branchName, defaultApplicationId, applicationPermission.getEditPermission())
|
||||||
|
.switchIfEmpty(Mono.error(new AppsmithException(
|
||||||
|
AppsmithError.NO_RESOURCE_FOUND, FieldName.APPLICATION, defaultApplicationId)))
|
||||||
|
.cache();
|
||||||
|
|
||||||
|
// A page-dto which must exist in the git file system is required,
|
||||||
|
// this existence can be guaranteed by using application mode = published
|
||||||
|
// in appsmith git system an application could be only published if it's commited, converse is also true,
|
||||||
|
// hence a published page would definitely be present in git fs.
|
||||||
|
Mono<PageDTO> pageDTOMono = applicationMonoCached
|
||||||
|
.flatMap(application -> newPageService
|
||||||
|
.findByApplicationIdAndApplicationMode(
|
||||||
|
application.getId(), pagePermission.getEditPermission(), ApplicationMode.PUBLISHED)
|
||||||
|
.next())
|
||||||
|
.switchIfEmpty(Mono.error(
|
||||||
|
new AppsmithException(AppsmithError.NO_RESOURCE_FOUND, FieldName.PAGE, defaultApplicationId)));
|
||||||
|
|
||||||
|
return applicationMonoCached.zipWith(pageDTOMono).flatMap(tuple2 -> {
|
||||||
|
Application branchedApplication = tuple2.getT1();
|
||||||
|
PageDTO pageDTO = tuple2.getT2();
|
||||||
|
|
||||||
|
AutoCommitResponseDTO autoCommitResponseDTO = new AutoCommitResponseDTO();
|
||||||
|
|
||||||
|
if (branchedApplication.getGitApplicationMetadata() == null) {
|
||||||
|
autoCommitResponseDTO.setAutoCommitResponse(NON_GIT_APP);
|
||||||
|
return Mono.just(autoCommitResponseDTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
String workspaceId = branchedApplication.getWorkspaceId();
|
||||||
|
GitArtifactMetadata gitArtifactMetadata = branchedApplication.getGitArtifactMetadata();
|
||||||
|
|
||||||
|
Mono<AutoCommitTriggerDTO> isAutoCommitRequiredMono =
|
||||||
|
autoCommitEligibilityHelper.isAutoCommitRequired(workspaceId, gitArtifactMetadata, pageDTO);
|
||||||
|
|
||||||
|
Mono<AutoCommitResponseDTO> autoCommitProgressDTOMono =
|
||||||
|
gitAutoCommitHelper.getAutoCommitProgress(defaultApplicationId, branchName);
|
||||||
|
|
||||||
|
return autoCommitProgressDTOMono.flatMap(autoCommitProgressDTO -> {
|
||||||
|
if (Set.of(LOCKED, IN_PROGRESS).contains(autoCommitProgressDTO.getAutoCommitResponse())) {
|
||||||
|
log.info(
|
||||||
|
"application with id: {}, has requested auto-commit for branch name: {}, however an event for branch name: {} is already in progress",
|
||||||
|
defaultApplicationId,
|
||||||
|
branchName,
|
||||||
|
autoCommitProgressDTO.getBranchName());
|
||||||
|
autoCommitResponseDTO.setAutoCommitResponse(autoCommitProgressDTO.getAutoCommitResponse());
|
||||||
|
autoCommitResponseDTO.setProgress(autoCommitProgressDTO.getProgress());
|
||||||
|
autoCommitResponseDTO.setBranchName(autoCommitProgressDTO.getBranchName());
|
||||||
|
return Mono.just(autoCommitResponseDTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
return isAutoCommitRequiredMono.flatMap(autoCommitTriggerDTO -> {
|
||||||
|
if (!Boolean.TRUE.equals(autoCommitTriggerDTO.getIsAutoCommitRequired())) {
|
||||||
|
log.info(
|
||||||
|
"application with id: {}, and branch name: {} is not eligible for autocommit",
|
||||||
|
defaultApplicationId,
|
||||||
|
branchName);
|
||||||
|
autoCommitResponseDTO.setAutoCommitResponse(IDLE);
|
||||||
|
return Mono.just(autoCommitResponseDTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Autocommit can be started
|
||||||
|
log.info(
|
||||||
|
"application with id: {}, and branch name: {} is eligible for autocommit",
|
||||||
|
defaultApplicationId,
|
||||||
|
branchName);
|
||||||
|
return gitAutoCommitHelper
|
||||||
|
.publishAutoCommitEvent(autoCommitTriggerDTO, defaultApplicationId, branchName)
|
||||||
|
.map(isEventPublished -> {
|
||||||
|
if (TRUE.equals(isEventPublished)) {
|
||||||
|
log.info(
|
||||||
|
"autocommit event for application with id: {}, and branch name: {} is published",
|
||||||
|
defaultApplicationId,
|
||||||
|
branchName);
|
||||||
|
autoCommitResponseDTO.setAutoCommitResponse(PUBLISHED);
|
||||||
|
return autoCommitResponseDTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info(
|
||||||
|
"application with id: {}, and branch name: {} does not fulfil the prerequisite for autocommit",
|
||||||
|
defaultApplicationId,
|
||||||
|
branchName);
|
||||||
|
autoCommitResponseDTO.setAutoCommitResponse(REQUIRED);
|
||||||
|
return autoCommitResponseDTO;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
package com.appsmith.server.git.autocommit;
|
||||||
|
|
||||||
|
import com.appsmith.server.applications.base.ApplicationService;
|
||||||
|
import com.appsmith.server.git.autocommit.helpers.AutoCommitEligibilityHelper;
|
||||||
|
import com.appsmith.server.git.autocommit.helpers.GitAutoCommitHelperImpl;
|
||||||
|
import com.appsmith.server.newpages.base.NewPageService;
|
||||||
|
import com.appsmith.server.solutions.ApplicationPermission;
|
||||||
|
import com.appsmith.server.solutions.PagePermission;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class AutoCommitServiceImpl extends AutoCommitServiceCEImpl implements AutoCommitService {
|
||||||
|
|
||||||
|
public AutoCommitServiceImpl(
|
||||||
|
ApplicationService applicationService,
|
||||||
|
ApplicationPermission applicationPermission,
|
||||||
|
NewPageService newPageService,
|
||||||
|
PagePermission pagePermission,
|
||||||
|
AutoCommitEligibilityHelper autoCommitEligibilityHelper,
|
||||||
|
GitAutoCommitHelperImpl gitAutoCommitHelper) {
|
||||||
|
super(
|
||||||
|
applicationService,
|
||||||
|
applicationPermission,
|
||||||
|
newPageService,
|
||||||
|
pagePermission,
|
||||||
|
autoCommitEligibilityHelper,
|
||||||
|
gitAutoCommitHelper);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -11,6 +11,8 @@ public interface AutoCommitEligibilityHelper {
|
||||||
|
|
||||||
Mono<Boolean> isClientMigrationRequired(PageDTO pageDTO);
|
Mono<Boolean> isClientMigrationRequired(PageDTO pageDTO);
|
||||||
|
|
||||||
|
Mono<Boolean> isClientMigrationRequiredFSOps(String workspaceId, GitArtifactMetadata gitMetadata, PageDTO pageDTO);
|
||||||
|
|
||||||
Mono<AutoCommitTriggerDTO> isAutoCommitRequired(
|
Mono<AutoCommitTriggerDTO> isAutoCommitRequired(
|
||||||
String workspaceId, GitArtifactMetadata gitArtifactMetadata, PageDTO pageDTO);
|
String workspaceId, GitArtifactMetadata gitArtifactMetadata, PageDTO pageDTO);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,12 @@ public class AutoCommitEligibilityHelperFallbackImpl implements AutoCommitEligib
|
||||||
return Mono.just(FALSE);
|
return Mono.just(FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Mono<Boolean> isClientMigrationRequiredFSOps(
|
||||||
|
String workspaceId, GitArtifactMetadata gitMetadata, PageDTO pageDTO) {
|
||||||
|
return Mono.just(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<AutoCommitTriggerDTO> isAutoCommitRequired(
|
public Mono<AutoCommitTriggerDTO> isAutoCommitRequired(
|
||||||
String workspaceId, GitArtifactMetadata gitArtifactMetadata, PageDTO pageDTO) {
|
String workspaceId, GitArtifactMetadata gitArtifactMetadata, PageDTO pageDTO) {
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,6 @@ package com.appsmith.server.git.autocommit.helpers;
|
||||||
|
|
||||||
import com.appsmith.external.annotations.FeatureFlagged;
|
import com.appsmith.external.annotations.FeatureFlagged;
|
||||||
import com.appsmith.external.enums.FeatureFlagEnum;
|
import com.appsmith.external.enums.FeatureFlagEnum;
|
||||||
import com.appsmith.external.git.constants.GitConstants.GitCommandConstants;
|
|
||||||
import com.appsmith.server.constants.ArtifactType;
|
|
||||||
import com.appsmith.server.domains.GitArtifactMetadata;
|
import com.appsmith.server.domains.GitArtifactMetadata;
|
||||||
import com.appsmith.server.domains.Layout;
|
import com.appsmith.server.domains.Layout;
|
||||||
import com.appsmith.server.dtos.AutoCommitTriggerDTO;
|
import com.appsmith.server.dtos.AutoCommitTriggerDTO;
|
||||||
|
|
@ -20,6 +18,8 @@ import org.springframework.context.annotation.Primary;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
import static com.appsmith.external.git.constants.GitConstants.GitCommandConstants.AUTO_COMMIT_ELIGIBILITY;
|
||||||
|
import static com.appsmith.server.constants.ArtifactType.APPLICATION;
|
||||||
import static java.lang.Boolean.FALSE;
|
import static java.lang.Boolean.FALSE;
|
||||||
import static java.lang.Boolean.TRUE;
|
import static java.lang.Boolean.TRUE;
|
||||||
|
|
||||||
|
|
@ -35,16 +35,14 @@ public class AutoCommitEligibilityHelperImpl extends AutoCommitEligibilityHelper
|
||||||
private final GitRedisUtils gitRedisUtils;
|
private final GitRedisUtils gitRedisUtils;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@FeatureFlagged(featureFlagName = FeatureFlagEnum.release_git_server_autocommit_feature_enabled)
|
@FeatureFlagged(featureFlagName = FeatureFlagEnum.release_git_autocommit_eligibility_enabled)
|
||||||
public Mono<Boolean> isServerAutoCommitRequired(String workspaceId, GitArtifactMetadata gitMetadata) {
|
public Mono<Boolean> isServerAutoCommitRequired(String workspaceId, GitArtifactMetadata gitMetadata) {
|
||||||
|
|
||||||
String defaultApplicationId = gitMetadata.getDefaultArtifactId();
|
String defaultApplicationId = gitMetadata.getDefaultArtifactId();
|
||||||
String branchName = gitMetadata.getBranchName();
|
String branchName = gitMetadata.getBranchName();
|
||||||
String repoName = gitMetadata.getRepoName();
|
|
||||||
|
|
||||||
Mono<Boolean> isServerMigrationRequiredMonoCached = commonGitFileUtils
|
Mono<Boolean> isServerMigrationRequiredMonoCached = commonGitFileUtils
|
||||||
.getMetadataServerSchemaMigrationVersion(
|
.getMetadataServerSchemaMigrationVersion(workspaceId, gitMetadata, FALSE, APPLICATION)
|
||||||
workspaceId, defaultApplicationId, repoName, branchName, ArtifactType.APPLICATION)
|
|
||||||
.map(serverSchemaVersion -> {
|
.map(serverSchemaVersion -> {
|
||||||
log.info(
|
log.info(
|
||||||
"server schema for application id : {} and branch name : {} is : {}",
|
"server schema for application id : {} and branch name : {} is : {}",
|
||||||
|
|
@ -56,22 +54,27 @@ public class AutoCommitEligibilityHelperImpl extends AutoCommitEligibilityHelper
|
||||||
.defaultIfEmpty(FALSE)
|
.defaultIfEmpty(FALSE)
|
||||||
.cache();
|
.cache();
|
||||||
|
|
||||||
return Mono.defer(() -> gitRedisUtils.addFileLock(defaultApplicationId, GitCommandConstants.METADATA, false))
|
return Mono.defer(() -> isServerMigrationRequiredMonoCached).onErrorResume(error -> {
|
||||||
.then(Mono.defer(() -> isServerMigrationRequiredMonoCached))
|
|
||||||
.then(Mono.defer(() -> gitRedisUtils.releaseFileLock(defaultApplicationId)))
|
|
||||||
.then(Mono.defer(() -> isServerMigrationRequiredMonoCached))
|
|
||||||
.onErrorResume(error -> {
|
|
||||||
log.debug(
|
log.debug(
|
||||||
"error while retrieving the metadata for defaultApplicationId : {}, branchName : {} error : {}",
|
"error while retrieving the metadata for defaultApplicationId : {}, branchName : {} error : {}",
|
||||||
defaultApplicationId,
|
defaultApplicationId,
|
||||||
branchName,
|
branchName,
|
||||||
error.getMessage());
|
error.getMessage());
|
||||||
return gitRedisUtils.releaseFileLock(defaultApplicationId).then(Mono.just(FALSE));
|
return Mono.just(FALSE);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method has been deprecated and is not being used anymore.
|
||||||
|
* It's been deprecated because, we are using the absolute source of truth
|
||||||
|
* that is the version key in the layout.
|
||||||
|
* /pages/<Page-Name>.json in file system for the finding out the Dsl in layout.
|
||||||
|
* @param pageDTO : pageDTO for the page for which migration was required.
|
||||||
|
* @return : a boolean whether the client requires a migration or not
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
@FeatureFlagged(featureFlagName = FeatureFlagEnum.release_git_autocommit_feature_enabled)
|
@Deprecated
|
||||||
|
@FeatureFlagged(featureFlagName = FeatureFlagEnum.release_git_autocommit_eligibility_enabled)
|
||||||
public Mono<Boolean> isClientMigrationRequired(PageDTO pageDTO) {
|
public Mono<Boolean> isClientMigrationRequired(PageDTO pageDTO) {
|
||||||
return dslMigrationUtils
|
return dslMigrationUtils
|
||||||
.getLatestDslVersion()
|
.getLatestDslVersion()
|
||||||
|
|
@ -91,26 +94,71 @@ public class AutoCommitEligibilityHelperImpl extends AutoCommitEligibilityHelper
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@FeatureFlagged(featureFlagName = FeatureFlagEnum.release_git_autocommit_feature_enabled)
|
@FeatureFlagged(featureFlagName = FeatureFlagEnum.release_git_autocommit_eligibility_enabled)
|
||||||
|
public Mono<Boolean> isClientMigrationRequiredFSOps(
|
||||||
|
String workspaceId, GitArtifactMetadata gitMetadata, PageDTO pageDTO) {
|
||||||
|
String defaultApplicationId = gitMetadata.getDefaultArtifactId();
|
||||||
|
String branchName = gitMetadata.getBranchName();
|
||||||
|
|
||||||
|
Mono<Integer> latestDslVersionMono = dslMigrationUtils.getLatestDslVersion();
|
||||||
|
|
||||||
|
Mono<Boolean> isClientMigrationRequired = latestDslVersionMono
|
||||||
|
.zipWith(commonGitFileUtils.getPageDslVersionNumber(
|
||||||
|
workspaceId, gitMetadata, pageDTO, TRUE, APPLICATION))
|
||||||
|
.map(tuple2 -> {
|
||||||
|
Integer latestDslVersion = tuple2.getT1();
|
||||||
|
org.json.JSONObject pageDSL = tuple2.getT2();
|
||||||
|
log.info("page dsl retrieved from file system");
|
||||||
|
return GitUtils.isMigrationRequired(pageDSL, latestDslVersion);
|
||||||
|
})
|
||||||
|
.defaultIfEmpty(FALSE)
|
||||||
|
.cache();
|
||||||
|
|
||||||
|
return Mono.defer(() -> isClientMigrationRequired).onErrorResume(error -> {
|
||||||
|
log.debug(
|
||||||
|
"error while fetching the dsl version for page : {}, defaultApplicationId : {}, branchName : {} error : {}",
|
||||||
|
pageDTO.getName(),
|
||||||
|
defaultApplicationId,
|
||||||
|
branchName,
|
||||||
|
error.getMessage());
|
||||||
|
return Mono.just(FALSE);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@FeatureFlagged(featureFlagName = FeatureFlagEnum.release_git_autocommit_eligibility_enabled)
|
||||||
public Mono<AutoCommitTriggerDTO> isAutoCommitRequired(
|
public Mono<AutoCommitTriggerDTO> isAutoCommitRequired(
|
||||||
String workspaceId, GitArtifactMetadata gitArtifactMetadata, PageDTO pageDTO) {
|
String workspaceId, GitArtifactMetadata gitArtifactMetadata, PageDTO pageDTO) {
|
||||||
|
|
||||||
|
String defaultApplicationId = gitArtifactMetadata.getDefaultApplicationId();
|
||||||
|
|
||||||
Mono<Boolean> isClientAutocommitRequiredMono =
|
Mono<Boolean> isClientAutocommitRequiredMono =
|
||||||
isClientMigrationRequired(pageDTO).defaultIfEmpty(FALSE);
|
isClientMigrationRequiredFSOps(workspaceId, gitArtifactMetadata, pageDTO);
|
||||||
|
|
||||||
Mono<Boolean> isServerAutocommitRequiredMono = isServerAutoCommitRequired(workspaceId, gitArtifactMetadata);
|
Mono<Boolean> isServerAutocommitRequiredMono =
|
||||||
|
isServerAutoCommitRequired(workspaceId, gitArtifactMetadata).cache();
|
||||||
|
|
||||||
return isServerAutocommitRequiredMono
|
return Mono.defer(() -> gitRedisUtils.addFileLock(defaultApplicationId, AUTO_COMMIT_ELIGIBILITY))
|
||||||
.zipWith(isClientAutocommitRequiredMono)
|
.then(isClientAutocommitRequiredMono.zipWhen(clientFlag -> {
|
||||||
.map(tuple2 -> {
|
Mono<Boolean> serverFlagMono = isServerAutocommitRequiredMono;
|
||||||
Boolean serverFlag = tuple2.getT1();
|
// if client is required to migrate then,
|
||||||
Boolean clientFlag = tuple2.getT2();
|
// there is no requirement to fetch server flag as server is subset of client migration.
|
||||||
|
if (Boolean.TRUE.equals(clientFlag)) {
|
||||||
|
serverFlagMono = Mono.just(TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return serverFlagMono;
|
||||||
|
}))
|
||||||
|
.flatMap(tuple2 -> {
|
||||||
|
Boolean clientFlag = tuple2.getT1();
|
||||||
|
Boolean serverFlag = tuple2.getT2();
|
||||||
|
|
||||||
AutoCommitTriggerDTO autoCommitTriggerDTO = new AutoCommitTriggerDTO();
|
AutoCommitTriggerDTO autoCommitTriggerDTO = new AutoCommitTriggerDTO();
|
||||||
autoCommitTriggerDTO.setIsClientAutoCommitRequired(TRUE.equals(clientFlag));
|
autoCommitTriggerDTO.setIsClientAutoCommitRequired(TRUE.equals(clientFlag));
|
||||||
autoCommitTriggerDTO.setIsServerAutoCommitRequired(TRUE.equals(serverFlag));
|
autoCommitTriggerDTO.setIsServerAutoCommitRequired(TRUE.equals(serverFlag));
|
||||||
autoCommitTriggerDTO.setIsAutoCommitRequired((TRUE.equals(serverFlag) || TRUE.equals(clientFlag)));
|
autoCommitTriggerDTO.setIsAutoCommitRequired((TRUE.equals(serverFlag) || TRUE.equals(clientFlag)));
|
||||||
return autoCommitTriggerDTO;
|
|
||||||
|
return gitRedisUtils.releaseFileLock(defaultApplicationId).then(Mono.just(autoCommitTriggerDTO));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
package com.appsmith.server.git.autocommit.helpers;
|
package com.appsmith.server.git.autocommit.helpers;
|
||||||
|
|
||||||
import com.appsmith.server.dtos.AutoCommitProgressDTO;
|
import com.appsmith.server.dtos.AutoCommitResponseDTO;
|
||||||
import com.appsmith.server.dtos.AutoCommitTriggerDTO;
|
import com.appsmith.server.dtos.AutoCommitTriggerDTO;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
public interface GitAutoCommitHelper {
|
public interface GitAutoCommitHelper {
|
||||||
|
|
||||||
Mono<AutoCommitProgressDTO> getAutoCommitProgress(String applicationId);
|
Mono<AutoCommitResponseDTO> getAutoCommitProgress(String defaultApplicationId, String branchName);
|
||||||
|
|
||||||
Mono<Boolean> autoCommitClientMigration(String defaultApplicationId, String branchName);
|
Mono<Boolean> autoCommitClientMigration(String defaultApplicationId, String branchName);
|
||||||
|
|
||||||
Mono<Boolean> autoCommitServerMigration(String defaultApplicationId, String branchName);
|
Mono<Boolean> autoCommitServerMigration(String defaultApplicationId, String branchName);
|
||||||
|
|
||||||
Mono<Boolean> autoCommitApplication(
|
Mono<Boolean> publishAutoCommitEvent(
|
||||||
AutoCommitTriggerDTO autoCommitTriggerDTO, String defaultApplicationId, String branchName);
|
AutoCommitTriggerDTO autoCommitTriggerDTO, String defaultApplicationId, String branchName);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package com.appsmith.server.git.autocommit.helpers;
|
package com.appsmith.server.git.autocommit.helpers;
|
||||||
|
|
||||||
import com.appsmith.server.dtos.AutoCommitProgressDTO;
|
import com.appsmith.server.dtos.AutoCommitResponseDTO;
|
||||||
import com.appsmith.server.dtos.AutoCommitTriggerDTO;
|
import com.appsmith.server.dtos.AutoCommitTriggerDTO;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
@ -19,12 +19,12 @@ public class GitAutoCommitHelperFallbackImpl implements GitAutoCommitHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<AutoCommitProgressDTO> getAutoCommitProgress(String applicationId) {
|
public Mono<AutoCommitResponseDTO> getAutoCommitProgress(String defaultApplicationId, String branchName) {
|
||||||
return Mono.empty();
|
return Mono.just(new AutoCommitResponseDTO(AutoCommitResponseDTO.AutoCommitResponse.IDLE));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<Boolean> autoCommitApplication(
|
public Mono<Boolean> publishAutoCommitEvent(
|
||||||
AutoCommitTriggerDTO autoCommitTriggerDTO, String defaultApplicationId, String branchName) {
|
AutoCommitTriggerDTO autoCommitTriggerDTO, String defaultApplicationId, String branchName) {
|
||||||
return Mono.just(Boolean.FALSE);
|
return Mono.just(Boolean.FALSE);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,10 @@ import com.appsmith.server.applications.base.ApplicationService;
|
||||||
import com.appsmith.server.domains.Application;
|
import com.appsmith.server.domains.Application;
|
||||||
import com.appsmith.server.domains.GitArtifactMetadata;
|
import com.appsmith.server.domains.GitArtifactMetadata;
|
||||||
import com.appsmith.server.domains.GitProfile;
|
import com.appsmith.server.domains.GitProfile;
|
||||||
import com.appsmith.server.dtos.AutoCommitProgressDTO;
|
import com.appsmith.server.dtos.AutoCommitResponseDTO;
|
||||||
import com.appsmith.server.dtos.AutoCommitTriggerDTO;
|
import com.appsmith.server.dtos.AutoCommitTriggerDTO;
|
||||||
import com.appsmith.server.events.AutoCommitEvent;
|
import com.appsmith.server.events.AutoCommitEvent;
|
||||||
import com.appsmith.server.git.AutoCommitEventHandler;
|
import com.appsmith.server.git.autocommit.AutoCommitEventHandler;
|
||||||
import com.appsmith.server.git.common.CommonGitService;
|
import com.appsmith.server.git.common.CommonGitService;
|
||||||
import com.appsmith.server.helpers.GitPrivateRepoHelper;
|
import com.appsmith.server.helpers.GitPrivateRepoHelper;
|
||||||
import com.appsmith.server.helpers.GitUtils;
|
import com.appsmith.server.helpers.GitUtils;
|
||||||
|
|
@ -23,6 +23,10 @@ import org.springframework.stereotype.Service;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
import static com.appsmith.server.dtos.AutoCommitResponseDTO.AutoCommitResponse.IDLE;
|
||||||
|
import static com.appsmith.server.dtos.AutoCommitResponseDTO.AutoCommitResponse.IN_PROGRESS;
|
||||||
|
import static com.appsmith.server.dtos.AutoCommitResponseDTO.AutoCommitResponse.LOCKED;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Primary
|
@Primary
|
||||||
@Service
|
@Service
|
||||||
|
|
@ -53,17 +57,26 @@ public class GitAutoCommitHelperImpl extends GitAutoCommitHelperFallbackImpl imp
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<AutoCommitProgressDTO> getAutoCommitProgress(String applicationId) {
|
public Mono<AutoCommitResponseDTO> getAutoCommitProgress(String defaultApplicationId, String branchName) {
|
||||||
return redisUtils
|
return redisUtils
|
||||||
.getRunningAutoCommitBranchName(applicationId)
|
.getRunningAutoCommitBranchName(defaultApplicationId)
|
||||||
.zipWith(redisUtils.getAutoCommitProgress(applicationId))
|
.zipWith(redisUtils.getAutoCommitProgress(defaultApplicationId))
|
||||||
.map(tuple2 -> {
|
.map(tuple2 -> {
|
||||||
AutoCommitProgressDTO autoCommitProgressDTO = new AutoCommitProgressDTO(Boolean.TRUE);
|
String branchNameFromRedis = tuple2.getT1();
|
||||||
autoCommitProgressDTO.setBranchName(tuple2.getT1());
|
|
||||||
autoCommitProgressDTO.setProgress(tuple2.getT2());
|
AutoCommitResponseDTO autoCommitResponseDTO = new AutoCommitResponseDTO();
|
||||||
return autoCommitProgressDTO;
|
autoCommitResponseDTO.setProgress(tuple2.getT2());
|
||||||
|
autoCommitResponseDTO.setBranchName(branchNameFromRedis);
|
||||||
|
|
||||||
|
if (branchNameFromRedis.equals(branchName)) {
|
||||||
|
autoCommitResponseDTO.setAutoCommitResponse(IN_PROGRESS);
|
||||||
|
} else {
|
||||||
|
autoCommitResponseDTO.setAutoCommitResponse(LOCKED);
|
||||||
|
}
|
||||||
|
|
||||||
|
return autoCommitResponseDTO;
|
||||||
})
|
})
|
||||||
.defaultIfEmpty(new AutoCommitProgressDTO(Boolean.FALSE));
|
.defaultIfEmpty(new AutoCommitResponseDTO(IDLE));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -114,7 +127,7 @@ public class GitAutoCommitHelperImpl extends GitAutoCommitHelperFallbackImpl imp
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@FeatureFlagged(featureFlagName = FeatureFlagEnum.release_git_server_autocommit_feature_enabled)
|
@FeatureFlagged(featureFlagName = FeatureFlagEnum.release_git_autocommit_feature_enabled)
|
||||||
public Mono<Boolean> autoCommitServerMigration(String defaultApplicationId, String branchName) {
|
public Mono<Boolean> autoCommitServerMigration(String defaultApplicationId, String branchName) {
|
||||||
return autoCommitApplication(defaultApplicationId, branchName, Boolean.FALSE);
|
return autoCommitApplication(defaultApplicationId, branchName, Boolean.FALSE);
|
||||||
}
|
}
|
||||||
|
|
@ -203,7 +216,7 @@ public class GitAutoCommitHelperImpl extends GitAutoCommitHelperFallbackImpl imp
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public Mono<Boolean> autoCommitApplication(
|
public Mono<Boolean> publishAutoCommitEvent(
|
||||||
AutoCommitTriggerDTO autoCommitTriggerDTO, String defaultApplicationId, String branchName) {
|
AutoCommitTriggerDTO autoCommitTriggerDTO, String defaultApplicationId, String branchName) {
|
||||||
|
|
||||||
if (!Boolean.TRUE.equals(autoCommitTriggerDTO.getIsAutoCommitRequired())) {
|
if (!Boolean.TRUE.equals(autoCommitTriggerDTO.getIsAutoCommitRequired())) {
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import com.appsmith.server.domains.GitArtifactMetadata;
|
||||||
import com.appsmith.server.domains.GitAuth;
|
import com.appsmith.server.domains.GitAuth;
|
||||||
import com.appsmith.server.domains.GitProfile;
|
import com.appsmith.server.domains.GitProfile;
|
||||||
import com.appsmith.server.dtos.ArtifactImportDTO;
|
import com.appsmith.server.dtos.ArtifactImportDTO;
|
||||||
import com.appsmith.server.dtos.AutoCommitProgressDTO;
|
import com.appsmith.server.dtos.AutoCommitResponseDTO;
|
||||||
import com.appsmith.server.dtos.GitCommitDTO;
|
import com.appsmith.server.dtos.GitCommitDTO;
|
||||||
import com.appsmith.server.dtos.GitConnectDTO;
|
import com.appsmith.server.dtos.GitConnectDTO;
|
||||||
import com.appsmith.server.dtos.GitDocsDTO;
|
import com.appsmith.server.dtos.GitDocsDTO;
|
||||||
|
|
@ -105,7 +105,8 @@ public interface CommonGitServiceCE {
|
||||||
|
|
||||||
Mono<Boolean> toggleAutoCommitEnabled(String defaultArtifactId, ArtifactType artifactType);
|
Mono<Boolean> toggleAutoCommitEnabled(String defaultArtifactId, ArtifactType artifactType);
|
||||||
|
|
||||||
Mono<AutoCommitProgressDTO> getAutoCommitProgress(String applicationId, ArtifactType artifactType);
|
Mono<AutoCommitResponseDTO> getAutoCommitProgress(
|
||||||
|
String applicationId, String branchName, ArtifactType artifactType);
|
||||||
|
|
||||||
Mono<Boolean> autoCommitApplication(String defaultApplicationId, String branchName, ArtifactType artifactType);
|
Mono<Boolean> autoCommitApplication(String defaultApplicationId, String branchName, ArtifactType artifactType);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ import com.appsmith.server.domains.Workspace;
|
||||||
import com.appsmith.server.dtos.ApplicationImportDTO;
|
import com.appsmith.server.dtos.ApplicationImportDTO;
|
||||||
import com.appsmith.server.dtos.ArtifactExchangeJson;
|
import com.appsmith.server.dtos.ArtifactExchangeJson;
|
||||||
import com.appsmith.server.dtos.ArtifactImportDTO;
|
import com.appsmith.server.dtos.ArtifactImportDTO;
|
||||||
import com.appsmith.server.dtos.AutoCommitProgressDTO;
|
import com.appsmith.server.dtos.AutoCommitResponseDTO;
|
||||||
import com.appsmith.server.dtos.GitCommitDTO;
|
import com.appsmith.server.dtos.GitCommitDTO;
|
||||||
import com.appsmith.server.dtos.GitConnectDTO;
|
import com.appsmith.server.dtos.GitConnectDTO;
|
||||||
import com.appsmith.server.dtos.GitDocsDTO;
|
import com.appsmith.server.dtos.GitDocsDTO;
|
||||||
|
|
@ -3377,8 +3377,9 @@ public class CommonGitServiceCEImpl implements CommonGitServiceCE {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<AutoCommitProgressDTO> getAutoCommitProgress(String artifactId, ArtifactType artifactType) {
|
public Mono<AutoCommitResponseDTO> getAutoCommitProgress(
|
||||||
return gitAutoCommitHelper.getAutoCommitProgress(artifactId);
|
String artifactId, String branchName, ArtifactType artifactType) {
|
||||||
|
return gitAutoCommitHelper.getAutoCommitProgress(artifactId, branchName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
package com.appsmith.server.helpers;
|
package com.appsmith.server.helpers;
|
||||||
|
|
||||||
import com.appsmith.external.git.FileInterface;
|
import com.appsmith.external.git.FileInterface;
|
||||||
|
import com.appsmith.external.git.operations.FileOperations;
|
||||||
|
import com.appsmith.external.models.ApplicationGitReference;
|
||||||
import com.appsmith.git.files.FileUtilsImpl;
|
import com.appsmith.git.files.FileUtilsImpl;
|
||||||
import com.appsmith.server.applications.git.ApplicationGitFileUtilsImpl;
|
|
||||||
import com.appsmith.server.helpers.ce.CommonGitFileUtilsCE;
|
import com.appsmith.server.helpers.ce.CommonGitFileUtilsCE;
|
||||||
import com.appsmith.server.services.AnalyticsService;
|
import com.appsmith.server.services.AnalyticsService;
|
||||||
import com.appsmith.server.services.SessionUserService;
|
import com.appsmith.server.services.SessionUserService;
|
||||||
|
import com.google.gson.Gson;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
@ -16,10 +18,12 @@ import org.springframework.stereotype.Component;
|
||||||
public class CommonGitFileUtils extends CommonGitFileUtilsCE {
|
public class CommonGitFileUtils extends CommonGitFileUtilsCE {
|
||||||
|
|
||||||
public CommonGitFileUtils(
|
public CommonGitFileUtils(
|
||||||
ApplicationGitFileUtilsImpl applicationGitFileUtils,
|
ArtifactGitFileUtils<ApplicationGitReference> applicationGitFileUtils,
|
||||||
FileInterface fileUtils,
|
FileInterface fileUtils,
|
||||||
|
FileOperations fileOperations,
|
||||||
AnalyticsService analyticsService,
|
AnalyticsService analyticsService,
|
||||||
SessionUserService sessionUserService) {
|
SessionUserService sessionUserService,
|
||||||
super(applicationGitFileUtils, fileUtils, analyticsService, sessionUserService);
|
Gson gson) {
|
||||||
|
super(applicationGitFileUtils, fileUtils, fileOperations, analyticsService, sessionUserService);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -177,6 +177,18 @@ public class GitUtils {
|
||||||
return isMigrationRequired;
|
return isMigrationRequired;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isMigrationRequired(org.json.JSONObject layoutDsl, Integer latestDslVersion) {
|
||||||
|
boolean isMigrationRequired = true;
|
||||||
|
String versionKey = "version";
|
||||||
|
if (layoutDsl.has(versionKey)) {
|
||||||
|
int currentDslVersion = layoutDsl.getInt(versionKey);
|
||||||
|
if (currentDslVersion >= latestDslVersion) {
|
||||||
|
isMigrationRequired = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return isMigrationRequired;
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean isAutoCommitEnabled(GitArtifactMetadata gitArtifactMetadata) {
|
public static boolean isAutoCommitEnabled(GitArtifactMetadata gitArtifactMetadata) {
|
||||||
return gitArtifactMetadata.getAutoCommitConfig() == null
|
return gitArtifactMetadata.getAutoCommitConfig() == null
|
||||||
|| gitArtifactMetadata.getAutoCommitConfig().getEnabled();
|
|| gitArtifactMetadata.getAutoCommitConfig().getEnabled();
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package com.appsmith.server.helpers.ce;
|
||||||
|
|
||||||
import com.appsmith.external.constants.AnalyticsEvents;
|
import com.appsmith.external.constants.AnalyticsEvents;
|
||||||
import com.appsmith.external.git.FileInterface;
|
import com.appsmith.external.git.FileInterface;
|
||||||
|
import com.appsmith.external.git.operations.FileOperations;
|
||||||
import com.appsmith.external.helpers.Stopwatch;
|
import com.appsmith.external.helpers.Stopwatch;
|
||||||
import com.appsmith.external.models.ApplicationGitReference;
|
import com.appsmith.external.models.ApplicationGitReference;
|
||||||
import com.appsmith.external.models.ArtifactGitReference;
|
import com.appsmith.external.models.ArtifactGitReference;
|
||||||
|
|
@ -11,8 +12,10 @@ import com.appsmith.git.constants.CommonConstants;
|
||||||
import com.appsmith.git.files.FileUtilsImpl;
|
import com.appsmith.git.files.FileUtilsImpl;
|
||||||
import com.appsmith.server.constants.ArtifactType;
|
import com.appsmith.server.constants.ArtifactType;
|
||||||
import com.appsmith.server.constants.FieldName;
|
import com.appsmith.server.constants.FieldName;
|
||||||
|
import com.appsmith.server.domains.GitArtifactMetadata;
|
||||||
import com.appsmith.server.dtos.ApplicationJson;
|
import com.appsmith.server.dtos.ApplicationJson;
|
||||||
import com.appsmith.server.dtos.ArtifactExchangeJson;
|
import com.appsmith.server.dtos.ArtifactExchangeJson;
|
||||||
|
import com.appsmith.server.dtos.PageDTO;
|
||||||
import com.appsmith.server.exceptions.AppsmithError;
|
import com.appsmith.server.exceptions.AppsmithError;
|
||||||
import com.appsmith.server.exceptions.AppsmithException;
|
import com.appsmith.server.exceptions.AppsmithException;
|
||||||
import com.appsmith.server.helpers.ArtifactGitFileUtils;
|
import com.appsmith.server.helpers.ArtifactGitFileUtils;
|
||||||
|
|
@ -25,6 +28,7 @@ import com.google.gson.JsonObject;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.eclipse.jgit.api.errors.GitAPIException;
|
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||||
|
import org.json.JSONObject;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
@ -37,6 +41,8 @@ import java.nio.file.Paths;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static com.appsmith.external.git.constants.ce.GitConstantsCE.GitCommandConstantsCE.CHECKOUT_BRANCH;
|
||||||
|
import static com.appsmith.external.git.constants.ce.GitConstantsCE.RECONSTRUCT_PAGE;
|
||||||
import static com.appsmith.git.constants.CommonConstants.CLIENT_SCHEMA_VERSION;
|
import static com.appsmith.git.constants.CommonConstants.CLIENT_SCHEMA_VERSION;
|
||||||
import static com.appsmith.git.constants.CommonConstants.FILE_FORMAT_VERSION;
|
import static com.appsmith.git.constants.CommonConstants.FILE_FORMAT_VERSION;
|
||||||
import static com.appsmith.git.constants.CommonConstants.SERVER_SCHEMA_VERSION;
|
import static com.appsmith.git.constants.CommonConstants.SERVER_SCHEMA_VERSION;
|
||||||
|
|
@ -50,6 +56,7 @@ public class CommonGitFileUtilsCE {
|
||||||
|
|
||||||
protected final ArtifactGitFileUtils<ApplicationGitReference> applicationGitFileUtils;
|
protected final ArtifactGitFileUtils<ApplicationGitReference> applicationGitFileUtils;
|
||||||
private final FileInterface fileUtils;
|
private final FileInterface fileUtils;
|
||||||
|
private final FileOperations fileOperations;
|
||||||
private final AnalyticsService analyticsService;
|
private final AnalyticsService analyticsService;
|
||||||
private final SessionUserService sessionUserService;
|
private final SessionUserService sessionUserService;
|
||||||
|
|
||||||
|
|
@ -282,15 +289,21 @@ public class CommonGitFileUtilsCE {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Mono<Map<String, Integer>> reconstructMetadataFromRepo(
|
public Mono<Map<String, Integer>> reconstructMetadataFromRepo(
|
||||||
String workspaceId, String applicationId, String repoName, String branchName, ArtifactType artifactType) {
|
String workspaceId,
|
||||||
|
String applicationId,
|
||||||
|
String repoName,
|
||||||
|
String branchName,
|
||||||
|
Boolean isResetToLastCommitRequired,
|
||||||
|
ArtifactType artifactType) {
|
||||||
|
|
||||||
ArtifactGitFileUtils<?> artifactGitFileUtils = getArtifactBasedFileHelper(artifactType);
|
ArtifactGitFileUtils<?> artifactGitFileUtils = getArtifactBasedFileHelper(artifactType);
|
||||||
Path baseRepoSuffix = artifactGitFileUtils.getRepoSuffixPath(workspaceId, applicationId, repoName);
|
Path baseRepoSuffix = artifactGitFileUtils.getRepoSuffixPath(workspaceId, applicationId, repoName);
|
||||||
|
|
||||||
return fileUtils
|
return fileUtils
|
||||||
.reconstructMetadataFromGitRepo(workspaceId, applicationId, repoName, branchName, baseRepoSuffix)
|
.reconstructMetadataFromGitRepo(
|
||||||
|
workspaceId, applicationId, repoName, branchName, baseRepoSuffix, isResetToLastCommitRequired)
|
||||||
.onErrorResume(error -> Mono.error(
|
.onErrorResume(error -> Mono.error(
|
||||||
new AppsmithException(AppsmithError.GIT_ACTION_FAILED, "checkout", error.getMessage())))
|
new AppsmithException(AppsmithError.GIT_ACTION_FAILED, CHECKOUT_BRANCH, error.getMessage())))
|
||||||
.map(metadata -> {
|
.map(metadata -> {
|
||||||
Gson gson = new Gson();
|
Gson gson = new Gson();
|
||||||
JsonObject metadataJsonObject =
|
JsonObject metadataJsonObject =
|
||||||
|
|
@ -311,19 +324,21 @@ public class CommonGitFileUtilsCE {
|
||||||
* Provides the server schema version in the application json for the given branch
|
* Provides the server schema version in the application json for the given branch
|
||||||
*
|
*
|
||||||
* @param workspaceId : workspaceId of the artifact
|
* @param workspaceId : workspaceId of the artifact
|
||||||
* @param defaultArtifactId : default branch id of the artifact
|
* @param gitArtifactMetadata : git artifact metadata of the application
|
||||||
* @param repoName : repository name
|
* @param isResetToLastCommitRequired : would we need to execute reset command
|
||||||
* @param branchName : current branch name of the artifact
|
|
||||||
* @param artifactType : artifact type of this operation
|
* @param artifactType : artifact type of this operation
|
||||||
* @return the server schema migration version number
|
* @return the server schema migration version number
|
||||||
*/
|
*/
|
||||||
public Mono<Integer> getMetadataServerSchemaMigrationVersion(
|
public Mono<Integer> getMetadataServerSchemaMigrationVersion(
|
||||||
String workspaceId,
|
String workspaceId,
|
||||||
String defaultArtifactId,
|
GitArtifactMetadata gitArtifactMetadata,
|
||||||
String repoName,
|
Boolean isResetToLastCommitRequired,
|
||||||
String branchName,
|
|
||||||
ArtifactType artifactType) {
|
ArtifactType artifactType) {
|
||||||
|
|
||||||
|
String defaultArtifactId = gitArtifactMetadata.getDefaultArtifactId();
|
||||||
|
String branchName = gitArtifactMetadata.getBranchName();
|
||||||
|
String repoName = gitArtifactMetadata.getRepoName();
|
||||||
|
|
||||||
if (!hasText(workspaceId)) {
|
if (!hasText(workspaceId)) {
|
||||||
return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.WORKSPACE_ID));
|
return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.WORKSPACE_ID));
|
||||||
}
|
}
|
||||||
|
|
@ -340,11 +355,69 @@ public class CommonGitFileUtilsCE {
|
||||||
return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.REPO_NAME));
|
return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.REPO_NAME));
|
||||||
}
|
}
|
||||||
|
|
||||||
return reconstructMetadataFromRepo(workspaceId, defaultArtifactId, repoName, branchName, artifactType)
|
Mono<Integer> serverSchemaNumberMono = reconstructMetadataFromRepo(
|
||||||
|
workspaceId, defaultArtifactId, repoName, branchName, isResetToLastCommitRequired, artifactType)
|
||||||
.map(metadataMap -> {
|
.map(metadataMap -> {
|
||||||
return metadataMap.getOrDefault(
|
return metadataMap.getOrDefault(
|
||||||
CommonConstants.SERVER_SCHEMA_VERSION, JsonSchemaVersions.serverVersion);
|
CommonConstants.SERVER_SCHEMA_VERSION, JsonSchemaVersions.serverVersion);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return Mono.create(
|
||||||
|
sink -> serverSchemaNumberMono.subscribe(sink::success, sink::error, null, sink.currentContext()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides the server schema version in the application json for the given branch
|
||||||
|
*
|
||||||
|
* @param workspaceId : workspace id of the application
|
||||||
|
* @param gitArtifactMetadata : git artifact metadata
|
||||||
|
* @param isResetToLastCommitRequired : whether git reset hard is required
|
||||||
|
* @param artifactType : artifact type of this operation
|
||||||
|
* @return the server schema migration version number
|
||||||
|
*/
|
||||||
|
public Mono<JSONObject> getPageDslVersionNumber(
|
||||||
|
String workspaceId,
|
||||||
|
GitArtifactMetadata gitArtifactMetadata,
|
||||||
|
PageDTO pageDTO,
|
||||||
|
Boolean isResetToLastCommitRequired,
|
||||||
|
ArtifactType artifactType) {
|
||||||
|
|
||||||
|
String defaultArtifactId = gitArtifactMetadata.getDefaultArtifactId();
|
||||||
|
String branchName = gitArtifactMetadata.getBranchName();
|
||||||
|
String repoName = gitArtifactMetadata.getRepoName();
|
||||||
|
|
||||||
|
if (!hasText(workspaceId)) {
|
||||||
|
return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.WORKSPACE_ID));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasText(defaultArtifactId)) {
|
||||||
|
return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.ARTIFACT_ID));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasText(branchName)) {
|
||||||
|
return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.BRANCH_NAME));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasText(repoName)) {
|
||||||
|
return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.REPO_NAME));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pageDTO == null) {
|
||||||
|
return Mono.error(new AppsmithException(AppsmithError.PAGE_ID_NOT_GIVEN, FieldName.PAGE));
|
||||||
|
}
|
||||||
|
|
||||||
|
ArtifactGitFileUtils<?> artifactGitFileUtils = getArtifactBasedFileHelper(artifactType);
|
||||||
|
Path baseRepoSuffix = artifactGitFileUtils.getRepoSuffixPath(workspaceId, defaultArtifactId, repoName);
|
||||||
|
|
||||||
|
Mono<JSONObject> jsonObjectMono = fileUtils
|
||||||
|
.reconstructPageFromGitRepo(pageDTO.getName(), branchName, baseRepoSuffix, isResetToLastCommitRequired)
|
||||||
|
.onErrorResume(error -> Mono.error(
|
||||||
|
new AppsmithException(AppsmithError.GIT_ACTION_FAILED, RECONSTRUCT_PAGE, error.getMessage())))
|
||||||
|
.map(pageJson -> {
|
||||||
|
return fileOperations.getMainContainer(pageJson);
|
||||||
|
});
|
||||||
|
|
||||||
|
return Mono.create(sink -> jsonObjectMono.subscribe(sink::success, sink::error, null, sink.currentContext()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Integer getServerSchemaVersion(JsonObject metadataJsonObject) {
|
private Integer getServerSchemaVersion(JsonObject metadataJsonObject) {
|
||||||
|
|
|
||||||
|
|
@ -94,13 +94,15 @@ public class PartialImportServiceCEImpl implements PartialImportServiceCE {
|
||||||
@Override
|
@Override
|
||||||
public Mono<Application> importResourceInPage(
|
public Mono<Application> importResourceInPage(
|
||||||
String workspaceId, String applicationId, String pageId, String branchName, Part file) {
|
String workspaceId, String applicationId, String pageId, String branchName, Part file) {
|
||||||
|
Mono<User> currUserMono = sessionUserService.getCurrentUser();
|
||||||
return importService
|
return importService
|
||||||
.extractArtifactExchangeJson(file)
|
.extractArtifactExchangeJson(file)
|
||||||
.flatMap(artifactExchangeJson -> {
|
.flatMap(artifactExchangeJson -> {
|
||||||
if (artifactExchangeJson instanceof ApplicationJson
|
if (artifactExchangeJson instanceof ApplicationJson
|
||||||
&& isImportableResource((ApplicationJson) artifactExchangeJson)) {
|
&& isImportableResource((ApplicationJson) artifactExchangeJson)) {
|
||||||
return importResourceInPage(
|
return importResourceInPage(workspaceId, applicationId, pageId, branchName, (ApplicationJson)
|
||||||
workspaceId, applicationId, pageId, branchName, (ApplicationJson) artifactExchangeJson);
|
artifactExchangeJson)
|
||||||
|
.zipWith(currUserMono);
|
||||||
} else {
|
} else {
|
||||||
return Mono.error(
|
return Mono.error(
|
||||||
new AppsmithException(
|
new AppsmithException(
|
||||||
|
|
@ -108,7 +110,21 @@ public class PartialImportServiceCEImpl implements PartialImportServiceCE {
|
||||||
"The file is not compatible with the current partial import operation. Please check the file and try again."));
|
"The file is not compatible with the current partial import operation. Please check the file and try again."));
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.map(BuildingBlockImportDTO::getApplication);
|
.flatMap(tuple -> {
|
||||||
|
final BuildingBlockImportDTO buildingBlockImportDTO = tuple.getT1();
|
||||||
|
final User user = tuple.getT2();
|
||||||
|
final Map<String, Object> eventData =
|
||||||
|
Map.of(FieldName.APPLICATION, buildingBlockImportDTO.getApplication());
|
||||||
|
final Map<String, Object> data = Map.of(
|
||||||
|
FieldName.APPLICATION_ID, applicationId,
|
||||||
|
FieldName.WORKSPACE_ID,
|
||||||
|
buildingBlockImportDTO.getApplication().getWorkspaceId(),
|
||||||
|
FieldName.EVENT_DATA, eventData);
|
||||||
|
|
||||||
|
return analyticsService
|
||||||
|
.sendEvent(AnalyticsEvents.PARTIAL_IMPORT.getEventName(), user.getUsername(), data)
|
||||||
|
.thenReturn(buildingBlockImportDTO.getApplication());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isImportableResource(ApplicationJson artifactExchangeJson) {
|
private boolean isImportableResource(ApplicationJson artifactExchangeJson) {
|
||||||
|
|
@ -128,8 +144,6 @@ public class PartialImportServiceCEImpl implements PartialImportServiceCE {
|
||||||
Mono<String> branchedPageIdMono =
|
Mono<String> branchedPageIdMono =
|
||||||
newPageService.findBranchedPageId(branchName, pageId, AclPermission.MANAGE_PAGES);
|
newPageService.findBranchedPageId(branchName, pageId, AclPermission.MANAGE_PAGES);
|
||||||
|
|
||||||
Mono<User> currUserMono = sessionUserService.getCurrentUser();
|
|
||||||
|
|
||||||
// Extract file and get App Json
|
// Extract file and get App Json
|
||||||
Mono<Application> partiallyImportedAppMono = getImportApplicationPermissions()
|
Mono<Application> partiallyImportedAppMono = getImportApplicationPermissions()
|
||||||
.flatMap(permissionProvider -> {
|
.flatMap(permissionProvider -> {
|
||||||
|
|
@ -273,25 +287,13 @@ public class PartialImportServiceCEImpl implements PartialImportServiceCE {
|
||||||
})
|
})
|
||||||
.as(transactionalOperator::transactional);
|
.as(transactionalOperator::transactional);
|
||||||
|
|
||||||
// Send Analytics event
|
return partiallyImportedAppMono.map(application -> {
|
||||||
return partiallyImportedAppMono.zipWith(currUserMono).flatMap(tuple -> {
|
|
||||||
Application application = tuple.getT1();
|
|
||||||
User user = tuple.getT2();
|
|
||||||
final Map<String, Object> eventData = Map.of(FieldName.APPLICATION, application);
|
|
||||||
|
|
||||||
final Map<String, Object> data = Map.of(
|
|
||||||
FieldName.APPLICATION_ID, application.getId(),
|
|
||||||
FieldName.WORKSPACE_ID, application.getWorkspaceId(),
|
|
||||||
FieldName.EVENT_DATA, eventData);
|
|
||||||
BuildingBlockImportDTO buildingBlockImportDTO = new BuildingBlockImportDTO();
|
BuildingBlockImportDTO buildingBlockImportDTO = new BuildingBlockImportDTO();
|
||||||
buildingBlockImportDTO.setApplication(application);
|
buildingBlockImportDTO.setApplication(application);
|
||||||
buildingBlockImportDTO.setWidgetDsl(applicationJson.getWidgets());
|
buildingBlockImportDTO.setWidgetDsl(applicationJson.getWidgets());
|
||||||
buildingBlockImportDTO.setRefactoredEntityNameMap(
|
buildingBlockImportDTO.setRefactoredEntityNameMap(
|
||||||
mappedImportableResourcesDTO.getRefactoringNameReference());
|
mappedImportableResourcesDTO.getRefactoringNameReference());
|
||||||
|
return buildingBlockImportDTO;
|
||||||
return analyticsService
|
|
||||||
.sendEvent(AnalyticsEvents.PARTIAL_IMPORT.getEventName(), user.getUsername(), data)
|
|
||||||
.thenReturn(buildingBlockImportDTO);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -244,12 +244,10 @@ public class UpdateLayoutServiceCEImpl implements UpdateLayoutServiceCE {
|
||||||
List<Mono<LayoutDTO>> monoList = new ArrayList<>();
|
List<Mono<LayoutDTO>> monoList = new ArrayList<>();
|
||||||
for (UpdateMultiplePageLayoutDTO.UpdatePageLayoutDTO pageLayout :
|
for (UpdateMultiplePageLayoutDTO.UpdatePageLayoutDTO pageLayout :
|
||||||
updateMultiplePageLayoutDTO.getPageLayouts()) {
|
updateMultiplePageLayoutDTO.getPageLayouts()) {
|
||||||
|
final Layout layout = new Layout();
|
||||||
|
layout.setDsl(pageLayout.getLayout().dsl());
|
||||||
Mono<LayoutDTO> updatedLayoutMono = this.updateLayout(
|
Mono<LayoutDTO> updatedLayoutMono = this.updateLayout(
|
||||||
pageLayout.getPageId(),
|
pageLayout.getPageId(), defaultApplicationId, pageLayout.getLayoutId(), layout, branchName);
|
||||||
defaultApplicationId,
|
|
||||||
pageLayout.getLayoutId(),
|
|
||||||
pageLayout.getLayout(),
|
|
||||||
branchName);
|
|
||||||
monoList.add(updatedLayoutMono);
|
monoList.add(updatedLayoutMono);
|
||||||
}
|
}
|
||||||
return Flux.merge(monoList).then(Mono.just(monoList.size()));
|
return Flux.merge(monoList).then(Mono.just(monoList.size()));
|
||||||
|
|
|
||||||
|
|
@ -123,8 +123,10 @@ public class JsonSchemaMigration {
|
||||||
applicationJson.setServerSchemaVersion(6);
|
applicationJson.setServerSchemaVersion(6);
|
||||||
case 6:
|
case 6:
|
||||||
MigrationHelperMethods.ensureXmlParserPresenceInCustomJsLibList(applicationJson);
|
MigrationHelperMethods.ensureXmlParserPresenceInCustomJsLibList(applicationJson);
|
||||||
|
|
||||||
applicationJson.setServerSchemaVersion(7);
|
applicationJson.setServerSchemaVersion(7);
|
||||||
|
case 7:
|
||||||
|
applicationJson.setServerSchemaVersion(8);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// Unable to detect the serverSchema
|
// Unable to detect the serverSchema
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,6 @@ import lombok.Getter;
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
public class JsonSchemaVersions {
|
public class JsonSchemaVersions {
|
||||||
public static final Integer serverVersion = 7;
|
public static final Integer serverVersion = 8;
|
||||||
public static final Integer clientVersion = 1;
|
public static final Integer clientVersion = 1;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -101,4 +101,7 @@ public interface NewPageServiceCE extends CrudService<NewPage, String> {
|
||||||
Application branchedApplication, List<NewPage> newPages, boolean viewMode, boolean isRecentlyAccessed);
|
Application branchedApplication, List<NewPage> newPages, boolean viewMode, boolean isRecentlyAccessed);
|
||||||
|
|
||||||
Mono<String> updateDependencyMap(String pageId, Map<String, List<String>> dependencyMap, String branchName);
|
Mono<String> updateDependencyMap(String pageId, Map<String, List<String>> dependencyMap, String branchName);
|
||||||
|
|
||||||
|
Flux<PageDTO> findByApplicationIdAndApplicationMode(
|
||||||
|
String applicationId, AclPermission permission, ApplicationMode applicationMode);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -687,4 +687,23 @@ public class NewPageServiceCEImpl extends BaseService<NewPageRepository, NewPage
|
||||||
return Mono.just(count.toString());
|
return Mono.just(count.toString());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Flux<PageDTO> findByApplicationIdAndApplicationMode(
|
||||||
|
String applicationId, AclPermission permission, ApplicationMode applicationMode) {
|
||||||
|
Boolean viewMode = ApplicationMode.PUBLISHED.equals(applicationMode);
|
||||||
|
return findNewPagesByApplicationId(applicationId, permission)
|
||||||
|
.filter(page -> {
|
||||||
|
PageDTO pageDTO;
|
||||||
|
if (ApplicationMode.PUBLISHED.equals(applicationMode)) {
|
||||||
|
pageDTO = page.getPublishedPage();
|
||||||
|
} else {
|
||||||
|
pageDTO = page.getUnpublishedPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isDeletedOrNull = pageDTO == null || pageDTO.getDeletedAt() != null;
|
||||||
|
return !isDeletedOrNull;
|
||||||
|
})
|
||||||
|
.flatMap(page -> getPageByViewMode(page, viewMode));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -95,8 +95,6 @@ public class ApplicationPageServiceImpl extends ApplicationPageServiceCEImpl imp
|
||||||
datasourceRepository,
|
datasourceRepository,
|
||||||
datasourcePermission,
|
datasourcePermission,
|
||||||
dslMigrationUtils,
|
dslMigrationUtils,
|
||||||
gitAutoCommitHelper,
|
|
||||||
autoCommitEligibilityHelper,
|
|
||||||
actionClonePageService,
|
actionClonePageService,
|
||||||
actionCollectionClonePageService);
|
actionCollectionClonePageService);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,9 +34,6 @@ import com.appsmith.server.dtos.PageNameIdDTO;
|
||||||
import com.appsmith.server.dtos.PluginTypeAndCountDTO;
|
import com.appsmith.server.dtos.PluginTypeAndCountDTO;
|
||||||
import com.appsmith.server.exceptions.AppsmithError;
|
import com.appsmith.server.exceptions.AppsmithError;
|
||||||
import com.appsmith.server.exceptions.AppsmithException;
|
import com.appsmith.server.exceptions.AppsmithException;
|
||||||
import com.appsmith.server.git.autocommit.helpers.AutoCommitEligibilityHelper;
|
|
||||||
import com.appsmith.server.git.autocommit.helpers.GitAutoCommitHelper;
|
|
||||||
import com.appsmith.server.helpers.CollectionUtils;
|
|
||||||
import com.appsmith.server.helpers.CommonGitFileUtils;
|
import com.appsmith.server.helpers.CommonGitFileUtils;
|
||||||
import com.appsmith.server.helpers.DSLMigrationUtils;
|
import com.appsmith.server.helpers.DSLMigrationUtils;
|
||||||
import com.appsmith.server.helpers.GitUtils;
|
import com.appsmith.server.helpers.GitUtils;
|
||||||
|
|
@ -127,8 +124,6 @@ public class ApplicationPageServiceCEImpl implements ApplicationPageServiceCE {
|
||||||
private final DatasourceRepository datasourceRepository;
|
private final DatasourceRepository datasourceRepository;
|
||||||
private final DatasourcePermission datasourcePermission;
|
private final DatasourcePermission datasourcePermission;
|
||||||
private final DSLMigrationUtils dslMigrationUtils;
|
private final DSLMigrationUtils dslMigrationUtils;
|
||||||
private final GitAutoCommitHelper gitAutoCommitHelper;
|
|
||||||
private final AutoCommitEligibilityHelper autoCommitEligibilityHelper;
|
|
||||||
private final ClonePageService<NewAction> actionClonePageService;
|
private final ClonePageService<NewAction> actionClonePageService;
|
||||||
private final ClonePageService<ActionCollection> actionCollectionClonePageService;
|
private final ClonePageService<ActionCollection> actionCollectionClonePageService;
|
||||||
|
|
||||||
|
|
@ -299,76 +294,7 @@ public class ApplicationPageServiceCEImpl implements ApplicationPageServiceCE {
|
||||||
return newPageService
|
return newPageService
|
||||||
.findNewPagesByApplicationId(branchedApplication.getId(), pagePermission.getReadPermission())
|
.findNewPagesByApplicationId(branchedApplication.getId(), pagePermission.getReadPermission())
|
||||||
.filter(newPage -> pageIds.contains(newPage.getId()))
|
.filter(newPage -> pageIds.contains(newPage.getId()))
|
||||||
.collectList()
|
.collectList();
|
||||||
.flatMap(newPageList -> {
|
|
||||||
if (Boolean.TRUE.equals(viewMode)) {
|
|
||||||
return Mono.just(newPageList);
|
|
||||||
}
|
|
||||||
|
|
||||||
// autocommit if migration is required
|
|
||||||
return migrateSchemasForGitConnectedApps(branchedApplication, newPageList)
|
|
||||||
.onErrorResume(error -> {
|
|
||||||
log.debug(
|
|
||||||
"Skipping the autocommit for applicationId : {} due to error; {}",
|
|
||||||
branchedApplication.getId(),
|
|
||||||
error.getMessage());
|
|
||||||
|
|
||||||
return Mono.just(Boolean.FALSE);
|
|
||||||
})
|
|
||||||
.thenReturn(newPageList);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Publishes the autocommit if it's eligible for one
|
|
||||||
* @param application : the branched application which requires schemaMigration
|
|
||||||
* @param newPages : list of pages from db
|
|
||||||
* @return : a boolean publisher
|
|
||||||
*/
|
|
||||||
private Mono<Boolean> migrateSchemasForGitConnectedApps(Application application, List<NewPage> newPages) {
|
|
||||||
|
|
||||||
if (CollectionUtils.isNullOrEmpty(newPages)) {
|
|
||||||
return Mono.just(Boolean.FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
GitArtifactMetadata gitMetadata = application.getGitArtifactMetadata();
|
|
||||||
|
|
||||||
if (application.getGitArtifactMetadata() == null) {
|
|
||||||
return Mono.just(Boolean.FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
String defaultApplicationId = gitMetadata.getDefaultArtifactId();
|
|
||||||
String branchName = gitMetadata.getBranchName();
|
|
||||||
String workspaceId = application.getWorkspaceId();
|
|
||||||
|
|
||||||
if (!StringUtils.hasText(branchName)) {
|
|
||||||
log.debug(
|
|
||||||
"Skipping the autocommit for applicationId : {}, branch name is not present", application.getId());
|
|
||||||
return Mono.just(Boolean.FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!StringUtils.hasText(defaultApplicationId)) {
|
|
||||||
log.debug(
|
|
||||||
"Skipping the autocommit for applicationId : {}, defaultApplicationId is not present",
|
|
||||||
application.getId());
|
|
||||||
return Mono.just(Boolean.FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// since this method is only called when the app is in edit mode
|
|
||||||
Mono<PageDTO> pageDTOMono = getPage(newPages.get(0), false);
|
|
||||||
|
|
||||||
return pageDTOMono.flatMap(pageDTO -> {
|
|
||||||
return autoCommitEligibilityHelper
|
|
||||||
.isAutoCommitRequired(workspaceId, gitMetadata, pageDTO)
|
|
||||||
.flatMap(autoCommitTriggerDTO -> {
|
|
||||||
if (Boolean.TRUE.equals(autoCommitTriggerDTO.getIsAutoCommitRequired())) {
|
|
||||||
return gitAutoCommitHelper.autoCommitApplication(
|
|
||||||
autoCommitTriggerDTO, defaultApplicationId, branchName);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Mono.just(Boolean.FALSE);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,37 @@
|
||||||
package com.appsmith.server.git;
|
package com.appsmith.server.git;
|
||||||
|
|
||||||
|
import com.appsmith.external.converters.ISOStringToInstantConverter;
|
||||||
|
import com.appsmith.external.dtos.ModifiedResources;
|
||||||
|
import com.appsmith.external.enums.FeatureFlagEnum;
|
||||||
|
import com.appsmith.external.git.GitExecutor;
|
||||||
import com.appsmith.external.models.ApplicationGitReference;
|
import com.appsmith.external.models.ApplicationGitReference;
|
||||||
import com.appsmith.server.constants.ArtifactType;
|
|
||||||
import com.appsmith.server.constants.SerialiseArtifactObjective;
|
import com.appsmith.server.constants.SerialiseArtifactObjective;
|
||||||
import com.appsmith.server.domains.Workspace;
|
import com.appsmith.server.domains.Workspace;
|
||||||
import com.appsmith.server.dtos.ApplicationImportDTO;
|
import com.appsmith.server.dtos.ApplicationImportDTO;
|
||||||
import com.appsmith.server.dtos.ApplicationJson;
|
import com.appsmith.server.dtos.ApplicationJson;
|
||||||
import com.appsmith.server.exports.internal.ExportService;
|
import com.appsmith.server.exports.internal.ExportService;
|
||||||
|
import com.appsmith.server.featureflags.CachedFeatures;
|
||||||
import com.appsmith.server.helpers.CommonGitFileUtils;
|
import com.appsmith.server.helpers.CommonGitFileUtils;
|
||||||
import com.appsmith.server.helpers.MockPluginExecutor;
|
import com.appsmith.server.helpers.MockPluginExecutor;
|
||||||
import com.appsmith.server.helpers.PluginExecutorHelper;
|
import com.appsmith.server.helpers.PluginExecutorHelper;
|
||||||
import com.appsmith.server.imports.internal.ImportService;
|
import com.appsmith.server.imports.internal.ImportService;
|
||||||
|
import com.appsmith.server.services.FeatureFlagService;
|
||||||
import com.appsmith.server.services.WorkspaceService;
|
import com.appsmith.server.services.WorkspaceService;
|
||||||
|
import com.appsmith.server.testhelpers.git.GitFileSystemTestHelper;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.eclipse.jgit.api.Git;
|
||||||
|
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||||
|
import org.eclipse.jgit.diff.DiffEntry;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Disabled;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
import org.mockito.Mockito;
|
import org.mockito.Mockito;
|
||||||
|
import org.mockito.stubbing.Answer;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.test.autoconfigure.data.mongo.AutoConfigureDataMongo;
|
import org.springframework.boot.test.autoconfigure.data.mongo.AutoConfigureDataMongo;
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
|
@ -37,10 +49,19 @@ import reactor.core.publisher.Flux;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
import reactor.test.StepVerifier;
|
import reactor.test.StepVerifier;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static com.appsmith.server.constants.ArtifactType.APPLICATION;
|
||||||
|
import static java.lang.Boolean.FALSE;
|
||||||
|
import static java.lang.Boolean.TRUE;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
|
||||||
|
|
@ -78,9 +99,6 @@ import static org.mockito.ArgumentMatchers.any;
|
||||||
@DirtiesContext
|
@DirtiesContext
|
||||||
public class ServerSchemaMigrationEnforcerTest {
|
public class ServerSchemaMigrationEnforcerTest {
|
||||||
|
|
||||||
@Autowired
|
|
||||||
Gson gson;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
WorkspaceService workspaceService;
|
WorkspaceService workspaceService;
|
||||||
|
|
||||||
|
|
@ -93,9 +111,28 @@ public class ServerSchemaMigrationEnforcerTest {
|
||||||
@Autowired
|
@Autowired
|
||||||
CommonGitFileUtils commonGitFileUtils;
|
CommonGitFileUtils commonGitFileUtils;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
GitFileSystemTestHelper gitFileSystemTestHelper;
|
||||||
|
|
||||||
|
@SpyBean
|
||||||
|
GitExecutor gitExecutor;
|
||||||
|
|
||||||
|
@SpyBean
|
||||||
|
FeatureFlagService featureFlagService;
|
||||||
|
|
||||||
@MockBean
|
@MockBean
|
||||||
PluginExecutorHelper pluginExecutorHelper;
|
PluginExecutorHelper pluginExecutorHelper;
|
||||||
|
|
||||||
|
private final Gson gson = new GsonBuilder()
|
||||||
|
.registerTypeAdapter(Instant.class, new ISOStringToInstantConverter())
|
||||||
|
.setPrettyPrinting()
|
||||||
|
.create();
|
||||||
|
|
||||||
|
private static final String DEFAULT_APPLICATION_ID = "default-app-id",
|
||||||
|
BRANCH_NAME = "develop",
|
||||||
|
REPO_NAME = "repoName",
|
||||||
|
WORKSPACE_ID = "test-workspace-id";
|
||||||
|
|
||||||
public static final String CUSTOM_JS_LIB_LIST = "jsLibraries";
|
public static final String CUSTOM_JS_LIB_LIST = "jsLibraries";
|
||||||
public static final String EXPORTED_APPLICATION = "application";
|
public static final String EXPORTED_APPLICATION = "application";
|
||||||
public static final String UNPUBLISHED_CUSTOM_JS_LIBS = "unpublishedCustomJSLibs";
|
public static final String UNPUBLISHED_CUSTOM_JS_LIBS = "unpublishedCustomJSLibs";
|
||||||
|
|
@ -167,6 +204,7 @@ public class ServerSchemaMigrationEnforcerTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@Disabled
|
||||||
@WithUserDetails(value = "api_user")
|
@WithUserDetails(value = "api_user")
|
||||||
public void importApplication_ThenExportApplication_MatchJson_equals_Success() throws URISyntaxException {
|
public void importApplication_ThenExportApplication_MatchJson_equals_Success() throws URISyntaxException {
|
||||||
String filePath = "ce-automation-test.json";
|
String filePath = "ce-automation-test.json";
|
||||||
|
|
@ -199,7 +237,7 @@ public class ServerSchemaMigrationEnforcerTest {
|
||||||
.exportByArtifactId(
|
.exportByArtifactId(
|
||||||
applicationImportDTO.getApplication().getId(),
|
applicationImportDTO.getApplication().getId(),
|
||||||
SerialiseArtifactObjective.VERSION_CONTROL,
|
SerialiseArtifactObjective.VERSION_CONTROL,
|
||||||
ArtifactType.APPLICATION)
|
APPLICATION)
|
||||||
.map(artifactExchangeJson -> (ApplicationJson) artifactExchangeJson);
|
.map(artifactExchangeJson -> (ApplicationJson) artifactExchangeJson);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -254,4 +292,138 @@ public class ServerSchemaMigrationEnforcerTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void savedFile_reSavedWithDifferentSerialisationLogic_diffOccurs()
|
||||||
|
throws URISyntaxException, IOException, GitAPIException {
|
||||||
|
|
||||||
|
ApplicationJson applicationJson =
|
||||||
|
gitFileSystemTestHelper.getApplicationJson(this.getClass().getResource("ce-automation-test.json"));
|
||||||
|
|
||||||
|
ModifiedResources modifiedResources = new ModifiedResources();
|
||||||
|
modifiedResources.setAllModified(true);
|
||||||
|
applicationJson.setModifiedResources(modifiedResources);
|
||||||
|
|
||||||
|
CachedFeatures cachedFeatures = new CachedFeatures();
|
||||||
|
cachedFeatures.setFeatures(Map.of(FeatureFlagEnum.release_git_autocommit_feature_enabled.name(), FALSE));
|
||||||
|
Mockito.when(featureFlagService.getCachedTenantFeatureFlags())
|
||||||
|
.thenAnswer((Answer<CachedFeatures>) invocations -> cachedFeatures);
|
||||||
|
|
||||||
|
gitFileSystemTestHelper.setupGitRepository(
|
||||||
|
WORKSPACE_ID, DEFAULT_APPLICATION_ID, BRANCH_NAME, REPO_NAME, applicationJson);
|
||||||
|
|
||||||
|
cachedFeatures.setFeatures(Map.of(FeatureFlagEnum.release_git_autocommit_feature_enabled.name(), TRUE));
|
||||||
|
Path suffixPath = Paths.get(WORKSPACE_ID, DEFAULT_APPLICATION_ID, REPO_NAME);
|
||||||
|
Path gitCompletePath = gitExecutor.createRepoPath(suffixPath);
|
||||||
|
|
||||||
|
commonGitFileUtils
|
||||||
|
.saveArtifactToLocalRepo(suffixPath, applicationJson, BRANCH_NAME)
|
||||||
|
.block();
|
||||||
|
|
||||||
|
try (Git gitRepo = Git.open(gitCompletePath.toFile())) {
|
||||||
|
List<DiffEntry> diffEntries = gitRepo.diff().call();
|
||||||
|
Set<String> fileChanges = Set.of(
|
||||||
|
"application.json",
|
||||||
|
"metadata.json",
|
||||||
|
"theme.json",
|
||||||
|
"datasources/JSON typicode API (1).json",
|
||||||
|
"datasources/TED postgres (1).json",
|
||||||
|
"datasources/mainGoogleSheetDS.json");
|
||||||
|
for (DiffEntry diff : diffEntries) {
|
||||||
|
assertThat(fileChanges).contains(diff.getOldPath());
|
||||||
|
assertThat(fileChanges).contains(diff.getNewPath());
|
||||||
|
assertThat(diff.getChangeType()).isEqualTo(DiffEntry.ChangeType.MODIFY);
|
||||||
|
}
|
||||||
|
assertThat(diffEntries.size()).isNotZero();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void savedFile_reSavedWithSameSerialisationLogic_noDiffOccurs()
|
||||||
|
throws URISyntaxException, IOException, GitAPIException {
|
||||||
|
|
||||||
|
ApplicationJson applicationJson =
|
||||||
|
gitFileSystemTestHelper.getApplicationJson(this.getClass().getResource("ce-automation-test.json"));
|
||||||
|
|
||||||
|
ModifiedResources modifiedResources = new ModifiedResources();
|
||||||
|
modifiedResources.setAllModified(true);
|
||||||
|
applicationJson.setModifiedResources(modifiedResources);
|
||||||
|
|
||||||
|
gitFileSystemTestHelper.setupGitRepository(
|
||||||
|
WORKSPACE_ID, DEFAULT_APPLICATION_ID, BRANCH_NAME, REPO_NAME, applicationJson);
|
||||||
|
|
||||||
|
Path suffixPath = Paths.get(WORKSPACE_ID, DEFAULT_APPLICATION_ID, REPO_NAME);
|
||||||
|
Path gitCompletePath = gitExecutor.createRepoPath(suffixPath);
|
||||||
|
|
||||||
|
commonGitFileUtils
|
||||||
|
.saveArtifactToLocalRepo(suffixPath, applicationJson, BRANCH_NAME)
|
||||||
|
.block();
|
||||||
|
|
||||||
|
try (Git gitRepo = Git.open(gitCompletePath.toFile())) {
|
||||||
|
List<DiffEntry> diffEntries = gitRepo.diff().call();
|
||||||
|
assertThat(diffEntries.size()).isZero();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@WithUserDetails(value = "api_user")
|
||||||
|
public void saveGitRepo_ImportAndThenExport_diffOccurs() throws URISyntaxException, IOException, GitAPIException {
|
||||||
|
ApplicationJson applicationJson =
|
||||||
|
gitFileSystemTestHelper.getApplicationJson(this.getClass().getResource("ce-automation-test.json"));
|
||||||
|
|
||||||
|
ModifiedResources modifiedResources = new ModifiedResources();
|
||||||
|
modifiedResources.setAllModified(true);
|
||||||
|
applicationJson.setModifiedResources(modifiedResources);
|
||||||
|
|
||||||
|
CachedFeatures cachedFeatures = new CachedFeatures();
|
||||||
|
cachedFeatures.setFeatures(Map.of(FeatureFlagEnum.release_git_autocommit_feature_enabled.name(), TRUE));
|
||||||
|
Mockito.when(featureFlagService.getCachedTenantFeatureFlags())
|
||||||
|
.thenAnswer((Answer<CachedFeatures>) invocations -> cachedFeatures);
|
||||||
|
|
||||||
|
gitFileSystemTestHelper.setupGitRepository(
|
||||||
|
WORKSPACE_ID, DEFAULT_APPLICATION_ID, BRANCH_NAME, REPO_NAME, applicationJson);
|
||||||
|
|
||||||
|
ApplicationJson jsonToBeImported = commonGitFileUtils
|
||||||
|
.reconstructArtifactExchangeJsonFromGitRepo(
|
||||||
|
WORKSPACE_ID, DEFAULT_APPLICATION_ID, REPO_NAME, BRANCH_NAME, APPLICATION)
|
||||||
|
.map(artifactExchangeJson -> (ApplicationJson) artifactExchangeJson)
|
||||||
|
.block();
|
||||||
|
|
||||||
|
Workspace newWorkspace = new Workspace();
|
||||||
|
newWorkspace.setName("Template Workspace1");
|
||||||
|
Workspace workspace = workspaceService.create(newWorkspace).block();
|
||||||
|
|
||||||
|
ApplicationJson exportedJson = importService
|
||||||
|
.importNewArtifactInWorkspaceFromJson(workspace.getId(), jsonToBeImported)
|
||||||
|
.flatMap(artifactExchangeJson -> {
|
||||||
|
return exportService
|
||||||
|
.exportByArtifactId(
|
||||||
|
artifactExchangeJson.getId(),
|
||||||
|
SerialiseArtifactObjective.VERSION_CONTROL,
|
||||||
|
APPLICATION)
|
||||||
|
.map(exportArtifactJson -> {
|
||||||
|
ApplicationJson applicationJson1 = (ApplicationJson) exportArtifactJson;
|
||||||
|
applicationJson1.setModifiedResources(modifiedResources);
|
||||||
|
return applicationJson1;
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.block();
|
||||||
|
|
||||||
|
Path suffixPath = Paths.get(WORKSPACE_ID, DEFAULT_APPLICATION_ID, REPO_NAME);
|
||||||
|
Path gitCompletePath = gitExecutor.createRepoPath(suffixPath);
|
||||||
|
|
||||||
|
// save back to the repository in order to compare the diff.
|
||||||
|
commonGitFileUtils
|
||||||
|
.saveArtifactToLocalRepo(suffixPath, exportedJson, BRANCH_NAME)
|
||||||
|
.block();
|
||||||
|
|
||||||
|
try (Git gitRepo = Git.open(gitCompletePath.toFile())) {
|
||||||
|
List<DiffEntry> diffEntries = gitRepo.diff().call();
|
||||||
|
assertThat(diffEntries.size()).isNotZero();
|
||||||
|
for (DiffEntry diffEntry : diffEntries) {
|
||||||
|
// assertion that no new file has been created
|
||||||
|
assertThat(diffEntry.getOldPath()).isEqualTo(diffEntry.getNewPath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,394 +0,0 @@
|
||||||
package com.appsmith.server.git.autocommit;
|
|
||||||
|
|
||||||
import com.appsmith.external.dtos.GitLogDTO;
|
|
||||||
import com.appsmith.external.enums.FeatureFlagEnum;
|
|
||||||
import com.appsmith.external.git.GitExecutor;
|
|
||||||
import com.appsmith.external.helpers.AppsmithBeanUtils;
|
|
||||||
import com.appsmith.server.acl.AclPermission;
|
|
||||||
import com.appsmith.server.applications.base.ApplicationService;
|
|
||||||
import com.appsmith.server.domains.Application;
|
|
||||||
import com.appsmith.server.domains.ApplicationMode;
|
|
||||||
import com.appsmith.server.domains.ApplicationPage;
|
|
||||||
import com.appsmith.server.domains.GitArtifactMetadata;
|
|
||||||
import com.appsmith.server.domains.GitAuth;
|
|
||||||
import com.appsmith.server.domains.GitProfile;
|
|
||||||
import com.appsmith.server.domains.Layout;
|
|
||||||
import com.appsmith.server.domains.NewPage;
|
|
||||||
import com.appsmith.server.dtos.ApplicationJson;
|
|
||||||
import com.appsmith.server.dtos.AutoCommitTriggerDTO;
|
|
||||||
import com.appsmith.server.dtos.PageDTO;
|
|
||||||
import com.appsmith.server.git.autocommit.helpers.AutoCommitEligibilityHelper;
|
|
||||||
import com.appsmith.server.git.common.CommonGitService;
|
|
||||||
import com.appsmith.server.helpers.DSLMigrationUtils;
|
|
||||||
import com.appsmith.server.helpers.GitPrivateRepoHelper;
|
|
||||||
import com.appsmith.server.migrations.JsonSchemaMigration;
|
|
||||||
import com.appsmith.server.migrations.JsonSchemaVersions;
|
|
||||||
import com.appsmith.server.newpages.base.NewPageService;
|
|
||||||
import com.appsmith.server.services.ApplicationPageService;
|
|
||||||
import com.appsmith.server.services.FeatureFlagService;
|
|
||||||
import com.appsmith.server.services.UserDataService;
|
|
||||||
import com.appsmith.server.testhelpers.git.GitFileSystemTestHelper;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import net.minidev.json.JSONObject;
|
|
||||||
import org.eclipse.jgit.api.errors.GitAPIException;
|
|
||||||
import org.eclipse.jgit.lib.BranchTrackingStatus;
|
|
||||||
import org.junit.jupiter.api.AfterEach;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
|
||||||
import org.junit.jupiter.api.Disabled;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
|
||||||
import org.mockito.Mockito;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
|
||||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
|
||||||
import org.springframework.boot.test.mock.mockito.SpyBean;
|
|
||||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
|
||||||
import reactor.core.publisher.Flux;
|
|
||||||
import reactor.core.publisher.Mono;
|
|
||||||
import reactor.test.StepVerifier;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.URISyntaxException;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.time.Duration;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import static com.appsmith.server.git.AutoCommitEventHandlerCEImpl.AUTO_COMMIT_MSG_FORMAT;
|
|
||||||
import static java.lang.Boolean.FALSE;
|
|
||||||
import static java.lang.Boolean.TRUE;
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
|
||||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
|
||||||
import static org.mockito.ArgumentMatchers.anyString;
|
|
||||||
import static org.mockito.Mockito.doReturn;
|
|
||||||
|
|
||||||
@ExtendWith(SpringExtension.class)
|
|
||||||
@SpringBootTest
|
|
||||||
@Slf4j
|
|
||||||
public class ApplicationPageServiceAutoCommitTest {
|
|
||||||
|
|
||||||
@SpyBean
|
|
||||||
ApplicationPageService applicationPageService;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
GitFileSystemTestHelper gitFileSystemTestHelper;
|
|
||||||
|
|
||||||
@SpyBean
|
|
||||||
GitExecutor gitExecutor;
|
|
||||||
|
|
||||||
@MockBean
|
|
||||||
FeatureFlagService featureFlagService;
|
|
||||||
|
|
||||||
@MockBean
|
|
||||||
DSLMigrationUtils dslMigrationUtils;
|
|
||||||
|
|
||||||
@MockBean
|
|
||||||
ApplicationService applicationService;
|
|
||||||
|
|
||||||
@MockBean
|
|
||||||
NewPageService newPageService;
|
|
||||||
|
|
||||||
@MockBean
|
|
||||||
CommonGitService commonGitService;
|
|
||||||
|
|
||||||
@MockBean
|
|
||||||
GitPrivateRepoHelper gitPrivateRepoHelper;
|
|
||||||
|
|
||||||
@SpyBean
|
|
||||||
AutoCommitEligibilityHelper autoCommitEligibilityHelper;
|
|
||||||
|
|
||||||
@MockBean
|
|
||||||
BranchTrackingStatus branchTrackingStatus;
|
|
||||||
|
|
||||||
@MockBean
|
|
||||||
UserDataService userDataService;
|
|
||||||
|
|
||||||
@SpyBean
|
|
||||||
JsonSchemaMigration jsonSchemaMigration;
|
|
||||||
|
|
||||||
Application testApplication;
|
|
||||||
|
|
||||||
Path baseRepoSuffix;
|
|
||||||
|
|
||||||
private static final Integer DSL_VERSION_NUMBER = 88;
|
|
||||||
private static final String WORKSPACE_ID = "test-workspace";
|
|
||||||
private static final String REPO_NAME = "test-repo";
|
|
||||||
private static final String BRANCH_NAME = "develop";
|
|
||||||
private static final String APP_JSON_NAME = "autocommit.json";
|
|
||||||
private static final String APP_NAME = "autocommit";
|
|
||||||
private static final Integer WAIT_DURATION_FOR_ASYNC_EVENT = 5;
|
|
||||||
private static final String PUBLIC_KEY = "public-key";
|
|
||||||
private static final String PRIVATE_KEY = "private-key";
|
|
||||||
private static final String REPO_URL = "domain.xy";
|
|
||||||
private static final String DEFAULT_APP_ID = "default-app-id", DEFAULT_BRANCH_NAME = "master";
|
|
||||||
|
|
||||||
private Application createApplication() {
|
|
||||||
Application application = new Application();
|
|
||||||
application.setName(APP_NAME);
|
|
||||||
application.setWorkspaceId(WORKSPACE_ID);
|
|
||||||
application.setId(DEFAULT_APP_ID);
|
|
||||||
|
|
||||||
ApplicationPage applicationPage = new ApplicationPage();
|
|
||||||
applicationPage.setId("testPageId");
|
|
||||||
applicationPage.setIsDefault(TRUE);
|
|
||||||
|
|
||||||
application.setPages(List.of(applicationPage));
|
|
||||||
GitArtifactMetadata gitArtifactMetadata = new GitArtifactMetadata();
|
|
||||||
gitArtifactMetadata.setBranchName(BRANCH_NAME);
|
|
||||||
gitArtifactMetadata.setDefaultBranchName(DEFAULT_BRANCH_NAME);
|
|
||||||
gitArtifactMetadata.setRepoName(REPO_NAME);
|
|
||||||
gitArtifactMetadata.setDefaultApplicationId(DEFAULT_APP_ID);
|
|
||||||
gitArtifactMetadata.setRemoteUrl(REPO_URL);
|
|
||||||
|
|
||||||
GitAuth gitAuth = new GitAuth();
|
|
||||||
gitAuth.setPrivateKey(PRIVATE_KEY);
|
|
||||||
gitAuth.setPublicKey(PUBLIC_KEY);
|
|
||||||
gitArtifactMetadata.setGitAuth(gitAuth);
|
|
||||||
|
|
||||||
application.setGitApplicationMetadata(gitArtifactMetadata);
|
|
||||||
return application;
|
|
||||||
}
|
|
||||||
|
|
||||||
private GitProfile createGitProfile() {
|
|
||||||
GitProfile gitProfile = new GitProfile();
|
|
||||||
gitProfile.setAuthorName("authorName");
|
|
||||||
gitProfile.setAuthorEmail("author@domain.xy");
|
|
||||||
return gitProfile;
|
|
||||||
}
|
|
||||||
|
|
||||||
private NewPage createNewPage() {
|
|
||||||
JSONObject jsonObject = new JSONObject();
|
|
||||||
jsonObject.put("key", "value");
|
|
||||||
jsonObject.put("version", DSL_VERSION_NUMBER);
|
|
||||||
|
|
||||||
Layout layout1 = new Layout();
|
|
||||||
layout1.setId("testLayoutId");
|
|
||||||
layout1.setDsl(jsonObject);
|
|
||||||
|
|
||||||
PageDTO pageDTO = new PageDTO();
|
|
||||||
pageDTO.setId("testPageId");
|
|
||||||
pageDTO.setApplicationId(DEFAULT_APP_ID);
|
|
||||||
pageDTO.setLayouts(List.of(layout1));
|
|
||||||
|
|
||||||
NewPage newPage = new NewPage();
|
|
||||||
newPage.setId("testPageId");
|
|
||||||
newPage.setApplicationId(DEFAULT_APP_ID);
|
|
||||||
newPage.setUnpublishedPage(pageDTO);
|
|
||||||
return newPage;
|
|
||||||
}
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
public void beforeTest() {
|
|
||||||
Mockito.when(featureFlagService.check(FeatureFlagEnum.release_git_server_autocommit_feature_enabled))
|
|
||||||
.thenReturn(Mono.just(TRUE));
|
|
||||||
|
|
||||||
Mockito.when(featureFlagService.check(FeatureFlagEnum.release_git_autocommit_feature_enabled))
|
|
||||||
.thenReturn(Mono.just(TRUE));
|
|
||||||
|
|
||||||
Mockito.when(commonGitService.fetchRemoteChanges(
|
|
||||||
any(Application.class), any(Application.class), anyString(), anyBoolean()))
|
|
||||||
.thenReturn(Mono.just(branchTrackingStatus));
|
|
||||||
|
|
||||||
Mockito.when(branchTrackingStatus.getBehindCount()).thenReturn(0);
|
|
||||||
|
|
||||||
// create New Pages
|
|
||||||
NewPage newPage = createNewPage();
|
|
||||||
|
|
||||||
// create application
|
|
||||||
testApplication = createApplication();
|
|
||||||
baseRepoSuffix = Paths.get(WORKSPACE_ID, DEFAULT_APP_ID, REPO_NAME);
|
|
||||||
|
|
||||||
doReturn(Mono.just("success"))
|
|
||||||
.when(gitExecutor)
|
|
||||||
.pushApplication(baseRepoSuffix, REPO_URL, PUBLIC_KEY, PRIVATE_KEY, BRANCH_NAME);
|
|
||||||
|
|
||||||
doReturn(Mono.just(newPage.getUnpublishedPage()))
|
|
||||||
.when(applicationPageService)
|
|
||||||
.getPage(any(NewPage.class), anyBoolean());
|
|
||||||
|
|
||||||
Mockito.when(newPageService.findNewPagesByApplicationId(anyString(), any(AclPermission.class)))
|
|
||||||
.thenReturn(Flux.just(newPage));
|
|
||||||
|
|
||||||
Mockito.when(applicationService.findByBranchNameAndDefaultApplicationId(
|
|
||||||
anyString(), anyString(), any(AclPermission.class)))
|
|
||||||
.thenReturn(Mono.just(testApplication));
|
|
||||||
|
|
||||||
Mockito.when(applicationService.findById(anyString(), any(AclPermission.class)))
|
|
||||||
.thenReturn(Mono.just(testApplication));
|
|
||||||
|
|
||||||
Mockito.when(gitPrivateRepoHelper.isBranchProtected(any(), anyString())).thenReturn(Mono.just(FALSE));
|
|
||||||
|
|
||||||
Mockito.when(userDataService.getGitProfileForCurrentUser(any())).thenReturn(Mono.just(createGitProfile()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@AfterEach
|
|
||||||
public void afterTest() {
|
|
||||||
gitFileSystemTestHelper.deleteWorkspaceDirectory(WORKSPACE_ID);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@Disabled
|
|
||||||
public void testAutoCommit_whenOnlyServerIsEligibleForMigration_commitSuccess()
|
|
||||||
throws URISyntaxException, IOException, GitAPIException {
|
|
||||||
|
|
||||||
ApplicationJson applicationJson =
|
|
||||||
gitFileSystemTestHelper.getApplicationJson(this.getClass().getResource(APP_JSON_NAME));
|
|
||||||
|
|
||||||
doReturn(Mono.just(new AutoCommitTriggerDTO(TRUE, FALSE, TRUE)))
|
|
||||||
.when(autoCommitEligibilityHelper)
|
|
||||||
.isAutoCommitRequired(anyString(), any(GitArtifactMetadata.class), any(PageDTO.class));
|
|
||||||
|
|
||||||
ApplicationJson applicationJson1 = new ApplicationJson();
|
|
||||||
AppsmithBeanUtils.copyNewFieldValuesIntoOldObject(applicationJson, applicationJson1);
|
|
||||||
applicationJson1.setServerSchemaVersion(JsonSchemaVersions.serverVersion + 1);
|
|
||||||
|
|
||||||
doReturn(Mono.just(applicationJson1))
|
|
||||||
.when(jsonSchemaMigration)
|
|
||||||
.migrateApplicationJsonToLatestSchema(any(ApplicationJson.class));
|
|
||||||
|
|
||||||
gitFileSystemTestHelper.setupGitRepository(
|
|
||||||
WORKSPACE_ID, DEFAULT_APP_ID, BRANCH_NAME, REPO_NAME, applicationJson);
|
|
||||||
|
|
||||||
// verifying the initial number of commits
|
|
||||||
StepVerifier.create(gitExecutor.getCommitHistory(baseRepoSuffix))
|
|
||||||
.assertNext(gitLogDTOs -> {
|
|
||||||
assertThat(gitLogDTOs).isNotEmpty();
|
|
||||||
assertThat(gitLogDTOs.size()).isEqualTo(2);
|
|
||||||
|
|
||||||
Set<String> commitMessages =
|
|
||||||
gitLogDTOs.stream().map(GitLogDTO::getCommitMessage).collect(Collectors.toSet());
|
|
||||||
assertThat(commitMessages).doesNotContain(String.format(AUTO_COMMIT_MSG_FORMAT, "UNKNOWN"));
|
|
||||||
})
|
|
||||||
.verifyComplete();
|
|
||||||
|
|
||||||
// this would trigger autocommit
|
|
||||||
Mono<List<GitLogDTO>> gitlogDTOsMono = applicationPageService
|
|
||||||
.getPagesBasedOnApplicationMode(testApplication, ApplicationMode.EDIT)
|
|
||||||
.then(Mono.delay(Duration.ofSeconds(WAIT_DURATION_FOR_ASYNC_EVENT)))
|
|
||||||
.then(gitExecutor.getCommitHistory(baseRepoSuffix));
|
|
||||||
|
|
||||||
// verifying final number of commits
|
|
||||||
StepVerifier.create(gitlogDTOsMono)
|
|
||||||
.assertNext(gitLogDTOs -> {
|
|
||||||
assertThat(gitLogDTOs).isNotEmpty();
|
|
||||||
assertThat(gitLogDTOs.size()).isEqualTo(3);
|
|
||||||
|
|
||||||
Set<String> commitMessages =
|
|
||||||
gitLogDTOs.stream().map(GitLogDTO::getCommitMessage).collect(Collectors.toSet());
|
|
||||||
assertThat(commitMessages).contains(String.format(AUTO_COMMIT_MSG_FORMAT, "UNKNOWN"));
|
|
||||||
})
|
|
||||||
.verifyComplete();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@Disabled
|
|
||||||
public void testAutoCommit_whenOnlyClientIsEligibleForMigration_commitSuccess()
|
|
||||||
throws GitAPIException, IOException, URISyntaxException {
|
|
||||||
ApplicationJson applicationJson =
|
|
||||||
gitFileSystemTestHelper.getApplicationJson(this.getClass().getResource(APP_JSON_NAME));
|
|
||||||
|
|
||||||
int pageDSLNumber = applicationJson
|
|
||||||
.getPageList()
|
|
||||||
.get(0)
|
|
||||||
.getUnpublishedPage()
|
|
||||||
.getLayouts()
|
|
||||||
.get(0)
|
|
||||||
.getDsl()
|
|
||||||
.getAsNumber("version")
|
|
||||||
.intValue();
|
|
||||||
|
|
||||||
doReturn(Mono.just(new AutoCommitTriggerDTO(TRUE, TRUE, FALSE)))
|
|
||||||
.when(autoCommitEligibilityHelper)
|
|
||||||
.isAutoCommitRequired(anyString(), any(GitArtifactMetadata.class), any(PageDTO.class));
|
|
||||||
|
|
||||||
Mockito.when(dslMigrationUtils.getLatestDslVersion()).thenReturn(Mono.just(pageDSLNumber + 1));
|
|
||||||
|
|
||||||
JSONObject dslAfterMigration = new JSONObject();
|
|
||||||
dslAfterMigration.put("key", "after migration");
|
|
||||||
|
|
||||||
// mock the dsl migration utils to return updated dsl when requested with older dsl
|
|
||||||
Mockito.when(dslMigrationUtils.migratePageDsl(any(JSONObject.class))).thenReturn(Mono.just(dslAfterMigration));
|
|
||||||
|
|
||||||
gitFileSystemTestHelper.setupGitRepository(
|
|
||||||
WORKSPACE_ID, DEFAULT_APP_ID, BRANCH_NAME, REPO_NAME, applicationJson);
|
|
||||||
|
|
||||||
// verifying the initial number of commits
|
|
||||||
StepVerifier.create(gitExecutor.getCommitHistory(baseRepoSuffix))
|
|
||||||
.assertNext(gitLogDTOs -> {
|
|
||||||
assertThat(gitLogDTOs).isNotEmpty();
|
|
||||||
assertThat(gitLogDTOs.size()).isEqualTo(2);
|
|
||||||
|
|
||||||
Set<String> commitMessages =
|
|
||||||
gitLogDTOs.stream().map(GitLogDTO::getCommitMessage).collect(Collectors.toSet());
|
|
||||||
assertThat(commitMessages).doesNotContain(String.format(AUTO_COMMIT_MSG_FORMAT, "UNKNOWN"));
|
|
||||||
})
|
|
||||||
.verifyComplete();
|
|
||||||
|
|
||||||
// this would trigger autocommit
|
|
||||||
Mono<List<GitLogDTO>> gitlogDTOsMono = applicationPageService
|
|
||||||
.getPagesBasedOnApplicationMode(testApplication, ApplicationMode.EDIT)
|
|
||||||
.then(Mono.delay(Duration.ofSeconds(WAIT_DURATION_FOR_ASYNC_EVENT)))
|
|
||||||
.then(gitExecutor.getCommitHistory(baseRepoSuffix));
|
|
||||||
|
|
||||||
// verifying final number of commits
|
|
||||||
StepVerifier.create(gitlogDTOsMono)
|
|
||||||
.assertNext(gitLogDTOs -> {
|
|
||||||
assertThat(gitLogDTOs).isNotEmpty();
|
|
||||||
assertThat(gitLogDTOs.size()).isEqualTo(3);
|
|
||||||
|
|
||||||
Set<String> commitMessages =
|
|
||||||
gitLogDTOs.stream().map(GitLogDTO::getCommitMessage).collect(Collectors.toSet());
|
|
||||||
assertThat(commitMessages).contains(String.format(AUTO_COMMIT_MSG_FORMAT, "UNKNOWN"));
|
|
||||||
})
|
|
||||||
.verifyComplete();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@Disabled
|
|
||||||
public void testAutoCommit_whenAutoCommitNotEligible_returnsFalse()
|
|
||||||
throws URISyntaxException, IOException, GitAPIException {
|
|
||||||
|
|
||||||
ApplicationJson applicationJson =
|
|
||||||
gitFileSystemTestHelper.getApplicationJson(this.getClass().getResource(APP_JSON_NAME));
|
|
||||||
|
|
||||||
doReturn(Mono.just(new AutoCommitTriggerDTO(FALSE, FALSE, FALSE)))
|
|
||||||
.when(autoCommitEligibilityHelper)
|
|
||||||
.isAutoCommitRequired(anyString(), any(GitArtifactMetadata.class), any(PageDTO.class));
|
|
||||||
|
|
||||||
gitFileSystemTestHelper.setupGitRepository(
|
|
||||||
WORKSPACE_ID, DEFAULT_APP_ID, BRANCH_NAME, REPO_NAME, applicationJson);
|
|
||||||
|
|
||||||
// verifying the initial number of commits
|
|
||||||
StepVerifier.create(gitExecutor.getCommitHistory(baseRepoSuffix))
|
|
||||||
.assertNext(gitLogDTOs -> {
|
|
||||||
assertThat(gitLogDTOs).isNotEmpty();
|
|
||||||
assertThat(gitLogDTOs.size()).isEqualTo(2);
|
|
||||||
|
|
||||||
Set<String> commitMessages =
|
|
||||||
gitLogDTOs.stream().map(GitLogDTO::getCommitMessage).collect(Collectors.toSet());
|
|
||||||
assertThat(commitMessages).doesNotContain(String.format(AUTO_COMMIT_MSG_FORMAT, "UNKNOWN"));
|
|
||||||
})
|
|
||||||
.verifyComplete();
|
|
||||||
|
|
||||||
// this would not trigger autocommit
|
|
||||||
Mono<List<GitLogDTO>> gitlogDTOsMono = applicationPageService
|
|
||||||
.getPagesBasedOnApplicationMode(testApplication, ApplicationMode.EDIT)
|
|
||||||
.then(Mono.delay(Duration.ofSeconds(WAIT_DURATION_FOR_ASYNC_EVENT)))
|
|
||||||
.then(gitExecutor.getCommitHistory(baseRepoSuffix));
|
|
||||||
|
|
||||||
// verifying final number of commits
|
|
||||||
StepVerifier.create(gitlogDTOsMono)
|
|
||||||
.assertNext(gitLogDTOs -> {
|
|
||||||
assertThat(gitLogDTOs).isNotEmpty();
|
|
||||||
assertThat(gitLogDTOs.size()).isEqualTo(2);
|
|
||||||
|
|
||||||
Set<String> commitMessages =
|
|
||||||
gitLogDTOs.stream().map(GitLogDTO::getCommitMessage).collect(Collectors.toSet());
|
|
||||||
assertThat(commitMessages).doesNotContain(String.format(AUTO_COMMIT_MSG_FORMAT, "UNKNOWN"));
|
|
||||||
})
|
|
||||||
.verifyComplete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -14,8 +14,6 @@ import com.appsmith.server.dtos.ApplicationJson;
|
||||||
import com.appsmith.server.dtos.PageDTO;
|
import com.appsmith.server.dtos.PageDTO;
|
||||||
import com.appsmith.server.events.AutoCommitEvent;
|
import com.appsmith.server.events.AutoCommitEvent;
|
||||||
import com.appsmith.server.featureflags.CachedFeatures;
|
import com.appsmith.server.featureflags.CachedFeatures;
|
||||||
import com.appsmith.server.git.AutoCommitEventHandler;
|
|
||||||
import com.appsmith.server.git.AutoCommitEventHandlerImpl;
|
|
||||||
import com.appsmith.server.git.GitRedisUtils;
|
import com.appsmith.server.git.GitRedisUtils;
|
||||||
import com.appsmith.server.helpers.CommonGitFileUtils;
|
import com.appsmith.server.helpers.CommonGitFileUtils;
|
||||||
import com.appsmith.server.helpers.DSLMigrationUtils;
|
import com.appsmith.server.helpers.DSLMigrationUtils;
|
||||||
|
|
@ -54,7 +52,7 @@ import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static com.appsmith.server.git.AutoCommitEventHandlerCEImpl.AUTO_COMMIT_MSG_FORMAT;
|
import static com.appsmith.server.git.autocommit.AutoCommitEventHandlerCEImpl.AUTO_COMMIT_MSG_FORMAT;
|
||||||
import static java.lang.Boolean.FALSE;
|
import static java.lang.Boolean.FALSE;
|
||||||
import static java.lang.Boolean.TRUE;
|
import static java.lang.Boolean.TRUE;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
@ -498,12 +496,12 @@ public class AutoCommitEventHandlerImplTest {
|
||||||
autoCommitEvent.getBranchName());
|
autoCommitEvent.getBranchName());
|
||||||
|
|
||||||
CachedFeatures cachedFeatures = new CachedFeatures();
|
CachedFeatures cachedFeatures = new CachedFeatures();
|
||||||
cachedFeatures.setFeatures(Map.of(FeatureFlagEnum.release_git_cleanup_feature_enabled.name(), FALSE));
|
cachedFeatures.setFeatures(Map.of(FeatureFlagEnum.release_git_autocommit_feature_enabled.name(), FALSE));
|
||||||
Mockito.when(featureFlagService.getCachedTenantFeatureFlags())
|
Mockito.when(featureFlagService.getCachedTenantFeatureFlags())
|
||||||
.thenAnswer((Answer<CachedFeatures>) invocations -> cachedFeatures);
|
.thenAnswer((Answer<CachedFeatures>) invocations -> cachedFeatures);
|
||||||
|
|
||||||
gitFileSystemTestHelper.setupGitRepository(autoCommitEvent, applicationJson);
|
gitFileSystemTestHelper.setupGitRepository(autoCommitEvent, applicationJson);
|
||||||
cachedFeatures.setFeatures(Map.of(FeatureFlagEnum.release_git_cleanup_feature_enabled.name(), TRUE));
|
cachedFeatures.setFeatures(Map.of(FeatureFlagEnum.release_git_autocommit_feature_enabled.name(), TRUE));
|
||||||
|
|
||||||
StepVerifier.create(autoCommitEventHandler
|
StepVerifier.create(autoCommitEventHandler
|
||||||
.autoCommitServerMigration(autoCommitEvent)
|
.autoCommitServerMigration(autoCommitEvent)
|
||||||
|
|
@ -536,7 +534,7 @@ public class AutoCommitEventHandlerImplTest {
|
||||||
gitFileSystemTestHelper.getApplicationJson(this.getClass().getResource("application.json"));
|
gitFileSystemTestHelper.getApplicationJson(this.getClass().getResource("application.json"));
|
||||||
|
|
||||||
CachedFeatures cachedFeatures = new CachedFeatures();
|
CachedFeatures cachedFeatures = new CachedFeatures();
|
||||||
cachedFeatures.setFeatures(Map.of(FeatureFlagEnum.release_git_cleanup_feature_enabled.name(), FALSE));
|
cachedFeatures.setFeatures(Map.of(FeatureFlagEnum.release_git_autocommit_feature_enabled.name(), FALSE));
|
||||||
Mockito.when(featureFlagService.getCachedTenantFeatureFlags())
|
Mockito.when(featureFlagService.getCachedTenantFeatureFlags())
|
||||||
.thenAnswer((Answer<CachedFeatures>) invocations -> cachedFeatures);
|
.thenAnswer((Answer<CachedFeatures>) invocations -> cachedFeatures);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,686 @@
|
||||||
|
package com.appsmith.server.git.autocommit;
|
||||||
|
|
||||||
|
import com.appsmith.external.dtos.GitLogDTO;
|
||||||
|
import com.appsmith.external.enums.FeatureFlagEnum;
|
||||||
|
import com.appsmith.external.git.GitExecutor;
|
||||||
|
import com.appsmith.external.helpers.AppsmithBeanUtils;
|
||||||
|
import com.appsmith.server.acl.AclPermission;
|
||||||
|
import com.appsmith.server.applications.base.ApplicationService;
|
||||||
|
import com.appsmith.server.domains.Application;
|
||||||
|
import com.appsmith.server.domains.ApplicationMode;
|
||||||
|
import com.appsmith.server.domains.ApplicationPage;
|
||||||
|
import com.appsmith.server.domains.GitArtifactMetadata;
|
||||||
|
import com.appsmith.server.domains.GitAuth;
|
||||||
|
import com.appsmith.server.domains.GitProfile;
|
||||||
|
import com.appsmith.server.domains.Layout;
|
||||||
|
import com.appsmith.server.dtos.ApplicationJson;
|
||||||
|
import com.appsmith.server.dtos.AutoCommitResponseDTO;
|
||||||
|
import com.appsmith.server.dtos.PageDTO;
|
||||||
|
import com.appsmith.server.git.autocommit.helpers.AutoCommitEligibilityHelper;
|
||||||
|
import com.appsmith.server.git.common.CommonGitService;
|
||||||
|
import com.appsmith.server.helpers.CommonGitFileUtils;
|
||||||
|
import com.appsmith.server.helpers.DSLMigrationUtils;
|
||||||
|
import com.appsmith.server.helpers.GitPrivateRepoHelper;
|
||||||
|
import com.appsmith.server.helpers.RedisUtils;
|
||||||
|
import com.appsmith.server.migrations.JsonSchemaMigration;
|
||||||
|
import com.appsmith.server.migrations.JsonSchemaVersions;
|
||||||
|
import com.appsmith.server.newpages.base.NewPageService;
|
||||||
|
import com.appsmith.server.services.FeatureFlagService;
|
||||||
|
import com.appsmith.server.services.UserDataService;
|
||||||
|
import com.appsmith.server.solutions.PagePermission;
|
||||||
|
import com.appsmith.server.testhelpers.git.GitFileSystemTestHelper;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import net.minidev.json.JSONObject;
|
||||||
|
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||||
|
import org.eclipse.jgit.lib.BranchTrackingStatus;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
|
import org.springframework.boot.test.mock.mockito.SpyBean;
|
||||||
|
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||||
|
import reactor.core.publisher.Flux;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
import reactor.test.StepVerifier;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static com.appsmith.server.git.autocommit.AutoCommitEventHandlerCEImpl.AUTO_COMMIT_MSG_FORMAT;
|
||||||
|
import static java.lang.Boolean.FALSE;
|
||||||
|
import static java.lang.Boolean.TRUE;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
|
import static org.mockito.Mockito.doReturn;
|
||||||
|
|
||||||
|
@ExtendWith(SpringExtension.class)
|
||||||
|
@SpringBootTest
|
||||||
|
@Slf4j
|
||||||
|
public class AutoCommitServiceTest {
|
||||||
|
|
||||||
|
@SpyBean
|
||||||
|
AutoCommitService autoCommitService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
GitFileSystemTestHelper gitFileSystemTestHelper;
|
||||||
|
|
||||||
|
@SpyBean
|
||||||
|
GitExecutor gitExecutor;
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
FeatureFlagService featureFlagService;
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
DSLMigrationUtils dslMigrationUtils;
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
ApplicationService applicationService;
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
NewPageService newPageService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
PagePermission pagePermission;
|
||||||
|
|
||||||
|
@SpyBean
|
||||||
|
RedisUtils redisUtils;
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
CommonGitService commonGitService;
|
||||||
|
|
||||||
|
@SpyBean
|
||||||
|
CommonGitFileUtils commonGitFileUtils;
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
GitPrivateRepoHelper gitPrivateRepoHelper;
|
||||||
|
|
||||||
|
@SpyBean
|
||||||
|
AutoCommitEligibilityHelper autoCommitEligibilityHelper;
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
BranchTrackingStatus branchTrackingStatus;
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
UserDataService userDataService;
|
||||||
|
|
||||||
|
@SpyBean
|
||||||
|
JsonSchemaMigration jsonSchemaMigration;
|
||||||
|
|
||||||
|
Application testApplication;
|
||||||
|
|
||||||
|
Path baseRepoSuffix;
|
||||||
|
|
||||||
|
private static final Integer DSL_VERSION_NUMBER = 88;
|
||||||
|
private static final String WORKSPACE_ID = "test-workspace";
|
||||||
|
private static final String REPO_NAME = "test-repo";
|
||||||
|
private static final String BRANCH_NAME = "develop";
|
||||||
|
private static final String APP_JSON_NAME = "autocommit.json";
|
||||||
|
private static final String APP_NAME = "autocommit";
|
||||||
|
private static final Integer WAIT_DURATION_FOR_ASYNC_EVENT = 5;
|
||||||
|
private static final String PUBLIC_KEY = "public-key";
|
||||||
|
private static final String PRIVATE_KEY = "private-key";
|
||||||
|
private static final String REPO_URL = "domain.xy";
|
||||||
|
private static final String DEFAULT_APP_ID = "default-app-id", DEFAULT_BRANCH_NAME = "master";
|
||||||
|
private static final Integer SERVER_SCHEMA_VERSION = JsonSchemaVersions.serverVersion;
|
||||||
|
|
||||||
|
private Application createApplication() {
|
||||||
|
Application application = new Application();
|
||||||
|
application.setName(APP_NAME);
|
||||||
|
application.setWorkspaceId(WORKSPACE_ID);
|
||||||
|
application.setId(DEFAULT_APP_ID);
|
||||||
|
|
||||||
|
ApplicationPage applicationPage = new ApplicationPage();
|
||||||
|
applicationPage.setId("testPageId");
|
||||||
|
applicationPage.setIsDefault(TRUE);
|
||||||
|
|
||||||
|
application.setPages(List.of(applicationPage));
|
||||||
|
GitArtifactMetadata gitArtifactMetadata = new GitArtifactMetadata();
|
||||||
|
gitArtifactMetadata.setBranchName(BRANCH_NAME);
|
||||||
|
gitArtifactMetadata.setDefaultBranchName(DEFAULT_BRANCH_NAME);
|
||||||
|
gitArtifactMetadata.setRepoName(REPO_NAME);
|
||||||
|
gitArtifactMetadata.setDefaultApplicationId(DEFAULT_APP_ID);
|
||||||
|
gitArtifactMetadata.setRemoteUrl(REPO_URL);
|
||||||
|
|
||||||
|
GitAuth gitAuth = new GitAuth();
|
||||||
|
gitAuth.setPrivateKey(PRIVATE_KEY);
|
||||||
|
gitAuth.setPublicKey(PUBLIC_KEY);
|
||||||
|
gitArtifactMetadata.setGitAuth(gitAuth);
|
||||||
|
|
||||||
|
application.setGitApplicationMetadata(gitArtifactMetadata);
|
||||||
|
return application;
|
||||||
|
}
|
||||||
|
|
||||||
|
private GitProfile createGitProfile() {
|
||||||
|
GitProfile gitProfile = new GitProfile();
|
||||||
|
gitProfile.setAuthorName("authorName");
|
||||||
|
gitProfile.setAuthorEmail("author@domain.xy");
|
||||||
|
return gitProfile;
|
||||||
|
}
|
||||||
|
|
||||||
|
private PageDTO createPageDTO() {
|
||||||
|
JSONObject jsonObject = new JSONObject();
|
||||||
|
jsonObject.put("key", "value");
|
||||||
|
jsonObject.put("version", DSL_VERSION_NUMBER);
|
||||||
|
|
||||||
|
Layout layout1 = new Layout();
|
||||||
|
layout1.setId("testLayoutId");
|
||||||
|
layout1.setDsl(jsonObject);
|
||||||
|
|
||||||
|
PageDTO pageDTO = new PageDTO();
|
||||||
|
pageDTO.setId("testPageId");
|
||||||
|
pageDTO.setApplicationId(DEFAULT_APP_ID);
|
||||||
|
pageDTO.setLayouts(List.of(layout1));
|
||||||
|
return pageDTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
private org.json.JSONObject getMockedDsl() {
|
||||||
|
org.json.JSONObject jsonObject = new org.json.JSONObject();
|
||||||
|
jsonObject.put("version", DSL_VERSION_NUMBER);
|
||||||
|
return jsonObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void mockAutoCommitTriggerResponse(Boolean serverMigration, Boolean clientMigration) {
|
||||||
|
doReturn(Mono.just(getMockedDsl()))
|
||||||
|
.when(commonGitFileUtils)
|
||||||
|
.getPageDslVersionNumber(anyString(), any(), any(), anyBoolean(), any());
|
||||||
|
|
||||||
|
Integer dslVersionNumber = clientMigration ? DSL_VERSION_NUMBER + 1 : DSL_VERSION_NUMBER;
|
||||||
|
Integer serverSchemaVersionNumber = serverMigration ? SERVER_SCHEMA_VERSION - 1 : SERVER_SCHEMA_VERSION;
|
||||||
|
|
||||||
|
doReturn(Mono.just(dslVersionNumber)).when(dslMigrationUtils).getLatestDslVersion();
|
||||||
|
|
||||||
|
// server as true
|
||||||
|
doReturn(Mono.just(serverSchemaVersionNumber))
|
||||||
|
.when(commonGitFileUtils)
|
||||||
|
.getMetadataServerSchemaMigrationVersion(anyString(), any(), anyBoolean(), any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void beforeTest() {
|
||||||
|
|
||||||
|
// create application
|
||||||
|
testApplication = createApplication();
|
||||||
|
baseRepoSuffix = Paths.get(WORKSPACE_ID, DEFAULT_APP_ID, REPO_NAME);
|
||||||
|
|
||||||
|
// used for fetching application on autocommit service and gitAutoCommitHelper.autocommit
|
||||||
|
Mockito.when(applicationService.findByBranchNameAndDefaultApplicationId(
|
||||||
|
anyString(), anyString(), any(AclPermission.class)))
|
||||||
|
.thenReturn(Mono.just(testApplication));
|
||||||
|
|
||||||
|
// create page-dto
|
||||||
|
PageDTO pageDTO = createPageDTO();
|
||||||
|
|
||||||
|
Mockito.when(newPageService.findByApplicationIdAndApplicationMode(
|
||||||
|
DEFAULT_APP_ID, pagePermission.getEditPermission(), ApplicationMode.PUBLISHED))
|
||||||
|
.thenReturn(Flux.just(pageDTO));
|
||||||
|
|
||||||
|
Mockito.when(featureFlagService.check(FeatureFlagEnum.release_git_autocommit_eligibility_enabled))
|
||||||
|
.thenReturn(Mono.just(TRUE));
|
||||||
|
|
||||||
|
Mockito.when(featureFlagService.check(FeatureFlagEnum.release_git_autocommit_feature_enabled))
|
||||||
|
.thenReturn(Mono.just(TRUE));
|
||||||
|
|
||||||
|
Mockito.when(commonGitService.fetchRemoteChanges(
|
||||||
|
any(Application.class), any(Application.class), anyString(), anyBoolean()))
|
||||||
|
.thenReturn(Mono.just(branchTrackingStatus));
|
||||||
|
|
||||||
|
Mockito.when(branchTrackingStatus.getBehindCount()).thenReturn(0);
|
||||||
|
|
||||||
|
doReturn(Mono.just("success"))
|
||||||
|
.when(gitExecutor)
|
||||||
|
.pushApplication(baseRepoSuffix, REPO_URL, PUBLIC_KEY, PRIVATE_KEY, BRANCH_NAME);
|
||||||
|
|
||||||
|
Mockito.when(applicationService.findById(anyString(), any(AclPermission.class)))
|
||||||
|
.thenReturn(Mono.just(testApplication));
|
||||||
|
|
||||||
|
Mockito.when(gitPrivateRepoHelper.isBranchProtected(any(), anyString())).thenReturn(Mono.just(FALSE));
|
||||||
|
|
||||||
|
Mockito.when(userDataService.getGitProfileForCurrentUser(any())).thenReturn(Mono.just(createGitProfile()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
public void afterTest() {
|
||||||
|
gitFileSystemTestHelper.deleteWorkspaceDirectory(WORKSPACE_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAutoCommit_whenOnlyServerIsEligibleForMigration_commitSuccess()
|
||||||
|
throws URISyntaxException, IOException, GitAPIException {
|
||||||
|
|
||||||
|
ApplicationJson applicationJson =
|
||||||
|
gitFileSystemTestHelper.getApplicationJson(this.getClass().getResource(APP_JSON_NAME));
|
||||||
|
|
||||||
|
mockAutoCommitTriggerResponse(TRUE, FALSE);
|
||||||
|
|
||||||
|
ApplicationJson applicationJson1 = new ApplicationJson();
|
||||||
|
AppsmithBeanUtils.copyNewFieldValuesIntoOldObject(applicationJson, applicationJson1);
|
||||||
|
applicationJson1.setServerSchemaVersion(JsonSchemaVersions.serverVersion + 1);
|
||||||
|
|
||||||
|
doReturn(Mono.just(applicationJson1))
|
||||||
|
.when(jsonSchemaMigration)
|
||||||
|
.migrateApplicationJsonToLatestSchema(any(ApplicationJson.class));
|
||||||
|
|
||||||
|
gitFileSystemTestHelper.setupGitRepository(
|
||||||
|
WORKSPACE_ID, DEFAULT_APP_ID, BRANCH_NAME, REPO_NAME, applicationJson);
|
||||||
|
|
||||||
|
// verifying the initial number of commits
|
||||||
|
StepVerifier.create(gitExecutor.getCommitHistory(baseRepoSuffix))
|
||||||
|
.assertNext(gitLogDTOs -> {
|
||||||
|
assertThat(gitLogDTOs).isNotEmpty();
|
||||||
|
assertThat(gitLogDTOs.size()).isEqualTo(2);
|
||||||
|
|
||||||
|
Set<String> commitMessages =
|
||||||
|
gitLogDTOs.stream().map(GitLogDTO::getCommitMessage).collect(Collectors.toSet());
|
||||||
|
assertThat(commitMessages).doesNotContain(String.format(AUTO_COMMIT_MSG_FORMAT, "UNKNOWN"));
|
||||||
|
})
|
||||||
|
.verifyComplete();
|
||||||
|
|
||||||
|
// redis-utils fixing
|
||||||
|
Mockito.when(redisUtils.getRunningAutoCommitBranchName(DEFAULT_APP_ID)).thenReturn(Mono.empty());
|
||||||
|
Mockito.when(redisUtils.getAutoCommitProgress(DEFAULT_APP_ID)).thenReturn(Mono.empty());
|
||||||
|
|
||||||
|
Mono<AutoCommitResponseDTO> autoCommitResponseDTOMono =
|
||||||
|
autoCommitService.autoCommitApplication(testApplication.getId(), BRANCH_NAME);
|
||||||
|
|
||||||
|
StepVerifier.create(autoCommitResponseDTOMono)
|
||||||
|
.assertNext(autoCommitResponseDTO -> {
|
||||||
|
assertThat(autoCommitResponseDTO.getAutoCommitResponse())
|
||||||
|
.isEqualTo(AutoCommitResponseDTO.AutoCommitResponse.PUBLISHED);
|
||||||
|
})
|
||||||
|
.verifyComplete();
|
||||||
|
|
||||||
|
// this would trigger autocommit
|
||||||
|
Mono<List<GitLogDTO>> gitlogDTOsMono = Mono.delay(Duration.ofSeconds(WAIT_DURATION_FOR_ASYNC_EVENT))
|
||||||
|
.then(gitExecutor.getCommitHistory(baseRepoSuffix));
|
||||||
|
|
||||||
|
// verifying final number of commits
|
||||||
|
StepVerifier.create(gitlogDTOsMono)
|
||||||
|
.assertNext(gitLogDTOs -> {
|
||||||
|
assertThat(gitLogDTOs).isNotEmpty();
|
||||||
|
assertThat(gitLogDTOs.size()).isEqualTo(3);
|
||||||
|
|
||||||
|
Set<String> commitMessages =
|
||||||
|
gitLogDTOs.stream().map(GitLogDTO::getCommitMessage).collect(Collectors.toSet());
|
||||||
|
assertThat(commitMessages).contains(String.format(AUTO_COMMIT_MSG_FORMAT, "UNKNOWN"));
|
||||||
|
})
|
||||||
|
.verifyComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAutoCommit_whenOnlyClientIsEligibleForMigration_commitSuccess()
|
||||||
|
throws GitAPIException, IOException, URISyntaxException {
|
||||||
|
ApplicationJson applicationJson =
|
||||||
|
gitFileSystemTestHelper.getApplicationJson(this.getClass().getResource(APP_JSON_NAME));
|
||||||
|
|
||||||
|
int pageDSLNumber = applicationJson
|
||||||
|
.getPageList()
|
||||||
|
.get(0)
|
||||||
|
.getUnpublishedPage()
|
||||||
|
.getLayouts()
|
||||||
|
.get(0)
|
||||||
|
.getDsl()
|
||||||
|
.getAsNumber("version")
|
||||||
|
.intValue();
|
||||||
|
|
||||||
|
mockAutoCommitTriggerResponse(FALSE, TRUE);
|
||||||
|
|
||||||
|
Mockito.when(dslMigrationUtils.getLatestDslVersion()).thenReturn(Mono.just(pageDSLNumber + 1));
|
||||||
|
|
||||||
|
JSONObject dslAfterMigration = new JSONObject();
|
||||||
|
dslAfterMigration.put("key", "after migration");
|
||||||
|
|
||||||
|
// mock the dsl migration utils to return updated dsl when requested with older dsl
|
||||||
|
Mockito.when(dslMigrationUtils.migratePageDsl(any(JSONObject.class))).thenReturn(Mono.just(dslAfterMigration));
|
||||||
|
|
||||||
|
gitFileSystemTestHelper.setupGitRepository(
|
||||||
|
WORKSPACE_ID, DEFAULT_APP_ID, BRANCH_NAME, REPO_NAME, applicationJson);
|
||||||
|
|
||||||
|
// verifying the initial number of commits
|
||||||
|
StepVerifier.create(gitExecutor.getCommitHistory(baseRepoSuffix))
|
||||||
|
.assertNext(gitLogDTOs -> {
|
||||||
|
assertThat(gitLogDTOs).isNotEmpty();
|
||||||
|
assertThat(gitLogDTOs.size()).isEqualTo(2);
|
||||||
|
|
||||||
|
Set<String> commitMessages =
|
||||||
|
gitLogDTOs.stream().map(GitLogDTO::getCommitMessage).collect(Collectors.toSet());
|
||||||
|
assertThat(commitMessages).doesNotContain(String.format(AUTO_COMMIT_MSG_FORMAT, "UNKNOWN"));
|
||||||
|
})
|
||||||
|
.verifyComplete();
|
||||||
|
|
||||||
|
// redis-utils fixing
|
||||||
|
Mockito.when(redisUtils.getRunningAutoCommitBranchName(DEFAULT_APP_ID)).thenReturn(Mono.empty());
|
||||||
|
|
||||||
|
Mockito.when(redisUtils.getAutoCommitProgress(DEFAULT_APP_ID)).thenReturn(Mono.empty());
|
||||||
|
|
||||||
|
// this would trigger autocommit
|
||||||
|
Mono<AutoCommitResponseDTO> autoCommitResponseDTOMono =
|
||||||
|
autoCommitService.autoCommitApplication(testApplication.getId(), BRANCH_NAME);
|
||||||
|
|
||||||
|
StepVerifier.create(autoCommitResponseDTOMono)
|
||||||
|
.assertNext(autoCommitResponseDTO -> {
|
||||||
|
assertThat(autoCommitResponseDTO.getAutoCommitResponse())
|
||||||
|
.isEqualTo(AutoCommitResponseDTO.AutoCommitResponse.PUBLISHED);
|
||||||
|
})
|
||||||
|
.verifyComplete();
|
||||||
|
|
||||||
|
Mono<List<GitLogDTO>> gitlogDTOsMono = Mono.delay(Duration.ofSeconds(WAIT_DURATION_FOR_ASYNC_EVENT))
|
||||||
|
.then(gitExecutor.getCommitHistory(baseRepoSuffix));
|
||||||
|
|
||||||
|
// verifying final number of commits
|
||||||
|
StepVerifier.create(gitlogDTOsMono)
|
||||||
|
.assertNext(gitLogDTOs -> {
|
||||||
|
assertThat(gitLogDTOs).isNotEmpty();
|
||||||
|
assertThat(gitLogDTOs.size()).isEqualTo(3);
|
||||||
|
|
||||||
|
Set<String> commitMessages =
|
||||||
|
gitLogDTOs.stream().map(GitLogDTO::getCommitMessage).collect(Collectors.toSet());
|
||||||
|
assertThat(commitMessages).contains(String.format(AUTO_COMMIT_MSG_FORMAT, "UNKNOWN"));
|
||||||
|
})
|
||||||
|
.verifyComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAutoCommit_whenAutoCommitNotEligible_returnsFalse()
|
||||||
|
throws URISyntaxException, IOException, GitAPIException {
|
||||||
|
|
||||||
|
ApplicationJson applicationJson =
|
||||||
|
gitFileSystemTestHelper.getApplicationJson(this.getClass().getResource(APP_JSON_NAME));
|
||||||
|
|
||||||
|
mockAutoCommitTriggerResponse(FALSE, FALSE);
|
||||||
|
|
||||||
|
gitFileSystemTestHelper.setupGitRepository(
|
||||||
|
WORKSPACE_ID, DEFAULT_APP_ID, BRANCH_NAME, REPO_NAME, applicationJson);
|
||||||
|
|
||||||
|
// verifying the initial number of commits
|
||||||
|
StepVerifier.create(gitExecutor.getCommitHistory(baseRepoSuffix))
|
||||||
|
.assertNext(gitLogDTOs -> {
|
||||||
|
assertThat(gitLogDTOs).isNotEmpty();
|
||||||
|
assertThat(gitLogDTOs.size()).isEqualTo(2);
|
||||||
|
|
||||||
|
Set<String> commitMessages =
|
||||||
|
gitLogDTOs.stream().map(GitLogDTO::getCommitMessage).collect(Collectors.toSet());
|
||||||
|
assertThat(commitMessages).doesNotContain(String.format(AUTO_COMMIT_MSG_FORMAT, "UNKNOWN"));
|
||||||
|
})
|
||||||
|
.verifyComplete();
|
||||||
|
|
||||||
|
// redis-utils fixing
|
||||||
|
Mockito.when(redisUtils.getRunningAutoCommitBranchName(DEFAULT_APP_ID)).thenReturn(Mono.empty());
|
||||||
|
|
||||||
|
Mockito.when(redisUtils.getAutoCommitProgress(DEFAULT_APP_ID)).thenReturn(Mono.empty());
|
||||||
|
|
||||||
|
// this would not trigger autocommit
|
||||||
|
Mono<AutoCommitResponseDTO> autoCommitResponseDTOMono =
|
||||||
|
autoCommitService.autoCommitApplication(testApplication.getId(), BRANCH_NAME);
|
||||||
|
|
||||||
|
StepVerifier.create(autoCommitResponseDTOMono)
|
||||||
|
.assertNext(autoCommitResponseDTO -> {
|
||||||
|
assertThat(autoCommitResponseDTO.getAutoCommitResponse())
|
||||||
|
.isEqualTo(AutoCommitResponseDTO.AutoCommitResponse.IDLE);
|
||||||
|
})
|
||||||
|
.verifyComplete();
|
||||||
|
|
||||||
|
Mono<List<GitLogDTO>> gitlogDTOsMono = Mono.delay(Duration.ofSeconds(WAIT_DURATION_FOR_ASYNC_EVENT))
|
||||||
|
.then(gitExecutor.getCommitHistory(baseRepoSuffix));
|
||||||
|
|
||||||
|
// verifying final number of commits
|
||||||
|
StepVerifier.create(gitlogDTOsMono)
|
||||||
|
.assertNext(gitLogDTOs -> {
|
||||||
|
assertThat(gitLogDTOs).isNotEmpty();
|
||||||
|
assertThat(gitLogDTOs.size()).isEqualTo(2);
|
||||||
|
|
||||||
|
Set<String> commitMessages =
|
||||||
|
gitLogDTOs.stream().map(GitLogDTO::getCommitMessage).collect(Collectors.toSet());
|
||||||
|
assertThat(commitMessages).doesNotContain(String.format(AUTO_COMMIT_MSG_FORMAT, "UNKNOWN"));
|
||||||
|
})
|
||||||
|
.verifyComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAutoCommit_whenAutoCommitAlreadyInProgressOnAnotherBranch_returnsLocked() {
|
||||||
|
// redis-utils fixing
|
||||||
|
Mockito.when(redisUtils.getRunningAutoCommitBranchName(DEFAULT_APP_ID))
|
||||||
|
.thenReturn(Mono.just(DEFAULT_BRANCH_NAME));
|
||||||
|
|
||||||
|
Mockito.when(redisUtils.getAutoCommitProgress(DEFAULT_APP_ID)).thenReturn(Mono.just(70));
|
||||||
|
|
||||||
|
// this would not trigger autocommit
|
||||||
|
Mono<AutoCommitResponseDTO> autoCommitResponseDTOMono =
|
||||||
|
autoCommitService.autoCommitApplication(testApplication.getId(), BRANCH_NAME);
|
||||||
|
|
||||||
|
StepVerifier.create(autoCommitResponseDTOMono)
|
||||||
|
.assertNext(autoCommitResponseDTO -> {
|
||||||
|
assertThat(autoCommitResponseDTO.getAutoCommitResponse())
|
||||||
|
.isEqualTo(AutoCommitResponseDTO.AutoCommitResponse.LOCKED);
|
||||||
|
assertThat(autoCommitResponseDTO.getBranchName()).isEqualTo(DEFAULT_BRANCH_NAME);
|
||||||
|
assertThat(autoCommitResponseDTO.getProgress()).isEqualTo(70);
|
||||||
|
})
|
||||||
|
.verifyComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAutoCommit_whenAutoCommitAlreadyInProgressOnSameBranch_returnsInProgress() {
|
||||||
|
// redis-utils fixing
|
||||||
|
Mockito.when(redisUtils.getRunningAutoCommitBranchName(DEFAULT_APP_ID)).thenReturn(Mono.just(BRANCH_NAME));
|
||||||
|
|
||||||
|
Mockito.when(redisUtils.getAutoCommitProgress(DEFAULT_APP_ID)).thenReturn(Mono.just(70));
|
||||||
|
|
||||||
|
// this would not trigger autocommit
|
||||||
|
Mono<AutoCommitResponseDTO> autoCommitResponseDTOMono =
|
||||||
|
autoCommitService.autoCommitApplication(testApplication.getId(), BRANCH_NAME);
|
||||||
|
|
||||||
|
StepVerifier.create(autoCommitResponseDTOMono)
|
||||||
|
.assertNext(autoCommitResponseDTO -> {
|
||||||
|
assertThat(autoCommitResponseDTO.getAutoCommitResponse())
|
||||||
|
.isEqualTo(AutoCommitResponseDTO.AutoCommitResponse.IN_PROGRESS);
|
||||||
|
assertThat(autoCommitResponseDTO.getBranchName()).isEqualTo(BRANCH_NAME);
|
||||||
|
assertThat(autoCommitResponseDTO.getProgress()).isEqualTo(70);
|
||||||
|
})
|
||||||
|
.verifyComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAutoCommit_whenNoGitMetadata_returnsNonGitApp() {
|
||||||
|
testApplication.setGitApplicationMetadata(null);
|
||||||
|
// used for fetching application on autocommit service and gitAutoCommitHelper.autocommit
|
||||||
|
Mockito.when(applicationService.findByBranchNameAndDefaultApplicationId(
|
||||||
|
anyString(), anyString(), any(AclPermission.class)))
|
||||||
|
.thenReturn(Mono.just(testApplication));
|
||||||
|
|
||||||
|
// this would not trigger autocommit
|
||||||
|
Mono<AutoCommitResponseDTO> autoCommitResponseDTOMono =
|
||||||
|
autoCommitService.autoCommitApplication(testApplication.getId(), BRANCH_NAME);
|
||||||
|
|
||||||
|
StepVerifier.create(autoCommitResponseDTOMono)
|
||||||
|
.assertNext(autoCommitResponseDTO -> {
|
||||||
|
assertThat(autoCommitResponseDTO.getAutoCommitResponse())
|
||||||
|
.isEqualTo(AutoCommitResponseDTO.AutoCommitResponse.NON_GIT_APP);
|
||||||
|
})
|
||||||
|
.verifyComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAutoCommit_whenAutoCommitEligibleButPrerequisiteNotComplete_returnsRequired() {
|
||||||
|
|
||||||
|
mockAutoCommitTriggerResponse(TRUE, FALSE);
|
||||||
|
|
||||||
|
// redis-utils fixing
|
||||||
|
Mockito.when(redisUtils.getRunningAutoCommitBranchName(DEFAULT_APP_ID)).thenReturn(Mono.empty());
|
||||||
|
|
||||||
|
Mockito.when(redisUtils.getAutoCommitProgress(DEFAULT_APP_ID)).thenReturn(Mono.empty());
|
||||||
|
|
||||||
|
// number of commits behind to make the pre-req fail
|
||||||
|
Mockito.when(branchTrackingStatus.getBehindCount()).thenReturn(1);
|
||||||
|
|
||||||
|
// this would not trigger autocommit
|
||||||
|
Mono<AutoCommitResponseDTO> autoCommitResponseDTOMono =
|
||||||
|
autoCommitService.autoCommitApplication(testApplication.getId(), BRANCH_NAME);
|
||||||
|
|
||||||
|
StepVerifier.create(autoCommitResponseDTOMono)
|
||||||
|
.assertNext(autoCommitResponseDTO -> {
|
||||||
|
assertThat(autoCommitResponseDTO.getAutoCommitResponse())
|
||||||
|
.isEqualTo(AutoCommitResponseDTO.AutoCommitResponse.REQUIRED);
|
||||||
|
})
|
||||||
|
.verifyComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void
|
||||||
|
testAutoCommit_whenServerIsRunningMigrationCallsAutocommitAgainOnSameBranch_ReturnsAutoCommitInProgress()
|
||||||
|
throws URISyntaxException, IOException, GitAPIException {
|
||||||
|
|
||||||
|
ApplicationJson applicationJson =
|
||||||
|
gitFileSystemTestHelper.getApplicationJson(this.getClass().getResource(APP_JSON_NAME));
|
||||||
|
|
||||||
|
mockAutoCommitTriggerResponse(TRUE, FALSE);
|
||||||
|
|
||||||
|
ApplicationJson applicationJson1 = new ApplicationJson();
|
||||||
|
AppsmithBeanUtils.copyNewFieldValuesIntoOldObject(applicationJson, applicationJson1);
|
||||||
|
applicationJson1.setServerSchemaVersion(JsonSchemaVersions.serverVersion + 1);
|
||||||
|
|
||||||
|
doReturn(Mono.just(applicationJson1))
|
||||||
|
.when(jsonSchemaMigration)
|
||||||
|
.migrateApplicationJsonToLatestSchema(any(ApplicationJson.class));
|
||||||
|
|
||||||
|
gitFileSystemTestHelper.setupGitRepository(
|
||||||
|
WORKSPACE_ID, DEFAULT_APP_ID, BRANCH_NAME, REPO_NAME, applicationJson);
|
||||||
|
|
||||||
|
// verifying the initial number of commits
|
||||||
|
StepVerifier.create(gitExecutor.getCommitHistory(baseRepoSuffix))
|
||||||
|
.assertNext(gitLogDTOs -> {
|
||||||
|
assertThat(gitLogDTOs).isNotEmpty();
|
||||||
|
assertThat(gitLogDTOs.size()).isEqualTo(2);
|
||||||
|
|
||||||
|
Set<String> commitMessages =
|
||||||
|
gitLogDTOs.stream().map(GitLogDTO::getCommitMessage).collect(Collectors.toSet());
|
||||||
|
assertThat(commitMessages).doesNotContain(String.format(AUTO_COMMIT_MSG_FORMAT, "UNKNOWN"));
|
||||||
|
})
|
||||||
|
.verifyComplete();
|
||||||
|
|
||||||
|
// redis-utils fixing
|
||||||
|
Mockito.when(redisUtils.getRunningAutoCommitBranchName(DEFAULT_APP_ID)).thenReturn(Mono.empty());
|
||||||
|
Mockito.when(redisUtils.getAutoCommitProgress(DEFAULT_APP_ID)).thenReturn(Mono.empty());
|
||||||
|
|
||||||
|
Mono<AutoCommitResponseDTO> autoCommitResponseDTOMono =
|
||||||
|
autoCommitService.autoCommitApplication(testApplication.getId(), BRANCH_NAME);
|
||||||
|
|
||||||
|
StepVerifier.create(autoCommitResponseDTOMono)
|
||||||
|
.assertNext(autoCommitResponseDTO -> assertThat(autoCommitResponseDTO.getAutoCommitResponse())
|
||||||
|
.isEqualTo(AutoCommitResponseDTO.AutoCommitResponse.PUBLISHED))
|
||||||
|
.verifyComplete();
|
||||||
|
|
||||||
|
// redis-utils fixing
|
||||||
|
Mockito.when(redisUtils.getRunningAutoCommitBranchName(DEFAULT_APP_ID)).thenReturn(Mono.just(BRANCH_NAME));
|
||||||
|
Mockito.when(redisUtils.getAutoCommitProgress(DEFAULT_APP_ID)).thenReturn(Mono.just(20));
|
||||||
|
|
||||||
|
StepVerifier.create(autoCommitService.autoCommitApplication(testApplication.getId(), BRANCH_NAME))
|
||||||
|
.assertNext(autoCommitResponseDTO -> {
|
||||||
|
assertThat(autoCommitResponseDTO.getAutoCommitResponse())
|
||||||
|
.isEqualTo(AutoCommitResponseDTO.AutoCommitResponse.IN_PROGRESS);
|
||||||
|
assertThat(autoCommitResponseDTO.getBranchName()).isEqualTo(BRANCH_NAME);
|
||||||
|
})
|
||||||
|
.verifyComplete();
|
||||||
|
|
||||||
|
// this would trigger autocommit
|
||||||
|
Mono<List<GitLogDTO>> gitlogDTOsMono = Mono.delay(Duration.ofSeconds(WAIT_DURATION_FOR_ASYNC_EVENT))
|
||||||
|
.then(gitExecutor.getCommitHistory(baseRepoSuffix));
|
||||||
|
|
||||||
|
// verifying final number of commits
|
||||||
|
StepVerifier.create(gitlogDTOsMono)
|
||||||
|
.assertNext(gitLogDTOs -> {
|
||||||
|
assertThat(gitLogDTOs).isNotEmpty();
|
||||||
|
assertThat(gitLogDTOs.size()).isEqualTo(3);
|
||||||
|
|
||||||
|
Set<String> commitMessages =
|
||||||
|
gitLogDTOs.stream().map(GitLogDTO::getCommitMessage).collect(Collectors.toSet());
|
||||||
|
assertThat(commitMessages).contains(String.format(AUTO_COMMIT_MSG_FORMAT, "UNKNOWN"));
|
||||||
|
})
|
||||||
|
.verifyComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAutoCommit_whenServerIsRunningMigrationCallsAutocommitAgainOnDiffBranch_ReturnsAutoCommitLocked()
|
||||||
|
throws URISyntaxException, IOException, GitAPIException {
|
||||||
|
|
||||||
|
ApplicationJson applicationJson =
|
||||||
|
gitFileSystemTestHelper.getApplicationJson(this.getClass().getResource(APP_JSON_NAME));
|
||||||
|
|
||||||
|
mockAutoCommitTriggerResponse(TRUE, FALSE);
|
||||||
|
|
||||||
|
ApplicationJson applicationJson1 = new ApplicationJson();
|
||||||
|
AppsmithBeanUtils.copyNewFieldValuesIntoOldObject(applicationJson, applicationJson1);
|
||||||
|
applicationJson1.setServerSchemaVersion(JsonSchemaVersions.serverVersion + 1);
|
||||||
|
|
||||||
|
doReturn(Mono.just(applicationJson1))
|
||||||
|
.when(jsonSchemaMigration)
|
||||||
|
.migrateApplicationJsonToLatestSchema(any(ApplicationJson.class));
|
||||||
|
|
||||||
|
gitFileSystemTestHelper.setupGitRepository(
|
||||||
|
WORKSPACE_ID, DEFAULT_APP_ID, BRANCH_NAME, REPO_NAME, applicationJson);
|
||||||
|
|
||||||
|
// verifying the initial number of commits
|
||||||
|
StepVerifier.create(gitExecutor.getCommitHistory(baseRepoSuffix))
|
||||||
|
.assertNext(gitLogDTOs -> {
|
||||||
|
assertThat(gitLogDTOs).isNotEmpty();
|
||||||
|
assertThat(gitLogDTOs.size()).isEqualTo(2);
|
||||||
|
|
||||||
|
Set<String> commitMessages =
|
||||||
|
gitLogDTOs.stream().map(GitLogDTO::getCommitMessage).collect(Collectors.toSet());
|
||||||
|
assertThat(commitMessages).doesNotContain(String.format(AUTO_COMMIT_MSG_FORMAT, "UNKNOWN"));
|
||||||
|
})
|
||||||
|
.verifyComplete();
|
||||||
|
|
||||||
|
// redis-utils fixing
|
||||||
|
Mockito.when(redisUtils.getRunningAutoCommitBranchName(DEFAULT_APP_ID)).thenReturn(Mono.empty());
|
||||||
|
|
||||||
|
Mockito.when(redisUtils.getAutoCommitProgress(DEFAULT_APP_ID)).thenReturn(Mono.empty());
|
||||||
|
|
||||||
|
Mono<AutoCommitResponseDTO> autoCommitResponseDTOMono =
|
||||||
|
autoCommitService.autoCommitApplication(testApplication.getId(), BRANCH_NAME);
|
||||||
|
|
||||||
|
StepVerifier.create(autoCommitResponseDTOMono)
|
||||||
|
.assertNext(autoCommitResponseDTO -> assertThat(autoCommitResponseDTO.getAutoCommitResponse())
|
||||||
|
.isEqualTo(AutoCommitResponseDTO.AutoCommitResponse.PUBLISHED))
|
||||||
|
.verifyComplete();
|
||||||
|
|
||||||
|
// redis-utils fixing
|
||||||
|
Mockito.when(redisUtils.getRunningAutoCommitBranchName(DEFAULT_APP_ID)).thenReturn(Mono.just(BRANCH_NAME));
|
||||||
|
|
||||||
|
Mockito.when(redisUtils.getAutoCommitProgress(DEFAULT_APP_ID)).thenReturn(Mono.just(20));
|
||||||
|
|
||||||
|
StepVerifier.create(autoCommitService.autoCommitApplication(testApplication.getId(), DEFAULT_BRANCH_NAME))
|
||||||
|
.assertNext(autoCommitResponseDTO -> {
|
||||||
|
assertThat(autoCommitResponseDTO.getAutoCommitResponse())
|
||||||
|
.isEqualTo(AutoCommitResponseDTO.AutoCommitResponse.LOCKED);
|
||||||
|
assertThat(autoCommitResponseDTO.getBranchName()).isEqualTo(BRANCH_NAME);
|
||||||
|
})
|
||||||
|
.verifyComplete();
|
||||||
|
|
||||||
|
// this would trigger autocommit
|
||||||
|
Mono<List<GitLogDTO>> gitlogDTOsMono = Mono.delay(Duration.ofSeconds(WAIT_DURATION_FOR_ASYNC_EVENT))
|
||||||
|
.then(gitExecutor.getCommitHistory(baseRepoSuffix));
|
||||||
|
|
||||||
|
// verifying final number of commits
|
||||||
|
StepVerifier.create(gitlogDTOsMono)
|
||||||
|
.assertNext(gitLogDTOs -> {
|
||||||
|
assertThat(gitLogDTOs).isNotEmpty();
|
||||||
|
assertThat(gitLogDTOs.size()).isEqualTo(3);
|
||||||
|
|
||||||
|
Set<String> commitMessages =
|
||||||
|
gitLogDTOs.stream().map(GitLogDTO::getCommitMessage).collect(Collectors.toSet());
|
||||||
|
assertThat(commitMessages).contains(String.format(AUTO_COMMIT_MSG_FORMAT, "UNKNOWN"));
|
||||||
|
})
|
||||||
|
.verifyComplete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,6 @@ package com.appsmith.server.git.autocommit.helpers;
|
||||||
|
|
||||||
import com.appsmith.external.dtos.ModifiedResources;
|
import com.appsmith.external.dtos.ModifiedResources;
|
||||||
import com.appsmith.external.enums.FeatureFlagEnum;
|
import com.appsmith.external.enums.FeatureFlagEnum;
|
||||||
import com.appsmith.external.git.constants.GitConstants;
|
|
||||||
import com.appsmith.server.constants.ArtifactType;
|
import com.appsmith.server.constants.ArtifactType;
|
||||||
import com.appsmith.server.domains.Application;
|
import com.appsmith.server.domains.Application;
|
||||||
import com.appsmith.server.domains.GitArtifactMetadata;
|
import com.appsmith.server.domains.GitArtifactMetadata;
|
||||||
|
|
@ -36,6 +35,7 @@ import java.io.IOException;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static com.appsmith.external.git.constants.ce.GitConstantsCE.GitCommandConstantsCE.AUTO_COMMIT_ELIGIBILITY;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
|
@ -92,18 +92,23 @@ public class AutoCommitEligibilityHelperTest {
|
||||||
return pageDTO;
|
return pageDTO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private org.json.JSONObject getPageDSl(Integer dslVersionNumber) {
|
||||||
|
org.json.JSONObject jsonObject = new org.json.JSONObject();
|
||||||
|
jsonObject.put("version", dslVersionNumber);
|
||||||
|
return jsonObject;
|
||||||
|
}
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void beforeEach() {
|
public void beforeEach() {
|
||||||
Mockito.when(featureFlagService.check(FeatureFlagEnum.release_git_autocommit_feature_enabled))
|
Mockito.when(featureFlagService.check(FeatureFlagEnum.release_git_autocommit_feature_enabled))
|
||||||
.thenReturn(Mono.just(Boolean.TRUE));
|
.thenReturn(Mono.just(Boolean.TRUE));
|
||||||
|
|
||||||
Mockito.when(featureFlagService.check(FeatureFlagEnum.release_git_server_autocommit_feature_enabled))
|
Mockito.when(featureFlagService.check(FeatureFlagEnum.release_git_autocommit_eligibility_enabled))
|
||||||
.thenReturn(Mono.just(Boolean.TRUE));
|
.thenReturn(Mono.just(Boolean.TRUE));
|
||||||
|
|
||||||
Mockito.when(dslMigrationUtils.getLatestDslVersion()).thenReturn(Mono.just(RANDOM_DSL_VERSION_NUMBER));
|
Mockito.when(dslMigrationUtils.getLatestDslVersion()).thenReturn(Mono.just(RANDOM_DSL_VERSION_NUMBER));
|
||||||
|
|
||||||
Mockito.when(gitRedisUtils.addFileLock(
|
Mockito.when(gitRedisUtils.addFileLock(DEFAULT_APPLICATION_ID, AUTO_COMMIT_ELIGIBILITY))
|
||||||
DEFAULT_APPLICATION_ID, GitConstants.GitCommandConstants.METADATA, false))
|
|
||||||
.thenReturn(Mono.just(Boolean.TRUE));
|
.thenReturn(Mono.just(Boolean.TRUE));
|
||||||
Mockito.when(gitRedisUtils.releaseFileLock(DEFAULT_APPLICATION_ID)).thenReturn(Mono.just(Boolean.TRUE));
|
Mockito.when(gitRedisUtils.releaseFileLock(DEFAULT_APPLICATION_ID)).thenReturn(Mono.just(Boolean.TRUE));
|
||||||
}
|
}
|
||||||
|
|
@ -114,11 +119,16 @@ public class AutoCommitEligibilityHelperTest {
|
||||||
GitArtifactMetadata gitArtifactMetadata = createGitMetadata();
|
GitArtifactMetadata gitArtifactMetadata = createGitMetadata();
|
||||||
PageDTO pageDTO = createPageDTO(RANDOM_DSL_VERSION_NUMBER - 1);
|
PageDTO pageDTO = createPageDTO(RANDOM_DSL_VERSION_NUMBER - 1);
|
||||||
|
|
||||||
|
Mockito.doReturn(Mono.just(getPageDSl(RANDOM_DSL_VERSION_NUMBER - 1)))
|
||||||
|
.when(commonGitFileUtils)
|
||||||
|
.getPageDslVersionNumber(
|
||||||
|
WORKSPACE_ID, gitArtifactMetadata, pageDTO, Boolean.TRUE, ArtifactType.APPLICATION);
|
||||||
|
|
||||||
// this leads to server migration requirement as true
|
// this leads to server migration requirement as true
|
||||||
Mockito.doReturn(Mono.just(JsonSchemaVersions.serverVersion - 1))
|
Mockito.doReturn(Mono.just(JsonSchemaVersions.serverVersion - 1))
|
||||||
.when(commonGitFileUtils)
|
.when(commonGitFileUtils)
|
||||||
.getMetadataServerSchemaMigrationVersion(
|
.getMetadataServerSchemaMigrationVersion(
|
||||||
WORKSPACE_ID, DEFAULT_APPLICATION_ID, REPO_NAME, BRANCH_NAME, ArtifactType.APPLICATION);
|
WORKSPACE_ID, gitArtifactMetadata, Boolean.TRUE, ArtifactType.APPLICATION);
|
||||||
|
|
||||||
Mono<AutoCommitTriggerDTO> autoCommitTriggerDTOMono =
|
Mono<AutoCommitTriggerDTO> autoCommitTriggerDTOMono =
|
||||||
autoCommitEligibilityHelper.isAutoCommitRequired(WORKSPACE_ID, gitArtifactMetadata, pageDTO);
|
autoCommitEligibilityHelper.isAutoCommitRequired(WORKSPACE_ID, gitArtifactMetadata, pageDTO);
|
||||||
|
|
@ -140,11 +150,16 @@ public class AutoCommitEligibilityHelperTest {
|
||||||
GitArtifactMetadata gitArtifactMetadata = createGitMetadata();
|
GitArtifactMetadata gitArtifactMetadata = createGitMetadata();
|
||||||
PageDTO pageDTO = createPageDTO(RANDOM_DSL_VERSION_NUMBER);
|
PageDTO pageDTO = createPageDTO(RANDOM_DSL_VERSION_NUMBER);
|
||||||
|
|
||||||
|
Mockito.doReturn(Mono.just(getPageDSl(RANDOM_DSL_VERSION_NUMBER)))
|
||||||
|
.when(commonGitFileUtils)
|
||||||
|
.getPageDslVersionNumber(
|
||||||
|
WORKSPACE_ID, gitArtifactMetadata, pageDTO, Boolean.TRUE, ArtifactType.APPLICATION);
|
||||||
|
|
||||||
// this leads to server migration requirement as false
|
// this leads to server migration requirement as false
|
||||||
Mockito.doReturn(Mono.just(JsonSchemaVersions.serverVersion))
|
Mockito.doReturn(Mono.just(JsonSchemaVersions.serverVersion))
|
||||||
.when(commonGitFileUtils)
|
.when(commonGitFileUtils)
|
||||||
.getMetadataServerSchemaMigrationVersion(
|
.getMetadataServerSchemaMigrationVersion(
|
||||||
WORKSPACE_ID, DEFAULT_APPLICATION_ID, REPO_NAME, BRANCH_NAME, ArtifactType.APPLICATION);
|
WORKSPACE_ID, gitArtifactMetadata, Boolean.FALSE, ArtifactType.APPLICATION);
|
||||||
|
|
||||||
Mono<AutoCommitTriggerDTO> autoCommitTriggerDTOMono =
|
Mono<AutoCommitTriggerDTO> autoCommitTriggerDTOMono =
|
||||||
autoCommitEligibilityHelper.isAutoCommitRequired(WORKSPACE_ID, gitArtifactMetadata, pageDTO);
|
autoCommitEligibilityHelper.isAutoCommitRequired(WORKSPACE_ID, gitArtifactMetadata, pageDTO);
|
||||||
|
|
@ -166,11 +181,16 @@ public class AutoCommitEligibilityHelperTest {
|
||||||
GitArtifactMetadata gitArtifactMetadata = createGitMetadata();
|
GitArtifactMetadata gitArtifactMetadata = createGitMetadata();
|
||||||
PageDTO pageDTO = createPageDTO(RANDOM_DSL_VERSION_NUMBER - 1);
|
PageDTO pageDTO = createPageDTO(RANDOM_DSL_VERSION_NUMBER - 1);
|
||||||
|
|
||||||
|
Mockito.doReturn(Mono.just(getPageDSl(RANDOM_DSL_VERSION_NUMBER - 1)))
|
||||||
|
.when(commonGitFileUtils)
|
||||||
|
.getPageDslVersionNumber(
|
||||||
|
WORKSPACE_ID, gitArtifactMetadata, pageDTO, Boolean.TRUE, ArtifactType.APPLICATION);
|
||||||
|
|
||||||
// this leads to server migration requirement as false
|
// this leads to server migration requirement as false
|
||||||
Mockito.doReturn(Mono.just(JsonSchemaVersions.serverVersion))
|
Mockito.doReturn(Mono.just(JsonSchemaVersions.serverVersion))
|
||||||
.when(commonGitFileUtils)
|
.when(commonGitFileUtils)
|
||||||
.getMetadataServerSchemaMigrationVersion(
|
.getMetadataServerSchemaMigrationVersion(
|
||||||
WORKSPACE_ID, DEFAULT_APPLICATION_ID, REPO_NAME, BRANCH_NAME, ArtifactType.APPLICATION);
|
WORKSPACE_ID, gitArtifactMetadata, Boolean.FALSE, ArtifactType.APPLICATION);
|
||||||
|
|
||||||
Mono<AutoCommitTriggerDTO> autoCommitTriggerDTOMono =
|
Mono<AutoCommitTriggerDTO> autoCommitTriggerDTOMono =
|
||||||
autoCommitEligibilityHelper.isAutoCommitRequired(WORKSPACE_ID, gitArtifactMetadata, pageDTO);
|
autoCommitEligibilityHelper.isAutoCommitRequired(WORKSPACE_ID, gitArtifactMetadata, pageDTO);
|
||||||
|
|
@ -178,8 +198,9 @@ public class AutoCommitEligibilityHelperTest {
|
||||||
StepVerifier.create(autoCommitTriggerDTOMono)
|
StepVerifier.create(autoCommitTriggerDTOMono)
|
||||||
.assertNext(autoCommitTriggerDTO -> {
|
.assertNext(autoCommitTriggerDTO -> {
|
||||||
assertThat(autoCommitTriggerDTO.getIsAutoCommitRequired()).isTrue();
|
assertThat(autoCommitTriggerDTO.getIsAutoCommitRequired()).isTrue();
|
||||||
|
// Since client is true, server is true as well
|
||||||
assertThat(autoCommitTriggerDTO.getIsServerAutoCommitRequired())
|
assertThat(autoCommitTriggerDTO.getIsServerAutoCommitRequired())
|
||||||
.isFalse();
|
.isTrue();
|
||||||
assertThat(autoCommitTriggerDTO.getIsClientAutoCommitRequired())
|
assertThat(autoCommitTriggerDTO.getIsClientAutoCommitRequired())
|
||||||
.isTrue();
|
.isTrue();
|
||||||
})
|
})
|
||||||
|
|
@ -192,11 +213,16 @@ public class AutoCommitEligibilityHelperTest {
|
||||||
GitArtifactMetadata gitArtifactMetadata = createGitMetadata();
|
GitArtifactMetadata gitArtifactMetadata = createGitMetadata();
|
||||||
PageDTO pageDTO = createPageDTO(RANDOM_DSL_VERSION_NUMBER);
|
PageDTO pageDTO = createPageDTO(RANDOM_DSL_VERSION_NUMBER);
|
||||||
|
|
||||||
|
Mockito.doReturn(Mono.just(getPageDSl(RANDOM_DSL_VERSION_NUMBER)))
|
||||||
|
.when(commonGitFileUtils)
|
||||||
|
.getPageDslVersionNumber(
|
||||||
|
WORKSPACE_ID, gitArtifactMetadata, pageDTO, Boolean.TRUE, ArtifactType.APPLICATION);
|
||||||
|
|
||||||
// this leads to server migration requirement as true
|
// this leads to server migration requirement as true
|
||||||
Mockito.doReturn(Mono.just(JsonSchemaVersions.serverVersion - 1))
|
Mockito.doReturn(Mono.just(JsonSchemaVersions.serverVersion - 1))
|
||||||
.when(commonGitFileUtils)
|
.when(commonGitFileUtils)
|
||||||
.getMetadataServerSchemaMigrationVersion(
|
.getMetadataServerSchemaMigrationVersion(
|
||||||
WORKSPACE_ID, DEFAULT_APPLICATION_ID, REPO_NAME, BRANCH_NAME, ArtifactType.APPLICATION);
|
WORKSPACE_ID, gitArtifactMetadata, Boolean.FALSE, ArtifactType.APPLICATION);
|
||||||
|
|
||||||
Mono<AutoCommitTriggerDTO> autoCommitTriggerDTOMono =
|
Mono<AutoCommitTriggerDTO> autoCommitTriggerDTOMono =
|
||||||
autoCommitEligibilityHelper.isAutoCommitRequired(WORKSPACE_ID, gitArtifactMetadata, pageDTO);
|
autoCommitEligibilityHelper.isAutoCommitRequired(WORKSPACE_ID, gitArtifactMetadata, pageDTO);
|
||||||
|
|
@ -220,7 +246,7 @@ public class AutoCommitEligibilityHelperTest {
|
||||||
Mockito.doReturn(Mono.just(JsonSchemaVersions.serverVersion))
|
Mockito.doReturn(Mono.just(JsonSchemaVersions.serverVersion))
|
||||||
.when(commonGitFileUtils)
|
.when(commonGitFileUtils)
|
||||||
.getMetadataServerSchemaMigrationVersion(
|
.getMetadataServerSchemaMigrationVersion(
|
||||||
WORKSPACE_ID, DEFAULT_APPLICATION_ID, REPO_NAME, BRANCH_NAME, ArtifactType.APPLICATION);
|
WORKSPACE_ID, gitArtifactMetadata, Boolean.TRUE, ArtifactType.APPLICATION);
|
||||||
|
|
||||||
Mono<Boolean> isServerMigrationRequiredMono =
|
Mono<Boolean> isServerMigrationRequiredMono =
|
||||||
autoCommitEligibilityHelper.isServerAutoCommitRequired(WORKSPACE_ID, gitArtifactMetadata);
|
autoCommitEligibilityHelper.isServerAutoCommitRequired(WORKSPACE_ID, gitArtifactMetadata);
|
||||||
|
|
@ -239,7 +265,7 @@ public class AutoCommitEligibilityHelperTest {
|
||||||
Mockito.doReturn(Mono.just(JsonSchemaVersions.serverVersion - 1))
|
Mockito.doReturn(Mono.just(JsonSchemaVersions.serverVersion - 1))
|
||||||
.when(commonGitFileUtils)
|
.when(commonGitFileUtils)
|
||||||
.getMetadataServerSchemaMigrationVersion(
|
.getMetadataServerSchemaMigrationVersion(
|
||||||
WORKSPACE_ID, DEFAULT_APPLICATION_ID, REPO_NAME, BRANCH_NAME, ArtifactType.APPLICATION);
|
WORKSPACE_ID, gitArtifactMetadata, Boolean.FALSE, ArtifactType.APPLICATION);
|
||||||
|
|
||||||
Mono<Boolean> isServerMigrationRequiredMono =
|
Mono<Boolean> isServerMigrationRequiredMono =
|
||||||
autoCommitEligibilityHelper.isServerAutoCommitRequired(WORKSPACE_ID, gitArtifactMetadata);
|
autoCommitEligibilityHelper.isServerAutoCommitRequired(WORKSPACE_ID, gitArtifactMetadata);
|
||||||
|
|
@ -252,7 +278,7 @@ public class AutoCommitEligibilityHelperTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void isServerMigrationRequired_whenFeatureIsFlagFalse_returnsFalse() {
|
public void isServerMigrationRequired_whenFeatureIsFlagFalse_returnsFalse() {
|
||||||
Mockito.when(featureFlagService.check(FeatureFlagEnum.release_git_server_autocommit_feature_enabled))
|
Mockito.when(featureFlagService.check(FeatureFlagEnum.release_git_autocommit_eligibility_enabled))
|
||||||
.thenReturn(Mono.just(Boolean.FALSE));
|
.thenReturn(Mono.just(Boolean.FALSE));
|
||||||
|
|
||||||
GitArtifactMetadata gitArtifactMetadata = createGitMetadata();
|
GitArtifactMetadata gitArtifactMetadata = createGitMetadata();
|
||||||
|
|
@ -268,10 +294,18 @@ public class AutoCommitEligibilityHelperTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void isClientMigrationRequired_whenLatestDslIsNotAhead_returnsFalse() {
|
public void isClientMigrationRequired_whenLatestDslIsNotAhead_returnsFalse() {
|
||||||
|
GitArtifactMetadata gitArtifactMetadata = createGitMetadata();
|
||||||
PageDTO pageDTO = createPageDTO(RANDOM_DSL_VERSION_NUMBER);
|
PageDTO pageDTO = createPageDTO(RANDOM_DSL_VERSION_NUMBER);
|
||||||
|
|
||||||
|
Mockito.doReturn(Mono.just(getPageDSl(RANDOM_DSL_VERSION_NUMBER)))
|
||||||
|
.when(commonGitFileUtils)
|
||||||
|
.getPageDslVersionNumber(
|
||||||
|
WORKSPACE_ID, gitArtifactMetadata, pageDTO, Boolean.TRUE, ArtifactType.APPLICATION);
|
||||||
|
|
||||||
Mockito.when(dslMigrationUtils.getLatestDslVersion()).thenReturn(Mono.just(RANDOM_DSL_VERSION_NUMBER));
|
Mockito.when(dslMigrationUtils.getLatestDslVersion()).thenReturn(Mono.just(RANDOM_DSL_VERSION_NUMBER));
|
||||||
|
|
||||||
Mono<Boolean> isClientMigrationRequiredMono = autoCommitEligibilityHelper.isClientMigrationRequired(pageDTO);
|
Mono<Boolean> isClientMigrationRequiredMono =
|
||||||
|
autoCommitEligibilityHelper.isClientMigrationRequiredFSOps(WORKSPACE_ID, gitArtifactMetadata, pageDTO);
|
||||||
|
|
||||||
StepVerifier.create(isClientMigrationRequiredMono)
|
StepVerifier.create(isClientMigrationRequiredMono)
|
||||||
.assertNext(isClientMigrationRequired ->
|
.assertNext(isClientMigrationRequired ->
|
||||||
|
|
@ -281,10 +315,18 @@ public class AutoCommitEligibilityHelperTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void isClientMigrationRequired_whenLatestDslIsAhead_returnsTrue() {
|
public void isClientMigrationRequired_whenLatestDslIsAhead_returnsTrue() {
|
||||||
|
GitArtifactMetadata gitArtifactMetadata = createGitMetadata();
|
||||||
PageDTO pageDTO = createPageDTO(RANDOM_DSL_VERSION_NUMBER - 1);
|
PageDTO pageDTO = createPageDTO(RANDOM_DSL_VERSION_NUMBER - 1);
|
||||||
|
|
||||||
|
Mockito.doReturn(Mono.just(getPageDSl(RANDOM_DSL_VERSION_NUMBER - 1)))
|
||||||
|
.when(commonGitFileUtils)
|
||||||
|
.getPageDslVersionNumber(
|
||||||
|
WORKSPACE_ID, gitArtifactMetadata, pageDTO, Boolean.TRUE, ArtifactType.APPLICATION);
|
||||||
|
|
||||||
Mockito.when(dslMigrationUtils.getLatestDslVersion()).thenReturn(Mono.just(RANDOM_DSL_VERSION_NUMBER));
|
Mockito.when(dslMigrationUtils.getLatestDslVersion()).thenReturn(Mono.just(RANDOM_DSL_VERSION_NUMBER));
|
||||||
|
|
||||||
Mono<Boolean> isClientMigrationRequiredMono = autoCommitEligibilityHelper.isClientMigrationRequired(pageDTO);
|
Mono<Boolean> isClientMigrationRequiredMono =
|
||||||
|
autoCommitEligibilityHelper.isClientMigrationRequiredFSOps(WORKSPACE_ID, gitArtifactMetadata, pageDTO);
|
||||||
|
|
||||||
StepVerifier.create(isClientMigrationRequiredMono)
|
StepVerifier.create(isClientMigrationRequiredMono)
|
||||||
.assertNext(isClientMigrationRequired ->
|
.assertNext(isClientMigrationRequired ->
|
||||||
|
|
@ -294,7 +336,7 @@ public class AutoCommitEligibilityHelperTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void isClientMigrationRequired_whenFeatureFlagIsFalse_returnsFalse() {
|
public void isClientMigrationRequired_whenFeatureFlagIsFalse_returnsFalse() {
|
||||||
Mockito.when(featureFlagService.check(FeatureFlagEnum.release_git_autocommit_feature_enabled))
|
Mockito.when(featureFlagService.check(FeatureFlagEnum.release_git_autocommit_eligibility_enabled))
|
||||||
.thenReturn(Mono.just(Boolean.FALSE));
|
.thenReturn(Mono.just(Boolean.FALSE));
|
||||||
|
|
||||||
PageDTO pageDTO = createPageDTO(RANDOM_DSL_VERSION_NUMBER);
|
PageDTO pageDTO = createPageDTO(RANDOM_DSL_VERSION_NUMBER);
|
||||||
|
|
@ -308,14 +350,11 @@ public class AutoCommitEligibilityHelperTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void isAutoCommitRequired_whenFeatureIsFlagFalse_returnsAllFalse() {
|
public void isAutoCommitRequired_whenFeatureIsFlagFalse_returnsAllFalse() {
|
||||||
Mockito.when(featureFlagService.check(FeatureFlagEnum.release_git_autocommit_feature_enabled))
|
Mockito.when(featureFlagService.check(FeatureFlagEnum.release_git_autocommit_eligibility_enabled))
|
||||||
.thenReturn(Mono.just(Boolean.FALSE));
|
|
||||||
|
|
||||||
Mockito.when(featureFlagService.check(FeatureFlagEnum.release_git_server_autocommit_feature_enabled))
|
|
||||||
.thenReturn(Mono.just(Boolean.FALSE));
|
.thenReturn(Mono.just(Boolean.FALSE));
|
||||||
|
|
||||||
GitArtifactMetadata gitArtifactMetadata = createGitMetadata();
|
GitArtifactMetadata gitArtifactMetadata = createGitMetadata();
|
||||||
PageDTO pageDTO = createPageDTO(RANDOM_DSL_VERSION_NUMBER);
|
PageDTO pageDTO = createPageDTO(RANDOM_DSL_VERSION_NUMBER - 1);
|
||||||
|
|
||||||
Mono<AutoCommitTriggerDTO> autoCommitTriggerDTOMono =
|
Mono<AutoCommitTriggerDTO> autoCommitTriggerDTOMono =
|
||||||
autoCommitEligibilityHelper.isAutoCommitRequired(WORKSPACE_ID, gitArtifactMetadata, pageDTO);
|
autoCommitEligibilityHelper.isAutoCommitRequired(WORKSPACE_ID, gitArtifactMetadata, pageDTO);
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,9 @@ import com.appsmith.server.domains.AutoCommitConfig;
|
||||||
import com.appsmith.server.domains.GitArtifactMetadata;
|
import com.appsmith.server.domains.GitArtifactMetadata;
|
||||||
import com.appsmith.server.domains.GitAuth;
|
import com.appsmith.server.domains.GitAuth;
|
||||||
import com.appsmith.server.domains.GitProfile;
|
import com.appsmith.server.domains.GitProfile;
|
||||||
import com.appsmith.server.dtos.AutoCommitProgressDTO;
|
import com.appsmith.server.dtos.AutoCommitResponseDTO;
|
||||||
import com.appsmith.server.events.AutoCommitEvent;
|
import com.appsmith.server.events.AutoCommitEvent;
|
||||||
import com.appsmith.server.git.AutoCommitEventHandler;
|
import com.appsmith.server.git.autocommit.AutoCommitEventHandler;
|
||||||
import com.appsmith.server.git.common.CommonGitService;
|
import com.appsmith.server.git.common.CommonGitService;
|
||||||
import com.appsmith.server.helpers.GitPrivateRepoHelper;
|
import com.appsmith.server.helpers.GitPrivateRepoHelper;
|
||||||
import com.appsmith.server.helpers.RedisUtils;
|
import com.appsmith.server.helpers.RedisUtils;
|
||||||
|
|
@ -32,6 +32,8 @@ import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
import reactor.test.StepVerifier;
|
import reactor.test.StepVerifier;
|
||||||
|
|
||||||
|
import static com.appsmith.server.dtos.AutoCommitResponseDTO.AutoCommitResponse.IDLE;
|
||||||
|
import static com.appsmith.server.dtos.AutoCommitResponseDTO.AutoCommitResponse.IN_PROGRESS;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||||
|
|
@ -241,14 +243,14 @@ public class GitAutoCommitHelperImplTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getAutoCommitProgress_WhenAutoCommitRunning_ReturnsValidResponse() {
|
public void getAutoCommitProgress_WhenAutoCommitRunning_ReturnsValidResponse() {
|
||||||
Mono<AutoCommitProgressDTO> progressDTOMono = redisUtils
|
Mono<AutoCommitResponseDTO> progressDTOMono = redisUtils
|
||||||
.startAutoCommit(defaultApplicationId, branchName)
|
.startAutoCommit(defaultApplicationId, branchName)
|
||||||
.then(redisUtils.setAutoCommitProgress(defaultApplicationId, 20))
|
.then(redisUtils.setAutoCommitProgress(defaultApplicationId, 20))
|
||||||
.then(gitAutoCommitHelper.getAutoCommitProgress(defaultApplicationId));
|
.then(gitAutoCommitHelper.getAutoCommitProgress(defaultApplicationId, branchName));
|
||||||
|
|
||||||
StepVerifier.create(progressDTOMono)
|
StepVerifier.create(progressDTOMono)
|
||||||
.assertNext(dto -> {
|
.assertNext(dto -> {
|
||||||
assertThat(dto.getIsRunning()).isTrue();
|
assertThat(dto.getAutoCommitResponse()).isEqualTo(IN_PROGRESS);
|
||||||
assertThat(dto.getProgress()).isEqualTo(20);
|
assertThat(dto.getProgress()).isEqualTo(20);
|
||||||
assertThat(dto.getBranchName()).isEqualTo(branchName);
|
assertThat(dto.getBranchName()).isEqualTo(branchName);
|
||||||
})
|
})
|
||||||
|
|
@ -257,15 +259,15 @@ public class GitAutoCommitHelperImplTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getAutoCommitProgress_WhenNoAutoCommitFinished_ReturnsValidResponse() {
|
public void getAutoCommitProgress_WhenNoAutoCommitFinished_ReturnsValidResponse() {
|
||||||
Mono<AutoCommitProgressDTO> progressDTOMono = redisUtils
|
Mono<AutoCommitResponseDTO> progressDTOMono = redisUtils
|
||||||
.startAutoCommit(defaultApplicationId, branchName)
|
.startAutoCommit(defaultApplicationId, branchName)
|
||||||
.then(redisUtils.setAutoCommitProgress(defaultApplicationId, 20))
|
.then(redisUtils.setAutoCommitProgress(defaultApplicationId, 20))
|
||||||
.then(redisUtils.finishAutoCommit(defaultApplicationId))
|
.then(redisUtils.finishAutoCommit(defaultApplicationId))
|
||||||
.then(gitAutoCommitHelper.getAutoCommitProgress(defaultApplicationId));
|
.then(gitAutoCommitHelper.getAutoCommitProgress(defaultApplicationId, branchName));
|
||||||
|
|
||||||
StepVerifier.create(progressDTOMono)
|
StepVerifier.create(progressDTOMono)
|
||||||
.assertNext(dto -> {
|
.assertNext(dto -> {
|
||||||
assertThat(dto.getIsRunning()).isFalse();
|
assertThat(dto.getAutoCommitResponse()).isEqualTo(IDLE);
|
||||||
assertThat(dto.getProgress()).isZero();
|
assertThat(dto.getProgress()).isZero();
|
||||||
assertThat(dto.getBranchName()).isNull();
|
assertThat(dto.getBranchName()).isNull();
|
||||||
})
|
})
|
||||||
|
|
@ -274,10 +276,11 @@ public class GitAutoCommitHelperImplTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getAutoCommitProgress_WhenNoAutoCommitRunning_ReturnsValidResponse() {
|
public void getAutoCommitProgress_WhenNoAutoCommitRunning_ReturnsValidResponse() {
|
||||||
Mono<AutoCommitProgressDTO> progressDTOMono = gitAutoCommitHelper.getAutoCommitProgress(defaultApplicationId);
|
Mono<AutoCommitResponseDTO> progressDTOMono =
|
||||||
|
gitAutoCommitHelper.getAutoCommitProgress(defaultApplicationId, branchName);
|
||||||
StepVerifier.create(progressDTOMono)
|
StepVerifier.create(progressDTOMono)
|
||||||
.assertNext(dto -> {
|
.assertNext(dto -> {
|
||||||
assertThat(dto.getIsRunning()).isFalse();
|
assertThat(dto.getAutoCommitResponse()).isEqualTo(IDLE);
|
||||||
assertThat(dto.getProgress()).isZero();
|
assertThat(dto.getProgress()).isZero();
|
||||||
assertThat(dto.getBranchName()).isNull();
|
assertThat(dto.getBranchName()).isNull();
|
||||||
})
|
})
|
||||||
|
|
@ -333,7 +336,7 @@ public class GitAutoCommitHelperImplTest {
|
||||||
|
|
||||||
application.setGitApplicationMetadata(metaData);
|
application.setGitApplicationMetadata(metaData);
|
||||||
|
|
||||||
Mockito.when(featureFlagService.check(FeatureFlagEnum.release_git_server_autocommit_feature_enabled))
|
Mockito.when(featureFlagService.check(FeatureFlagEnum.release_git_autocommit_feature_enabled))
|
||||||
.thenReturn(Mono.just(Boolean.FALSE));
|
.thenReturn(Mono.just(Boolean.FALSE));
|
||||||
|
|
||||||
StepVerifier.create(gitAutoCommitHelper.autoCommitServerMigration(defaultApplicationId, branchName))
|
StepVerifier.create(gitAutoCommitHelper.autoCommitServerMigration(defaultApplicationId, branchName))
|
||||||
|
|
@ -358,7 +361,7 @@ public class GitAutoCommitHelperImplTest {
|
||||||
|
|
||||||
application.setGitApplicationMetadata(metaData);
|
application.setGitApplicationMetadata(metaData);
|
||||||
|
|
||||||
Mockito.when(featureFlagService.check(FeatureFlagEnum.release_git_server_autocommit_feature_enabled))
|
Mockito.when(featureFlagService.check(FeatureFlagEnum.release_git_autocommit_feature_enabled))
|
||||||
.thenReturn(Mono.just(Boolean.TRUE));
|
.thenReturn(Mono.just(Boolean.TRUE));
|
||||||
|
|
||||||
Mockito.when(applicationService.findById(anyString(), any(AclPermission.class)))
|
Mockito.when(applicationService.findById(anyString(), any(AclPermission.class)))
|
||||||
|
|
@ -396,7 +399,7 @@ public class GitAutoCommitHelperImplTest {
|
||||||
|
|
||||||
application.setGitApplicationMetadata(metaData);
|
application.setGitApplicationMetadata(metaData);
|
||||||
|
|
||||||
Mockito.when(featureFlagService.check(FeatureFlagEnum.release_git_server_autocommit_feature_enabled))
|
Mockito.when(featureFlagService.check(FeatureFlagEnum.release_git_autocommit_feature_enabled))
|
||||||
.thenReturn(Mono.just(Boolean.TRUE));
|
.thenReturn(Mono.just(Boolean.TRUE));
|
||||||
|
|
||||||
Mockito.when(applicationService.findById(anyString(), any(AclPermission.class)))
|
Mockito.when(applicationService.findById(anyString(), any(AclPermission.class)))
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,34 @@
|
||||||
package com.appsmith.server.helpers;
|
package com.appsmith.server.helpers;
|
||||||
|
|
||||||
|
import com.appsmith.server.constants.ArtifactType;
|
||||||
|
import com.appsmith.server.domains.Application;
|
||||||
|
import com.appsmith.server.dtos.ApplicationJson;
|
||||||
|
import com.appsmith.server.dtos.CacheableApplicationJson;
|
||||||
|
import com.appsmith.server.solutions.ApplicationPermission;
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import mockwebserver3.MockResponse;
|
||||||
|
import mockwebserver3.MockWebServer;
|
||||||
|
import org.junit.jupiter.api.AfterAll;
|
||||||
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
|
import org.springframework.boot.test.mock.mockito.SpyBean;
|
||||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
import reactor.test.StepVerifier;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.time.Instant;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This test is written based on the inspiration from the tutorial:
|
* This test is written based on the inspiration from the tutorial:
|
||||||
|
|
@ -11,155 +37,139 @@ import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||||
@ExtendWith(SpringExtension.class)
|
@ExtendWith(SpringExtension.class)
|
||||||
@SpringBootTest
|
@SpringBootTest
|
||||||
public class CacheableTemplateHelperTemplateJsonDataTest {
|
public class CacheableTemplateHelperTemplateJsonDataTest {
|
||||||
// private static final ObjectMapper objectMapper = new ObjectMapper();
|
private static final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
// private static MockWebServer mockCloudServices;
|
private static MockWebServer mockCloudServices;
|
||||||
//
|
|
||||||
// @MockBean
|
@MockBean
|
||||||
// ApplicationPermission applicationPermission;
|
ApplicationPermission applicationPermission;
|
||||||
//
|
|
||||||
// @MockBean
|
@Autowired
|
||||||
// private CloudServicesConfig cloudServicesConfig;
|
CacheableTemplateHelper cacheableTemplateHelper;
|
||||||
//
|
|
||||||
// @Autowired
|
@SpyBean
|
||||||
// CacheableTemplateHelper cacheableTemplateHelper;
|
CacheableTemplateHelper spyCacheableTemplateHelper;
|
||||||
//
|
|
||||||
// @SpyBean
|
String baseUrl;
|
||||||
// CacheableTemplateHelper spyCacheableTemplateHelper;
|
|
||||||
//
|
@BeforeAll
|
||||||
// @BeforeAll
|
public static void setUp() throws IOException {
|
||||||
// public static void setUp() throws IOException {
|
mockCloudServices = new MockWebServer();
|
||||||
// mockCloudServices = new MockWebServer();
|
mockCloudServices.start();
|
||||||
// mockCloudServices.start();
|
}
|
||||||
// }
|
|
||||||
//
|
@AfterAll
|
||||||
// @AfterAll
|
public static void tearDown() throws IOException {
|
||||||
// public static void tearDown() throws IOException {
|
mockCloudServices.shutdown();
|
||||||
// mockCloudServices.shutdown();
|
}
|
||||||
// }
|
|
||||||
//
|
@BeforeEach
|
||||||
// @BeforeEach
|
public void initialize() {
|
||||||
// public void initialize() {
|
baseUrl = String.format("http://localhost:%s", mockCloudServices.getPort());
|
||||||
// String baseUrl = String.format("http://localhost:%s", mockCloudServices.getPort());
|
}
|
||||||
//
|
|
||||||
// // mock the cloud services config so that it returns mock server url as cloud
|
/* Scenarios covered via this test:
|
||||||
// // service base url
|
* 1. CacheableTemplateHelper doesn't have the POJO or has an empty POJO.
|
||||||
// Mockito.when(cloudServicesConfig.getBaseUrl()).thenReturn(baseUrl);
|
* 2. Fetch the templates via the normal flow by mocking CS.
|
||||||
// }
|
* 3. Check if the CacheableTemplateHelper.getApplicationTemplateList() is the same as the object returned by
|
||||||
//
|
the normal flow function. This will ensure that the cache is being set correctly.
|
||||||
// private ApplicationTemplate create(String id, String title) {
|
* 4. From the above steps we now have the cache set.
|
||||||
// ApplicationTemplate applicationTemplate = new ApplicationTemplate();
|
* 5. Fetch the templates again, verify the data is the same as the one fetched in step 2.
|
||||||
// applicationTemplate.setId(id);
|
* 6. Verify the cache is used and not the mock. This is done by asserting the lastUpdated time of the cache.
|
||||||
// applicationTemplate.setTitle(title);
|
*/
|
||||||
// return applicationTemplate;
|
@Test
|
||||||
// }
|
public void getApplicationJson_cacheIsEmpty_VerifyDataSavedInCache() throws JsonProcessingException {
|
||||||
//
|
ApplicationJson applicationJson = new ApplicationJson();
|
||||||
// /* Scenarios covered via this test:
|
applicationJson.setArtifactJsonType(ArtifactType.APPLICATION);
|
||||||
// * 1. CacheableTemplateHelper doesn't have the POJO or has an empty POJO.
|
applicationJson.setExportedApplication(new Application());
|
||||||
// * 2. Fetch the templates via the normal flow by mocking CS.
|
|
||||||
// * 3. Check if the CacheableTemplateHelper.getApplicationTemplateList() is the same as the object returned by
|
assertThat(cacheableTemplateHelper.getCacheableApplicationJsonMap().size())
|
||||||
// the normal flow function. This will ensure that the cache is being set correctly.
|
.isEqualTo(0);
|
||||||
// * 4. From the above steps we now have the cache set.
|
|
||||||
// * 5. Fetch the templates again, verify the data is the same as the one fetched in step 2.
|
// mock the server to return a template when it's called
|
||||||
// * 6. Verify the cache is used and not the mock. This is done by asserting the lastUpdated time of the cache.
|
mockCloudServices.enqueue(new MockResponse()
|
||||||
// */
|
.setBody(objectMapper.writeValueAsString(applicationJson))
|
||||||
// @Test
|
.addHeader("Content-Type", "application/json"));
|
||||||
// public void getApplicationJson_cacheIsEmpty_VerifyDataSavedInCache() throws JsonProcessingException {
|
|
||||||
// ApplicationJson applicationJson = new ApplicationJson();
|
Mono<CacheableApplicationJson> templateListMono =
|
||||||
// applicationJson.setArtifactJsonType(ArtifactType.APPLICATION);
|
cacheableTemplateHelper.getApplicationByTemplateId("templateId", baseUrl);
|
||||||
// applicationJson.setExportedApplication(new Application());
|
|
||||||
//
|
final Instant[] timeFromCache = {Instant.now()};
|
||||||
// assertThat(cacheableTemplateHelper.getCacheableApplicationJsonMap().size())
|
// make sure we've received the response returned by the mockCloudServices
|
||||||
// .isEqualTo(0);
|
StepVerifier.create(templateListMono)
|
||||||
//
|
.assertNext(cacheableApplicationJson1 -> {
|
||||||
// // mock the server to return a template when it's called
|
assertThat(cacheableApplicationJson1.getApplicationJson()).isNotNull();
|
||||||
// mockCloudServices.enqueue(new MockResponse()
|
timeFromCache[0] = cacheableApplicationJson1.getCacheExpiryTime();
|
||||||
// .setBody(objectMapper.writeValueAsString(applicationJson))
|
})
|
||||||
// .addHeader("Content-Type", "application/json"));
|
.verifyComplete();
|
||||||
//
|
|
||||||
// Mono<CacheableApplicationJson> templateListMono =
|
// Fetch the same application json again and verify the time stamp to confirm value is coming from POJO
|
||||||
// cacheableTemplateHelper.getApplicationByTemplateId("templateId",
|
StepVerifier.create(cacheableTemplateHelper.getApplicationByTemplateId("templateId", baseUrl))
|
||||||
// cloudServicesConfig.getBaseUrl());
|
.assertNext(cacheableApplicationJson1 -> {
|
||||||
//
|
assertThat(cacheableApplicationJson1.getApplicationJson()).isNotNull();
|
||||||
// final Instant[] timeFromCache = {Instant.now()};
|
assertThat(cacheableApplicationJson1.getCacheExpiryTime()).isEqualTo(timeFromCache[0]);
|
||||||
// // make sure we've received the response returned by the mockCloudServices
|
})
|
||||||
// StepVerifier.create(templateListMono)
|
.verifyComplete();
|
||||||
// .assertNext(cacheableApplicationJson1 -> {
|
assertThat(cacheableTemplateHelper.getCacheableApplicationJsonMap().size())
|
||||||
// assertThat(cacheableApplicationJson1.getApplicationJson()).isNotNull();
|
.isEqualTo(1);
|
||||||
// timeFromCache[0] = cacheableApplicationJson1.getCacheExpiryTime();
|
}
|
||||||
// })
|
|
||||||
// .verifyComplete();
|
/* Scenarios covered via this test:
|
||||||
//
|
* 1. Mock the cache isCacheValid to return false, so the cache is invalidated
|
||||||
// // Fetch the same application json again and verify the time stamp to confirm value is coming from POJO
|
* 2. Fetch the templates again, verify the data is from the mock and not from the cache.
|
||||||
// StepVerifier.create(cacheableTemplateHelper.getApplicationByTemplateId(
|
*/
|
||||||
// "templateId", cloudServicesConfig.getBaseUrl()))
|
@Test
|
||||||
// .assertNext(cacheableApplicationJson1 -> {
|
public void getApplicationJson_cacheIsDirty_verifyDataIsFetchedFromSource() {
|
||||||
// assertThat(cacheableApplicationJson1.getApplicationJson()).isNotNull();
|
ApplicationJson applicationJson = new ApplicationJson();
|
||||||
// assertThat(cacheableApplicationJson1.getCacheExpiryTime()).isEqualTo(timeFromCache[0]);
|
Application test = new Application();
|
||||||
// })
|
test.setName("New Application");
|
||||||
// .verifyComplete();
|
applicationJson.setArtifactJsonType(ArtifactType.APPLICATION);
|
||||||
// assertThat(cacheableTemplateHelper.getCacheableApplicationJsonMap().size())
|
applicationJson.setExportedApplication(test);
|
||||||
// .isEqualTo(1);
|
|
||||||
// }
|
// mock the server to return the above three templates
|
||||||
//
|
mockCloudServices.enqueue(new MockResponse()
|
||||||
// /* Scenarios covered via this test:
|
.setBody(new Gson().toJson(applicationJson))
|
||||||
// * 1. Mock the cache isCacheValid to return false, so the cache is invalidated
|
.addHeader("Content-Type", "application/json"));
|
||||||
// * 2. Fetch the templates again, verify the data is from the mock and not from the cache.
|
|
||||||
// */
|
Mockito.doReturn(false).when(spyCacheableTemplateHelper).isCacheValid(any());
|
||||||
// @Test
|
|
||||||
// public void getApplicationJson_cacheIsDirty_verifyDataIsFetchedFromSource() {
|
// make sure we've received the response returned by the mock
|
||||||
// ApplicationJson applicationJson = new ApplicationJson();
|
StepVerifier.create(spyCacheableTemplateHelper.getApplicationByTemplateId("templateId", baseUrl))
|
||||||
// Application test = new Application();
|
.assertNext(cacheableApplicationJson1 -> {
|
||||||
// test.setName("New Application");
|
assertThat(cacheableApplicationJson1.getApplicationJson()).isNotNull();
|
||||||
// applicationJson.setArtifactJsonType(ArtifactType.APPLICATION);
|
assertThat(cacheableApplicationJson1
|
||||||
// applicationJson.setExportedApplication(test);
|
.getApplicationJson()
|
||||||
//
|
.getExportedApplication()
|
||||||
// // mock the server to return the above three templates
|
.getName())
|
||||||
// mockCloudServices.enqueue(new MockResponse()
|
.isEqualTo("New Application");
|
||||||
// .setBody(new Gson().toJson(applicationJson))
|
})
|
||||||
// .addHeader("Content-Type", "application/json"));
|
.verifyComplete();
|
||||||
//
|
}
|
||||||
// Mockito.doReturn(false).when(spyCacheableTemplateHelper).isCacheValid(any());
|
|
||||||
//
|
@Test
|
||||||
// // make sure we've received the response returned by the mock
|
public void getApplicationJson_cacheKeyIsMissing_verifyDataIsFetchedFromSource() {
|
||||||
// StepVerifier.create(spyCacheableTemplateHelper.getApplicationByTemplateId(
|
ApplicationJson applicationJson1 = new ApplicationJson();
|
||||||
// "templateId", cloudServicesConfig.getBaseUrl()))
|
Application application = new Application();
|
||||||
// .assertNext(cacheableApplicationJson1 -> {
|
application.setName("Test Application");
|
||||||
// assertThat(cacheableApplicationJson1.getApplicationJson()).isNotNull();
|
applicationJson1.setArtifactJsonType(ArtifactType.APPLICATION);
|
||||||
// assertThat(cacheableApplicationJson1
|
applicationJson1.setExportedApplication(application);
|
||||||
// .getApplicationJson()
|
|
||||||
// .getExportedApplication()
|
assertThat(cacheableTemplateHelper.getCacheableApplicationJsonMap().size())
|
||||||
// .getName())
|
.isEqualTo(1);
|
||||||
// .isEqualTo("New Application");
|
|
||||||
// })
|
mockCloudServices.enqueue(new MockResponse()
|
||||||
// .verifyComplete();
|
.setBody(new Gson().toJson(applicationJson1))
|
||||||
// }
|
.addHeader("Content-Type", "application/json"));
|
||||||
//
|
|
||||||
// @Test
|
// make sure we've received the response returned by the mock
|
||||||
// public void getApplicationJson_cacheKeyIsMissing_verifyDataIsFetchedFromSource() {
|
StepVerifier.create(cacheableTemplateHelper.getApplicationByTemplateId("templateId1", baseUrl))
|
||||||
// ApplicationJson applicationJson1 = new ApplicationJson();
|
.assertNext(cacheableApplicationJson1 -> {
|
||||||
// Application application = new Application();
|
assertThat(cacheableApplicationJson1.getApplicationJson()).isNotNull();
|
||||||
// application.setName("Test Application");
|
assertThat(cacheableApplicationJson1
|
||||||
// applicationJson1.setArtifactJsonType(ArtifactType.APPLICATION);
|
.getApplicationJson()
|
||||||
// applicationJson1.setExportedApplication(application);
|
.getExportedApplication()
|
||||||
//
|
.getName())
|
||||||
// assertThat(cacheableTemplateHelper.getCacheableApplicationJsonMap().size())
|
.isEqualTo("Test Application");
|
||||||
// .isEqualTo(1);
|
})
|
||||||
//
|
.verifyComplete();
|
||||||
// mockCloudServices.enqueue(new MockResponse()
|
}
|
||||||
// .setBody(new Gson().toJson(applicationJson1))
|
|
||||||
// .addHeader("Content-Type", "application/json"));
|
|
||||||
//
|
|
||||||
// // make sure we've received the response returned by the mock
|
|
||||||
// StepVerifier.create(cacheableTemplateHelper.getApplicationByTemplateId(
|
|
||||||
// "templateId1", cloudServicesConfig.getBaseUrl()))
|
|
||||||
// .assertNext(cacheableApplicationJson1 -> {
|
|
||||||
// assertThat(cacheableApplicationJson1.getApplicationJson()).isNotNull();
|
|
||||||
// assertThat(cacheableApplicationJson1
|
|
||||||
// .getApplicationJson()
|
|
||||||
// .getExportedApplication()
|
|
||||||
// .getName())
|
|
||||||
// .isEqualTo("Test Application");
|
|
||||||
// })
|
|
||||||
// .verifyComplete();
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
package com.appsmith.server.helpers;
|
package com.appsmith.server.helpers;
|
||||||
|
|
||||||
import com.appsmith.server.configurations.CloudServicesConfig;
|
|
||||||
import com.appsmith.server.dtos.ApplicationTemplate;
|
import com.appsmith.server.dtos.ApplicationTemplate;
|
||||||
import com.appsmith.server.dtos.CacheableApplicationTemplate;
|
import com.appsmith.server.dtos.CacheableApplicationTemplate;
|
||||||
import com.appsmith.server.solutions.ApplicationPermission;
|
import com.appsmith.server.solutions.ApplicationPermission;
|
||||||
|
|
@ -11,7 +10,6 @@ import mockwebserver3.MockWebServer;
|
||||||
import org.junit.jupiter.api.AfterAll;
|
import org.junit.jupiter.api.AfterAll;
|
||||||
import org.junit.jupiter.api.BeforeAll;
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Disabled;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
import org.mockito.Mockito;
|
import org.mockito.Mockito;
|
||||||
|
|
@ -32,7 +30,6 @@ import static org.mockito.ArgumentMatchers.any;
|
||||||
|
|
||||||
@ExtendWith(SpringExtension.class)
|
@ExtendWith(SpringExtension.class)
|
||||||
@SpringBootTest
|
@SpringBootTest
|
||||||
@Disabled
|
|
||||||
public class CacheableTemplateHelperTemplateMetadataTest {
|
public class CacheableTemplateHelperTemplateMetadataTest {
|
||||||
|
|
||||||
private static final ObjectMapper objectMapper = new ObjectMapper();
|
private static final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
|
@ -41,15 +38,14 @@ public class CacheableTemplateHelperTemplateMetadataTest {
|
||||||
@MockBean
|
@MockBean
|
||||||
ApplicationPermission applicationPermission;
|
ApplicationPermission applicationPermission;
|
||||||
|
|
||||||
@MockBean
|
|
||||||
private CloudServicesConfig cloudServicesConfig;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
CacheableTemplateHelper cacheableTemplateHelper;
|
CacheableTemplateHelper cacheableTemplateHelper;
|
||||||
|
|
||||||
@SpyBean
|
@SpyBean
|
||||||
CacheableTemplateHelper spyCacheableTemplateHelper;
|
CacheableTemplateHelper spyCacheableTemplateHelper;
|
||||||
|
|
||||||
|
String baseUrl;
|
||||||
|
|
||||||
@BeforeAll
|
@BeforeAll
|
||||||
public static void setUp() throws IOException {
|
public static void setUp() throws IOException {
|
||||||
mockCloudServices = new MockWebServer();
|
mockCloudServices = new MockWebServer();
|
||||||
|
|
@ -63,11 +59,7 @@ public class CacheableTemplateHelperTemplateMetadataTest {
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
String baseUrl = String.format("http://localhost:%s", mockCloudServices.getPort());
|
baseUrl = String.format("http://localhost:%s", mockCloudServices.getPort());
|
||||||
|
|
||||||
// mock the cloud services config so that it returns mock server url as cloud
|
|
||||||
// service base url
|
|
||||||
Mockito.when(cloudServicesConfig.getBaseUrl()).thenReturn(baseUrl);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ApplicationTemplate create(String id, String title) {
|
private ApplicationTemplate create(String id, String title) {
|
||||||
|
|
@ -99,7 +91,7 @@ public class CacheableTemplateHelperTemplateMetadataTest {
|
||||||
.addHeader("Content-Type", "application/json"));
|
.addHeader("Content-Type", "application/json"));
|
||||||
|
|
||||||
Mono<CacheableApplicationTemplate> templateListMono =
|
Mono<CacheableApplicationTemplate> templateListMono =
|
||||||
cacheableTemplateHelper.getTemplates("recently-used", cloudServicesConfig.getBaseUrl());
|
cacheableTemplateHelper.getTemplates("recently-used", baseUrl);
|
||||||
|
|
||||||
final Instant[] timeFromCache = {Instant.now()};
|
final Instant[] timeFromCache = {Instant.now()};
|
||||||
StepVerifier.create(templateListMono)
|
StepVerifier.create(templateListMono)
|
||||||
|
|
@ -114,7 +106,7 @@ public class CacheableTemplateHelperTemplateMetadataTest {
|
||||||
.verifyComplete();
|
.verifyComplete();
|
||||||
|
|
||||||
// Fetch again and verify the time stamp to confirm value is coming from POJO
|
// Fetch again and verify the time stamp to confirm value is coming from POJO
|
||||||
StepVerifier.create(cacheableTemplateHelper.getTemplates("recently-used", cloudServicesConfig.getBaseUrl()))
|
StepVerifier.create(cacheableTemplateHelper.getTemplates("recently-used", baseUrl))
|
||||||
.assertNext(cacheableApplicationTemplate1 -> {
|
.assertNext(cacheableApplicationTemplate1 -> {
|
||||||
assertThat(cacheableApplicationTemplate1.getApplicationTemplateList())
|
assertThat(cacheableApplicationTemplate1.getApplicationTemplateList())
|
||||||
.hasSize(3);
|
.hasSize(3);
|
||||||
|
|
@ -141,7 +133,7 @@ public class CacheableTemplateHelperTemplateMetadataTest {
|
||||||
.setBody(objectMapper.writeValueAsString(List.of(templateFour, templateFive, templateSix)))
|
.setBody(objectMapper.writeValueAsString(List.of(templateFour, templateFive, templateSix)))
|
||||||
.addHeader("Content-Type", "application/json"));
|
.addHeader("Content-Type", "application/json"));
|
||||||
|
|
||||||
StepVerifier.create(spyCacheableTemplateHelper.getTemplates("recently-used", cloudServicesConfig.getBaseUrl()))
|
StepVerifier.create(spyCacheableTemplateHelper.getTemplates("recently-used", baseUrl))
|
||||||
.assertNext(cacheableApplicationTemplate1 -> {
|
.assertNext(cacheableApplicationTemplate1 -> {
|
||||||
assertThat(cacheableApplicationTemplate1.getApplicationTemplateList())
|
assertThat(cacheableApplicationTemplate1.getApplicationTemplateList())
|
||||||
.hasSize(3);
|
.hasSize(3);
|
||||||
|
|
|
||||||
|
|
@ -1023,13 +1023,13 @@ public class LayoutActionServiceTest {
|
||||||
|
|
||||||
for (int i = 0; i < testPages.size(); i++) {
|
for (int i = 0; i < testPages.size(); i++) {
|
||||||
PageDTO page = testPages.get(i);
|
PageDTO page = testPages.get(i);
|
||||||
Layout layout = page.getLayouts().get(0);
|
final UpdateMultiplePageLayoutDTO.LayoutDTO layout =
|
||||||
layout.setDsl(createTestDslWithTestWidget("Layout" + (i + 1)));
|
new UpdateMultiplePageLayoutDTO.LayoutDTO(createTestDslWithTestWidget("Layout" + (i + 1)));
|
||||||
|
|
||||||
UpdateMultiplePageLayoutDTO.UpdatePageLayoutDTO pageLayoutDTO =
|
UpdateMultiplePageLayoutDTO.UpdatePageLayoutDTO pageLayoutDTO =
|
||||||
new UpdateMultiplePageLayoutDTO.UpdatePageLayoutDTO();
|
new UpdateMultiplePageLayoutDTO.UpdatePageLayoutDTO();
|
||||||
pageLayoutDTO.setPageId(page.getId());
|
pageLayoutDTO.setPageId(page.getId());
|
||||||
pageLayoutDTO.setLayoutId(layout.getId());
|
pageLayoutDTO.setLayoutId(page.getLayouts().get(0).getId());
|
||||||
pageLayoutDTO.setLayout(layout);
|
pageLayoutDTO.setLayout(layout);
|
||||||
multiplePageLayoutDTO.getPageLayouts().add(pageLayoutDTO);
|
multiplePageLayoutDTO.getPageLayouts().add(pageLayoutDTO);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
echo "Running as: $(id)"
|
tlog "Running as: $(id)"
|
||||||
|
|
||||||
stacks_path=/appsmith-stacks
|
stacks_path=/appsmith-stacks
|
||||||
|
|
||||||
|
|
@ -48,7 +48,7 @@ init_env_file() {
|
||||||
# Build an env file with current env variables. We single-quote the values, as well as escaping any single-quote characters.
|
# Build an env file with current env variables. We single-quote the values, as well as escaping any single-quote characters.
|
||||||
printenv | grep -E '^APPSMITH_|^MONGO_' | sed "s/'/'\\\''/g; s/=/='/; s/$/'/" > "$TMP/pre-define.env"
|
printenv | grep -E '^APPSMITH_|^MONGO_' | sed "s/'/'\\\''/g; s/=/='/; s/$/'/" > "$TMP/pre-define.env"
|
||||||
|
|
||||||
echo "Initialize .env file"
|
tlog "Initialize .env file"
|
||||||
if ! [[ -e "$ENV_PATH" ]]; then
|
if ! [[ -e "$ENV_PATH" ]]; then
|
||||||
# Generate new docker.env file when initializing container for first time or in Heroku which does not have persistent volume
|
# Generate new docker.env file when initializing container for first time or in Heroku which does not have persistent volume
|
||||||
echo "Generating default configuration file"
|
echo "Generating default configuration file"
|
||||||
|
|
@ -74,7 +74,7 @@ init_env_file() {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
echo "Load environment configuration"
|
tlog "Load environment configuration"
|
||||||
set -o allexport
|
set -o allexport
|
||||||
. "$ENV_PATH"
|
. "$ENV_PATH"
|
||||||
. "$TMP/pre-define.env"
|
. "$TMP/pre-define.env"
|
||||||
|
|
@ -111,20 +111,20 @@ if [[ -n "${FILESTORE_IP_ADDRESS-}" ]]; then
|
||||||
FILESTORE_IP_ADDRESS="$(echo "$FILESTORE_IP_ADDRESS" | xargs)"
|
FILESTORE_IP_ADDRESS="$(echo "$FILESTORE_IP_ADDRESS" | xargs)"
|
||||||
FILE_SHARE_NAME="$(echo "$FILE_SHARE_NAME" | xargs)"
|
FILE_SHARE_NAME="$(echo "$FILE_SHARE_NAME" | xargs)"
|
||||||
|
|
||||||
echo "Running appsmith for cloudRun"
|
tlog "Running appsmith for cloudRun"
|
||||||
echo "creating mount point"
|
tlog "creating mount point"
|
||||||
mkdir -p "$stacks_path"
|
mkdir -p "$stacks_path"
|
||||||
echo "Mounting File Sytem"
|
tlog "Mounting File Sytem"
|
||||||
mount -t nfs -o nolock "$FILESTORE_IP_ADDRESS:/$FILE_SHARE_NAME" /appsmith-stacks
|
mount -t nfs -o nolock "$FILESTORE_IP_ADDRESS:/$FILE_SHARE_NAME" /appsmith-stacks
|
||||||
echo "Mounted File Sytem"
|
tlog "Mounted File Sytem"
|
||||||
echo "Setting HOSTNAME for Cloudrun"
|
tlog "Setting HOSTNAME for Cloudrun"
|
||||||
export HOSTNAME="cloudrun"
|
export HOSTNAME="cloudrun"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
function get_maximum_heap() {
|
function get_maximum_heap() {
|
||||||
resource=$(ulimit -u)
|
resource=$(ulimit -u)
|
||||||
echo "Resource : $resource"
|
tlog "Resource : $resource"
|
||||||
if [[ "$resource" -le 256 ]]; then
|
if [[ "$resource" -le 256 ]]; then
|
||||||
maximum_heap=128
|
maximum_heap=128
|
||||||
elif [[ "$resource" -le 512 ]]; then
|
elif [[ "$resource" -le 512 ]]; then
|
||||||
|
|
@ -140,7 +140,7 @@ function setup_backend_heap_arg() {
|
||||||
|
|
||||||
unset_unused_variables() {
|
unset_unused_variables() {
|
||||||
# Check for enviroment vairalbes
|
# Check for enviroment vairalbes
|
||||||
echo "Checking environment configuration"
|
tlog "Checking environment configuration"
|
||||||
if [[ -z "${APPSMITH_MAIL_ENABLED}" ]]; then
|
if [[ -z "${APPSMITH_MAIL_ENABLED}" ]]; then
|
||||||
unset APPSMITH_MAIL_ENABLED # If this field is empty is might cause application crash
|
unset APPSMITH_MAIL_ENABLED # If this field is empty is might cause application crash
|
||||||
fi
|
fi
|
||||||
|
|
@ -169,7 +169,7 @@ unset_unused_variables() {
|
||||||
}
|
}
|
||||||
|
|
||||||
configure_database_connection_url() {
|
configure_database_connection_url() {
|
||||||
echo "Configuring database connection URL"
|
tlog "Configuring database connection URL"
|
||||||
isPostgresUrl=0
|
isPostgresUrl=0
|
||||||
isMongoUrl=0
|
isMongoUrl=0
|
||||||
# Check if APPSMITH_DB_URL is not set
|
# Check if APPSMITH_DB_URL is not set
|
||||||
|
|
@ -186,17 +186,17 @@ configure_database_connection_url() {
|
||||||
}
|
}
|
||||||
|
|
||||||
check_db_uri() {
|
check_db_uri() {
|
||||||
echo "Checking APPSMITH_DB_URL"
|
tlog "Checking APPSMITH_DB_URL"
|
||||||
isUriLocal=1
|
isUriLocal=1
|
||||||
if [[ $APPSMITH_DB_URL == *"localhost"* || $APPSMITH_DB_URL == *"127.0.0.1"* ]]; then
|
if [[ $APPSMITH_DB_URL == *"localhost"* || $APPSMITH_DB_URL == *"127.0.0.1"* ]]; then
|
||||||
echo "Detected local DB"
|
tlog "Detected local DB"
|
||||||
isUriLocal=0
|
isUriLocal=0
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
init_mongodb() {
|
init_mongodb() {
|
||||||
if [[ $isUriLocal -eq 0 ]]; then
|
if [[ $isUriLocal -eq 0 ]]; then
|
||||||
echo "Initializing local database"
|
tlog "Initializing local database"
|
||||||
MONGO_DB_PATH="$stacks_path/data/mongodb"
|
MONGO_DB_PATH="$stacks_path/data/mongodb"
|
||||||
MONGO_LOG_PATH="$MONGO_DB_PATH/log"
|
MONGO_LOG_PATH="$MONGO_DB_PATH/log"
|
||||||
MONGO_DB_KEY="$MONGO_DB_PATH/key"
|
MONGO_DB_KEY="$MONGO_DB_PATH/key"
|
||||||
|
|
@ -213,7 +213,7 @@ init_mongodb() {
|
||||||
}
|
}
|
||||||
|
|
||||||
init_replica_set() {
|
init_replica_set() {
|
||||||
echo "Checking initialized database"
|
tlog "Checking initialized database"
|
||||||
shouldPerformInitdb=1
|
shouldPerformInitdb=1
|
||||||
for path in \
|
for path in \
|
||||||
"$MONGO_DB_PATH/WiredTiger" \
|
"$MONGO_DB_PATH/WiredTiger" \
|
||||||
|
|
@ -227,21 +227,21 @@ init_replica_set() {
|
||||||
done
|
done
|
||||||
|
|
||||||
if [[ $isUriLocal -gt 0 && -f /proc/cpuinfo ]] && ! grep --quiet avx /proc/cpuinfo; then
|
if [[ $isUriLocal -gt 0 && -f /proc/cpuinfo ]] && ! grep --quiet avx /proc/cpuinfo; then
|
||||||
echo "====================================================================================================" >&2
|
tlog "====================================================================================================" >&2
|
||||||
echo "==" >&2
|
tlog "==" >&2
|
||||||
echo "== AVX instruction not found in your CPU. Appsmith's embedded MongoDB may not start. Please use an external MongoDB instance instead." >&2
|
tlog "== AVX instruction not found in your CPU. Appsmith's embedded MongoDB may not start. Please use an external MongoDB instance instead." >&2
|
||||||
echo "== See https://docs.appsmith.com/getting-started/setup/instance-configuration/custom-mongodb-redis#custom-mongodb for instructions." >&2
|
tlog "== See https://docs.appsmith.com/getting-started/setup/instance-configuration/custom-mongodb-redis#custom-mongodb for instructions." >&2
|
||||||
echo "==" >&2
|
tlog "==" >&2
|
||||||
echo "====================================================================================================" >&2
|
tlog "====================================================================================================" >&2
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $shouldPerformInitdb -gt 0 && $isUriLocal -eq 0 ]]; then
|
if [[ $shouldPerformInitdb -gt 0 && $isUriLocal -eq 0 ]]; then
|
||||||
echo "Initializing Replica Set for local database"
|
tlog "Initializing Replica Set for local database"
|
||||||
# Start installed MongoDB service - Dependencies Layer
|
# Start installed MongoDB service - Dependencies Layer
|
||||||
mongod --fork --port 27017 --dbpath "$MONGO_DB_PATH" --logpath "$MONGO_LOG_PATH"
|
mongod --fork --port 27017 --dbpath "$MONGO_DB_PATH" --logpath "$MONGO_LOG_PATH"
|
||||||
echo "Waiting 10s for MongoDB to start"
|
tlog "Waiting 10s for MongoDB to start"
|
||||||
sleep 10
|
sleep 10
|
||||||
echo "Creating MongoDB user"
|
tlog "Creating MongoDB user"
|
||||||
mongosh "127.0.0.1/appsmith" --eval "db.createUser({
|
mongosh "127.0.0.1/appsmith" --eval "db.createUser({
|
||||||
user: '$APPSMITH_MONGODB_USER',
|
user: '$APPSMITH_MONGODB_USER',
|
||||||
pwd: '$APPSMITH_MONGODB_PASSWORD',
|
pwd: '$APPSMITH_MONGODB_PASSWORD',
|
||||||
|
|
@ -251,20 +251,20 @@ init_replica_set() {
|
||||||
}, 'readWrite']
|
}, 'readWrite']
|
||||||
}
|
}
|
||||||
)"
|
)"
|
||||||
echo "Enabling Replica Set"
|
tlog "Enabling Replica Set"
|
||||||
mongod --dbpath "$MONGO_DB_PATH" --shutdown || true
|
mongod --dbpath "$MONGO_DB_PATH" --shutdown || true
|
||||||
mongod --fork --port 27017 --dbpath "$MONGO_DB_PATH" --logpath "$MONGO_LOG_PATH" --replSet mr1 --keyFile "$MONGODB_TMP_KEY_PATH" --bind_ip localhost
|
mongod --fork --port 27017 --dbpath "$MONGO_DB_PATH" --logpath "$MONGO_LOG_PATH" --replSet mr1 --keyFile "$MONGODB_TMP_KEY_PATH" --bind_ip localhost
|
||||||
echo "Waiting 10s for MongoDB to start with Replica Set"
|
tlog "Waiting 10s for MongoDB to start with Replica Set"
|
||||||
sleep 10
|
sleep 10
|
||||||
mongosh "$APPSMITH_DB_URL" --eval 'rs.initiate()'
|
mongosh "$APPSMITH_DB_URL" --eval 'rs.initiate()'
|
||||||
mongod --dbpath "$MONGO_DB_PATH" --shutdown || true
|
mongod --dbpath "$MONGO_DB_PATH" --shutdown || true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $isUriLocal -gt 0 ]]; then
|
if [[ $isUriLocal -gt 0 ]]; then
|
||||||
echo "Checking Replica Set of external MongoDB"
|
tlog "Checking Replica Set of external MongoDB"
|
||||||
|
|
||||||
if appsmithctl check-replica-set; then
|
if appsmithctl check-replica-set; then
|
||||||
echo "MongoDB ReplicaSet is enabled"
|
tlog "MongoDB ReplicaSet is enabled"
|
||||||
else
|
else
|
||||||
echo -e "\033[0;31m***************************************************************************************\033[0m"
|
echo -e "\033[0;31m***************************************************************************************\033[0m"
|
||||||
echo -e "\033[0;31m* MongoDB Replica Set is not enabled *\033[0m"
|
echo -e "\033[0;31m* MongoDB Replica Set is not enabled *\033[0m"
|
||||||
|
|
@ -301,7 +301,7 @@ check_setup_custom_ca_certificates() {
|
||||||
if is_empty_directory "$container_ca_certs_path"; then
|
if is_empty_directory "$container_ca_certs_path"; then
|
||||||
rmdir -v "$container_ca_certs_path"
|
rmdir -v "$container_ca_certs_path"
|
||||||
else
|
else
|
||||||
echo "The 'ca-certificates' directory inside the container is not empty. Please clear it and restart to use certs from 'stacks/ca-certs' directory." >&2
|
tlog "The 'ca-certificates' directory inside the container is not empty. Please clear it and restart to use certs from 'stacks/ca-certs' directory." >&2
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
@ -325,11 +325,11 @@ setup-custom-ca-certificates() (
|
||||||
rm -f "$store" "$opts_file"
|
rm -f "$store" "$opts_file"
|
||||||
|
|
||||||
if [[ -n "$(ls "$stacks_ca_certs_path"/*.pem 2>/dev/null)" ]]; then
|
if [[ -n "$(ls "$stacks_ca_certs_path"/*.pem 2>/dev/null)" ]]; then
|
||||||
echo "Looks like you have some '.pem' files in your 'ca-certs' folder. Please rename them to '.crt' to be picked up automatically.".
|
tlog "Looks like you have some '.pem' files in your 'ca-certs' folder. Please rename them to '.crt' to be picked up automatically.".
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! [[ -d "$stacks_ca_certs_path" && "$(find "$stacks_ca_certs_path" -maxdepth 1 -type f -name '*.crt' | wc -l)" -gt 0 ]]; then
|
if ! [[ -d "$stacks_ca_certs_path" && "$(find "$stacks_ca_certs_path" -maxdepth 1 -type f -name '*.crt' | wc -l)" -gt 0 ]]; then
|
||||||
echo "No custom CA certificates found."
|
tlog "No custom CA certificates found."
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
@ -389,7 +389,7 @@ check_redis_compatible_page_size() {
|
||||||
--data '{ "userId": "'"$HOSTNAME"'", "event":"RedisCompile" }' \
|
--data '{ "userId": "'"$HOSTNAME"'", "event":"RedisCompile" }' \
|
||||||
https://api.segment.io/v1/track \
|
https://api.segment.io/v1/track \
|
||||||
|| true
|
|| true
|
||||||
echo "Compile Redis stable with page size of $page_size"
|
tlog "Compile Redis stable with page size of $page_size"
|
||||||
apt-get update
|
apt-get update
|
||||||
apt-get install --yes build-essential
|
apt-get install --yes build-essential
|
||||||
curl --connect-timeout 5 --location https://download.redis.io/redis-stable.tar.gz | tar -xz -C /tmp
|
curl --connect-timeout 5 --location https://download.redis.io/redis-stable.tar.gz | tar -xz -C /tmp
|
||||||
|
|
@ -399,15 +399,14 @@ check_redis_compatible_page_size() {
|
||||||
popd
|
popd
|
||||||
rm -rf /tmp/redis-stable
|
rm -rf /tmp/redis-stable
|
||||||
else
|
else
|
||||||
echo "Redis is compatible with page size of $page_size"
|
tlog "Redis is compatible with page size of $page_size"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
init_postgres() {
|
init_postgres() {
|
||||||
# Initialize embedded postgres by default; set APPSMITH_ENABLE_EMBEDDED_DB to 0, to use existing cloud postgres mockdb instance
|
# Initialize embedded postgres by default; set APPSMITH_ENABLE_EMBEDDED_DB to 0, to use existing cloud postgres mockdb instance
|
||||||
if [[ ${APPSMITH_ENABLE_EMBEDDED_DB: -1} != 0 ]]; then
|
if [[ ${APPSMITH_ENABLE_EMBEDDED_DB: -1} != 0 ]]; then
|
||||||
echo ""
|
tlog "Checking initialized local postgres"
|
||||||
echo "Checking initialized local postgres"
|
|
||||||
POSTGRES_DB_PATH="$stacks_path/data/postgres/main"
|
POSTGRES_DB_PATH="$stacks_path/data/postgres/main"
|
||||||
|
|
||||||
mkdir -p "$POSTGRES_DB_PATH" "$TMP/pg-runtime"
|
mkdir -p "$POSTGRES_DB_PATH" "$TMP/pg-runtime"
|
||||||
|
|
@ -416,9 +415,9 @@ init_postgres() {
|
||||||
chown -R postgres:postgres "$POSTGRES_DB_PATH" "$TMP/pg-runtime"
|
chown -R postgres:postgres "$POSTGRES_DB_PATH" "$TMP/pg-runtime"
|
||||||
|
|
||||||
if [[ -e "$POSTGRES_DB_PATH/PG_VERSION" ]]; then
|
if [[ -e "$POSTGRES_DB_PATH/PG_VERSION" ]]; then
|
||||||
echo "Found existing Postgres, Skipping initialization"
|
tlog "Found existing Postgres, Skipping initialization"
|
||||||
else
|
else
|
||||||
echo "Initializing local postgresql database"
|
tlog "Initializing local postgresql database"
|
||||||
mkdir -p "$POSTGRES_DB_PATH"
|
mkdir -p "$POSTGRES_DB_PATH"
|
||||||
|
|
||||||
# Postgres does not allow it's server to be run with super user access, we use user postgres and the file system owner also needs to be the same user postgres
|
# Postgres does not allow it's server to be run with super user access, we use user postgres and the file system owner also needs to be the same user postgres
|
||||||
|
|
@ -510,11 +509,11 @@ check_db_uri
|
||||||
if [[ -z "${DYNO}" ]]; then
|
if [[ -z "${DYNO}" ]]; then
|
||||||
if [[ $isMongoUrl -eq 1 ]]; then
|
if [[ $isMongoUrl -eq 1 ]]; then
|
||||||
# Setup MongoDB and initialize replica set
|
# Setup MongoDB and initialize replica set
|
||||||
echo "Initializing MongoDB"
|
tlog "Initializing MongoDB"
|
||||||
init_mongodb
|
init_mongodb
|
||||||
init_replica_set
|
init_replica_set
|
||||||
elif [[ $isPostgresUrl -eq 1 ]]; then
|
elif [[ $isPostgresUrl -eq 1 ]]; then
|
||||||
echo "Initializing Postgres"
|
tlog "Initializing Postgres"
|
||||||
# init_postgres
|
# init_postgres
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
|
|
|
||||||
5
deploy/docker/fs/opt/bin/tlog
Normal file
5
deploy/docker/fs/opt/bin/tlog
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
#!/bin/sh
|
||||||
|
# Running this with `sh` since it's very tiny, and doesn't need the big bash.
|
||||||
|
|
||||||
|
# Printing time in UTC.
|
||||||
|
echo "$(date -u +%FT%T.%3NZ)" "$@"
|
||||||
Loading…
Reference in New Issue
Block a user