Skip to content

Commit

Permalink
deploy app from git (#510)
Browse files Browse the repository at this point in the history
* deploy app from git, create option to deploy apps from git repositories

* added condtional on git options for headless state, added tests

* added new index.js

* fixed failing test

* adjusted updated code per comments

* updates saved to app-form

* app-card saved

* made updates to code from pr review

* Rearranged the radio options to be below the titles

* made updates per/requests; changed helper text, enabled disabled fields, added key:values to repository object

* updated index.js

* updated form to take in editable config directory and ref

* updated index

* updated index.js

* updated index.js

* added repository to server endpoint when git repo

* fixed keep-alive and public on git repo app

* updated error handling for git clone to use backend messaging

* update Error message to be more generic

---------

Co-authored-by: Kilian <[email protected]>
  • Loading branch information
kildre and Kilian authored Nov 18, 2024
1 parent 6489b46 commit 9ec3ec4
Show file tree
Hide file tree
Showing 12 changed files with 1,264 additions and 557 deletions.
62 changes: 31 additions & 31 deletions jhub_apps/static/js/index.js

Large diffs are not rendered by default.

10 changes: 6 additions & 4 deletions ui/src/components/app-card/app-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { UserState } from '@src/types/user';
import axios from 'axios';
import React, { useEffect, useState } from 'react';
import { useRecoilState } from 'recoil';

import {
currentApp,
currentNotification,
Expand Down Expand Up @@ -122,7 +123,7 @@ export const AppCard = ({
{
id: 'start',
title: 'Start',
onClick: () => {
onClick: async () => {
// Allow admins to start shared apps
if (isShared && !currentUserData?.admin) {
// Show error if it's a shared app
Expand All @@ -140,7 +141,7 @@ export const AppCard = ({
{
id: 'stop',
title: 'Stop',
onClick: () => {
onClick: async () => {
// Allow admins to stop shared apps
if (isShared && !currentUserData?.admin) {
setNotification(
Expand All @@ -157,8 +158,9 @@ export const AppCard = ({
{
id: 'edit',
title: 'Edit',
onClick: () =>
(window.location.href = `${API_BASE_URL}/edit-app?id=${id}`),
onClick: () => {
window.location.href = `${API_BASE_URL}/edit-app?id=${id}`;
},
visible: true,
disabled: isShared || id === '' || !isAppCard,
},
Expand Down
125 changes: 102 additions & 23 deletions ui/src/components/app-form/app-form.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ import { app, environments, frameworks, profiles } from '@src/data/api';
import { currentUser } from '@src/data/user';
import axios from '@src/utils/axios';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { act, fireEvent, render } from '@testing-library/react';
import { act, fireEvent, render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import MockAdapter from 'axios-mock-adapter';
import { BrowserRouter } from 'react-router-dom';
import { RecoilRoot } from 'recoil';
import { vi } from 'vitest';
import { currentUser as defaultUser } from '../../store';
import { AppForm } from './app-form';

Expand Down Expand Up @@ -42,7 +43,7 @@ describe('AppForm', () => {
<RecoilRoot>
<QueryClientProvider client={queryClient}>
<BrowserRouter>
<AppForm />
<AppForm isEditMode={false} />
</BrowserRouter>
</QueryClientProvider>
</RecoilRoot>,
Expand All @@ -60,7 +61,7 @@ describe('AppForm', () => {
<RecoilRoot>
<QueryClientProvider client={queryClient}>
<BrowserRouter>
<AppForm />
<AppForm isEditMode={false} />
</BrowserRouter>
</QueryClientProvider>
</RecoilRoot>,
Expand All @@ -82,7 +83,7 @@ describe('AppForm', () => {
<RecoilRoot>
<QueryClientProvider client={queryClient}>
<BrowserRouter>
<AppForm />
<AppForm isEditMode={false} />
</BrowserRouter>
</QueryClientProvider>
</RecoilRoot>,
Expand All @@ -102,7 +103,7 @@ describe('AppForm', () => {
<RecoilRoot>
<QueryClientProvider client={queryClient}>
<BrowserRouter>
<AppForm />
<AppForm isEditMode={false} />
</BrowserRouter>
</QueryClientProvider>
</RecoilRoot>,
Expand All @@ -128,7 +129,7 @@ describe('AppForm', () => {
<RecoilRoot>
<QueryClientProvider client={queryClient}>
<BrowserRouter>
<AppForm />
<AppForm isEditMode={false} />
</BrowserRouter>
</QueryClientProvider>
</RecoilRoot>,
Expand All @@ -152,7 +153,7 @@ describe('AppForm', () => {
<RecoilRoot>
<QueryClientProvider client={queryClient}>
<BrowserRouter>
<AppForm />
<AppForm isEditMode={false} />
</BrowserRouter>
</QueryClientProvider>
</RecoilRoot>,
Expand All @@ -174,7 +175,7 @@ describe('AppForm', () => {
<RecoilRoot initializeState={({ set }) => set(defaultUser, currentUser)}>
<QueryClientProvider client={queryClient}>
<BrowserRouter>
<AppForm />
<AppForm isEditMode={false} />
</BrowserRouter>
</QueryClientProvider>
</RecoilRoot>,
Expand Down Expand Up @@ -220,7 +221,7 @@ describe('AppForm', () => {
<RecoilRoot>
<QueryClientProvider client={queryClient}>
<BrowserRouter>
<AppForm />
<AppForm isEditMode={false} />
</BrowserRouter>
</QueryClientProvider>
</RecoilRoot>,
Expand Down Expand Up @@ -272,7 +273,7 @@ describe('AppForm', () => {
<RecoilRoot>
<QueryClientProvider client={queryClient}>
<BrowserRouter>
<AppForm />
<AppForm isEditMode={false} />
</BrowserRouter>
</QueryClientProvider>
</RecoilRoot>,
Expand Down Expand Up @@ -310,7 +311,7 @@ describe('AppForm', () => {
<RecoilRoot>
<QueryClientProvider client={queryClient}>
<BrowserRouter>
<AppForm />
<AppForm isEditMode={false} />
</BrowserRouter>
</QueryClientProvider>
</RecoilRoot>,
Expand Down Expand Up @@ -364,7 +365,7 @@ describe('AppForm', () => {
<RecoilRoot>
<QueryClientProvider client={queryClient}>
<BrowserRouter>
<AppForm />
<AppForm isEditMode={false} />
</BrowserRouter>
</QueryClientProvider>
</RecoilRoot>,
Expand Down Expand Up @@ -434,7 +435,7 @@ describe('AppForm', () => {
<RecoilRoot>
<QueryClientProvider client={queryClient}>
<BrowserRouter>
<AppForm />
<AppForm isEditMode={false} />
</BrowserRouter>
</QueryClientProvider>
</RecoilRoot>,
Expand Down Expand Up @@ -478,7 +479,7 @@ describe('AppForm', () => {
<RecoilRoot>
<QueryClientProvider client={queryClient}>
<BrowserRouter>
<AppForm id="app-1" />
<AppForm isEditMode={true} id="app-1" />
</BrowserRouter>
</QueryClientProvider>
</RecoilRoot>,
Expand Down Expand Up @@ -520,7 +521,7 @@ describe('AppForm', () => {
<RecoilRoot>
<QueryClientProvider client={queryClient}>
<BrowserRouter>
<AppForm id="app-1" />
<AppForm isEditMode={true} id="app-1" />
</BrowserRouter>
</QueryClientProvider>
</RecoilRoot>,
Expand Down Expand Up @@ -559,7 +560,7 @@ describe('AppForm', () => {
<RecoilRoot>
<QueryClientProvider client={queryClient}>
<BrowserRouter>
<AppForm />
<AppForm isEditMode={false} />
</BrowserRouter>
</QueryClientProvider>
</RecoilRoot>,
Expand All @@ -584,7 +585,7 @@ describe('AppForm', () => {
<RecoilRoot>
<QueryClientProvider client={queryClient}>
<BrowserRouter>
<AppForm />
<AppForm isEditMode={false} />
</BrowserRouter>
</QueryClientProvider>
</RecoilRoot>,
Expand Down Expand Up @@ -624,7 +625,7 @@ describe('AppForm', () => {
<RecoilRoot>
<QueryClientProvider client={queryClient}>
<BrowserRouter>
<AppForm id="app-1" />
<AppForm isEditMode={true} id="app-1" />
</BrowserRouter>
</QueryClientProvider>
</RecoilRoot>,
Expand Down Expand Up @@ -659,7 +660,7 @@ describe('AppForm', () => {
<RecoilRoot>
<QueryClientProvider client={queryClient}>
<BrowserRouter>
<AppForm />
<AppForm isEditMode={false} />
</BrowserRouter>
</QueryClientProvider>
</RecoilRoot>,
Expand Down Expand Up @@ -691,7 +692,7 @@ describe('AppForm', () => {
<RecoilRoot>
<QueryClientProvider client={queryClient}>
<BrowserRouter>
<AppForm />
<AppForm isEditMode={false} />
</BrowserRouter>
</QueryClientProvider>
</RecoilRoot>,
Expand Down Expand Up @@ -725,7 +726,7 @@ describe('AppForm', () => {
<RecoilRoot>
<QueryClientProvider client={queryClient}>
<BrowserRouter>
<AppForm />
<AppForm isEditMode={false} />
</BrowserRouter>
</QueryClientProvider>
</RecoilRoot>,
Expand All @@ -747,7 +748,7 @@ describe('AppForm', () => {
<RecoilRoot>
<QueryClientProvider client={queryClient}>
<BrowserRouter>
<AppForm />
<AppForm isEditMode={false} />
</BrowserRouter>
</QueryClientProvider>
</RecoilRoot>,
Expand Down Expand Up @@ -793,7 +794,7 @@ describe('AppForm', () => {
<RecoilRoot>
<QueryClientProvider client={queryClient}>
<BrowserRouter>
<AppForm id="app-1" />
<AppForm isEditMode={true} id="app-1" />
</BrowserRouter>
</QueryClientProvider>
</RecoilRoot>,
Expand Down Expand Up @@ -821,4 +822,82 @@ describe('AppForm', () => {
expect(window.location.pathname).not.toBe('/edit-app');
}
});

test('sets the branch to customRef or defaults to "main"', async () => {
render(
<RecoilRoot>
<QueryClientProvider client={queryClient}>
<BrowserRouter>
<AppForm isEditMode={false} deployOption="git" />
</BrowserRouter>
</QueryClientProvider>
</RecoilRoot>,
);

const branchField = screen.getByLabelText(/Branch/i);

// Simulate input to test default to 'main'
fireEvent.change(branchField, { target: { value: 'main' } });
expect(branchField).toHaveValue('main');

// Test updating customRef
fireEvent.change(branchField, { target: { value: 'new-branch' } });
expect(branchField).toHaveValue('new-branch');
});

test('sets customRef to an empty string when deployOption is "git" and customRef is empty', async () => {
render(
<RecoilRoot>
<QueryClientProvider client={queryClient}>
<BrowserRouter>
<AppForm isEditMode={false} deployOption="git" />
</BrowserRouter>
</QueryClientProvider>
</RecoilRoot>,
);

const branchField = screen.getByLabelText(/Branch/i);

// Simulate empty customRef for git deployOption
fireEvent.change(branchField, { target: { value: '' } });
expect(branchField).toHaveValue('');
});
test('displays "Invalid GitHub URL format" error when URL is in the wrong format', async () => {
render(
<RecoilRoot>
<QueryClientProvider client={queryClient}>
<BrowserRouter>
<AppForm isEditMode={false} deployOption="git" />
</BrowserRouter>
</QueryClientProvider>
</RecoilRoot>,
);

// Adjust the label text to match the exact rendering, if needed
const gitUrlInput = screen.getByLabelText(/Git Repository URL/i);
fireEvent.change(gitUrlInput, { target: { value: 'invalid-url' } });

const fetchButton = screen.getByText(/Fetch App Configuration/i);
await act(async () => {
fireEvent.click(fetchButton);
});

// Verify if the modal contains the error message
expect(screen.getByRole('dialog')).toHaveTextContent(
'Invalid GitHub URL format.',
);
});

test('renders git-url-input', () => {
render(
<RecoilRoot>
<QueryClientProvider client={queryClient}>
<BrowserRouter>
<AppForm deployOption="git" isEditMode={false} />
</BrowserRouter>
</QueryClientProvider>
</RecoilRoot>,
);
expect(screen.getByTestId('git-url-input')).toBeInTheDocument();
});
});
Loading

0 comments on commit 9ec3ec4

Please sign in to comment.