Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Extension, ExtensionDeclaration } from '../types';

type ImageEnvironment = {
/** Environment variable key */
key: string;
/** The input field's label */
label: string;
/** Default value to use as a placeholder */
defaultValue?: string;
/** Description of the environment variable */
description?: string;
};

export type ImportEnvironment = ExtensionDeclaration<
'dev-console.import/environment',
{
/** Name of the image stream to provide custom environment variables for */
imageStreamName: string;
/** List of supported image stream tags */
imageStreamTags: string[];
/** List of environment variables */
environments: ImageEnvironment[];
}
>;

// Type guards

export const isImportEnvironment = (e: Extension): e is ImportEnvironment => {
return e.type === 'dev-console.import/environment';
};
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ export * from './topology';
export * from './create-resource';
export * from './user-preferences';
export * from './horizontal-nav-tabs';
export * from './import-environments';
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
import { FeatureFlag, ModelFeatureFlag } from '../extensions/feature-flags';
import { FileUpload } from '../extensions/file-upload';
import { HorizontalNavTab } from '../extensions/horizontal-nav-tabs';
import { ImportEnvironment } from '../extensions/import-environments';
import {
HrefNavItem,
ResourceNSNavItem,
Expand Down Expand Up @@ -64,6 +65,7 @@ export type SupportedExtension =
| YAMLTemplate
| AddAction
| AddActionGroup
| ImportEnvironment
| ClusterGlobalConfig
| HrefNavItem
| ResourceNSNavItem
Expand Down
15 changes: 15 additions & 0 deletions frontend/packages/dev-console/console-extensions.json
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,21 @@
]
}
},
{
"type": "dev-console.import/environment",
"properties": {
"imageStreamName": "nodejs",
"imageStreamTags": ["16-ubi8", "14-ubi8", "14-ubi8-minimal", "12-ubi8", "latest"],
"environments": [
{
"key": "NPM_RUN",
"label": "%devconsole~Run command%",
"description": "%devconsole~Optional parameter for Node.js applications to define the npm run <command>.%",
"defaultValue": "start"
}
]
}
},
{
"type": "console.catalog/item-type",
"properties": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,3 +203,13 @@ Feature: Create Application from git form
| git_url |
| https://github.com/sclorg/httpd-ex.git |
| https://github.com/sclorg/nginx-ex.git |

@regression
Scenario: Provide custom build environments for nodejs git import
Given user is at Import from Git form
When user enters Git Repo URL as "https://github.com/sclorg/nodejs-ex"
And user enters run command for "NPM_RUN" as "build2"
And user enters Name as "nodejs-env"
And user clicks Create button on Add page
Then user will be redirected to Topology page
And user is able to navigate to Build #1 for deployment "nodejs-env" and see environment variable "NPM_RUN" in Environment tab of details page
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export enum authenticationType {
export enum resources {
Deployments = 'Deployments',
BuildConfigs = 'Build Configs',
Builds = 'Builds',
Services = 'Services',
ImageStreams = 'Image Streams',
Routes = 'Routes',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,13 @@ export const addPage = {
}
},
verifyCard: (cardName: string) => cy.get(cardTitle).should('contain.text', cardName),
setBuildEnvField: (envKey: string, value: string) =>
cy
.get(`#form-input-image-imageEnv-${envKey}-field`)
.scrollIntoView()
.should('be.visible')
.clear()
.type(value),
};

export const verifyAddPage = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import { Given, When, Then } from 'cypress-cucumber-preprocessor/steps';
import { switchPerspective, devNavigationMenu, pageTitle, addOptions } from '../../constants';
import { detailsPage } from '@console/cypress-integration-tests/views/details-page';
import {
switchPerspective,
devNavigationMenu,
pageTitle,
addOptions,
resources,
} from '../../constants';
import { topologyPO } from '../../pageObjects';
import {
gitPage,
Expand All @@ -10,6 +17,8 @@ import {
topologyHelper,
perspective,
navigateTo,
topologySidePane,
app,
} from '../../pages';

Given('user is at Add page', () => {
Expand Down Expand Up @@ -88,3 +97,20 @@ Then('user can see {string} card on the Add page', (cardName: string) => {
When('user selects {string} card from add page', (cardName: string) => {
addPage.selectCardFromOptions(cardName);
});

When('user enters run command for {string} as {string}', (envKey: string, value: string) => {
addPage.setBuildEnvField(envKey, value);
});

Then(
'user is able to navigate to Build #1 for deployment {string} and see environment variable {string} in Environment tab of details page',
(name: string, env: string) => {
topologyPage.clickOnNode(name);
topologySidePane.selectTab('Resources');
topologySidePane.selectResource(resources.Builds, 'aut-addflow-git', `${name}-1`);
app.waitForLoad();
detailsPage.selectTab('Environment');
app.waitForLoad();
cy.get(`input[data-test="pairs-list-name"][value="${env}"]`).should('exist');
},
);
2 changes: 2 additions & 0 deletions frontend/packages/dev-console/locales/en/devconsole.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
"Browse the catalog to discover and deploy operator managed services": "Browse the catalog to discover and deploy operator managed services",
"Upload JAR file": "Upload JAR file",
"Upload a JAR file from your local desktop to OpenShift": "Upload a JAR file from your local desktop to OpenShift",
"Run command": "Run command",
"Optional parameter for Node.js applications to define the npm run <command>.": "Optional parameter for Node.js applications to define the npm run <command>.",
"Builder Images": "Builder Images",
"Browse for container images that support a particular language or framework. Cluster administrators can customize the content made available in the catalog.": "Browse for container images that support a particular language or framework. Cluster administrators can customize the content made available in the catalog.",
"**Builder Images** are container images that build source code for a particular language or framework.": "**Builder Images** are container images that build source code for a particular language or framework.",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import * as React from 'react';
import { TextInputTypes } from '@patternfly/react-core';
import {
ImportEnvironment,
isImportEnvironment,
useResolvedExtensions,
} from '@console/dynamic-plugin-sdk';
import { InputField } from '@console/shared';

interface BuilderImageEnvironmentsProps {
name: string;
imageStreamName: string;
imageStreamTag: string;
}

const BuilderImageEnvironments: React.FC<BuilderImageEnvironmentsProps> = ({
name,
imageStreamName,
imageStreamTag,
}) => {
const [environmentExtensions, resolved] = useResolvedExtensions<ImportEnvironment>(
isImportEnvironment,
);

const filteredExtensions = React.useMemo(
() =>
environmentExtensions?.filter(
(e) =>
e.properties.imageStreamName === imageStreamName &&
e.properties.imageStreamTags.includes(imageStreamTag),
),
[environmentExtensions, imageStreamName, imageStreamTag],
);

if (!resolved) {
return null;
}
return (
<>
{filteredExtensions.map(({ properties }) =>
properties.environments.map((env) => (
<InputField
key={`${properties.imageStreamName}-${env.key}`}
type={TextInputTypes.text}
name={`${name}.${env.key}`}
label={env.label}
helpText={env.description}
placeholder={env.defaultValue}
/>
)),
)}
</>
);
};

export default BuilderImageEnvironments;
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
getPorts,
} from '../../../utils/imagestream-utils';
import { useSafeK8s } from '../../../utils/safe-k8s-hook';
import BuilderImageEnvironments from './BuilderImageEnvironments';
import ImageStreamInfo from './ImageStreamInfo';

export interface BuilderImageTagSelectorProps {
Expand Down Expand Up @@ -79,6 +80,11 @@ const BuilderImageTagSelector: React.FC<BuilderImageTagSelectorProps> = ({
/>
</div>
{imageTag && showImageInfo && <ImageStreamInfo displayName={displayName} tag={imageTag} />}
<BuilderImageEnvironments
name="image.imageEnv"
imageStreamName={imageName}
imageStreamTag={selectedImageTag}
/>
</>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ export const createOrUpdateBuildConfig = (
application: { name: applicationName },
git: { url: repository, type: gitType, ref = 'master', dir: contextDir, secret: secretName },
docker: { dockerfilePath },
image: { tag: selectedTag },
image: { tag: selectedTag, imageEnv },
build: { env, triggers, strategy: buildStrategy },
labels: userLabels,
} = formData;
Expand All @@ -182,6 +182,11 @@ export const createOrUpdateBuildConfig = (
let buildStrategyData;

let desiredContextDir = contextDir;
const customBuildEnvs = imageEnv
? Object.keys(imageEnv)
.filter((k) => !!imageEnv[k])
.map((k) => ({ name: k, value: imageEnv[k] }))
: [];

switch (buildStrategy) {
case 'Devfile':
Expand All @@ -198,7 +203,7 @@ export const createOrUpdateBuildConfig = (
default:
buildStrategyData = {
sourceStrategy: {
env,
env: [...env, ...customBuildEnvs],
from: {
kind: 'ImageStreamTag',
name: `${imageStreamName}:${selectedTag}`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ export interface ImageData {
tag: string;
tagObj: object;
ports: ContainerPort[];
imageEnv?: { [key: string]: string };
}

export interface ImageStreamImageData {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ When('user switches to the {string} tab', (tab: string) => {
});

When('user clicks on the link for the {string} of helm release', (resource: string) => {
topologySidePane.selectResource(resource, Cypress.env('NAMESPACE'));
topologySidePane.selectResource(resource, Cypress.env('NAMESPACE'), 'nodejs-release');
});

Given('user is at Add page', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ export const detailsPage = {
},
isLoaded: () => cy.byTestID('skeleton-detail-view').should('not.exist'),
breadcrumb: (breadcrumbIndex: number) => cy.byLegacyTestID(`breadcrumb-link-${breadcrumbIndex}`),
selectTab: (name: string) => {
cy.get(`a[data-test-id="horizontal-link-public~${name}"]`)
.should('exist')
.click();
},
};

export namespace DetailsPageSelector {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,31 +125,36 @@ export const topologySidePane = {
cy.byTestActionID('Delete Application').should('be.visible');
cy.get(topologyPO.addToApplicationInContext).should('be.visible');
},
selectResource: (opt: resources | string, namespace: string) => {
selectResource: (opt: resources | string, namespace: string, name: string) => {
switch (opt) {
case 'Deployments':
case resources.Deployments: {
cy.get(`[href="/k8s/ns/${namespace}/deployments/nodejs-release"]`).click();
cy.get(`[href="/k8s/ns/${namespace}/deployments/${name}"]`).click();
break;
}
case 'Build Configs':
case resources.BuildConfigs: {
cy.get(`[href="/k8s/ns/${namespace}/buildconfigs/nodejs-release"]`).click();
cy.get(`[href="/k8s/ns/${namespace}/buildconfigs/${name}"]`).click();
break;
}
case 'Builds':
case resources.Builds: {
cy.get(`[href="/k8s/ns/${namespace}/builds/${name}]`).click();
break;
}
case 'Services':
case resources.Services: {
cy.get(`[href="/k8s/ns/${namespace}/services/nodejs-release"]`).click();
cy.get(`[href="/k8s/ns/${namespace}/services/${name}"]`).click();
break;
}
case 'Image Streams':
case resources.ImageStreams: {
cy.get(`[href="/k8s/ns/${namespace}/imagestreams/nodejs-release"]`).click();
cy.get(`[href="/k8s/ns/${namespace}/imagestreams/${name}"]`).click();
break;
}
case 'Routes':
case resources.Routes: {
cy.get(`[href="/k8s/ns/${namespace}/routes/nodejs-release"]`).click();
cy.get(`[href="/k8s/ns/${namespace}/routes/${name}"]`).click();
break;
}
default: {
Expand Down