Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Switch Adaptation Project's generator/wizard to use Open Source writers #1775

Open
wants to merge 55 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
d207584
feat: enhance writer for ADP Project to be able to create proper ADP …
IvoSG Mar 24, 2024
bb4a0a0
feat: enhance s4hana project generation
IvoSG Mar 25, 2024
363a702
feat: enhance cf project generation
IvoSG Apr 2, 2024
2cffde0
Merge branch 'main' of https://github.com/SAP/open-ux-tools into feat…
IvoSG Apr 2, 2024
774f0ac
fix/lint errors and tests
IvoSG Apr 2, 2024
a9ae35a
fix: unit tests and code corrections
IvoSG Apr 3, 2024
ef58dd5
Linting auto fix commit
github-actions[bot] Apr 3, 2024
9aa7edc
chore: add changeset
IvoSG Apr 3, 2024
0d0bef9
Merge branch 'feat/1611/writersForAdpProjects' of https://github.com/…
IvoSG Apr 3, 2024
464b534
fix: sonar security issue
IvoSG Apr 3, 2024
5ad6495
Merge branch 'main' into feat/1611/writersForAdpProjects
IvoSG Apr 3, 2024
82b0238
chore: split the project template files for the different environments
IvoSG Apr 16, 2024
32a3214
chore: use btp-utils to check the running environment
IvoSG Apr 16, 2024
5956a34
chore: split the writers logic
IvoSG Apr 16, 2024
8a25655
chore: add writer factory to instantiate class for different environm…
IvoSG Apr 16, 2024
5d6d4cb
fix: remove cf writer logic, move project utils and fix ui5-deploy.ya…
IvoSG Apr 24, 2024
004b5cb
chore: use one project template for onprem and s4 project types
IvoSG Apr 24, 2024
f28ca6e
fix: ui5-deploy.yaml writer and add appredload middleware
IvoSG Apr 25, 2024
43ca69a
chore: revert all writers factory logic, revert project template stru…
IvoSG Apr 26, 2024
4af85b2
Merge branch 'main' into feat/1611/writersForAdpProjects
IvoSG Apr 26, 2024
8ac89f4
chore: revert autoupdated import type
IvoSG Apr 26, 2024
09d5cf4
fix: add whitespace
IvoSG Apr 26, 2024
d42387b
fix: merge issue
IvoSG Apr 26, 2024
0e31e07
Merge branch 'main' into feat/1611/writersForAdpProjects
IvoSG Apr 30, 2024
2507b01
chore: change types and remove unit tests for cf
IvoSG Apr 30, 2024
cb495b2
fix: default url if not provided
IvoSG Apr 30, 2024
0ca6004
fix: remove .env file, write only changes in apdescr content, use fra…
IvoSG May 16, 2024
3dba791
fix: typo
IvoSG May 16, 2024
6c21e2f
Merge branch 'main' into feat/1611/writersForAdpProjects
IvoSG May 16, 2024
0516fc4
Merge branch 'main' into feat/1611/writersForAdpProjects
IvoSG May 17, 2024
35a6347
fix: migrator ui5 yaml writers
IvoSG May 17, 2024
a2c2b71
chore: remove credentials from ui5.yaml config, move inbound change l…
IvoSG May 22, 2024
1da5255
Merge branch 'main' into feat/1611/writersForAdpProjects
IvoSG May 22, 2024
3bed8d2
Merge branch 'main' of https://github.com/SAP/open-ux-tools into feat…
IvoSG May 23, 2024
edb43db
Merge branch 'main' into feat/1611/writersForAdpProjects
IvoSG May 23, 2024
b970461
Merge branch 'main' into feat/1611/writersForAdpProjects
tobiasqueck May 24, 2024
31153cf
Merge branch 'main' into feat/1611/writersForAdpProjects
tobiasqueck May 27, 2024
196fc44
chore: resolve code review comments
IvoSG May 29, 2024
0e12110
Merge branch 'main' into feat/1611/writersForAdpProjects
IvoSG May 29, 2024
4158c84
Merge branch 'main' into feat/1611/writersForAdpProjects
IvoSG May 29, 2024
113e2af
Merge branch 'main' into feat/1611/writersForAdpProjects
IvoSG May 30, 2024
513b0f7
Merge branch 'main' into feat/1611/writersForAdpProjects
IvoSG Jun 3, 2024
328b15d
Merge branch 'main' into feat/1611/writersForAdpProjects
IvoSG Jun 3, 2024
c05b0dd
fix: add JSDoc to the types, remove unused tests and revert fs, cover…
IvoSG Jun 4, 2024
8f5b365
Merge branch 'main' into feat/1611/writersForAdpProjects
IvoSG Jun 4, 2024
bce2d5c
Merge branch 'main' into feat/1611/writersForAdpProjects
IvoSG Jun 4, 2024
db1a539
Merge branch 'main' into feat/1611/writersForAdpProjects
IvoSG Jun 4, 2024
a6ac36a
chore: move new inbound navigation properties to an internal type
IvoSG Jun 5, 2024
78f7a82
Merge branch 'main' into feat/1611/writersForAdpProjects
IvoSG Jun 5, 2024
c190b64
fix: adapt existed tests
IvoSG Jun 5, 2024
a933d59
test: adding missing tests, refactoring tests
IvoSG Jun 6, 2024
5e74a2a
fix: resolve sonar issue
IvoSG Jun 6, 2024
be4d7e1
Merge branch 'main' into feat/1611/writersForAdpProjects
IvoSG Jun 6, 2024
515d984
Merge branch 'main' into feat/1611/writersForAdpProjects
IvoSG Jun 6, 2024
114591d
Merge branch 'main' into feat/1611/writersForAdpProjects
GDamyanov Jun 7, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/famous-panthers-occur.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@sap-ux/adp-tooling': minor
'@sap-ux/preview-middleware': patch
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove preview-middleware and axios-extension from the changeset.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

