Skip to content

Commit

Permalink
refactor(template): use env var for cicd template check
Browse files Browse the repository at this point in the history
refs #477
  • Loading branch information
ygrishajev committed Dec 3, 2024
1 parent 9a8d68d commit 3650daa
Show file tree
Hide file tree
Showing 15 changed files with 96 additions and 74 deletions.
4 changes: 3 additions & 1 deletion apps/deploy-web/env/.env
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@ NEXT_PUBLIC_REDIRECT_URI='https://console.akash.network/new-deployment'
NEXT_PUBLIC_GITHUB_APP_INSTALLATION_URL='https://github.com/apps/akash-console-build-and-deploy-app/installations/new'
NEXT_PUBLIC_BITBUCKET_CLIENT_ID=tdH2xfRkTcdqVP6cwW
NEXT_PUBLIC_GITHUB_CLIENT_ID=Iv23lidSwihrsSL7aGew
NEXT_PUBLIC_GITLAB_CLIENT_ID=beb5370aad2fdb6147edb44248d20d30c3e189ddfb40c26f651c77bbe949d5a8
NEXT_PUBLIC_GITLAB_CLIENT_ID=beb5370aad2fdb6147edb44248d20d30c3e189ddfb40c26f651c77bbe949d5a8

NEXT_PUBLIC_CI_CD_IMAGE_NAME=hoomanhq/automation
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
"use client";

import { createRef, FC, useEffect, useState } from "react";
import type { TemplateOutput } from "@akashnetwork/http-sdk/src/template/template-http.service";
import { Alert, Button, buttonVariants, Spinner, Tabs, TabsList, TabsTrigger } from "@akashnetwork/ui/components";
import { cn } from "@akashnetwork/ui/utils";
import { ArrowLeft } from "iconoir-react";
Expand All @@ -16,7 +15,7 @@ import { useWallet } from "@src/context/WalletProvider";
import { useDeploymentDetail } from "@src/queries/useDeploymentQuery";
import { useDeploymentLeaseList } from "@src/queries/useLeaseQuery";
import { useProviderList } from "@src/queries/useProvidersQuery";
import { extractRepositoryUrl, isImageInYaml } from "@src/services/remote-deploy/remote-deployment-controller.service";
import { extractRepositoryUrl, isCiCdImageInYaml } from "@src/services/remote-deploy/remote-deployment-controller.service";
import { AnalyticsCategory, AnalyticsEvents } from "@src/types/analytics";
import { RouteStep } from "@src/types/route-steps.type";
import { getDeploymentLocalData } from "@src/utils/deploymentLocalDataUtils";
Expand All @@ -32,18 +31,17 @@ import { ManifestUpdate } from "./ManifestUpdate";

export interface DeploymentDetailProps {
dseq: string;
remoteDeployTemplate: TemplateOutput;
}

