Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions workspaces/bulk-import/.changeset/lucky-poets-notice.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@red-hat-developer-hub/backstage-plugin-bulk-import-backend': minor
'@red-hat-developer-hub/backstage-plugin-bulk-import-common': minor
'@red-hat-developer-hub/backstage-plugin-bulk-import': minor
---

Implement the execution of import orchestrator workflows with the help of the bulk-import plugin.
1 change: 1 addition & 0 deletions workspaces/bulk-import/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,4 @@ site

# E2E test reports
e2e-test-report/
packages/backend/.devModeTemp
36 changes: 35 additions & 1 deletion workspaces/bulk-import/app-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@ backend:
# information on the format
auth:
dangerouslyDisableDefaultAuthPolicy: true
allowGuestAccess: true
externalAccess:
- type: static
options:
# notsecret
# echo mycurlpasswd | base64
token: bXljdXJscGFzc3dkCg==
subject: my-external-feed
# keys:
# - secret: ${BACKEND_SECRET}
baseUrl: http://localhost:7007
Expand Down Expand Up @@ -121,8 +129,34 @@ catalog:
# see https://backstage.io/docs/permissions/getting-started for more on the permission framework
permission:
# setting this to `false` will disable permissions
enabled: true
enabled: false
# scaffolder template execution configuration. Disabled by default.
# bulkImport:
# importTemplate: template:default/create-pr-with-catalog-info
# importAPI: scaffolder