---

Adds writer functionality for generation of Adaptation Project's
nikmace marked this conversation as resolved.
Show resolved Hide resolved
2 changes: 2 additions & 0 deletions packages/adp-tooling/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@ export * from './types';
export * from './preview/adp-preview';
export { generate } from './writer';
export { generateChange } from './writer/editors';
export { generateEnv } from './writer/s4hana';
export { generateCf } from './writer/cf';
export { promptGeneratorInput, PromptDefaults } from './base/prompt';
67 changes: 65 additions & 2 deletions packages/adp-tooling/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { UI5FlexLayer } from '@sap-ux/project-access';
import type { DestinationAbapTarget, UrlAbapTarget } from '@sap-ux/system-access';
import type { Adp } from '@sap-ux/ui5-config';
import type { Adp, BspApp } from '@sap-ux/ui5-config';
import type { Editor } from 'mem-fs-editor';

export interface DescriptorVariant {
Expand Down Expand Up @@ -35,23 +35,40 @@ export interface AdpWriterConfig {
target: AbapTarget;
ui5?: {
tobiasqueck marked this conversation as resolved.
Show resolved Hide resolved
minVersion?: string;
ui5Version?: string;
ui5EndpointUrl?: string;
nikmace marked this conversation as resolved.
Show resolved Hide resolved
};
package?: {
name?: string;
description?: string;
};
flp?: {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That object is odd. bspName and credentials are used to access the original app while title, subtitle and inboundId are only being used in the i18n file. Did you miss adding a change to the appdescr if these properties are present or did I miss it in the code or is there some magic backend functionality that does something on deploy?

What is the difference between bspName and reference in the app section?

Copy link
Contributor Author

@IvoSG IvoSG May 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently, the title, subtitle and inbound id are only used in the i18n file because the appdescr information comes already filtered after the prompting.
bspName is the base app repoName and reference is the base app id

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed on the phone, please add the change for the inbound communication to the appdescr template file with the condtion that the flp object is provided

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The change for the inbound it's more complex to be in the aprdescr template and because of that it's passed with other changes in the content

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it is too complex for ejs, implement it as a plain function and then add it to the list of changes. Most importantly move the logic here because you have a reference to it in your generated i18n.properties file

flpTitle?: string;
flpSubtitle?: string;
nikmace marked this conversation as resolved.
Show resolved Hide resolved
inboundId?: string;
bspName?: string;
languages?: language[];
};
customConfig?: AdpCustomConfig;
/**
* Optional: configuration for deployment to ABAP
*/
deploy?: Adp;
deploy?: Adp | BspApp;
options?: {
/**
* Optional: if set to true then the generated project will be recognized by the SAP Fiori tools
*/
fioriTools?: boolean;
isRunningInBAS?: boolean;
isCloudProject?: boolean;
};
}

export interface language {
nikmace marked this conversation as resolved.
Show resolved Hide resolved
sap: string;
i18n: string;
}

export interface ManifestAppdescr {
fileName: string;
layer: string;
Expand Down Expand Up @@ -347,3 +364,49 @@ export interface AdpProjectData {
reference: string;
id: string;
}

export interface AdpCustomConfig {
adp?: {
safeMode: boolean;
nikmace marked this conversation as resolved.
Show resolved Hide resolved
};
}

export interface CfModuleData {
appHostId: string;
appName: string;
appVersion: string;
appId: string;
module: string;
moduleTitle: string;
appVariantId: string;
projectName: string;
i18nGuid: string;
projectPath: string;
addSecurity: string;
addStandaloneApprouter: boolean;
sapCloudService: string;
xsSecurityProjectName: string;
org: string;
space: string;
html5RepoRuntime: string;
}

export interface CfAdpConfig {
componentname: string;
nikmace marked this conversation as resolved.
Show resolved Hide resolved
safeMode: boolean;
appvariant: string;
layer: string;
isOVPApp: boolean;
isFioriElement: boolean;
nikmace marked this conversation as resolved.
Show resolved Hide resolved
environment: string;
ui5Version: string;
cfSpace: string;
cfOrganization: string;
cfApiUrl: string;
}

export interface CfWriterConfig {
app: CfModuleData;
appdescr: ManifestAppdescr;
adpConfig: CfAdpConfig;
}
51 changes: 51 additions & 0 deletions packages/adp-tooling/src/writer/cf.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { join } from 'path';
import { create as createStorage } from 'mem-fs';
import type { Editor } from 'mem-fs-editor';
import { create } from 'mem-fs-editor';
import type { CfWriterConfig, ManifestAppdescr } from '../types';

/**
* Writes the adp-project template to the mem-fs-editor instance.
*
* @param basePath - the base path
* @param config - the writer configuration
* @param fs - the memfs editor instance
* @returns the updated memfs editor instance
*/
export async function generateCf(basePath: string, config: CfWriterConfig, fs?: Editor): Promise<Editor> {
if (!fs) {
fs = create(createStorage());
}
const tmplPath = join(__dirname, '../../templates/projects/cf');

fs.copyTpl(join(tmplPath, '**/*.*'), join(basePath), config.app, undefined, {
globOptions: { dot: true, ignore: ['**/xs-security.json', '**/approuter/*.*', '**/manifest.appdescr_variant'] },
processDestinationPath: (filePath: string) =>
filePath
.replace(/gitignore.tmpl/g, '.gitignore')
.replace(/i18n\/i18n.properties/g, 'webapp/i18n/i18n.properties')
});
IvoSG marked this conversation as resolved.
Show resolved Hide resolved

// manifest.appdescr_variant
const appdescrTplPath = join(tmplPath, 'manifest.appdescr_variant');
const appdescrPath = join(basePath, 'webapp/manifest.appdescr_variant');
const baseAppdescrContent: ManifestAppdescr = JSON.parse(fs.read(appdescrTplPath));
config.appdescr.content = [...baseAppdescrContent.content, ...config.appdescr.content];
Object.assign(baseAppdescrContent, config.appdescr);
fs.writeJSON(appdescrPath, baseAppdescrContent);
// .adp/config.json
const adpConfigPath = join(basePath, '.adp/config.json');
fs.writeJSON(adpConfigPath, config.adpConfig);
// approuter
if (config.app.addStandaloneApprouter) {
fs.copyTpl(join(tmplPath, 'approuter/*.*'), join(basePath, 'approuter'), config.app);
}
// xs-security.json
if (!fs.exists(join(config.app.projectPath, 'xs-security.json'))) {
fs.copyTpl(join(tmplPath, 'xs-security.json'), join(config.app.projectPath, 'xs-security.json'), {
projectName: config.app.xsSecurityProjectName
});
}
nikmace marked this conversation as resolved.
Show resolved Hide resolved

return fs;
}
8 changes: 5 additions & 3 deletions packages/adp-tooling/src/writer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ function setDefaults(config: AdpWriterConfig): AdpWriterConfig {
target: { ...config.target },
ui5: { ...config.ui5 },
deploy: config.deploy ? { ...config.deploy } : undefined,
options: { ...config.options }
options: { ...config.options },
flp: config.flp ? { ...config.flp } : undefined,
customConfig: { ...config.customConfig }
};
configWithDefaults.app.title ??= `Adaptation of ${config.app.reference}`;
configWithDefaults.app.layer ??= 'CUSTOMER_BASE';
Expand All @@ -42,11 +44,11 @@ export async function generate(basePath: string, config: AdpWriterConfig, fs?: E
if (!fs) {
fs = create(createStorage());
}
const tmplPath = join(__dirname, '../../templates/project');
const tmplPath = join(__dirname, '../../templates/projects/abap');
const fullConfig = setDefaults(config);

fs.copyTpl(join(tmplPath, '**/*.*'), join(basePath), fullConfig, undefined, {
globOptions: { dot: true },
globOptions: { dot: true, ignore: config.options?.isRunningInBAS ? [] : ['**/pom.xml'] },
processDestinationPath: (filePath: string) => filePath.replace(/gitignore.tmpl/g, '.gitignore')
});

Expand Down
48 changes: 46 additions & 2 deletions packages/adp-tooling/src/writer/options.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { CustomMiddleware, UI5Config } from '@sap-ux/ui5-config';
import type { CustomMiddleware, UI5Config, CustomTask, AbapTarget } from '@sap-ux/ui5-config';
import type { AdpWriterConfig } from '../types';

/**
Expand All @@ -9,7 +9,17 @@ import type { AdpWriterConfig } from '../types';
*/
export function enhanceUI5Yaml(ui5Config: UI5Config, config: AdpWriterConfig) {
const middlewares = config.options?.fioriTools ? getFioriToolsMiddlwares(config) : getOpenSourceMiddlewares(config);
ui5Config.setConfiguration({ propertiesFileSourceEncoding: 'UTF-8' });
ui5Config.addCustomMiddleware(middlewares);

if (config.customConfig?.adp) {
ui5Config.addCustomConfiguration('adp', config.customConfig.adp);
}
if (config.options?.isRunningInBAS && config.options?.isCloudProject && config.ui5?.ui5Version) {
ui5Config.addUI5Framework('SAPUI5', config.ui5.ui5Version, []);
const tasks = getAdpCloudCustomTasks(config);
ui5Config.addCustomTasks(tasks);
}
}

/**
Expand Down Expand Up @@ -61,8 +71,9 @@ function getFioriToolsMiddlwares(config: AdpWriterConfig): CustomMiddleware<unkn
configuration: {
ignoreCertErrors: false,
ui5: {
version: config?.ui5?.minVersion,
path: ['/resources', '/test-resources'],
url: 'https://ui5.sap.com'
url: config?.ui5?.ui5EndpointUrl
},
backend: [
{
Expand Down Expand Up @@ -120,3 +131,36 @@ function getOpenSourceMiddlewares(config: AdpWriterConfig): CustomMiddleware<obj
}
];
}

/**
* Get a list of required custom tasks using the Fiori tools.
*
* @param config full project configuration
* @returns list of required tasks.
*/
function getAdpCloudCustomTasks(config: AdpWriterConfig & { target: AbapTarget }): CustomTask[] {
const user = 'env:ABAP_USERNAME';
const pass = 'env:ABAP_PASSWORD';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned in my other comment, this shouldn't be here. In the very worst case that there is a valid scenario for this, use at least FIORI_TOOLS_USER and FIORI_TOOLS_PASSWORD because they are available if any previous Fiori tools task or middleware relied on user/password.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed on the phone, please remove it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


return [
{
name: 'app-variant-bundler-build',
beforeTask: 'escapeNonAsciiCharacters',
configuration: {
type: 'abap',
destination: config.target?.destination,
appName: config?.flp?.bspName,
languages: config?.flp?.languages?.map((language: { sap: string; i18n: string }) => {
return {
sap: language.sap,
i18n: language.i18n
};
}),
credentials: {
username: user,
password: pass
}
}
}
];
}
22 changes: 22 additions & 0 deletions packages/adp-tooling/src/writer/s4hana.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { join } from 'path';
import { create as createStorage } from 'mem-fs';
import type { Editor } from 'mem-fs-editor';
import { create } from 'mem-fs-editor';

/**
* Writes the s4hana env file to the mem-fs-editor instance.
*
* @param basePath - the base path
* @param data - personal data intended to be exposed as env variables
* @param fs - the memfs editor instance
* @returns the updated memfs editor instance
*/
export async function generateEnv(basePath: string, data: string, fs?: Editor): Promise<Editor> {
nikmace marked this conversation as resolved.
Show resolved Hide resolved
if (!fs) {
fs = create(createStorage());
}

fs.write(join(basePath, '.env'), data);
nikmace marked this conversation as resolved.
Show resolved Hide resolved

return fs;
}
26 changes: 0 additions & 26 deletions packages/adp-tooling/templates/project/package.json

This file was deleted.

This file was deleted.

58 changes: 58 additions & 0 deletions packages/adp-tooling/templates/projects/abap/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
{
"name": "<%= package.name %>",
"version": "0.1.0",<% if (locals.options?.isRunningInBAS && locals.options?.isCloudProject) { %>
"main": "index.js",<% } %>
"private": true,
"description": "<%= package.description %>",
"keywords": [
"ui5",
"sapui5",
"adaptation-project"
],<% if (locals.options?.isRunningInBAS && locals.options?.isCloudProject) { %>
"repository": {
"type": "git",
"build": "ui5.js build --verbose --include-task generateCachebusterInfo"
},
"author": "",
"license": "ISC",
"ui5": {
"dependencies": ["@sap/ui5-builder-webide-extension", "@ui5/task-adaptation"]
},<% } %>
"devDependencies": {
<%if (locals.options?.fioriTools) {%>"@sap/ux-ui5-tooling": "^1.11.4"<%} else {%>"@sap-ux/backend-proxy-middleware": "^0.7.5",
nikmace marked this conversation as resolved.
Show resolved Hide resolved
"@sap-ux/preview-middleware": "^0.11.1",
"@sap-ux/ui5-proxy-middleware": "^1.3.0",
"@sap-ux/deploy-tooling": "^0.11.7"<%}%>,<% if (locals.options?.isRunningInBAS && locals.options?.isCloudProject) { %>
"@sap/ui5-builder-webide-extension": "1.0.x",
"@sapui5/ts-types": "^1.85.1",
"@types/js-yaml": "^4.0.5",
"@types/semver": "^7.3.13",
"@ui5/task-adaptation": "^1.0.10",
"bestzip": "2.1.4",
"rimraf": "3.0.2",<% } %>
"@ui5/cli": "^3.6.0"
},<% if (locals.options?.isRunningInBAS && locals.options?.isCloudProject) { %>
"dependencies": {
"dotenv": "^16.0.3",
"inquirer": "^8.2.5",
"json-diff": "^1.0.6",
"prompt-sync": "^4.2.0",
"prompts": "^2.4.2",
"xml-js": "^1.6.11"
},<% } %>
"scripts": {<% if (locals.options?.isCloudProject) { %>
"build": "ui5 build --include-task=generateCachebusterInfo && npm run zip",
"prebuild": "npm run clean",
"zip": "cd dist && npx bestzip ../<%= package.name %>.zip *",
"clean": "npx rimraf <%= package.name %>.zip dist",
"build-ui5": "npm explore @ui5/task-adaptation && npm run rollup",
"deploy": "npm run build && fiori deploy --config ui5-deploy.yaml && rimraf archive.zip",
"undeploy": "fiori undeploy --config ui5-deploy.yaml",
"deploy-test": "npm run build && fiori deploy --config ui5-deploy.yaml --testMode true"<% } else { %>
"build": "ui5 build --exclude-task generateFlexChangesBundle generateComponentPreload --clean-dest",
"start": "<%= locals.options?.fioriTools ? 'fiori run' : 'ui5 serve' %> --open /test/flp.html#app-preview",
"start-editor": "<%= locals.options?.fioriTools ? 'fiori run' : 'ui5 serve' %> --open /test/adaptation-editor.html"<%if (locals.deploy) {%>,
"deploy": "ui5 build --config ui5-deploy.yaml --exclude-task <%= locals.options?.fioriTools ? 'deploy-to-abap' : 'abap-deploy-task' %> generateFlexChangesBundle generateComponentPreload --clean-dest && <%= locals.options?.fioriTools ? 'fiori deploy' : 'deploy' %> --config ui5-deploy.yaml",
nikmace marked this conversation as resolved.
Show resolved Hide resolved
"undeploy": "<%= locals.options?.fioriTools ? 'fiori undeploy' : 'undeploy' %> --config ui5-deploy.yaml --lrep \"apps/<%= app.reference %>/appVariants/<%= app.id %>/\""<%}%><% } %>
}
}