Skip to content

Commit f1990c3

Browse files
committed
add documentation and make the plugin public
1 parent e73181e commit f1990c3

File tree

18 files changed

+264
-150
lines changed

18 files changed

+264
-150
lines changed

plugins/argocd/README.md

Lines changed: 130 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,145 @@
1-
# argocd
1+
# Argocd plugin for Backstage
22

33
Welcome to the argocd plugin!
44

55
_This plugin was created through the Backstage CLI_
66

77
## Getting started
88

9-
Your plugin has been added to the example app in this repository, meaning you'll be able to access it by running `yarn start` in the root directory, and then navigating to [/argocd](http://localhost:3000/argocd).
9+
Your plugin has been added to the example app in this repository, meaning you'll be able to access it by running `yarn start` in the root directory, and then navigating to [/argocd/deployment-lifecycle](http://localhost:3000/argocd/deployment-lifecycle).
1010

1111
You can also serve the plugin in isolation by running `yarn start` in the plugin directory.
1212
This method of serving the plugin provides quicker iteration speed and a faster startup and hot reloads.
1313
It is only meant for local development, and the setup for it can be found inside the [/dev](./dev) directory.
1414

15+
## For Administrators
16+
17+
### Installation and configuration
18+
19+
#### Prerequisites
20+
21+
- Install `@roadiehq/backstage-plugin-argo-cd-backend` plugin using the following command from the root directory
22+
<!-- configure it by following [Argo CD Backend Plugin docs](https://www.npmjs.com/package/@roadiehq/backstage-plugin-argo-cd-backend) -->
23+
24+
```bash
25+
yarn workspace app add @roadiehq/backstage-plugin-argo-cd-backend
26+
```
27+
28+
- Create plugin file for ArgoCD backend in your `packages/backend/src/plugins/` directory.
29+
30+
```ts
31+
// packages/backend/src/plugins/argocd.ts
32+
33+
import { createRouter } from '@roadiehq/backstage-plugin-argo-cd-backend';
34+
35+
import { PluginEnvironment } from '../types';
36+
37+
export default async function createPlugin({
38+
logger,
39+
config,
40+
}: PluginEnvironment) {
41+
return await createRouter({ logger, config });
42+
}
43+
```
44+
45+
- Modify your backend router to expose the APIs for ArgoCD backend
46+
47+
```ts
48+
// packages/backend/src/index.ts
49+
50+
import argocd from './plugins/argocd';
51+
...
52+
53+
const argocdEnv = useHotMemoize(module, () => createEnv('argocd'));
54+
...
55+
apiRouter.use('/argocd', await argocd(argocdEnv));
56+
```
57+
58+
- add argocd instance information in app.config.yaml
59+
60+
```ts
61+
argocd:
62+
appLocatorMethods:
63+
- type: 'config'
64+
instances:
65+
- name: argoInstance1
66+
url: https://argoInstance1.com
67+
username: ${ARGOCD_USERNAME}
68+
password: ${ARGOCD_PASSWORD}
69+
- name: argoInstance2
70+
url: https://argoInstance2.com
71+
username: ${ARGOCD_USERNAME}
72+
password: ${ARGOCD_PASSWORD}
73+
```
74+
75+
#### How to add argocd frontend plugin to Backstage app
76+
77+
1. Install the Argocd plugin using the following command:
78+
79+
```bash
80+
yarn workspace app add @janus-idp/backstage-plugin-argocd
81+
```
82+
83+
2. Add deployment summary and deployment lifecycle compoennt to the `entityPage.tsx` source file:
84+
85+
```ts
86+
// packages/app/src/components/catalog/EntityPage.tsx
87+
import {
88+
ArgocdDeploymentSummary,
89+
ArgocdDeploymentLifecycle
90+
isArgocdConfigured,
91+
} from '@janus-idp/backstage-plugin-argocd';
92+
93+
const overviewContent = (
94+
<Grid container spacing={3} alignItems="stretch">
95+
...
96+
<EntitySwitch>
97+
<EntitySwitch.Case if={e => Boolean(isArgocdConfigured(e))}>
98+
<Grid item sm={12}>
99+
<ArgocdDeploymentSummary />
100+
</Grid>
101+
</EntitySwitch.Case>
102+
</EntitySwitch>
103+
...
104+
</Grid>
105+
);
106+
107+
108+
const cicdcontent = (
109+
<EntitySwitch>
110+
{/* ... */}
111+
{/* highlight-add-start */}
112+
...
113+
<EntitySwitch.Case if={e => Boolean(isArgocdConfigured(e))}>
114+
<Grid item sm={12}>
115+
<ArgocdDeploymentLifecycle />
116+
</Grid>
117+
</EntitySwitch.Case>
118+
{/* highlight-add-end */}
119+
</EntitySwitch>
120+
);
121+
```
122+
123+
- The following annotation is added to the entity's `catalog-info.yaml` file to enable argocd features in the backstage instance:
124+
125+
```yaml
126+
annotations:
127+
...
128+
129+
argocd/app-selector: 'rht-gitops.com/janus-argocd=quarkus-app'
130+
131+
```
132+
133+
- To switch between argocd instances, you can use the following annotation
134+
135+
```yaml
136+
annotations:
137+
...
138+
argocd/instance-name: 'argoInstance2'
139+
```
140+
141+
**_Note: If this annotation is not set, the plugin will defaultto the first argocd instance configured in the `app.config.yaml`_**
142+
15143
## Loading as Dynamic Plugin
16144

17145
This plugin can be loaded in backstage showcase application as a dynamic plugin.

plugins/argocd/dev/__data__/config.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ import { Config } from '@kubernetes/client-node';
33
export const mockArgocdConfig: Config = {
44
argocd: {
55
baseUrl: 'https://localhost:8080',
6-
username: 'argocd-test-account',
7-
password: 'argocd-test-pass',
86
appLocatorMethods: [
97
{
108
type: 'config',

plugins/argocd/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
"main": "src/index.ts",
55
"types": "src/index.ts",
66
"license": "Apache-2.0",
7-
"private": true,
87
"publishConfig": {
98
"access": "public",
109
"main": "dist/index.esm.js",
@@ -50,6 +49,7 @@
5049
},
5150
"devDependencies": {
5251
"@backstage/cli": "0.26.2",
52+
"@backstage/config": "1.2.0",
5353
"@backstage/core-app-api": "1.12.3",
5454
"@backstage/dev-utils": "1.0.30",
5555
"@backstage/test-utils": "1.5.3",

plugins/argocd/src/api/__tests__/index.test.ts

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { IdentityApi } from '@backstage/core-plugin-api';
33
import { ArgoCDApiClient } from '..';
44
import { mockApplication } from '../../../dev/__data__';
55

6-
export const getIdentityApiStub: IdentityApi = {
6+
const getIdentityApiStub: IdentityApi = {
77
getProfileInfo: jest.fn(),
88
getBackstageIdentity: jest.fn(),
99
async getCredentials() {
@@ -35,7 +35,7 @@ describe('API calls', () => {
3535

3636
test('fetches app based on provided projectName', async () => {
3737
const client = new ArgoCDApiClient({
38-
backendBaseUrl: 'http://test.com',
38+
backendBaseUrl: 'https://test.com',
3939
useNamespacedApps: false,
4040
identityApi: getIdentityApiStub,
4141
});
@@ -47,7 +47,7 @@ describe('API calls', () => {
4747
});
4848

4949
expect(global.fetch).toHaveBeenCalledWith(
50-
'http://test.com/api/argocd/applications?project=test',
50+
'https://test.com/api/argocd/applications?project=test',
5151
expect.objectContaining({
5252
headers: {
5353
'Content-Type': 'application/json',
@@ -58,7 +58,7 @@ describe('API calls', () => {
5858
});
5959
test('fetches app based on provided appSelector', async () => {
6060
const client = new ArgoCDApiClient({
61-
backendBaseUrl: 'http://test.com',
61+
backendBaseUrl: 'https://test.com',
6262
useNamespacedApps: false,
6363
identityApi: getIdentityApiStub,
6464
});
@@ -69,7 +69,7 @@ describe('API calls', () => {
6969
});
7070

7171
expect(global.fetch).toHaveBeenCalledWith(
72-
'http://test.com/api/argocd/applications/selector/my-test-app-selector?selector=my-test-app-selector',
72+
'https://test.com/api/argocd/applications/selector/my-test-app-selector?selector=my-test-app-selector',
7373
expect.objectContaining({
7474
headers: {
7575
'Content-Type': 'application/json',
@@ -90,17 +90,19 @@ describe('API calls', () => {
9090
);
9191

9292
const client = new ArgoCDApiClient({
93-
backendBaseUrl: 'http://test.com',
93+
backendBaseUrl: 'https://test.com',
9494
useNamespacedApps: false,
9595
identityApi: getIdentityApiStub,
9696
});
97-
97+
let error;
9898
try {
9999
await client.listApps({
100100
url: '',
101101
appSelector: 'my-test-app-selector',
102102
});
103-
} catch (error: any) {
103+
} catch (e: any) {
104+
error = e;
105+
} finally {
104106
expect(error.message).toBe(
105107
'failed to fetch data, status Internal server error: Something went wrong',
106108
);
@@ -109,7 +111,7 @@ describe('API calls', () => {
109111

110112
test('should not pass the token for the guest user', async () => {
111113
const client = new ArgoCDApiClient({
112-
backendBaseUrl: 'http://test.com',
114+
backendBaseUrl: 'https://test.com',
113115
useNamespacedApps: false,
114116
identityApi: {
115117
...getIdentityApiStub,
@@ -126,7 +128,7 @@ describe('API calls', () => {
126128
});
127129

128130
expect(global.fetch).toHaveBeenCalledWith(
129-
'http://test.com/api/argocd/applications?project=test',
131+
'https://test.com/api/argocd/applications?project=test',
130132
expect.objectContaining({
131133
headers: undefined,
132134
}),
@@ -146,7 +148,7 @@ describe('API calls', () => {
146148

147149
test('should return the revision details', async () => {
148150
const client = new ArgoCDApiClient({
149-
backendBaseUrl: 'http://test.com',
151+
backendBaseUrl: 'https://test.com',
150152
useNamespacedApps: false,
151153
identityApi: getIdentityApiStub,
152154
});
@@ -158,7 +160,7 @@ describe('API calls', () => {
158160
});
159161

160162
expect(global.fetch).toHaveBeenCalledWith(
161-
'http://test.com/api/argocd/argoInstance/main/applications/name/my-test-app/revisions/12345/metadata',
163+
'https://test.com/api/argocd/argoInstance/main/applications/name/my-test-app/revisions/12345/metadata',
162164
expect.objectContaining({
163165
headers: {
164166
'Content-Type': 'application/json',
@@ -181,7 +183,7 @@ describe('API calls', () => {
181183

182184
test('should return empty list if the revisionIds are not passed', async () => {
183185
const client = new ArgoCDApiClient({
184-
backendBaseUrl: 'http://test.com',
186+
backendBaseUrl: 'https://test.com',
185187
useNamespacedApps: false,
186188
identityApi: getIdentityApiStub,
187189
});
@@ -197,7 +199,7 @@ describe('API calls', () => {
197199

198200
test('should return the list of revision details', async () => {
199201
const client = new ArgoCDApiClient({
200-
backendBaseUrl: 'http://test.com',
202+
backendBaseUrl: 'https://test.com',
201203
useNamespacedApps: false,
202204
identityApi: getIdentityApiStub,
203205
});
@@ -210,7 +212,7 @@ describe('API calls', () => {
210212
});
211213

212214
expect(global.fetch).toHaveBeenCalledWith(
213-
'http://test.com/api/argocd/argoInstance/main/applications/name/quarkus-app-dev/revisions/90f9758b7033a4bbb7c33a35ee474d61091644bc/metadata',
215+
'https://test.com/api/argocd/argoInstance/main/applications/name/quarkus-app-dev/revisions/90f9758b7033a4bbb7c33a35ee474d61091644bc/metadata',
214216
expect.objectContaining({
215217
headers: {
216218
'Content-Type': 'application/json',

plugins/argocd/src/components/AppStatus/__tests__/AppHealthStatus.test.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@ describe('AppHealthStatus', () => {
99
test('should return default component', () => {
1010
render(<AppHealthStatus app={mockApplication} />);
1111

12-
screen.getByTestId('healthy-icon');
13-
screen.getByText('Healthy');
12+
expect(screen.queryByTestId('healthy-icon')).toBeInTheDocument();
13+
expect(screen.queryByText('Healthy')).toBeInTheDocument();
1414
});
1515

1616
test('should return application health chip component', () => {
1717
render(<AppHealthStatus app={mockApplication} isChip />);
1818

19-
screen.getByTestId('app-health-status-chip');
19+
expect(screen.getByTestId('app-health-status-chip')).toBeInTheDocument();
2020
});
2121
});

plugins/argocd/src/components/AppStatus/__tests__/AppSyncStatus.test.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@ describe('AppSyncStatus', () => {
99
test('should return default component', () => {
1010
render(<AppSyncStatus app={mockApplication} />);
1111

12-
screen.getByTestId('synced-icon');
13-
screen.getByText('Synced');
12+
expect(screen.getByTestId('synced-icon')).toBeInTheDocument();
13+
expect(screen.getByText('Synced')).toBeInTheDocument();
1414
});
1515

1616
test('should return application health chip component', () => {
1717
render(<AppSyncStatus app={mockApplication} isChip />);
1818

19-
screen.getByTestId('app-sync-status-chip');
19+
expect(screen.getByTestId('app-sync-status-chip')).toBeInTheDocument();
2020
});
2121
});

plugins/argocd/src/components/AppStatus/__tests__/StatusHeading.test.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ import { Application } from '../../../types';
77
import StatusHeading from '../StatusHeading';
88

99
describe('StatusHeading', () => {
10-
test('should not render if the application is not available ', () => {
10+
test('should not render if the application is not available', () => {
1111
render(<StatusHeading app={null as unknown as Application} />);
1212
expect(screen.queryByText('app-sync-status-chip')).not.toBeInTheDocument();
1313
});
1414

15-
test('should render if the application is available ', () => {
15+
test('should render if the application is available', () => {
1616
render(<StatusHeading app={mockApplication} />);
1717

1818
expect(screen.queryByTestId('app-health-status-chip')).toBeInTheDocument();

0 commit comments

Comments
 (0)