Skip to content

Commit bb99f6f

Browse files
authored
Merge pull request #114 from IBM/feature/cs_srvpgm
Update multi-module support and add tests
2 parents 01b1545 + 3a020f4 commit bb99f6f

File tree

20 files changed

+1165
-3
lines changed

20 files changed

+1165
-3
lines changed

cli/src/builders/bob.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,18 @@ export class BobProject {
1515
let list: DirectoryTargets = {};
1616

1717
for (let target of targets.getTargets()) {
18+
let dirname: string|undefined;
1819
if (target.relativePath) {
19-
const dirname = path.dirname(target.relativePath);
20+
dirname = path.dirname(target.relativePath);
21+
} else if (target.type === `PGM`) {
22+
// If there is no relative path, this might mean it's a multimodule program
23+
const possibleModule = targets.getTarget({systemName: target.systemName, type: `MODULE`});
24+
if (possibleModule) {
25+
dirname = path.dirname(possibleModule.relativePath);
26+
}
27+
}
28+
29+
if (dirname) {
2030
if (list[dirname] === undefined) list[dirname] = [];
2131

2232
list[dirname].push(target);
@@ -85,7 +95,7 @@ class RulesFile {
8595

8696
const existingLine = this.parsed.find(r => r.target === objName && r.isUserWritten !== true);
8797

88-
const lineContent = `${path.relative(this.subdir, target.relativePath)} ${target.headers ? target.headers.join(` `) + ` ` : ``}${target.deps.filter(d => d.reference !== true).map(d => `${d.systemName}.${d.type}`).join(` `)}`.trimEnd();
98+
const lineContent = `${target.relativePath ? path.relative(this.subdir, target.relativePath) + ' ' : ``}${target.headers ? target.headers.join(` `) + ` ` : ``}${target.deps.filter(d => d.reference !== true).map(d => `${d.systemName}.${d.type}`).join(` `)}`.trimEnd();
8999

90100
if (existingLine) {
91101
existingLine.ogLine = `${objName}: ${lineContent}`;

cli/src/targets.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -979,7 +979,7 @@ export class Targets {
979979
const pathDetail = path.parse(localPath);
980980
// define internal imports
981981
ileObject.imports = cache.procedures
982-
.filter((proc: any) => proc.keyword[`EXTPROC`])
982+
.filter((proc: any) => proc.keyword[`EXTPROC`] && !proc.keyword[`EXPORT`])
983983
.map(ref => {
984984
const keyword = ref.keyword;
985985
let importName: string = ref.name;
@@ -1507,6 +1507,7 @@ export class Targets {
15071507
systemName: currentTarget.systemName,
15081508
imports: currentTarget.imports,
15091509
exports: [],
1510+
headers: currentTarget.headers,
15101511
type: `MODULE`,
15111512
relativePath: basePath,
15121513
extension: path.extname(basePath).substring(1)
@@ -1521,6 +1522,7 @@ export class Targets {
15211522
// Clean up imports for module and program
15221523
newModTarget.imports = currentTarget.imports;
15231524
currentTarget.imports = undefined;
1525+
currentTarget.headers = undefined;
15241526

15251527
this.createOrAppend(currentTarget, newModule);
15261528
}

cli/src/utils.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ export function getSystemNameFromPath(inputName: string) {
2727
name = parts[1];
2828
}
2929

30+
if (baseName.toUpperCase().endsWith(`.TEST`)) {
31+
name = name.substring(0, name.length - 5);
32+
}
33+
3034
// We start the system name with the suppliedPrefix
3135
let systemName = prefix;
3236

cli/test/cs_srvpgm.test.ts

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import { beforeAll, describe, expect, test } from 'vitest';
2+
3+
import { Targets } from '../src/targets'
4+
import { MakeProject } from '../src/builders/make';
5+
import { setupFixture } from './fixtures/projects';
6+
import { ReadFileSystem } from '../src/readFileSystem';
7+
import { BobProject } from '../src/builders/bob';
8+
9+
describe(`pseudo tests`, () => {
10+
const project = setupFixture(`cs_srvpgm`);
11+
12+
const fs = new ReadFileSystem();
13+
const targets = new Targets(project.cwd, fs);
14+
let make: MakeProject;
15+
16+
beforeAll(async () => {
17+
project.setup();
18+
await targets.loadProject();
19+
20+
expect(targets.getTargets().length).toBeGreaterThan(0);
21+
targets.resolveBinder();
22+
23+
make = new MakeProject(project.cwd, targets);
24+
});
25+
26+
test(`That test files are understood`, () => {
27+
expect(targets).toBeDefined();
28+
29+
const testModule = targets.getTarget({systemName: `EMPTEST`, type: `MODULE`});
30+
expect(testModule).toBeDefined();
31+
32+
expect(testModule.deps.length).toBe(3);
33+
expect(testModule.deps.find(f => f.systemName === `EMPLOYEE`)).toBeDefined();
34+
expect(testModule.deps.find(f => f.systemName === `DEPARTMENT`)).toBeDefined();
35+
expect(testModule.deps.find(f => f.systemName === `EMPDET`)).toBeDefined();
36+
});
37+
38+
test('Deps are picked up for the module', () => {
39+
const empdet = targets.getTarget({systemName: `EMPDET`, type: `MODULE`});
40+
expect(empdet).toBeDefined();
41+
42+
expect(empdet.deps.length).toBe(2);
43+
expect(empdet.deps.find(f => f.systemName === `EMPLOYEE`)).toBeDefined();
44+
expect(empdet.deps.find(f => f.systemName === `DEPARTMENT`)).toBeDefined();
45+
46+
const employees = targets.getTarget({systemName: `EMPLOYEES`, type: `PGM`});
47+
expect(employees).toBeDefined();
48+
49+
expect(employees.deps.length).toBe(4);
50+
expect(employees.deps.find(f => f.systemName === `EMPLOYEES` && f.type === `MODULE`)).toBeDefined();
51+
expect(employees.deps.find(f => f.systemName === `EMPDET` && f.type === `MODULE`)).toBeDefined();
52+
expect(employees.deps.find(f => f.systemName === `EMPS` && f.type === `FILE`)).toBeDefined();
53+
expect(employees.deps.find(f => f.systemName === `EMPLOYEE` && f.type === `FILE`)).toBeDefined();
54+
});
55+
56+
test('ibmi-bob rules', () => {
57+
const bobProject = new BobProject(targets);
58+
59+
const files = bobProject.createRules();
60+
61+
expect(files[`Rules.mk`]).toBeDefined();
62+
expect(files[`Rules.mk`]).toBe(`SUBDIRS = qddssrc qrpglesrc qtestsrc`);
63+
64+
expect(files[`qtestsrc/Rules.mk`]).toBe(`EMPTEST.MODULE: emptest.test.sqlrpgle qrpgleref/empdet.rpgleinc EMPLOYEE.FILE DEPARTMENT.FILE EMPDET.MODULE`)
65+
66+
console.log(files[`qrpglesrc/Rules.mk`]);
67+
expect(files[`qrpglesrc/Rules.mk`]).toContain(`EMPLOYEES.MODULE: employees.pgm.sqlrpgle qrpgleref/constants.rpgleinc qrpgleref/empdet.rpgleinc`);
68+
expect(files[`qrpglesrc/Rules.mk`]).toContain(`EMPLOYEES.PGM: EMPLOYEE.FILE EMPS.FILE EMPDET.MODULE EMPLOYEES.MODULE`);
69+
});
70+
71+
test('makefile', () => {
72+
const makefile = new MakeProject(targets.getCwd(), targets);
73+
74+
const contents = makefile.getMakefile().join(`\n`);
75+
76+
expect(contents).toContain(`$(PREPATH)/EMPLOYEES.PGM:`);
77+
expect(contents).toContain(`system "CRTPGM PGM($(BIN_LIB)/EMPLOYEES) ENTMOD(EMPLOYEES) MODULE(EMPDET EMPLOYEES) TGTRLS(*CURRENT) BNDDIR($(BNDDIR)) ACTGRP(*NEW)" > .logs/employees.splf`);
78+
});
79+
});
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
--https://www.ibm.com/docs/en/i/7.3?topic=tables-department-table-department
2+
3+
CREATE OR REPLACE TABLE DEPARTMENT
4+
(DEPTNO CHAR(3) NOT NULL,
5+
DEPTNAME VARCHAR(36) NOT NULL,
6+
MGRNO CHAR(6) NOT NULL,
7+
ADMRDEPT CHAR(3) NOT NULL,
8+
LOCATION CHAR(16) NOT NULL,
9+
PRIMARY KEY (DEPTNO));
10+
11+
ALTER TABLE DEPARTMENT
12+
ADD FOREIGN KEY ROD (ADMRDEPT)
13+
REFERENCES DEPARTMENT
14+
ON DELETE CASCADE;
15+
16+
-- Remove circular reference
17+
--ALTER TABLE DEPARTMENT
18+
-- ADD FOREIGN KEY RDE (MGRNO)
19+
-- REFERENCES EMPLOYEE
20+
-- ON DELETE SET NULL;
21+
22+
-- CREATE UNIQUE INDEX XDEPT1
23+
-- ON DEPARTMENT (DEPTNO);
24+
25+
-- CREATE INDEX XDEPT2
26+
-- ON DEPARTMENT (MGRNO);
27+
28+
-- CREATE INDEX XDEPT3
29+
-- ON DEPARTMENT (ADMRDEPT);
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
A INDARA
2+
A CA03(03)
3+
A R SFLDTA SFL
4+
A RRN 4Y 0H
5+
A* DISPLAY DTA
6+
A XSEL 1A B 7 8
7+
A XID 3A O 7 12
8+
A XNAME 38A O 7 16
9+
A* COLOR HELLO
10+
A R SFLCTL SFLCTL(SFLDTA)
11+
A SFLPAG(0014)
12+
A SFLSIZ(9999)
13+
A OVERLAY
14+
A 85 SFLDSPCTL
15+
A 95 SFLDSP
16+
A N85 SFLCLR
17+
A SFLRRN 4S 0H SFLRCDNBR(CURSOR)
18+
A*
19+
A 6 6'Opt'
20+
A DSPATR(HI)
21+
A DSPATR(UL)
22+
A 6 12'ID'
23+
A DSPATR(HI)
24+
A DSPATR(UL)
25+
A 6 16'Name'
26+
A DSPATR(UL)
27+
A COLOR(WHT)
28+
A R FOOTER_FMT
29+
A OVERLAY
30+
A 3 6'F3=Exit'
31+
A COLOR(BLU)
32+
A 2 35'Departments'
33+
A DSPATR(UL)
34+
A COLOR(WHT)
35+
A 4 6'5=View 8=New Employee'
36+
A COLOR(BLU)
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
-- https://www.ibm.com/docs/en/i/7.3?topic=tables-employee-table-employee
2+
3+
CREATE OR REPLACE TABLE EMPLOYEE
4+
(EMPNO CHAR(6) NOT NULL,
5+
FIRSTNME VARCHAR(12) NOT NULL,
6+
MIDINIT CHAR(1) NOT NULL,
7+
LASTNAME VARCHAR(15) NOT NULL,
8+
WORKDEPT CHAR(3) ,
9+
PHONENO CHAR(4) ,
10+
HIREDATE DATE ,
11+
JOB CHAR(8) ,
12+
EDLEVEL SMALLINT NOT NULL,
13+
SEX CHAR(1) ,
14+
BIRTHDATE DATE ,
15+
SALARY DECIMAL(9,2) ,
16+
BONUS DECIMAL(9,2) ,
17+
COMM DECIMAL(9,2) ,
18+
PRIMARY KEY (EMPNO));
19+
20+
-- Remove circular reference
21+
-- ALTER TABLE EMPLOYEE
22+
-- ADD FOREIGN KEY RED (WORKDEPT)
23+
-- REFERENCES DEPARTMENT
24+
-- ON DELETE SET NULL;
25+
26+
ALTER TABLE EMPLOYEE
27+
ADD CONSTRAINT NUMBER
28+
CHECK (PHONENO >= '0000' AND PHONENO <= '9998');
29+
30+
-- CREATE UNIQUE INDEX XEMP1
31+
-- ON EMPLOYEE (EMPNO);
32+
33+
-- CREATE INDEX XEMP2
34+
-- ON EMPLOYEE (WORKDEPT);
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
A INDARA
2+
A CA12(12)
3+
A R SFLDTA SFL
4+
A RRN 4Y 0H
5+
A* DISPLAY DTA
6+
A XSEL 1A B 7 8
7+
A XID 6A O 7 12
8+
A XNAME 30A O 7 20
9+
A XJOB 8A O 7 52
10+
A* COLOR HELLO
11+
A R SFLCTL SFLCTL(SFLDTA)
12+
A SFLPAG(0014)
13+
A SFLSIZ(9999)
14+
A OVERLAY
15+
A 85 SFLDSPCTL
16+
A 95 SFLDSP
17+
A N85 SFLCLR
18+
A SFLRRN 4S 0H SFLRCDNBR(CURSOR)
19+
A*
20+
A 6 6'Opt'
21+
A DSPATR(HI)
22+
A DSPATR(UL)
23+
A 6 12'ID'
24+
A DSPATR(HI)
25+
A DSPATR(UL)
26+
A 6 20'Name'
27+
A DSPATR(UL)
28+
A COLOR(WHT)
29+
A 6 52'Job'
30+
A DSPATR(UL)
31+
A COLOR(WHT)
32+
A 5 52'Total'
33+
A DSPATR(UL)
34+
A COLOR(WHT)
35+
A XTOT 9S 2O 5 61
36+
A R FOOTER_FMT
37+
A OVERLAY
38+
A 3 06'F12=Back'
39+
A COLOR(BLU)
40+
A 2 35'Employees'
41+
A DSPATR(UL)
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
A INDARA
2+
A CA12(12)
3+
A R DETAIL
4+
A 6 10'ID'
5+
A DSPATR(HI)
6+
A DSPATR(UL)
7+
A XID 6A O 6 14
8+
9+
A 7 7'First'
10+
A DSPATR(UL)
11+
A COLOR(WHT)
12+
A XFIRST 12A B 7 14
13+
14+
A 8 5'Initial'
15+
A DSPATR(UL)
16+
A COLOR(WHT)
17+
A XINIT 1A B 8 14
18+
19+
A 9 8'Last'
20+
A DSPATR(UL)
21+
A COLOR(WHT)
22+
A XLAST 15A B 9 14
23+
24+
A 10 2'Department'
25+
A DSPATR(UL)
26+
A COLOR(WHT)
27+
A XDEPT 3A O 10 14
28+
29+
A 11 9'Job'
30+
A DSPATR(UL)
31+
A COLOR(WHT)
32+
A XJOB 8A B 11 14
33+
34+
A 12 6'Salary'
35+
A DSPATR(UL)
36+
A COLOR(WHT)
37+
A XSAL 10A B 12 14
38+
39+
A 13 7'Phone'
40+
A DSPATR(UL)
41+
A COLOR(WHT)
42+
A XTEL 4A B 13 14
43+
44+
A XERR 50A O 15 14COLOR(RED)
45+
A R HEADER_FMT
46+
A OVERLAY
47+
A 3 06'F12=Back Enter=Create'
48+
A COLOR(BLU)
49+
A 2 33'New Employee'
50+
A DSPATR(UL)
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
-------------------------------------------------------------------------------
2+
-- This procedure will create 5 records into the department table
3+
-------------------------------------------------------------------------------
4+
5+
create or replace procedure popdept()
6+
language sql
7+
Result Sets 0
8+
Modifies SQL Data
9+
Specific popdept
10+
begin
11+
declare i int default 1;
12+
declare deptno char(3);
13+
declare deptname varchar(36);
14+
declare mgrno char(6);
15+
declare admrdept char(3);
16+
declare loc char(16);
17+
18+
while i <= 5 do
19+
-- Generate random data (you can adjust this as needed)
20+
set deptno = right('000' || cast(rand()*1000 as int), 3);
21+
set mgrno = right('00000' || cast(rand()*1000000 as int), 6);
22+
set admrdept = right('000' || cast(rand()*1000 as int), 3);
23+
set loc = 'Location ' || deptno;
24+
25+
-- Assign department names based on specified categories
26+
case
27+
when i = 1 then set deptname = 'Admin';
28+
when i = 2 then set deptname = 'IT';
29+
when i = 3 then set deptname = 'Finance';
30+
when i = 4 then set deptname = 'Management';
31+
when i = 5 then set deptname = 'HR';
32+
end case;
33+
34+
-- Insert into department table
35+
insert into department (deptno, deptname, mgrno, admrdept, location)
36+
values (deptno, deptname, mgrno, admrdept, loc) with nc;
37+
38+
set i = i + 1;
39+
end while;
40+
end;

0 commit comments

Comments
 (0)