export const DeploymentDetail: FC<DeploymentDetailProps> = ({ dseq, remoteDeployTemplate }) => {
export const DeploymentDetail: FC<DeploymentDetailProps> = ({ dseq }) => {
const router = useRouter();
const [activeTab, setActiveTab] = useState("LEASES");
const [editedManifest, setEditedManifest] = useState<string | null>(null);
const { address, isWalletLoaded } = useWallet();
const { isSettingsInit } = useSettings();
const [leaseRefs, setLeaseRefs] = useState<Array<any>>([]);
const [deploymentManifest, setDeploymentManifest] = useState<string | null>(null);
const isRemoteDeploy: boolean = !!editedManifest && !!isImageInYaml(editedManifest, remoteDeployTemplate?.deploy);
const isRemoteDeploy: boolean = !!editedManifest && !!isCiCdImageInYaml(editedManifest);
const repo: string | null = isRemoteDeploy ? extractRepositoryUrl(editedManifest) : null;

const {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"use client";
import { FC, useEffect, useState } from "react";
import { FC, useCallback, useEffect, useState } from "react";
import { TemplateOutput } from "@akashnetwork/http-sdk/src/template/template-http.service";
import { useAtomValue } from "jotai";
import { useRouter, useSearchParams } from "next/navigation";

Expand All @@ -8,7 +9,7 @@ import { CI_CD_TEMPLATE_ID } from "@src/config/remote-deploy.config";
import { useLocalNotes } from "@src/context/LocalNoteProvider";
import { useSdlBuilder } from "@src/context/SdlBuilderProvider";
import { useTemplates } from "@src/context/TemplatesProvider";
import { isImageInYaml } from "@src/services/remote-deploy/remote-deployment-controller.service";
import { isCiCdImageInYaml } from "@src/services/remote-deploy/remote-deployment-controller.service";
import sdlStore from "@src/store/sdlStore";
import { TemplateCreation } from "@src/types";
import { RouteStep } from "@src/types/route-steps.type";
Expand All @@ -20,15 +21,19 @@ import { ManifestEdit } from "./ManifestEdit";
import { CustomizedSteppers } from "./Stepper";
import { TemplateList } from "./TemplateList";

export const NewDeploymentContainer: FC = () => {
export interface NewDeploymentContainerProps {
template?: TemplateOutput;
templateId?: string;
}

export const NewDeploymentContainer: FC<NewDeploymentContainerProps> = ({ template: requestedTemplate, templateId }) => {
const [isGitProviderTemplate, setIsGitProviderTemplate] = useState<boolean>(false);
const { isLoading: isLoadingTemplates, templates } = useTemplates();
const [activeStep, setActiveStep] = useState<number | null>(null);
const [selectedTemplate, setSelectedTemplate] = useState<TemplateCreation | null>(null);
const [editedManifest, setEditedManifest] = useState<string | null>(null);
const deploySdl = useAtomValue(sdlStore.deploySdl);
const { getDeploymentData } = useLocalNotes();
const { getTemplateById } = useTemplates();
const router = useRouter();
const searchParams = useSearchParams();
const dseq = searchParams?.get("dseq");
Expand Down Expand Up @@ -78,8 +83,7 @@ export const NewDeploymentContainer: FC = () => {
toggleCmp("ssh");
}

const cicdTemplate = getTemplateById(CI_CD_TEMPLATE_ID);
const isRemoteYamlImage = isImageInYaml(template?.content as string, cicdTemplate?.deploy);
const isRemoteYamlImage = isCiCdImageInYaml(template?.content as string);
const queryStep = searchParams?.get("step");
if (queryStep !== RouteStep.editDeployment) {
if (isRemoteYamlImage) {
Expand Down Expand Up @@ -113,34 +117,25 @@ export const NewDeploymentContainer: FC = () => {
return template;
};

const getGalleryTemplate = (): Partial<{
code: string;
name: string;
content: string;
valuesToChange: any[];
config: { ssh?: boolean };
}> | null => {
const queryTemplateId = searchParams?.get("templateId");
if (queryTemplateId) {
const templateById = getTemplateById(queryTemplateId as string);
if (templateById) {
return {
const getGalleryTemplate = useCallback(():
| Partial<{
code: string;
name: string;
content: string;
valuesToChange: any[];
config: { ssh?: boolean };
}>
| undefined => {
return requestedTemplate
? {
code: "empty",
name: templateById.name,
content: templateById.deploy,
valuesToChange: templateById.valuesToChange || [],
config: templateById.config
};
}

const hardCodedTemplate = hardcodedTemplates.find(t => t.code === queryTemplateId);
if (hardCodedTemplate) {
return hardCodedTemplate;
}
}

return null;
};
name: requestedTemplate.name,
content: requestedTemplate.deploy,
valuesToChange: [],
config: requestedTemplate.config
}
: hardcodedTemplates.find(t => t.code === templateId);
}, [requestedTemplate, templateId]);

function getStepIndexByParam(step: (typeof RouteStep)[keyof typeof RouteStep] | null) {
switch (step) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import { useSnackbar } from "notistack";

import { EnvFormModal } from "@src/components/sdl/EnvFormModal";
import { EnvVarList } from "@src/components/sdl/EnvVarList";
import { CI_CD_TEMPLATE_ID, CURRENT_SERVICE, protectedEnvironmentVariables } from "@src/config/remote-deploy.config";
import { browserEnvConfig } from "@src/config/browser-env.config";
import { CURRENT_SERVICE, protectedEnvironmentVariables } from "@src/config/remote-deploy.config";
import { SdlBuilderProvider } from "@src/context/SdlBuilderProvider";
import { useTemplates } from "@src/context/TemplatesProvider";
import { EnvVarUpdater } from "@src/services/remote-deploy/remote-deployment-controller.service";
import { tokens } from "@src/store/remoteDeployStore";
import { SdlBuilderFormValuesType, ServiceType } from "@src/types";
Expand All @@ -26,8 +26,6 @@ const RemoteDeployUpdate = ({ sdlString, onManifestChange }: { sdlString: string
const [isEditingEnv, setIsEditingEnv] = useState<number | boolean | null>(false);
const { control, watch, setValue } = useForm<SdlBuilderFormValuesType>({ defaultValues: { services: [defaultService] } });
const { fields: services } = useFieldArray({ control, name: "services", keyName: "id" });
const { getTemplateById } = useTemplates();
const remoteDeployTemplate = getTemplateById(CI_CD_TEMPLATE_ID);
const envVarUpdater = useMemo(() => new EnvVarUpdater(services), [services]);

useEffect(() => {
Expand All @@ -51,10 +49,7 @@ const RemoteDeployUpdate = ({ sdlString, onManifestChange }: { sdlString: string

const createAndValidateSdl = (yamlStr: string) => {
try {
if (!yamlStr) return [];
const services = importSimpleSdl(yamlStr);

return services;
return yamlStr ? importSimpleSdl(yamlStr) : [];
} catch (err) {
if (err.name === "YAMLException" || err.name === "CustomValidationError") {
enqueueSnackbar(<Snackbar title={err.message} />, { variant: "error" });
Expand All @@ -65,7 +60,7 @@ const RemoteDeployUpdate = ({ sdlString, onManifestChange }: { sdlString: string
}
}
};
return remoteDeployTemplate?.deploy?.includes(services?.[0]?.image) && services?.[0]?.env && services?.[0]?.env?.length > 0 ? (
return services?.[0]?.image.startsWith(browserEnvConfig.NEXT_PUBLIC_CI_CD_IMAGE_NAME) && services?.[0]?.env && services?.[0]?.env?.length > 0 ? (
<div className="flex flex-col gap-6 rounded border bg-card px-4 py-6 md:px-6">
<div className="flex flex-col gap-3 rounded border bg-card px-6 py-6 text-card-foreground">
<div className="flex items-center justify-between gap-5">
Expand Down
3 changes: 2 additions & 1 deletion apps/deploy-web/src/config/browser-env.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,6 @@ export const browserEnvConfig = validateStaticEnvVars({
NEXT_PUBLIC_BITBUCKET_CLIENT_ID: process.env.NEXT_PUBLIC_BITBUCKET_CLIENT_ID,
NEXT_PUBLIC_GITLAB_CLIENT_ID: process.env.NEXT_PUBLIC_GITLAB_CLIENT_ID,
NEXT_PUBLIC_GITHUB_CLIENT_ID: process.env.NEXT_PUBLIC_GITHUB_CLIENT_ID,
NEXT_PUBLIC_GA_MEASUREMENT_ID: process.env.NEXT_PUBLIC_GA_MEASUREMENT_ID
NEXT_PUBLIC_GA_MEASUREMENT_ID: process.env.NEXT_PUBLIC_GA_MEASUREMENT_ID,
NEXT_PUBLIC_CI_CD_IMAGE_NAME: process.env.NEXT_PUBLIC_CI_CD_IMAGE_NAME
});
6 changes: 4 additions & 2 deletions apps/deploy-web/src/config/env-config.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ export const browserEnvSchema = z.object({
NEXT_PUBLIC_GITHUB_APP_INSTALLATION_URL: z.string().url(),
NEXT_PUBLIC_BITBUCKET_CLIENT_ID: z.string().optional(),
NEXT_PUBLIC_GITLAB_CLIENT_ID: z.string().optional(),
NEXT_PUBLIC_GITHUB_CLIENT_ID: z.string().optional()
NEXT_PUBLIC_GITHUB_CLIENT_ID: z.string().optional(),
NEXT_PUBLIC_CI_CD_IMAGE_NAME: z.string()
});

export const serverEnvSchema = browserEnvSchema.extend({
Expand All @@ -42,7 +43,8 @@ export const serverEnvSchema = browserEnvSchema.extend({
BASE_API_SANDBOX_URL: z.string().url(),
GITHUB_CLIENT_SECRET: z.string(),
BITBUCKET_CLIENT_SECRET: z.string(),
GITLAB_CLIENT_SECRET: z.string()
GITLAB_CLIENT_SECRET: z.string(),
NEXT_PUBLIC_CI_CD_IMAGE_NAME: z.string()
});

export type BrowserEnvConfig = z.infer<typeof browserEnvSchema>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export const useSdlBuilder = () => {
};

export const withSdlBuilder = (options: SdlBuilderProviderProps = {}) =>
function wrapWithSdlBuilder<P extends JSX.IntrinsicAttributes>(Component: React.ComponentType<P>): FC<P> | React.ComponentType<P> {
function wrapWithSdlBuilder<P extends Record<string, any>>(Component: React.ComponentType<P>): FC<P> | React.ComponentType<P> {
return function WrappedComponent(props: P) {
return (
<SdlBuilderProvider {...options}>
Expand Down
24 changes: 11 additions & 13 deletions apps/deploy-web/src/lib/nextjs/getValidatedServerSIdeProps.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
import { GetServerSidePropsContext, GetServerSidePropsResult, PreviewData } from "next/types";
import { GetServerSidePropsContext, GetServerSidePropsResult } from "next/types";
import type { ParsedUrlQuery } from "querystring";
import { z } from "zod";

export const getValidatedServerSideProps = <
Props extends { [key: string]: any } = { [key: string]: any },
Params extends ParsedUrlQuery = ParsedUrlQuery,
Preview extends PreviewData = PreviewData,
Schema extends z.ZodObject<any, any, any> = z.ZodObject<{ params: z.ZodObject<any, any, any> }, any, any>
>(
type ContextParamsSchema = z.ZodObject<Record<string, z.ZodString | z.ZodNumber | z.ZodOptional<z.ZodString> | z.ZodOptional<z.ZodNumber>>>;

type ContextSchema = z.ZodObject<{ params?: ContextParamsSchema; query?: ContextParamsSchema }>;

export const getValidatedServerSideProps = <Props extends { [key: string]: any }, Schema extends ContextSchema = ContextSchema>(
schema: Schema,
handler: (
context: Omit<GetServerSidePropsContext<Params, Preview>, "params"> & { params: z.infer<Schema>["params"] }
) => Promise<GetServerSidePropsResult<Props>>
): ((context: GetServerSidePropsContext<Params, Preview>) => Promise<GetServerSidePropsResult<Props>>) => {
handler: (context: Omit<GetServerSidePropsContext, "params" | "query"> & z.infer<Schema>) => Promise<GetServerSidePropsResult<Props>>
): ((context: GetServerSidePropsContext<ParsedUrlQuery>) => Promise<GetServerSidePropsResult<Props>>) => {
return context => {
const { params } = schema.parse(context);
return handler({ ...context, params });
const validated = schema.parse(context);

return handler({ ...context, ...validated });
};
};
3 changes: 3 additions & 0 deletions apps/deploy-web/src/pages/deploy-linux/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { NewDeploymentContainer } from "@src/components/new-deployment/NewDeploymentContainer";
import { withSdlBuilder } from "@src/context/SdlBuilderProvider/SdlBuilderProvider";
import { getServerSideProps } from "../new-deployment";

export default withSdlBuilder({
componentsSet: "ssh",
imageSource: "ssh-vms"
})(NewDeploymentContainer);

export { getServerSideProps };
5 changes: 0 additions & 5 deletions apps/deploy-web/src/pages/deployments/[dseq]/index.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { z } from "zod";

import { DeploymentDetail } from "@src/components/deployments/DeploymentDetail";
import { CI_CD_TEMPLATE_ID } from "@src/config/remote-deploy.config";
import { getValidatedServerSideProps } from "@src/lib/nextjs/getValidatedServerSIdeProps";
import { services } from "@src/services/http/http-server.service";

export default DeploymentDetail;

Expand All @@ -14,11 +12,8 @@ const contextSchema = z.object({
});

export const getServerSideProps = getValidatedServerSideProps(contextSchema, async ({ params }) => {
const remoteDeployTemplate = await services.template.findById(CI_CD_TEMPLATE_ID);

return {
props: {
remoteDeployTemplate,
dseq: params.dseq
}
};
Expand Down
26 changes: 25 additions & 1 deletion apps/deploy-web/src/pages/new-deployment/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,28 @@
import { NewDeploymentContainer } from "@src/components/new-deployment/NewDeploymentContainer";
import { z } from "zod";

import { NewDeploymentContainer, NewDeploymentContainerProps } from "@src/components/new-deployment/NewDeploymentContainer";
import { withSdlBuilder } from "@src/context/SdlBuilderProvider/SdlBuilderProvider";
import { getValidatedServerSideProps } from "@src/lib/nextjs/getValidatedServerSIdeProps";
import { services } from "@src/services/http/http-server.service";

export default withSdlBuilder()(NewDeploymentContainer);

const contextSchema = z.object({
query: z.object({
templateId: z.string().optional()
})
});

export const getServerSideProps = getValidatedServerSideProps<NewDeploymentContainerProps, typeof contextSchema>(contextSchema, async ({ query }) => {
if (!query.templateId) {
return { props: {} };
}

const template = await services.template.findById(query.templateId);

if (template && query.templateId) {
return { props: { template, templateId: query.templateId } };
}

return { props: {} };
});
1 change: 1 addition & 0 deletions apps/deploy-web/src/queries/queryKeys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export class QueryKeys {
static getBlockKey = (id: string) => ["BLOCK", id];
static getBalancesKey = (address?: string) => (address ? ["BALANCES", address] : []);
static getTemplatesKey = () => ["TEMPLATES"];
static getTemplateKey = (id: string) => ["TEMPLATES", id];
static getProviderAttributesSchema = () => ["PROVIDER_ATTRIBUTES_SCHEMA"];
static getDepositParamsKey = () => ["DEPOSIT_PARAMS"];
static getGpuModelsKey = () => ["GPU_MODELS"];
Expand Down
7 changes: 7 additions & 0 deletions apps/deploy-web/src/queries/useTemplateQuery.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import { QueryKey, useMutation, useQuery, useQueryClient, UseQueryOptions } from "react-query";
import { UseQueryResult } from "react-query/types/react/types";
import { TemplateOutput } from "@akashnetwork/http-sdk/src/template/template-http.service";
import { Snackbar } from "@akashnetwork/ui/components";
import axios from "axios";
import { useRouter } from "next/navigation";
import { useSnackbar } from "notistack";

import { useCustomUser } from "@src/hooks/useCustomUser";
import { services } from "@src/services/http/http-browser.service";
import { ITemplate } from "@src/types";
import { ApiUrlService } from "@src/utils/apiUtils";
import { UrlService } from "@src/utils/urlUtils";
Expand Down Expand Up @@ -130,3 +133,7 @@ export function useTemplates(options = {}) {
refetchOnReconnect: false
});
}

export function useTemplateById(id: string, options: UseQueryOptions<TemplateOutput, Error, any, QueryKey> = {}): UseQueryResult<TemplateOutput> {
return useQuery(QueryKeys.getTemplateKey(id), () => services.template.findById(id), options);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { nanoid } from "nanoid";

import { browserEnvConfig } from "@src/config/browser-env.config";
import { SdlBuilderFormValuesType, ServiceType } from "@src/types";

export class EnvVarUpdater {
Expand Down Expand Up @@ -35,8 +36,8 @@ export function formatUrlWithoutInitialPath(url?: string): string | undefined {
return url?.split("/").slice(-2).join("/");
}

export function isImageInYaml(yml: string, cicdYml?: string): boolean | undefined {
return cicdYml?.includes(yml?.split("service-1:")?.[1]?.split("expose:")?.[0]?.split("image: ")?.[1]);
export function isCiCdImageInYaml(yml: string): boolean | undefined {
return yml.includes(browserEnvConfig.NEXT_PUBLIC_CI_CD_IMAGE_NAME);
}

export function extractRepositoryUrl(yml?: string | null): string | null {
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 3650daa

Please sign in to comment.