chore: git api - adding new apis (#38681)

## Description
- Introduces new api contracts for git
- Adds feature flag `release_git_api_contracts_enabled`


Fixes https://github.com/appsmithorg/appsmith/issues/38500

## Automation

/ok-to-test tags="@tag.Git"

### 🔍 Cypress test results
<!-- This is an auto-generated comment: Cypress test results  -->
> [!TIP]
> 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉
> Workflow run:
<https://github.com/appsmithorg/appsmith/actions/runs/12810595516>
> Commit: 8f05bbfb0b9259c3ee40464099416b75688a4bd1
> <a
href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=12810595516&attempt=1"
target="_blank">Cypress dashboard</a>.
> Tags: `@tag.Git`
> Spec:
> <hr>Thu, 16 Jan 2025 15:05:20 UTC
<!-- end of auto-generated comment: Cypress test results  -->


## Communication
Should the DevRel and Marketing teams inform users about this change?
- [ ] Yes
- [ ] No


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

## Release Notes

- **New Features**
    - Introduced a new feature flag `release_git_api_contracts_enabled`
    - Added support for enhanced Git API contract handling

- **Improvements**
    - Updated type definitions for Git-related operations
    - Refined request and response handling for Git artifacts
    - Improved type safety for Git references and branches

- **Changes**
- Modified several Git-related request and saga functions to support new
API contracts
    - Updated artifact type enum values to use lowercase representations
    - Introduced new interfaces for Git references and branches

- **Technical Updates**
    - Added conditional logic for feature flag-based request processing
    - Restructured type definitions across multiple Git-related modules
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Rudraprasad Das 2025-01-21 11:19:18 +01:00 committed by GitHub
parent 16e121ce73
commit 704e4735ad
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
73 changed files with 996 additions and 138 deletions

View File

@ -46,6 +46,7 @@ export const FEATURE_FLAG = {
release_gs_all_sheets_options_enabled:
"release_gs_all_sheets_options_enabled",
release_git_modularisation_enabled: "release_git_modularisation_enabled",
release_git_api_contracts_enabled: "release_git_api_contracts_enabled",
ab_premium_datasources_view_enabled: "ab_premium_datasources_view_enabled",
kill_session_recordings_enabled: "kill_session_recordings_enabled",
config_mask_session_recordings_enabled:
@ -92,6 +93,7 @@ export const DEFAULT_FEATURE_FLAG_VALUE: FeatureFlags = {
release_table_html_column_type_enabled: false,
release_gs_all_sheets_options_enabled: false,
release_git_modularisation_enabled: false,
release_git_api_contracts_enabled: false,
ab_premium_datasources_view_enabled: false,
kill_session_recordings_enabled: false,
config_user_session_recordings_enabled: true,

View File

@ -9,9 +9,9 @@ import { Button, Link, Option, Select, Text } from "@appsmith/ads";
import React, { useCallback, useEffect, useMemo, useState } from "react";
import styled from "styled-components";
import AnalyticsUtil from "ee/utils/AnalyticsUtil";
import type { FetchBranchesResponseData } from "git/requests/fetchBranchesRequest.types";
import noop from "lodash/noop";
import { useAppsmithEnterpriseUrl } from "git/hooks/useAppsmithEnterpriseUrl";
import type { GitBranch } from "git/types";
const Container = styled.div`
padding-top: 8px;
@ -45,7 +45,7 @@ const StyledLink = styled(Link)`
`;
interface DefaultBranchViewProps {
branches: FetchBranchesResponseData | null;
branches: GitBranch[] | null;
isGitProtectedFeatureLicensed: boolean;
updateDefaultBranch?: (branchName: string) => void;
}

View File

@ -33,8 +33,8 @@ import LocalBranchList from "./LocalBranchList";
import { useFilteredBranches } from "./hooks/useFilteredBranches";
import useActiveHoverIndex from "./hooks/useActiveHoverIndex";
import { Space } from "pages/Editor/gitSync/components/StyledComponents";
import type { FetchBranchesResponseData } from "git/requests/fetchBranchesRequest.types";
import type { FetchProtectedBranchesResponseData } from "git/requests/fetchProtectedBranchesRequest.types";
import type { GitBranch } from "git/types";
const ListContainer = styled.div`
flex: 1;
@ -229,7 +229,7 @@ export function Header({
}
interface BranchListViewProps {
branches: FetchBranchesResponseData | null;
branches: GitBranch[] | null;
checkoutBranch: (branch: string) => void;
checkoutDestBranch: string | null;
createBranch: (branch: string) => void;

View File

@ -1,8 +1,8 @@
import type { Branch } from "entities/GitSync";
import type { GitBranch } from "git/types";
import { useEffect, useState } from "react";
export function useFilteredBranches(
branches: Array<Branch>,
branches: Array<GitBranch>,
searchText: string,
) {
const lowercaseSearchText = searchText.toLowerCase();
@ -10,15 +10,15 @@ export function useFilteredBranches(
useEffect(
function setFilteredBranchesEffect() {
const matched = branches.filter((b: Branch) =>
const matched = branches.filter((b) =>
lowercaseSearchText
? b.branchName.toLowerCase().includes(lowercaseSearchText)
: true,
);
const branchNames = [
...matched.filter((b: Branch) => b.default),
...matched.filter((b: Branch) => !b.default),
].map((b: Branch) => b.branchName);
...matched.filter((b) => b.default),
...matched.filter((b) => !b.default),
].map((b) => b.branchName);
setFilteredBranches(branchNames);
},

View File

@ -31,7 +31,7 @@ export const useGitContext = () => {
interface GitContextProviderProps {
// artifact
artifactType: keyof typeof GitArtifactType | null;
artifactType: GitArtifactType | null;
baseArtifactId: string | null;
artifact: ApplicationPayload | null;
artifacts: ApplicationPayload[] | null;

View File

@ -31,10 +31,10 @@ import MergeStatus from "./MergeStatus";
import ConflictError from "git/components/ConflictError";
import MergeSuccessIndicator from "./MergeSuccessIndicator";
import { noop } from "lodash";
import type { FetchBranchesResponseData } from "git/requests/fetchBranchesRequest.types";
import type { FetchProtectedBranchesResponseData } from "git/requests/fetchProtectedBranchesRequest.types";
import type { FetchMergeStatusResponseData } from "git/requests/fetchMergeStatusRequest.types";
import type { GitApiError } from "git/store/types";
import type { GitBranch } from "git/types";
const Container = styled.div`
min-height: 360px;
@ -64,7 +64,7 @@ interface BranchOption {
}
interface TabMergeViewProps {
branches: FetchBranchesResponseData | null;
branches: GitBranch[] | null;
clearMergeStatus: () => void;
currentBranch: string | null;
fetchBranches: () => void;

View File

@ -13,10 +13,10 @@ import AnalyticsUtil from "ee/utils/AnalyticsUtil";
import { DOCS_BRANCH_PROTECTION_URL } from "constants/ThirdPartyConstants";
import { GIT_REMOTE_BRANCH_PREFIX } from "git/constants/misc";
import { useAppsmithEnterpriseUrl } from "git/hooks/useAppsmithEnterpriseUrl";
import type { FetchBranchesResponseData } from "git/requests/fetchBranchesRequest.types";
import xor from "lodash/xor";
import noop from "lodash/noop";
import type { FetchProtectedBranchesResponseData } from "git/requests/fetchProtectedBranchesRequest.types";
import type { GitBranch } from "git/types";
const Container = styled.div`
padding-top: 16px;
@ -50,7 +50,7 @@ const StyledLink = styled(Link)`
`;
interface ProtectedBranchesViewProps {
branches: FetchBranchesResponseData | null;
branches: GitBranch[] | null;
defaultBranch: string | null;
isProtectedBranchesLicensed: boolean;
isUpdateProtectedBranchesLoading: boolean;

View File

@ -1,7 +1,7 @@
export enum GitArtifactType {
Application = "Application",
Package = "Package",
Workflow = "Workflow",
Application = "applications",
Package = "packages",
Workflow = "workflows",
}
export enum GitOpsTab {

View File

@ -0,0 +1,8 @@
import type { GitBranch, GitRef } from "git/types";
export default function refToBranchList(refs: GitRef[]): GitBranch[] {
return refs.map((ref) => ({
branchName: ref.refName,
default: ref.default,
}));
}

View File

@ -9,9 +9,12 @@ import {
selectDeleteBranchState,
selectCurrentBranch,
} from "git/store/selectors/gitArtifactSelectors";
import { useCallback } from "react";
import { useCallback, useMemo } from "react";
import { useDispatch } from "react-redux";
import useArtifactSelector from "./useArtifactSelector";
import refToBranchList from "git/helpers/refToBranchList";
import useGitFeatureFlags from "./useGitFeatureFlags";
import type { GitBranch } from "git/types";
export default function useBranches() {
const { artifact, artifactDef } = useGitContext();
@ -21,6 +24,20 @@ export default function useBranches() {
// fetch branches
const branchesState = useArtifactSelector(selectFetchBranchesState);
const { release_git_api_contracts_enabled: isGitApiContractsEnabled } =
useGitFeatureFlags();
const branches = useMemo(() => {
if (!Array.isArray(branchesState?.value)) {
return null;
}
if (!isGitApiContractsEnabled) {
return branchesState.value;
}
return refToBranchList(branchesState.value);
}, [branchesState?.value, isGitApiContractsEnabled]);
const fetchBranches = useCallback(() => {
if (artifactDef && artifactId) {
@ -106,7 +123,7 @@ export default function useBranches() {
);
return {
branches: branchesState?.value ?? null,
branches: branches as GitBranch[] | null,
isFetchBranchesLoading: branchesState?.loading ?? false,
fetchBranchesError: branchesState?.error ?? null,
fetchBranches,

View File

@ -8,9 +8,13 @@ export default function useGitFeatureFlags() {
const license_git_continuous_delivery_enabled = useFeatureFlag(
FEATURE_FLAG.license_git_continuous_delivery_enabled,
);
const release_git_api_contracts_enabled = useFeatureFlag(
FEATURE_FLAG.release_git_api_contracts_enabled,
);
return {
license_git_branch_protection_enabled,
license_git_continuous_delivery_enabled,
release_git_api_contracts_enabled,
};
}

View File

@ -6,7 +6,7 @@ import type {
import { GIT_BASE_URL } from "./constants";
import Api from "api/Api";
export default async function checkoutBranchRequest(
export default async function checkoutBranchRequestOld(
branchedApplicationId: string,
params: CheckoutBranchRequestParams,
): AxiosPromise<CheckoutBranchResponse> {

View File

@ -0,0 +1,37 @@
import type { AxiosPromise } from "axios";
import { GIT_BASE_URL } from "./constants";
import Api from "api/Api";
import type { GitArtifactType } from "git/constants/enums";
import type {
CheckoutRefRequestParams,
CheckoutRefResponse,
} from "./checkoutRefRequest.types";
import checkoutBranchRequestOld from "./checkoutBranchRequest";
async function checkoutRefRequestNew(
artifactType: GitArtifactType,
refArtifactid: string,
params: CheckoutRefRequestParams,
): AxiosPromise<CheckoutRefResponse> {
return Api.post(
`${GIT_BASE_URL}/${artifactType}/${refArtifactid}/checkout-ref`,
params,
);
}
export default async function checkoutRefRequest(
artifactType: GitArtifactType,
refArtifactid: string,
params: CheckoutRefRequestParams,
isNew: boolean,
) {
if (isNew) {
return checkoutRefRequestNew(artifactType, refArtifactid, params);
} else {
const checkoutBranchParams = {
branchName: params.refName,
};
return checkoutBranchRequestOld(refArtifactid, checkoutBranchParams);
}
}

View File

@ -0,0 +1,12 @@
import type { ApiResponse } from "api/types";
import type { GitArtifact } from "git/store/types";
export interface CheckoutRefRequestParams {
refType: "branch" | "tag";
refName: string;
message?: string;
}
export type CheckoutRefResponseData = GitArtifact;
export type CheckoutRefResponse = ApiResponse<CheckoutRefResponseData>;

View File

@ -5,8 +5,9 @@ import type {
} from "./commitRequest.types";
import { GIT_BASE_URL } from "./constants";
import type { AxiosPromise } from "axios";
import type { GitArtifactType } from "git/constants/enums";
export default async function commitRequest(
async function commitRequestOld(
branchedApplicationId: string,
params: CommitRequestParams,
): AxiosPromise<CommitResponse> {
@ -15,3 +16,27 @@ export default async function commitRequest(
params,
);
}
async function commitRequestNew(
artifactType: GitArtifactType,
refArtifactId: string,
params: CommitRequestParams,
): AxiosPromise<CommitResponse> {
return Api.post(
`${GIT_BASE_URL}/${artifactType}/${refArtifactId}/commit`,
params,
);
}
export default async function commitRequest(
artifactType: GitArtifactType,
refArtifactId: string,
params: CommitRequestParams,
isNew: boolean,
) {
if (isNew) {
return commitRequestNew(artifactType, refArtifactId, params);
} else {
return commitRequestOld(refArtifactId, params);
}
}

View File

@ -5,10 +5,35 @@ import type {
ConnectResponse,
} from "./connectRequest.types";
import type { AxiosPromise } from "axios";
import type { GitArtifactType } from "git/constants/enums";
export default async function connectRequest(
async function connectRequestOld(
baseApplicationId: string,
params: ConnectRequestParams,
): AxiosPromise<ConnectResponse> {
return Api.post(`${GIT_BASE_URL}/connect/app/${baseApplicationId}`, params);
}
async function connectRequestNew(
artifactType: GitArtifactType,
baseArtifactId: string,
params: ConnectRequestParams,
): AxiosPromise<ConnectResponse> {
return Api.post(
`${GIT_BASE_URL}/${artifactType}/${baseArtifactId}/connect`,
params,
);
}
export default async function connectRequest(
artifactType: GitArtifactType,
baseArtifactId: string,
params: ConnectRequestParams,
isNew: boolean,
) {
if (isNew) {
return connectRequestNew(artifactType, baseArtifactId, params);
} else {
return connectRequestOld(baseArtifactId, params);
}
}

View File

@ -6,7 +6,7 @@ import type {
import { GIT_BASE_URL } from "./constants";
import Api from "api/Api";
export default async function createBranchRequest(
export default async function createBranchRequestOld(
branchedApplicationId: string,
params: CreateBranchRequestParams,
): AxiosPromise<CreateBranchResponse> {

View File

@ -0,0 +1,37 @@
import type { AxiosPromise } from "axios";
import { GIT_BASE_URL } from "./constants";
import Api from "api/Api";
import type { GitArtifactType } from "git/constants/enums";
import type {
CreateRefRequestParams,
CreateRefResponse,
} from "./createRefRequest.types";
import createBranchRequestOld from "./createBranchRequest";
async function createRefRequestNew(
artifactType: GitArtifactType,
refArtifactId: string,
params: CreateRefRequestParams,
): AxiosPromise<CreateRefResponse> {
return Api.post(
`${GIT_BASE_URL}/${artifactType}/${refArtifactId}/create-ref`,
params,
);
}
export default async function createRefRequest(
artifactType: GitArtifactType,
refArtifactId: string,
params: CreateRefRequestParams,
isNew: boolean,
) {
if (isNew) {
return createRefRequestNew(artifactType, refArtifactId, params);
} else {
const createBranchParams = {
branchName: params.refName,
};
return createBranchRequestOld(refArtifactId, createBranchParams);
}
}

View File

@ -0,0 +1,11 @@
import type { ApiResponse } from "api/types";
import type { GitArtifact } from "git/store/types";
export interface CreateRefRequestParams {
refType: "branch" | "tag";
refName: string;
}
export type CreateRefResponseData = GitArtifact;
export type CreateRefResponse = ApiResponse<CreateRefResponseData>;

View File

@ -6,7 +6,7 @@ import type {
import { GIT_BASE_URL } from "./constants";
import Api from "api/Api";
export default async function deleteBranchRequest(
export default async function deleteBranchRequestOld(
baseApplicationId: string,
params: DeleteBranchRequestParams,
): AxiosPromise<DeleteBranchResponse> {

View File

@ -0,0 +1,37 @@
import type { AxiosPromise } from "axios";
import type {
DeleteRefRequestParams,
DeleteRefResponse,
} from "./deleteRefRequest.types";
import { GIT_BASE_URL } from "./constants";
import Api from "api/Api";
import type { GitArtifactType } from "git/constants/enums";
import deleteBranchRequestOld from "./deleteBranchRequest";
async function deleteRefRequestNew(
artifactType: GitArtifactType,
baseArtifactId: string,
params: DeleteRefRequestParams,
): AxiosPromise<DeleteRefResponse> {
return Api.delete(
`${GIT_BASE_URL}/${artifactType}/${baseArtifactId}/ref`,
params,
);
}
export default async function deleteRefRequest(
artifactType: GitArtifactType,
baseArtifactId: string,
params: DeleteRefRequestParams,
isNew: boolean,
) {
if (isNew) {
return deleteRefRequestNew(artifactType, baseArtifactId, params);
} else {
const deleteBranchParams = {
branchName: params.refName,
};
return deleteBranchRequestOld(baseArtifactId, deleteBranchParams);
}
}

View File

@ -0,0 +1,11 @@
import type { ApiResponse } from "api/types";
import type { GitArtifact } from "git/store/types";
export interface DeleteRefRequestParams {
refType: "branch" | "tag";
refName: string;
}
export type DeleteRefResponseData = GitArtifact;
export type DeleteRefResponse = ApiResponse<DeleteRefResponseData>;

View File

@ -2,9 +2,29 @@ import Api from "api/Api";
import { GIT_BASE_URL } from "./constants";
import type { AxiosPromise } from "axios";
import type { DiscardResponse } from "./discardRequest.types";
import type { GitArtifactType } from "git/constants/enums";
export default async function discardRequest(
async function discardRequestOld(
branchedApplicationId: string,
): AxiosPromise<DiscardResponse> {
return Api.put(`${GIT_BASE_URL}/discard/app/${branchedApplicationId}`);
}
async function discardRequestNew(
artifactType: GitArtifactType,
refArtifactId: string,
): AxiosPromise<DiscardResponse> {
return Api.put(`${GIT_BASE_URL}/${artifactType}/${refArtifactId}/discard`);
}
export default async function discardRequest(
artifactType: GitArtifactType,
refArtifactId: string,
isNew: boolean,
) {
if (isNew) {
return discardRequestNew(artifactType, refArtifactId);
} else {
return discardRequestOld(refArtifactId);
}
}

View File

@ -1,4 +1,6 @@
import type { ApiResponse } from "api/types";
import type { GitArtifact } from "git/store/types";
export type DiscardResponse = ApiResponse<GitArtifact>;
export type DiscardResponseData = GitArtifact;
export type DiscardResponse = ApiResponse<DiscardResponseData>;

View File

@ -2,9 +2,31 @@ import type { AxiosPromise } from "axios";
import { GIT_BASE_URL } from "./constants";
import type { DisconnectResponse } from "./disconnectRequest.types";
import Api from "api/Api";
import type { GitArtifactType } from "git/constants/enums";
export default async function disconnectRequest(
async function disconnectRequestOld(
baseApplicationId: string,
): AxiosPromise<DisconnectResponse> {
return Api.post(`${GIT_BASE_URL}/disconnect/app/${baseApplicationId}`);
}
async function disconnectRequestNew(
artifactType: GitArtifactType,
baseArtifactId: string,
): AxiosPromise<DisconnectResponse> {
return Api.post(
`${GIT_BASE_URL}/${artifactType}/${baseArtifactId}/disconnect`,
);
}
export default async function disconnectRequest(
artifactType: GitArtifactType,
baseArtifactId: string,
isNew: boolean,
) {
if (isNew) {
return disconnectRequestNew(artifactType, baseArtifactId);
} else {
return disconnectRequestOld(baseArtifactId);
}
}

View File

@ -1,6 +1,6 @@
import type { ApiResponse } from "api/types";
import type { ApplicationPayload } from "entities/Application";
import type { GitArtifact } from "git/store/types";
export interface DisconnectResponseData extends ApplicationPayload {}
export type DisconnectResponseData = GitArtifact;
export type DisconnectResponse = ApiResponse<DisconnectResponseData>;

View File

@ -2,11 +2,33 @@ import Api from "api/Api";
import { GIT_BASE_URL } from "./constants";
import type { AxiosPromise } from "axios";
import type { FetchAutocommitProgressResponse } from "./fetchAutocommitProgressRequest.types";
import type { GitArtifactType } from "git/constants/enums";
export default async function fetchAutocommitProgressRequest(
async function fetchAutocommitProgressRequestOld(
baseApplicationId: string,
): AxiosPromise<FetchAutocommitProgressResponse> {
return Api.get(
`${GIT_BASE_URL}/auto-commit/progress/app/${baseApplicationId}`,
);
}
async function fetchAutocommitProgressRequestNew(
artifactType: GitArtifactType,
baseArtifactId: string,
): AxiosPromise<FetchAutocommitProgressResponse> {
return Api.get(
`${GIT_BASE_URL}/${artifactType}/${baseArtifactId}/auto-commit/progress`,
);
}
export default async function fetchAutocommitProgressRequest(
artifactType: GitArtifactType,
baseArtifactId: string,
isNew: boolean,
) {
if (isNew) {
return fetchAutocommitProgressRequestNew(artifactType, baseArtifactId);
} else {
return fetchAutocommitProgressRequestOld(baseArtifactId);
}
}

View File

@ -6,10 +6,29 @@ import type {
FetchGlobalSSHKeyResponse,
} from "./fetchGlobalSSHKeyRequest.types";
export default async function fetchGlobalSSHKeyRequest(
async function fetchGlobalSSHKeyRequestOld(
params: FetchGlobalSSHKeyRequestParams,
): AxiosPromise<FetchGlobalSSHKeyResponse> {
const url = `${GIT_BASE_URL}/import/keys?keyType=${params.keyType}`;
return Api.get(url);
}
async function fetchGlobalSSHKeyRequestNew(
params: FetchGlobalSSHKeyRequestParams,
): AxiosPromise<FetchGlobalSSHKeyResponse> {
const url = `${GIT_BASE_URL}/artifacts/import/keys?keyType=${params.keyType}`;
return Api.get(url);
}
export default async function fetchGlobalSSHKeyRequest(
params: FetchGlobalSSHKeyRequestParams,
isNew: boolean,
): AxiosPromise<FetchGlobalSSHKeyResponse> {
if (isNew) {
return fetchGlobalSSHKeyRequestNew(params);
} else {
return fetchGlobalSSHKeyRequestOld(params);
}
}

View File

@ -2,9 +2,29 @@ import Api from "api/Api";
import type { AxiosPromise } from "axios";
import { GIT_BASE_URL } from "./constants";
import type { FetchLocalProfileResponse } from "./fetchLocalProfileRequest.types";
import type { GitArtifactType } from "git/constants/enums";
export default async function fetchLocalProfileRequest(
async function fetchLocalProfileRequestOld(
baseApplicationId: string,
): AxiosPromise<FetchLocalProfileResponse> {
return Api.get(`${GIT_BASE_URL}/profile/app/${baseApplicationId}`);
}
async function fetchLocalProfileRequestNew(
artifactType: GitArtifactType,
baseArtifactId: string,
): AxiosPromise<FetchLocalProfileResponse> {
return Api.get(`${GIT_BASE_URL}/${artifactType}/${baseArtifactId}/profile`);
}
export default async function fetchLocalProfileRequest(
artifactType: GitArtifactType,
baseArtifactId: string,
isNew: boolean,
): AxiosPromise<FetchLocalProfileResponse> {
if (isNew) {
return fetchLocalProfileRequestNew(artifactType, baseArtifactId);
} else {
return fetchLocalProfileRequestOld(baseArtifactId);
}
}

View File

@ -5,8 +5,9 @@ import type {
} from "./fetchMergeStatusRequest.types";
import Api from "api/Api";
import { GIT_BASE_URL } from "./constants";
import type { GitArtifactType } from "git/constants/enums";
export default async function fetchMergeStatusRequest(
async function fetchMergeStatusRequestOld(
branchedApplicationId: string,
params: FetchMergeStatusRequestParams,
): AxiosPromise<FetchMergeStatusResponse> {
@ -15,3 +16,27 @@ export default async function fetchMergeStatusRequest(
params,
);
}
async function fetchMergeStatusRequestNew(
artifactType: GitArtifactType,
refArtifactId: string,
params: FetchMergeStatusRequestParams,
): AxiosPromise<FetchMergeStatusResponse> {
return Api.post(
`${GIT_BASE_URL}/${artifactType}/${refArtifactId}/merge/status`,
params,
);
}
export default async function fetchMergeStatusRequest(
artifactType: GitArtifactType,
refArtifactId: string,
params: FetchMergeStatusRequestParams,
isNew: boolean,
): AxiosPromise<FetchMergeStatusResponse> {
if (isNew) {
return fetchMergeStatusRequestNew(artifactType, refArtifactId, params);
} else {
return fetchMergeStatusRequestOld(refArtifactId, params);
}
}

View File

@ -2,9 +2,29 @@ import Api from "api/Api";
import { GIT_BASE_URL } from "./constants";
import type { AxiosPromise } from "axios";
import type { FetchMetadataResponse } from "./fetchMetadataRequest.types";
import type { GitArtifactType } from "git/constants/enums";
export default async function fetchMetadataRequest(
async function fetchMetadataRequestOld(
baseApplicationId: string,
): AxiosPromise<FetchMetadataResponse> {
return Api.get(`${GIT_BASE_URL}/metadata/app/${baseApplicationId}`);
}
async function fetchMetadataRequestNew(
artifactType: GitArtifactType,
baseArtifactId: string,
): AxiosPromise<FetchMetadataResponse> {
return Api.get(`${GIT_BASE_URL}/${artifactType}/${baseArtifactId}/metadata`);
}
export default async function fetchMetadataRequest(
artifactType: GitArtifactType,
baseArtifactId: string,
isNew: boolean,
): AxiosPromise<FetchMetadataResponse> {
if (isNew) {
return fetchMetadataRequestNew(artifactType, baseArtifactId);
} else {
return fetchMetadataRequestOld(baseArtifactId);
}
}

View File

@ -2,9 +2,29 @@ import Api from "api/Api";
import { GIT_BASE_URL } from "./constants";
import type { AxiosPromise } from "axios";
import type { FetchProtectedBranchesResponse } from "./fetchProtectedBranchesRequest.types";
import type { GitArtifactType } from "git/constants/enums";
export default async function fetchProtectedBranchesRequest(
async function fetchProtectedBranchesRequestOld(
baseApplicationId: string,
): AxiosPromise<FetchProtectedBranchesResponse> {
return Api.get(`${GIT_BASE_URL}/branch/app/${baseApplicationId}/protected`);
}
async function fetchProtectedBranchesRequestNew(
artifactType: GitArtifactType,
baseArtifactId: string,
): AxiosPromise<FetchProtectedBranchesResponse> {
return Api.get(`${GIT_BASE_URL}/${artifactType}/${baseArtifactId}/protected`);
}
export default async function fetchProtectedBranchesRequest(
artifactType: GitArtifactType,
baseArtifactId: string,
isNew: boolean,
): AxiosPromise<FetchProtectedBranchesResponse> {
if (isNew) {
return fetchProtectedBranchesRequestNew(artifactType, baseArtifactId);
} else {
return fetchProtectedBranchesRequestOld(baseArtifactId);
}
}

View File

@ -0,0 +1,38 @@
import Api from "api/Api";
import { GIT_BASE_URL } from "./constants";
import type {
FetchRefsRequestParams,
FetchRefsResponse,
} from "./fetchRefsRequest.types";
import type { AxiosPromise } from "axios";
import type { GitArtifactType } from "git/constants/enums";
import fetchBranchesRequest from "./fetchBranchesRequest";
async function fetchRefsRequestNew(
artifactType: GitArtifactType,
refArtifactId: string,
params: FetchRefsRequestParams,
): AxiosPromise<FetchRefsResponse> {
return Api.get(
`${GIT_BASE_URL}/${artifactType}/${refArtifactId}/refs`,
undefined,
{ params },
);
}
export default async function fetchRefsRequest(
artifactType: GitArtifactType,
refArtifactId: string,
params: FetchRefsRequestParams,
isNew: boolean,
) {
if (isNew) {
return fetchRefsRequestNew(artifactType, refArtifactId, params);
} else {
const fetchBranchesParams = {
pruneBranches: params.pruneRefs,
};
return fetchBranchesRequest(refArtifactId, fetchBranchesParams);
}
}

View File

@ -0,0 +1,11 @@
import type { ApiResponse } from "api/types";
import type { GitRef } from "git/types";
export interface FetchRefsRequestParams {
pruneRefs: boolean;
refType: "branch" | "tag";
}
export type FetchRefsResponseData = GitRef[];
export type FetchRefsResponse = ApiResponse<FetchRefsResponseData>;

View File

@ -4,7 +4,7 @@ import Api from "api/Api";
import { APPLICATION_BASE_URL } from "./constants";
export default async function fetchSSHKeyRequest(
baseApplicationId: string,
baseArtifactId: string,
): AxiosPromise<FetchSSHKeyResponse> {
return Api.get(`${APPLICATION_BASE_URL}/ssh-keypair/${baseApplicationId}`);
return Api.get(`${APPLICATION_BASE_URL}/ssh-keypair/${baseArtifactId}`);
}

View File

@ -5,10 +5,35 @@ import type {
} from "./fetchStatusRequest.types";
import { GIT_BASE_URL } from "./constants";
import type { AxiosPromise } from "axios";
import type { GitArtifactType } from "git/constants/enums";
export default async function fetchStatusRequest(
async function fetchStatusRequestOld(
branchedApplicationId: string,
params: FetchStatusRequestParams = { compareRemote: true },
): AxiosPromise<FetchStatusResponse> {
return Api.get(`${GIT_BASE_URL}/status/app/${branchedApplicationId}`, params);
}
async function fetchStatusRequestNew(
artifactType: GitArtifactType,
baseArtifactId: string,
params: FetchStatusRequestParams,
): AxiosPromise<FetchStatusResponse> {
return Api.get(
`${GIT_BASE_URL}/${artifactType}/${baseArtifactId}/status`,
params,
);
}
export default async function fetchStatusRequest(
artifactType: GitArtifactType,
baseArtifactId: string,
params: FetchStatusRequestParams,
isNew: boolean,
): AxiosPromise<FetchStatusResponse> {
if (isNew) {
return fetchStatusRequestNew(artifactType, baseArtifactId, params);
} else {
return fetchStatusRequestOld(baseArtifactId, params);
}
}

View File

@ -7,10 +7,10 @@ import { APPLICATION_BASE_URL } from "./constants";
import Api from "api/Api";
export default async function generateSSHKeyRequest(
baseApplicationId: string,
baseArtifactId: string,
params: GenerateSSHKeyRequestParams,
): AxiosPromise<GenerateSSHKeyResponse> {
const url = `${APPLICATION_BASE_URL}/ssh-keypair/${baseApplicationId}?keyType=${params.keyType}`;
const url = `${APPLICATION_BASE_URL}/ssh-keypair/${baseArtifactId}?keyType=${params.keyType}`;
return Api.post(url);
}

View File

@ -6,9 +6,30 @@ import type {
} from "./gitImportRequest.types";
import type { AxiosPromise } from "axios";
export default async function gitImportRequest(
async function gitImportRequestOld(
workspaceId: string,
params: GitImportRequestParams,
): AxiosPromise<GitImportResponse> {
return Api.post(`${GIT_BASE_URL}/import/${workspaceId}`, params);
}
async function gitImportRequestNew(
workspaceId: string,
params: GitImportRequestParams,
): AxiosPromise<GitImportResponse> {
return Api.post(`${GIT_BASE_URL}/artifacts/import`, params, {
params: { workspaceId },
});
}
export default async function gitImportRequest(
workspaceId: string,
params: GitImportRequestParams,
isNew: boolean,
): AxiosPromise<GitImportResponse> {
if (isNew) {
return gitImportRequestNew(workspaceId, params);
} else {
return gitImportRequestOld(workspaceId, params);
}
}

View File

@ -2,10 +2,35 @@ import Api from "api/Api";
import type { MergeRequestParams, MergeResponse } from "./mergeRequest.types";
import { GIT_BASE_URL } from "./constants";
import type { AxiosPromise } from "axios";
import type { GitArtifactType } from "git/constants/enums";
export default async function mergeRequest(
async function mergeRequestOld(
branchedApplicationId: string,
params: MergeRequestParams,
): AxiosPromise<MergeResponse> {
return Api.post(`${GIT_BASE_URL}/merge/app/${branchedApplicationId}`, params);
}
async function mergeRequestNew(
artifactType: GitArtifactType,
refArtifactId: string,
params: MergeRequestParams,
): AxiosPromise<MergeResponse> {
return Api.post(
`${GIT_BASE_URL}/${artifactType}/${refArtifactId}/merge`,
params,
);
}
export default async function mergeRequest(
artifactType: GitArtifactType,
refArtifactId: string,
params: MergeRequestParams,
isNew: boolean,
): AxiosPromise<MergeResponse> {
if (isNew) {
return mergeRequestNew(artifactType, refArtifactId, params);
} else {
return mergeRequestOld(refArtifactId, params);
}
}

View File

@ -2,9 +2,29 @@ import Api from "api/Api";
import { GIT_BASE_URL } from "./constants";
import type { AxiosPromise } from "axios";
import type { PullResponse } from "./pullRequest.types";
import type { GitArtifactType } from "git/constants/enums";
export default async function pullRequest(
async function pullRequestOld(
branchedApplicationId: string,
): AxiosPromise<PullResponse> {
return Api.get(`${GIT_BASE_URL}/pull/app/${branchedApplicationId}`);
}
async function pullRequestNew(
artifactType: GitArtifactType,
refArtifactId: string,
): AxiosPromise<PullResponse> {
return Api.get(`${GIT_BASE_URL}/${artifactType}/${refArtifactId}/pull`);
}
export default async function pullRequest(
artifactType: GitArtifactType,
refArtifactId: string,
isNew: boolean,
): AxiosPromise<PullResponse> {
if (isNew) {
return pullRequestNew(artifactType, refArtifactId);
} else {
return pullRequestOld(refArtifactId);
}
}

View File

@ -2,11 +2,33 @@ import Api from "api/Api";
import { GIT_BASE_URL } from "./constants";
import type { AxiosPromise } from "axios";
import type { ToggleAutocommitResponse } from "./toggleAutocommitRequest.types";
import type { GitArtifactType } from "git/constants/enums";
export default async function toggleAutocommitRequest(
async function toggleAutocommitRequestOld(
baseApplicationId: string,
): AxiosPromise<ToggleAutocommitResponse> {
return Api.patch(
`${GIT_BASE_URL}/auto-commit/toggle/app/${baseApplicationId}`,
);
}
async function toggleAutocommitRequestNew(
artifactType: GitArtifactType,
baseArtifactId: string,
): AxiosPromise<ToggleAutocommitResponse> {
return Api.patch(
`${GIT_BASE_URL}/${artifactType}/${baseArtifactId}/auto-commit/toggle`,
);
}
export default async function toggleAutocommitRequest(
artifactType: GitArtifactType,
baseArtifactId: string,
isNew: boolean,
): AxiosPromise<ToggleAutocommitResponse> {
if (isNew) {
return toggleAutocommitRequestNew(artifactType, baseArtifactId);
} else {
return toggleAutocommitRequestOld(baseArtifactId);
}
}

View File

@ -2,9 +2,31 @@ import Api from "api/Api";
import { GIT_BASE_URL } from "./constants";
import type { AxiosPromise } from "axios";
import type { TriggerAutocommitResponse } from "./triggerAutocommitRequest.types";
import type { GitArtifactType } from "git/constants/enums";
export default async function triggerAutocommitRequest(
async function triggerAutocommitRequestOld(
branchedApplicationId: string,
): AxiosPromise<TriggerAutocommitResponse> {
return Api.post(`${GIT_BASE_URL}/auto-commit/app/${branchedApplicationId}`);
}
async function triggerAutocommitRequestNew(
artifactType: GitArtifactType,
refArtifactId: string,
): AxiosPromise<TriggerAutocommitResponse> {
return Api.post(
`${GIT_BASE_URL}/${artifactType}/${refArtifactId}/auto-commit`,
);
}
export default async function triggerAutocommitRequest(
artifactType: GitArtifactType,
refArtifactId: string,
isNew: boolean,
): AxiosPromise<TriggerAutocommitResponse> {
if (isNew) {
return triggerAutocommitRequestNew(artifactType, refArtifactId);
} else {
return triggerAutocommitRequestOld(refArtifactId);
}
}

View File

@ -5,10 +5,35 @@ import type {
} from "./updateLocalProfileRequest.types";
import Api from "api/Api";
import { GIT_BASE_URL } from "./constants";
import type { GitArtifactType } from "git/constants/enums";
export default async function updateLocalProfileRequest(
async function updateLocalProfileRequestOld(
baseApplicationId: string,
params: UpdateLocalProfileRequestParams,
): AxiosPromise<UpdateLocalProfileResponse> {
return Api.put(`${GIT_BASE_URL}/profile/app/${baseApplicationId}`, params);
}
async function updateLocalProfileRequestNew(
artifactType: GitArtifactType,
baseArtifactId: string,
params: UpdateLocalProfileRequestParams,
): AxiosPromise<UpdateLocalProfileResponse> {
return Api.put(
`${GIT_BASE_URL}/${artifactType}/${baseArtifactId}/profile`,
params,
);
}
export default async function updateLocalProfileRequest(
artifactType: GitArtifactType,
baseArtifactId: string,
params: UpdateLocalProfileRequestParams,
isNew: boolean,
): AxiosPromise<UpdateLocalProfileResponse> {
if (isNew) {
return updateLocalProfileRequestNew(artifactType, baseArtifactId, params);
} else {
return updateLocalProfileRequestOld(baseArtifactId, params);
}
}

View File

@ -5,8 +5,9 @@ import type {
UpdateProtectedBranchesResponse,
} from "./updateProtectedBranchesRequest.types";
import type { AxiosPromise } from "axios";
import type { GitArtifactType } from "git/constants/enums";
export default async function updateProtectedBranchesRequest(
async function updateProtectedBranchesRequestOld(
baseApplicationId: string,
params: UpdateProtectedBranchesRequestParams,
): AxiosPromise<UpdateProtectedBranchesResponse> {
@ -15,3 +16,31 @@ export default async function updateProtectedBranchesRequest(
params,
);
}
async function updateProtectedBranchesRequestNew(
artifactType: GitArtifactType,
baseArtifactId: string,
params: UpdateProtectedBranchesRequestParams,
): AxiosPromise<UpdateProtectedBranchesResponse> {
return Api.post(
`${GIT_BASE_URL}/${artifactType}/${baseArtifactId}/protected`,
params,
);
}
export default async function updateProtectedBranchesRequest(
artifactType: GitArtifactType,
baseArtifactId: string,
params: UpdateProtectedBranchesRequestParams,
isNew: boolean,
): AxiosPromise<UpdateProtectedBranchesResponse> {
if (isNew) {
return updateProtectedBranchesRequestNew(
artifactType,
baseArtifactId,
params,
);
} else {
return updateProtectedBranchesRequestOld(baseArtifactId, params);
}
}

View File

@ -1,13 +1,15 @@
import { call, put, select, take } from "redux-saga/effects";
import type { CheckoutBranchInitPayload } from "../store/actions/checkoutBranchActions";
import { GitArtifactType } from "../constants/enums";
import checkoutBranchRequest from "../requests/checkoutBranchRequest";
import type {
CheckoutBranchRequestParams,
CheckoutBranchResponse,
} from "../requests/checkoutBranchRequest.types";
import { gitArtifactActions } from "../store/gitArtifactSlice";
import type { GitArtifactPayloadAction } from "../store/types";
import log from "loglevel";
import { captureException } from "@sentry/react";
import { selectGitApiContractsEnabled } from "git/store/selectors/gitFeatureFlagSelectors";
import type {
CheckoutRefRequestParams,
CheckoutRefResponse,
} from "git/requests/checkoutRefRequest.types";
// internal dependencies
import { builderURL } from "ee/RouteBuilder";
@ -19,21 +21,30 @@ import { FocusEntity, identifyEntityFromPath } from "navigation/FocusEntity";
import { validateResponse } from "sagas/ErrorSagas";
import history from "utils/history";
import type { JSCollectionDataState } from "ee/reducers/entityReducers/jsActionsReducer";
import log from "loglevel";
import { captureException } from "@sentry/react";
import checkoutRefRequest from "git/requests/checkoutRefRequest";
export default function* checkoutBranchSaga(
action: GitArtifactPayloadAction<CheckoutBranchInitPayload>,
) {
const { artifactDef, artifactId, branchName } = action.payload;
let response: CheckoutBranchResponse | undefined;
let response: CheckoutRefResponse | undefined;
try {
const params: CheckoutBranchRequestParams = {
branchName,
const params: CheckoutRefRequestParams = {
refType: "branch",
refName: branchName,
};
const isGitApiContractsEnabled: boolean = yield select(
selectGitApiContractsEnabled,
);
response = yield call(checkoutBranchRequest, artifactId, params);
response = yield call(
checkoutRefRequest,
artifactDef.artifactType,
artifactId,
params,
isGitApiContractsEnabled,
);
const isValidResponse: boolean = yield validateResponse(response);
if (response && isValidResponse) {

View File

@ -17,6 +17,7 @@ import { gitGlobalActions } from "git/store/gitGlobalSlice";
import type { ApplicationPayload } from "entities/Application";
import { getCurrentApplication } from "ee/selectors/applicationSelectors";
import { ReduxActionTypes } from "ee/constants/ReduxActionConstants";
import { selectGitApiContractsEnabled } from "git/store/selectors/gitFeatureFlagSelectors";
export default function* commitSaga(
action: GitArtifactPayloadAction<CommitInitPayload>,
@ -30,8 +31,17 @@ export default function* commitSaga(
commitMessage: action.payload.commitMessage,
doPush: action.payload.doPush,
};
const isGitApiContractsEnabled: boolean = yield select(
selectGitApiContractsEnabled,
);
response = yield call(commitRequest, artifactId, params);
response = yield call(
commitRequest,
artifactDef.artifactType,
artifactId,
params,
isGitApiContractsEnabled,
);
const isValidResponse: boolean = yield validateResponse(response, false);

View File

@ -22,6 +22,7 @@ import { gitGlobalActions } from "git/store/gitGlobalSlice";
import { getCurrentApplication } from "ee/selectors/applicationSelectors";
import type { ApplicationPayload } from "entities/Application";
import { ReduxActionTypes } from "ee/constants/ReduxActionConstants";
import { selectGitApiContractsEnabled } from "git/store/selectors/gitFeatureFlagSelectors";
export default function* connectSaga(
action: GitArtifactPayloadAction<ConnectInitPayload>,
@ -36,7 +37,17 @@ export default function* connectSaga(
gitProfile: action.payload.gitProfile,
};
response = yield call(connectRequest, artifactDef.baseArtifactId, params);
const isGitApiContractsEnabled: boolean = yield select(
selectGitApiContractsEnabled,
);
response = yield call(
connectRequest,
artifactDef.artifactType,
artifactDef.baseArtifactId,
params,
isGitApiContractsEnabled,
);
const isValidResponse: boolean = yield validateResponse(response, false);

View File

@ -1,10 +1,5 @@
import { call, put } from "redux-saga/effects";
import { call, put, select } from "redux-saga/effects";
import type { CreateBranchInitPayload } from "../store/actions/createBranchActions";
import createBranchRequest from "../requests/createBranchRequest";
import type {
CreateBranchRequestParams,
CreateBranchResponse,
} from "../requests/createBranchRequest.types";
import { gitArtifactActions } from "../store/gitArtifactSlice";
import type { GitArtifactPayloadAction } from "../store/types";
@ -12,29 +7,46 @@ import type { GitArtifactPayloadAction } from "../store/types";
import { validateResponse } from "sagas/ErrorSagas";
import { captureException } from "@sentry/react";
import log from "loglevel";
import createRefRequest from "git/requests/createRefRequest";
import type {
CreateRefRequestParams,
CreateRefResponse,
} from "git/requests/createRefRequest.types";
import { selectGitApiContractsEnabled } from "git/store/selectors/gitFeatureFlagSelectors";
export default function* createBranchSaga(
action: GitArtifactPayloadAction<CreateBranchInitPayload>,
) {
const { artifactDef, artifactId } = action.payload;
let response: CreateBranchResponse | undefined;
let response: CreateRefResponse | undefined;
try {
const params: CreateBranchRequestParams = {
branchName: action.payload.branchName,
const params: CreateRefRequestParams = {
refType: "branch",
refName: action.payload.branchName,
};
response = yield call(createBranchRequest, artifactId, params);
const isGitApiContractsEnabled: boolean = yield select(
selectGitApiContractsEnabled,
);
response = yield call(
createRefRequest,
artifactDef.artifactType,
artifactId,
params,
isGitApiContractsEnabled,
);
const isValidResponse: boolean = yield validateResponse(response);
if (isValidResponse) {
// yield put(
// gitArtifactActions.fetchBranchesInit({
// artifactDef,
// artifactId,
// pruneBranches: true,
// }),
// );
yield put(
gitArtifactActions.fetchBranchesInit({
artifactDef,
artifactId,
pruneBranches: true,
}),
);
yield put(
gitArtifactActions.checkoutBranchInit({
artifactDef,

View File

@ -1,35 +1,41 @@
import type { DeleteBranchInitPayload } from "../store/actions/deleteBranchActions";
import deleteBranchRequest from "../requests/deleteBranchRequest";
import type {
DeleteBranchRequestParams,
DeleteBranchResponse,
} from "../requests/deleteBranchRequest.types";
import { gitArtifactActions } from "../store/gitArtifactSlice";
import type { GitArtifactPayloadAction } from "../store/types";
import { call, put } from "redux-saga/effects";
// internal dependencies
import { call, put, select } from "redux-saga/effects";
import { validateResponse } from "sagas/ErrorSagas";
import log from "loglevel";
import { captureException } from "@sentry/react";
import { toast } from "@appsmith/ads";
import { createMessage, DELETE_BRANCH_SUCCESS } from "ee/constants/messages";
import { selectGitApiContractsEnabled } from "git/store/selectors/gitFeatureFlagSelectors";
import deleteRefRequest from "git/requests/deleteRefRequest";
import type {
DeleteRefRequestParams,
DeleteRefResponse,
} from "git/requests/deleteRefRequest.types";
export default function* deleteBranchSaga(
action: GitArtifactPayloadAction<DeleteBranchInitPayload>,
) {
const { artifactDef, artifactId } = action.payload;
let response: DeleteBranchResponse | undefined;
let response: DeleteRefResponse | undefined;
try {
const params: DeleteBranchRequestParams = {
branchName: action.payload.branchName,
const params: DeleteRefRequestParams = {
refType: "branch",
refName: action.payload.branchName,
};
const isGitApiContractsEnabled: boolean = yield select(
selectGitApiContractsEnabled,
);
response = yield call(
deleteBranchRequest,
deleteRefRequest,
artifactDef.artifactType,
artifactDef.baseArtifactId,
params,
isGitApiContractsEnabled,
);
const isValidResponse: boolean = yield validateResponse(response);

View File

@ -6,9 +6,10 @@ import discardRequest from "git/requests/discardRequest";
import type { DiscardResponse } from "git/requests/discardRequest.types";
import type { DiscardInitPayload } from "git/store/actions/discardActions";
import { gitArtifactActions } from "git/store/gitArtifactSlice";
import { selectGitApiContractsEnabled } from "git/store/selectors/gitFeatureFlagSelectors";
import type { GitArtifactPayloadAction } from "git/store/types";
import log from "loglevel";
import { call, delay, put } from "redux-saga/effects";
import { call, delay, put, select } from "redux-saga/effects";
import { validateResponse } from "sagas/ErrorSagas";
export default function* discardSaga(
@ -19,7 +20,16 @@ export default function* discardSaga(
let response: DiscardResponse | undefined;
try {
response = yield call(discardRequest, artifactId);
const isGitApiContractsEnabled: boolean = yield select(
selectGitApiContractsEnabled,
);
response = yield call(
discardRequest,
artifactDef.artifactType,
artifactId,
isGitApiContractsEnabled,
);
const isValidResponse: boolean = yield validateResponse(response);
if (response && isValidResponse) {

View File

@ -6,6 +6,7 @@ import disconnectRequest from "git/requests/disconnectRequest";
import type { DisconnectResponse } from "git/requests/disconnectRequest.types";
import { gitArtifactActions } from "git/store/gitArtifactSlice";
import { selectDisconnectArtifactDef } from "git/store/selectors/gitArtifactSelectors";
import { selectGitApiContractsEnabled } from "git/store/selectors/gitFeatureFlagSelectors";
import type { GitArtifactDef, GitArtifactPayloadAction } from "git/store/types";
import log from "loglevel";
import { call, put, select } from "redux-saga/effects";
@ -21,9 +22,15 @@ export default function* disconnectSaga(action: GitArtifactPayloadAction) {
let response: DisconnectResponse | undefined;
try {
const isGitApiContractsEnabled: boolean = yield select(
selectGitApiContractsEnabled,
);
response = yield call(
disconnectRequest,
disconnectArtifactDef.artifactType,
disconnectArtifactDef.baseArtifactId,
isGitApiContractsEnabled,
);
const isValidResponse: boolean = yield validateResponse(response);

View File

@ -1,28 +1,40 @@
import type { FetchBranchesInitPayload } from "../store/actions/fetchBranchesActions";
import fetchBranchesRequest from "git/requests/fetchBranchesRequest";
import type {
FetchBranchesRequestParams,
FetchBranchesResponse,
} from "git/requests/fetchBranchesRequest.types";
import { gitArtifactActions } from "git/store/gitArtifactSlice";
import type { GitArtifactPayloadAction } from "../store/types";
import { call, put } from "redux-saga/effects";
import { call, put, select } from "redux-saga/effects";
import { validateResponse } from "sagas/ErrorSagas";
import log from "loglevel";
import { captureException } from "@sentry/react";
import fetchRefsRequest from "git/requests/fetchRefsRequest";
import { selectGitApiContractsEnabled } from "git/store/selectors/gitFeatureFlagSelectors";
import type {
FetchRefsRequestParams,
FetchRefsResponse,
} from "git/requests/fetchRefsRequest.types";
export default function* fetchBranchesSaga(
action: GitArtifactPayloadAction<FetchBranchesInitPayload>,
) {
const { artifactDef, artifactId } = action.payload;
let response: FetchBranchesResponse | undefined;
let response: FetchRefsResponse | undefined;
try {
const params: FetchBranchesRequestParams = {
pruneBranches: action.payload.pruneBranches,
const params: FetchRefsRequestParams = {
refType: "branch",
pruneRefs: action.payload.pruneBranches ?? true,
};
response = yield call(fetchBranchesRequest, artifactId, params);
const isGitApiContractsEnabled: boolean = yield select(
selectGitApiContractsEnabled,
);
response = yield call(
fetchRefsRequest,
artifactDef.artifactType,
artifactId,
params,
isGitApiContractsEnabled,
);
const isValidResponse: boolean = yield validateResponse(response, false);
if (response && isValidResponse) {

View File

@ -6,9 +6,10 @@ import type {
} from "git/requests/generateSSHKeyRequest.types";
import type { FetchGlobalSSHKeyInitPayload } from "git/store/actions/fetchGlobalSSHKeyActions";
import { gitGlobalActions } from "git/store/gitGlobalSlice";
import { selectGitApiContractsEnabled } from "git/store/selectors/gitFeatureFlagSelectors";
import type { GitArtifactPayloadAction } from "git/store/types";
import log from "loglevel";
import { call, put } from "redux-saga/effects";
import { call, put, select } from "redux-saga/effects";
import { validateResponse } from "sagas/ErrorSagas";
export function* fetchGlobalSSHKeySaga(
@ -21,7 +22,15 @@ export function* fetchGlobalSSHKeySaga(
keyType: action.payload.keyType,
};
response = yield call(fetchGlobalSSHKeyRequest, params);
const isGitApiContractsEnabled: boolean = yield select(
selectGitApiContractsEnabled,
);
response = yield call(
fetchGlobalSSHKeyRequest,
params,
isGitApiContractsEnabled,
);
const isValidResponse: boolean = yield validateResponse(response);
if (response && isValidResponse) {

View File

@ -2,10 +2,11 @@ import fetchLocalProfileRequest from "git/requests/fetchLocalProfileRequest";
import type { FetchLocalProfileResponse } from "git/requests/fetchLocalProfileRequest.types";
import { gitArtifactActions } from "git/store/gitArtifactSlice";
import type { GitArtifactPayloadAction } from "../store/types";
import { call, put } from "redux-saga/effects";
import { call, put, select } from "redux-saga/effects";
import { validateResponse } from "sagas/ErrorSagas";
import log from "loglevel";
import { captureException } from "@sentry/react";
import { selectGitApiContractsEnabled } from "git/store/selectors/gitFeatureFlagSelectors";
export default function* fetchLocalProfileSaga(
action: GitArtifactPayloadAction,
@ -14,7 +15,16 @@ export default function* fetchLocalProfileSaga(
let response: FetchLocalProfileResponse | undefined;
try {
response = yield call(fetchLocalProfileRequest, artifactDef.baseArtifactId);
const isGitApiContractsEnabled: boolean = yield select(
selectGitApiContractsEnabled,
);
response = yield call(
fetchLocalProfileRequest,
artifactDef.artifactType,
artifactDef.baseArtifactId,
isGitApiContractsEnabled,
);
const isValidResponse: boolean = yield validateResponse(response);
if (response && isValidResponse) {

View File

@ -6,9 +6,10 @@ import type {
} from "git/requests/fetchMergeStatusRequest.types";
import type { FetchMergeStatusInitPayload } from "git/store/actions/fetchMergeStatusActions";
import { gitArtifactActions } from "git/store/gitArtifactSlice";
import { selectGitApiContractsEnabled } from "git/store/selectors/gitFeatureFlagSelectors";
import type { GitArtifactPayloadAction } from "git/store/types";
import log from "loglevel";
import { call, put } from "redux-saga/effects";
import { call, put, select } from "redux-saga/effects";
import { validateResponse } from "sagas/ErrorSagas";
export default function* fetchMergeStatusSaga(
@ -23,7 +24,17 @@ export default function* fetchMergeStatusSaga(
sourceBranch: action.payload.sourceBranch,
};
response = yield call(fetchMergeStatusRequest, artifactId, params);
const isGitApiContractsEnabled: boolean = yield select(
selectGitApiContractsEnabled,
);
response = yield call(
fetchMergeStatusRequest,
artifactDef.artifactType,
artifactId,
params,
isGitApiContractsEnabled,
);
const isValidResponse: boolean = yield validateResponse(response);
if (response && isValidResponse) {

View File

@ -2,9 +2,10 @@ import { captureException } from "@sentry/react";
import fetchMetadataRequest from "git/requests/fetchMetadataRequest";
import type { FetchMetadataResponse } from "git/requests/fetchMetadataRequest.types";
import { gitArtifactActions } from "git/store/gitArtifactSlice";
import { selectGitApiContractsEnabled } from "git/store/selectors/gitFeatureFlagSelectors";
import type { GitArtifactPayloadAction } from "git/store/types";
import log from "loglevel";
import { call, put } from "redux-saga/effects";
import { call, put, select } from "redux-saga/effects";
import { validateResponse } from "sagas/ErrorSagas";
export default function* fetchMetadataSaga(action: GitArtifactPayloadAction) {
@ -12,7 +13,16 @@ export default function* fetchMetadataSaga(action: GitArtifactPayloadAction) {
let response: FetchMetadataResponse | undefined;
try {
response = yield call(fetchMetadataRequest, artifactDef.baseArtifactId);
const isGitApiContractsEnabled: boolean = yield select(
selectGitApiContractsEnabled,
);
response = yield call(
fetchMetadataRequest,
artifactDef.artifactType,
artifactDef.baseArtifactId,
isGitApiContractsEnabled,
);
const isValidResponse: boolean = yield validateResponse(response, false);
if (response && isValidResponse) {

View File

@ -2,9 +2,10 @@ import { captureException } from "@sentry/react";
import fetchProtectedBranchesRequest from "git/requests/fetchProtectedBranchesRequest";
import type { FetchProtectedBranchesResponse } from "git/requests/fetchProtectedBranchesRequest.types";
import { gitArtifactActions } from "git/store/gitArtifactSlice";
import { selectGitApiContractsEnabled } from "git/store/selectors/gitFeatureFlagSelectors";
import type { GitArtifactPayloadAction } from "git/store/types";
import log from "loglevel";
import { call, put } from "redux-saga/effects";
import { call, put, select } from "redux-saga/effects";
import { validateResponse } from "sagas/ErrorSagas";
export default function* fetchProtectedBranchesSaga(
@ -14,9 +15,15 @@ export default function* fetchProtectedBranchesSaga(
let response: FetchProtectedBranchesResponse | undefined;
try {
const isGitApiContractsEnabled: boolean = yield select(
selectGitApiContractsEnabled,
);
response = yield call(
fetchProtectedBranchesRequest,
artifactDef.artifactType,
artifactDef.baseArtifactId,
isGitApiContractsEnabled,
);
const isValidResponse: boolean = yield validateResponse(response);

View File

@ -3,9 +3,10 @@ import fetchStatusRequest from "git/requests/fetchStatusRequest";
import type { FetchStatusResponse } from "git/requests/fetchStatusRequest.types";
import type { FetchStatusInitPayload } from "git/store/actions/fetchStatusActions";
import { gitArtifactActions } from "git/store/gitArtifactSlice";
import { selectGitApiContractsEnabled } from "git/store/selectors/gitFeatureFlagSelectors";
import type { GitArtifactPayloadAction } from "git/store/types";
import log from "loglevel";
import { call, put } from "redux-saga/effects";
import { call, put, select } from "redux-saga/effects";
import { validateResponse } from "sagas/ErrorSagas";
export default function* fetchStatusSaga(
@ -15,7 +16,18 @@ export default function* fetchStatusSaga(
let response: FetchStatusResponse | undefined;
try {
response = yield call(fetchStatusRequest, artifactId);
const params = { compareRemote: true };
const isGitApiContractsEnabled: boolean = yield select(
selectGitApiContractsEnabled,
);
response = yield call(
fetchStatusRequest,
artifactDef.artifactType,
artifactId,
params,
isGitApiContractsEnabled,
);
const isValidResponse: boolean = yield validateResponse(response);
if (response && isValidResponse) {

View File

@ -16,6 +16,7 @@ import { showReconnectDatasourceModal } from "ee/actions/applicationActions";
import type { Workspace } from "ee/constants/workspaceConstants";
import { getFetchedWorkspaces } from "ee/selectors/workspaceSelectors";
import { GitErrorCodes } from "git/constants/enums";
import { selectGitApiContractsEnabled } from "git/store/selectors/gitFeatureFlagSelectors";
export default function* gitImportSaga(
action: PayloadAction<GitImportInitPayload>,
@ -26,7 +27,16 @@ export default function* gitImportSaga(
let response: GitImportResponse | undefined;
try {
response = yield call(gitImportRequest, workspaceId, params);
const isGitApiContractsEnabled: boolean = yield select(
selectGitApiContractsEnabled,
);
response = yield call(
gitImportRequest,
workspaceId,
params,
isGitApiContractsEnabled,
);
const isValidResponse: boolean = yield validateResponse(response);
if (response && isValidResponse) {

View File

@ -3,9 +3,10 @@ import mergeRequest from "git/requests/mergeRequest";
import type { MergeResponse } from "git/requests/mergeRequest.types";
import type { MergeInitPayload } from "git/store/actions/mergeActions";
import { gitArtifactActions } from "git/store/gitArtifactSlice";
import { selectGitApiContractsEnabled } from "git/store/selectors/gitFeatureFlagSelectors";
import type { GitArtifactPayloadAction } from "git/store/types";
import log from "loglevel";
import { call, put } from "redux-saga/effects";
import { call, put, select } from "redux-saga/effects";
import { validateResponse } from "sagas/ErrorSagas";
export default function* mergeSaga(
@ -20,7 +21,17 @@ export default function* mergeSaga(
destinationBranch: action.payload.destinationBranch,
};
response = yield call(mergeRequest, artifactId, params);
const isGitApiContractsEnabled: boolean = yield select(
selectGitApiContractsEnabled,
);
response = yield call(
mergeRequest,
artifactDef.artifactType,
artifactId,
params,
isGitApiContractsEnabled,
);
const isValidResponse: boolean = yield validateResponse(response);

View File

@ -13,6 +13,7 @@ import { initEditorAction } from "actions/initActions";
import { APP_MODE } from "entities/App";
import log from "loglevel";
import { captureException } from "@sentry/react";
import { selectGitApiContractsEnabled } from "git/store/selectors/gitFeatureFlagSelectors";
export default function* pullSaga(
action: GitArtifactPayloadAction<PullInitPayload>,
@ -21,7 +22,16 @@ export default function* pullSaga(
let response: PullResponse | undefined;
try {
response = yield call(pullRequest, artifactId);
const isGitApiContractsEnabled: boolean = yield select(
selectGitApiContractsEnabled,
);
response = yield call(
pullRequest,
artifactDef.artifactType,
artifactId,
isGitApiContractsEnabled,
);
const isValidResponse: boolean = yield validateResponse(response);
if (response && isValidResponse) {

View File

@ -2,9 +2,10 @@ import { captureException } from "@sentry/react";
import toggleAutocommitRequest from "git/requests/toggleAutocommitRequest";
import type { ToggleAutocommitResponse } from "git/requests/toggleAutocommitRequest.types";
import { gitArtifactActions } from "git/store/gitArtifactSlice";
import { selectGitApiContractsEnabled } from "git/store/selectors/gitFeatureFlagSelectors";
import type { GitArtifactPayloadAction } from "git/store/types";
import log from "loglevel";
import { call, put } from "redux-saga/effects";
import { call, put, select } from "redux-saga/effects";
import { validateResponse } from "sagas/ErrorSagas";
export default function* toggleAutocommitSaga(
@ -14,7 +15,16 @@ export default function* toggleAutocommitSaga(
let response: ToggleAutocommitResponse | undefined;
try {
response = yield call(toggleAutocommitRequest, artifactDef.baseArtifactId);
const isGitApiContractsEnabled: boolean = yield select(
selectGitApiContractsEnabled,
);
response = yield call(
toggleAutocommitRequest,
artifactDef.artifactType,
artifactDef.baseArtifactId,
isGitApiContractsEnabled,
);
const isValidResponse: boolean = yield validateResponse(response);
if (isValidResponse) {

View File

@ -27,6 +27,7 @@ import type { Task } from "redux-saga";
import { validateResponse } from "sagas/ErrorSagas";
import log from "loglevel";
import { captureException } from "@sentry/react";
import { selectGitApiContractsEnabled } from "git/store/selectors/gitFeatureFlagSelectors";
const AUTOCOMMIT_POLL_DELAY = 1000;
const AUTOCOMMIT_WHITELISTED_STATES = [
@ -56,8 +57,17 @@ function* pollAutocommitProgressSaga(params: PollAutocommitProgressParams) {
const { artifactDef, artifactId } = params;
let triggerResponse: TriggerAutocommitResponse | undefined;
const isGitApiContractsEnabled: boolean = yield select(
selectGitApiContractsEnabled,
);
try {
triggerResponse = yield call(triggerAutocommitRequest, artifactId);
triggerResponse = yield call(
triggerAutocommitRequest,
artifactDef.artifactType,
artifactId,
isGitApiContractsEnabled,
);
const isValidResponse: boolean = yield validateResponse(triggerResponse);
if (triggerResponse && isValidResponse) {
@ -88,9 +98,12 @@ function* pollAutocommitProgressSaga(params: PollAutocommitProgressParams) {
yield put(
gitArtifactActions.fetchAutocommitProgressInit({ artifactDef }),
);
progressResponse = yield call(
fetchAutocommitProgressRequest,
artifactDef.artifactType,
artifactDef.baseArtifactId,
isGitApiContractsEnabled,
);
const isValidResponse: boolean =
yield validateResponse(progressResponse);

View File

@ -6,10 +6,11 @@ import type {
} from "git/requests/updateLocalProfileRequest.types";
import { gitArtifactActions } from "../store/gitArtifactSlice";
import type { GitArtifactPayloadAction } from "../store/types";
import { call, put } from "redux-saga/effects";
import { call, put, select } from "redux-saga/effects";
import { validateResponse } from "sagas/ErrorSagas";
import log from "loglevel";
import { captureException } from "@sentry/react";
import { selectGitApiContractsEnabled } from "git/store/selectors/gitFeatureFlagSelectors";
export default function* updateLocalProfileSaga(
action: GitArtifactPayloadAction<UpdateLocalProfileInitPayload>,
@ -24,10 +25,16 @@ export default function* updateLocalProfileSaga(
useGlobalProfile: action.payload.useGlobalProfile,
};
const isGitApiContractsEnabled: boolean = yield select(
selectGitApiContractsEnabled,
);
response = yield call(
updateLocalProfileRequest,
artifactDef.artifactType,
artifactDef.baseArtifactId,
params,
isGitApiContractsEnabled,
);
const isValidResponse: boolean = yield validateResponse(response);

View File

@ -6,9 +6,10 @@ import type {
} from "git/requests/updateProtectedBranchesRequest.types";
import type { UpdateProtectedBranchesInitPayload } from "git/store/actions/updateProtectedBranchesActions";
import { gitArtifactActions } from "git/store/gitArtifactSlice";
import { selectGitApiContractsEnabled } from "git/store/selectors/gitFeatureFlagSelectors";
import type { GitArtifactPayloadAction } from "git/store/types";
import log from "loglevel";
import { call, put } from "redux-saga/effects";
import { call, put, select } from "redux-saga/effects";
import { validateResponse } from "sagas/ErrorSagas";
export default function* updateProtectedBranchesSaga(
@ -22,10 +23,16 @@ export default function* updateProtectedBranchesSaga(
branchNames: action.payload.branchNames,
};
const isGitApiContractsEnabled: boolean = yield select(
selectGitApiContractsEnabled,
);
response = yield call(
updateProtectedBranchesRequest,
artifactDef.artifactType,
artifactDef.baseArtifactId,
params,
isGitApiContractsEnabled,
);
const isValidResponse: boolean = yield validateResponse(response);

View File

@ -1,9 +1,9 @@
import { createArtifactAction } from "../helpers/createArtifactAction";
import type { GitAsyncErrorPayload } from "../types";
import type { CheckoutBranchRequestParams } from "git/requests/checkoutBranchRequest.types";
export interface CheckoutBranchInitPayload extends CheckoutBranchRequestParams {
export interface CheckoutBranchInitPayload {
artifactId: string;
branchName: string;
}
export const checkoutBranchInitAction =

View File

@ -1,9 +1,9 @@
import { createArtifactAction } from "../helpers/createArtifactAction";
import type { GitAsyncErrorPayload } from "../types";
import type { CreateBranchRequestParams } from "git/requests/createBranchRequest.types";
export interface CreateBranchInitPayload extends CreateBranchRequestParams {
export interface CreateBranchInitPayload {
artifactId: string;
branchName: string;
}
export const createBranchInitAction =

View File

@ -1,9 +1,9 @@
import { createArtifactAction } from "../helpers/createArtifactAction";
import type { GitAsyncErrorPayload } from "../types";
import type { DeleteBranchRequestParams } from "../../requests/deleteBranchRequest.types";
export interface DeleteBranchInitPayload extends DeleteBranchRequestParams {
export interface DeleteBranchInitPayload {
artifactId: string;
branchName: string;
}
export const deleteBranchInitAction =

View File

@ -1,12 +1,10 @@
import type {
FetchBranchesRequestParams,
FetchBranchesResponseData,
} from "../../requests/fetchBranchesRequest.types";
import type { GitAsyncErrorPayload, GitAsyncSuccessPayload } from "../types";
import { createArtifactAction } from "../helpers/createArtifactAction";
import type { FetchRefsResponseData } from "git/requests/fetchRefsRequest.types";
export interface FetchBranchesInitPayload extends FetchBranchesRequestParams {
export interface FetchBranchesInitPayload {
artifactId: string;
pruneBranches?: boolean;
}
export const fetchBranchesInitAction =
@ -18,7 +16,7 @@ export const fetchBranchesInitAction =
});
export const fetchBranchesSuccessAction = createArtifactAction<
GitAsyncSuccessPayload<FetchBranchesResponseData>
GitAsyncSuccessPayload<FetchRefsResponseData>
>((state, action) => {
state.apiResponses.branches.loading = false;
state.apiResponses.branches.value = action.payload.responseData;

View File

@ -0,0 +1,9 @@
import { createSelector } from "reselect";
import { selectFeatureFlags } from "ee/selectors/featureFlagsSelectors";
import { FEATURE_FLAG } from "ee/entities/FeatureFlag";
export const selectGitApiContractsEnabled = createSelector(
selectFeatureFlags,
(featureFlags) =>
featureFlags[FEATURE_FLAG.release_git_api_contracts_enabled] ?? false,
);

View File

@ -5,7 +5,6 @@ import type {
GitSettingsTab,
} from "../constants/enums";
import type { FetchGlobalProfileResponseData } from "../requests/fetchGlobalProfileRequest.types";
import type { FetchBranchesResponseData } from "../requests/fetchBranchesRequest.types";
import type { FetchLocalProfileResponseData } from "../requests/fetchLocalProfileRequest.types";
import type { FetchStatusResponseData } from "git/requests/fetchStatusRequest.types";
import type { FetchMergeStatusResponseData } from "git/requests/fetchMergeStatusRequest.types";
@ -19,6 +18,7 @@ import type {
} from "git/ee/store/types";
import type { FetchGlobalSSHKeyResponseData } from "git/requests/fetchGlobalSSHKeyRequest.types";
import type { ApplicationPayload } from "entities/Application";
import type { FetchRefsResponseData } from "git/requests/fetchRefsRequest.types";
export interface GitApiError extends ApiResponseError {
errorType?: string;
@ -45,7 +45,7 @@ export interface GitArtifactAPIResponsesReduxState
discard: GitAsyncStateWithoutValue;
mergeStatus: GitAsyncState<FetchMergeStatusResponseData>;
merge: GitAsyncStateWithoutValue;
branches: GitAsyncState<FetchBranchesResponseData>;
branches: GitAsyncState<FetchRefsResponseData>;
checkoutBranch: GitAsyncStateWithoutValue;
createBranch: GitAsyncStateWithoutValue;
deleteBranch: GitAsyncStateWithoutValue;
@ -68,7 +68,7 @@ export interface GitArtifactUIReduxState
connectModalOpen: boolean;
connectSuccessModalOpen: boolean;
disconnectBaseArtifactId: string | null;
disconnectArtifactType: keyof typeof GitArtifactType | null;
disconnectArtifactType: GitArtifactType | null;
disconnectArtifactName: string | null;
branchPopupOpen: boolean;
checkoutDestBranch: string | null;
@ -85,7 +85,7 @@ export interface GitArtifactUIReduxState
export type GitArtifact = ApplicationPayload;
export interface GitArtifactDef {
artifactType: keyof typeof GitArtifactType;
artifactType: GitArtifactType;
baseArtifactId: string;
}
export interface GitArtifactReduxState {

View File

@ -0,0 +1,11 @@
export interface GitRef {
refName: string;
refType: string;
createdFromLocal: string;
default: boolean;
}
export interface GitBranch {
branchName: string;
default: boolean;
}