orchestrator:
sonataFlowService:
# uncomment the next line to use podman instead of docker
# runtime: podman
baseUrl: http://localhost
port: 8899
autoStart: false
# If you're using a MacBook with M-series chips, uncomment the line below to use ARM images.
# To pull the image, you'll first need to authenticate with the registry.
# For more information, visit: https://red.ht/410mMNU.
container: registry.redhat.io/openshift-serverless-1/logic-swf-devmode-rhel8:1.36.0
# notsecret
notificationsBearerToken: bXljdXJscGFzc3dkCg==
notificationsUrl: http://host.docker.internal:7007
# uncomment the next line if you are using podman:
# notificationsUrl: http://host.containers.internal:7007
# By default the Dev Mode workflows are Ephemeral. If you want to persist the data across restarts,
# uncomment the next two lines, read more: https://www.rhdhorchestrator.io/blog/devmode-vs-prodmode/
# persistence:
# path: ./.devModeTemp/db_persistence # this will be under packages/backend
workflowsSource:
gitRepositoryUrl: https://github.com/AndrienkoAleksandr/backstage-orchestrator-workflows.git
localPath: ./.devModeTemp/repository # this will be under packages/backend
dataIndexService:
url: http://localhost:8899
7 changes: 4 additions & 3 deletions workspaces/bulk-import/examples/org.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ apiVersion: backstage.io/v1alpha1
kind: User
metadata:
name: guest
namespace: development
spec:
memberOf: [guests]
---
Expand All @@ -20,11 +21,11 @@ apiVersion: backstage.io/v1alpha1
kind: User
metadata:
# replace this with <your_github_id>
name: lholmquist
name: AndrienkoAleksandr
spec:
profile:
# replace this with <your_github_email>
email: lholmqui@redhat.com
email: oandriie@redhat.com
memberOf: [rhdh-ui-test]
---
apiVersion: backstage.io/v1alpha1
Expand All @@ -38,4 +39,4 @@ spec:
displayName: RHDH UI test
children: []
# replace member with <your_github_id> on L23
members: [lholmquist]
members: [AndrienkoAleksandr]
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,4 @@ spec:
action: catalog:register
input:
optional: true
repoContentsUrl: https://${{ parameters.gitProviderHost }}/${{ parameters.organization }}/${{ parameters.name }}/blob/${{ parameters.branchName }}/catalog-info.yaml
repoContentsUrl: https://${{ parameters.gitProviderHost }}/${{ parameters.organization }}/${{ parameters.name }}/blob/${{ parameters.targetBranchName }}/catalog-info.yaml
6 changes: 5 additions & 1 deletion workspaces/bulk-import/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,11 @@
"resolutions": {
"@types/react": "^18",
"@types/react-dom": "^18",
"refractor@npm:3.6.0/prismjs": "^1.30.0"
"refractor@npm:3.6.0/prismjs": "^1.30.0",
"@backstage/backend-defaults": "0.13.1",
"@backstage/backend-plugin-api": "1.5.0",
"@backstage/backend-test-utils": "1.9.1",
"@backstage/plugin-catalog-backend-module-gitlab": "0.7.5"
},
"prettier": "@spotify/prettier-config",
"lint-staged": {
Expand Down
41 changes: 38 additions & 3 deletions workspaces/bulk-import/packages/app/e2e-tests/app.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,23 +50,56 @@ test.describe('Bulk Import', () => {
test.beforeAll(async ({ browser }) => {
context = await browser.newContext();
sharedPage = await context.newPage();

await mockBulkImportRepositoriesResponse(sharedPage, mockRepositoriesData);
await sharedPage.goto('/');

const enterButton = sharedPage.getByRole('button', { name: 'Enter' });
await expect(enterButton).toBeVisible();
await enterButton.click();

// Wait for authentication to complete - wait for sidebar or main content to appear
await sharedPage.waitForLoadState('networkidle');
// Additional wait to ensure auth state is fully initialized
await sharedPage.waitForTimeout(500);

const currentLocale = await sharedPage.evaluate(
() => globalThis.navigator.language,
);

// Wait for catalog to load BEFORE switching locale
// This ensures catalog is loaded in English, then we switch locale
const maxRetries = 3;
const waitTimeout = 5000;

for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
// Wait for the sidebar to be visible before navigating
await expect(sharedPage.getByText('My Company Catalog')).toBeVisible();
// Wait for catalog to load - use English text since we haven't switched locale yet
await expect(sharedPage.getByText('All Components (1)')).toBeVisible({
timeout: waitTimeout,
});

break; // nice catalog loaded
} catch (error) {
if (attempt === maxRetries) {
const html = await sharedPage.content();
throw new Error(
`Catalog not loaded after ${maxRetries} retries. Error: ${error}. HTML snapshot: ${html}`,
);
}

await sharedPage.reload();
await sharedPage.waitForLoadState('networkidle');
}
}

// Now switch locale AFTER catalog is loaded
await switchToLocale(sharedPage, currentLocale);
translations = getTranslations(currentLocale);
previewSidebarSnapshots = getPreviewSidebarSnapshots(translations);

await expect(sharedPage.getByText('My Company Catalog')).toBeVisible();

await expect(
sharedPage.getByRole('link', { name: translations.sidebar.bulkImport }),
).toBeVisible();
Expand Down Expand Up @@ -152,6 +185,9 @@ test.describe('Bulk Import', () => {
sharedPage.getByText(translations.status.readyToImport).first(),
).toBeVisible();
await sharedPage.getByTestId('preview-file').first().click();

// Wait for sidebar to be fully visible and loaded
await expect(sidebar).toBeVisible();
await expect(sidebar.locator('h5')).toContainText('backend-service');
await expect(sidebar).toMatchAriaSnapshot(`
- button "${translations.common.save}"
Expand Down Expand Up @@ -220,7 +256,6 @@ test.describe('Bulk Import', () => {
.getByTestId('add-repository-footer')
.getByRole('button', { name: translations.common.import })
.click();
await sharedPage.waitForTimeout(2000);
await expect(
sharedPage.getByText(translations.status.imported),
).toBeVisible();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ export async function switchToLocale(
await page.getByRole('button', { name: 'English' }).click();
await page.getByRole('option', { name: locale }).click();
await page.locator('a').filter({ hasText: 'Home' }).click();
// Wait for page to settle after locale switch and reload
await page.waitForLoadState('networkidle');
}
}

Expand Down
39 changes: 33 additions & 6 deletions workspaces/bulk-import/packages/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"lint": "backstage-cli package lint"
},
"dependencies": {
"@backstage-community/plugin-rbac": "^1.33.2",
"@backstage/app-defaults": "^1.7.2",
"@backstage/catalog-model": "^1.7.6",
"@backstage/cli": "^0.34.5",
Expand All @@ -32,11 +33,13 @@
"@backstage/plugin-catalog-graph": "^0.5.3",
"@backstage/plugin-catalog-import": "^0.13.7",
"@backstage/plugin-catalog-react": "^1.21.3",
"@backstage/plugin-notifications": "^0.5.11",
"@backstage/plugin-org": "^0.6.46",
"@backstage/plugin-permission-react": "^0.4.38",
"@backstage/plugin-scaffolder": "^1.34.3",
"@backstage/plugin-search": "^1.5.0",
"@backstage/plugin-search-react": "^1.10.0",
"@backstage/plugin-signals": "^0.0.25",
"@backstage/plugin-techdocs": "^1.16.0",
"@backstage/plugin-techdocs-module-addons-contrib": "^1.1.30",
"@backstage/plugin-techdocs-react": "^1.3.5",
Expand All @@ -48,24 +51,48 @@
"@mui/material": "5.18.0",
"@mui/styles": "5.18.0",
"@red-hat-developer-hub/backstage-plugin-bulk-import": "workspace:^",
"@red-hat-developer-hub/backstage-plugin-bulk-import-common": "workspace:^",
"@red-hat-developer-hub/backstage-plugin-orchestrator": "5.3.0",
"@red-hat-developer-hub/backstage-plugin-orchestrator-form-widgets": "1.5.0",
"@red-hat-developer-hub/backstage-plugin-theme": "^0.12.0",
"history": "^5.0.0",
"@tanstack/react-query": "^4.29.21",
"formik": "^2.4.5",
"history": "^5.3.0",
"js-yaml": "^4.1.0",
"lodash": "^4.17.21",
"react": "^18.0.2",
"react-dom": "^18.0.2",
"react-router": "^6.3.0",
"react-router-dom": "^6.3.0",
"react-use": "^17.2.4"
"react-use": "^17.4.0",
"yaml": "^2.0.0",
"yup": "^1.4.0"
},
"peerDependencies": {
"react": "16.13.1 || ^17.0.0 || ^18.0.0",
"react-router-dom": "^6.0.0"
},
"devDependencies": {
"@axe-core/playwright": "^4.11.0",
"@backstage/cli": "^0.34.5",
"@backstage/core-app-api": "^1.19.2",
"@backstage/dev-utils": "^1.1.17",
"@backstage/test-utils": "^1.7.13",
"@playwright/test": "1.57.0",
"@testing-library/dom": "^9.0.0",
"@red-hat-developer-hub/backstage-plugin-theme": "^0.11.0",
"@spotify/prettier-config": "^15.0.0",
"@testing-library/dom": "^10.0.0",
"@testing-library/jest-dom": "^6.0.0",
"@testing-library/react": "^14.0.0",
"@testing-library/user-event": "^14.0.0",
"@testing-library/react": "^15.0.0",
"@testing-library/user-event": "14.6.1",
"@types/js-yaml": "^4.0.9",
"@types/lodash": "^4.14.151",
"@types/react": "^18.2.58",
"@types/react-dom": "*",
"cross-env": "^7.0.0"
"cross-env": "^7.0.0",
"msw": "1.3.5",
"prettier": "3.6.2",
"react": "16.13.1 || ^17.0.0 || ^18.0.0"
},
"browserslist": {
"production": [
Expand Down
23 changes: 20 additions & 3 deletions workspaces/bulk-import/packages/app/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {
OAuthRequestDialog,
SignInPage,
} from '@backstage/core-components';
import { githubAuthApiRef } from '@backstage/core-plugin-api';
import { githubAuthApiRef, gitlabAuthApiRef } from '@backstage/core-plugin-api';
import { apiDocsPlugin, ApiExplorerPage } from '@backstage/plugin-api-docs';
import {
CatalogEntityPage,
Expand All @@ -46,20 +46,27 @@ import {
import { ReportIssue } from '@backstage/plugin-techdocs-module-addons-contrib';
import { TechDocsAddons } from '@backstage/plugin-techdocs-react';
import { UserSettingsPage } from '@backstage/plugin-user-settings';
import {
OrchestratorPage,
orchestratorTranslations,
} from '@red-hat-developer-hub/backstage-plugin-orchestrator';
import { BulkImportPage } from '@red-hat-developer-hub/backstage-plugin-bulk-import';
import { bulkImportTranslations } from '@red-hat-developer-hub/backstage-plugin-bulk-import/alpha';
import { getThemes } from '@red-hat-developer-hub/backstage-plugin-theme';
import { NotificationsPage } from '@backstage/plugin-notifications';
import { SignalsDisplay } from '@backstage/plugin-signals';
import { RbacPage } from '@backstage-community/plugin-rbac';
import { Navigate, Route } from 'react-router-dom';
import { apis } from './apis';
import { entityPage } from './components/catalog/EntityPage';
import { Root } from './components/Root';
import { searchPage } from './components/search/SearchPage';
import { bulkImportTranslations } from '@red-hat-developer-hub/backstage-plugin-bulk-import/alpha';

const app = createApp({
apis,
__experimentalTranslations: {
availableLanguages: ['en', 'de', 'es', 'fr', 'it', 'ja'],
resources: [bulkImportTranslations],
resources: [bulkImportTranslations, orchestratorTranslations],
},
bindRoutes({ bind }) {
bind(catalogPlugin.externalRoutes, {
Expand Down Expand Up @@ -91,6 +98,12 @@ const app = createApp({
message: 'Sign in using GitHub',
apiRef: githubAuthApiRef,
},
{
id: 'gitlab-auth-provider',
title: 'GitLab',
message: 'Sign in using GitLab',
apiRef: gitlabAuthApiRef,
},
]}
/>
),
Expand Down Expand Up @@ -134,13 +147,17 @@ const routes = (
<Route path="/catalog-graph" element={<CatalogGraphPage />} />
<Route path="/bulk-import" element={<Navigate to="repositories" />} />
<Route path="/bulk-import/repositories" element={<BulkImportPage />} />
<Route path="/notifications" element={<NotificationsPage />} />
<Route path="/orchestrator" element={<OrchestratorPage />} />
<Route path="/rbac" element={<RbacPage />} />
</FlatRoutes>
);

export default app.createRoot(
<>
<AlertDisplay />
<OAuthRequestDialog />
<SignalsDisplay />
<AppRouter>
<Root>{routes}</Root>
</AppRouter>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import { BulkImportSidebarItem } from '@red-hat-developer-hub/backstage-plugin-b
import { PropsWithChildren } from 'react';
import LogoFull from './LogoFull';
import LogoIcon from './LogoIcon';
import { NotificationsSidebarItem } from '@backstage/plugin-notifications';

const useSidebarLogoStyles = makeStyles({
root: {
Expand Down Expand Up @@ -97,6 +98,11 @@ export const Root = ({ children }: PropsWithChildren<{}>) => {
to="create"
text="Create..."
/>
<SidebarItem
icon={() => <></>}
to="orchestrator"
text="Orchestrator"
/>
<BulkImportSidebarItem />

{/* End global nav */}
Expand All @@ -112,6 +118,7 @@ export const Root = ({ children }: PropsWithChildren<{}>) => {
icon={<UserSettingsSignInAvatar />}
to="/settings"
>
<NotificationsSidebarItem />
<SidebarSettings />
</SidebarGroup>
</Sidebar>
Expand Down
Loading