blog
blog copied to clipboard
Enforcing RPGLE language styles with GitHub Actions, Jenkins, GitLab Runner, and more
RPGLE language tools has come a long way in terms of tooling for Visual Studio Code. Writing RPGLE in VS Code is a reality in 2023 (it was in 2022 as well!) and I am excited to share that RPGLE language tools has been expanded further.
RPGLE language tools' real name is 'vscode-rpgle'. It's always been a VS Code extension. Inside of vscode-rpgle is what we call 'language'. This is the part that parses and lints the RPGLE code.
If you weren't aware, there has been a linter for RPGLE for quite some time. Developers can configure the lint rules in a file called rpglint.json
and then see the lint errors in real time while they edit code.
The linter has always been embedded in vscode-rpgle since it was created. Until now! I am excited to share that the linter is now available as a command: rpglint
. It uses the same code as 'language' from the RPGLE language tools.
rpglint is intended to be used against code that reside in git repositories. You can see use rpglint with source members and streamfiles with RPGLE language tools inside of Visual Studio Code.
How to install the linter CLI?
rpglint can be installed through npm (yes, that means it depends on Node.js). You can see the package on npmjs.com! rpglint is intended to be installed globally and not at a project level. To do that, you can simply run:
npm i @halcyontech/rpglint -g
Now, from any terminal on your device, you can use the rpglint
command. I recommend trying rpglint -h
first:
barrymac:cli barry$ rpglint -h
rpglint (derived from vscode-rpgle).
See who's contributed: https://github.com/halcyon-tech/vscode-rpgle/graphs/contributors
Rules are inherited from the 'rpglint.json' found in the working directory.
This configuration file usually lives in '.vscode/rpglint.json'.
# truncated
This shows the help screen with the available parameters.
But how do I actually use it?
Let's test rpglint with the IBM sample repository, Company System! ibmi-company_system
is available on GitHub and anybody can clone it. For this example, we will clone it to our local device and then run against rpglint against it.
# cd to where the repo will be created
barry$ cd ~/Downloads/
# clone the repository. HTTPS clone should work for everyone
barry$ git clone [email protected]:IBM/ibmi-company_system.git
Cloning into 'ibmi-company_system'...
remote: Enumerating objects: 194, done.
remote: Counting objects: 100% (194/194), done.
remote: Compressing objects: 100% (97/97), done.
remote: Total 194 (delta 96), reused 185 (delta 90), pack-reused 0
Receiving objects: 100% (194/194), 28.16 KiB | 1.56 MiB/s, done.
Resolving deltas: 100% (96/96), done.
# cd into the repository
barry$ cd ibmi-company_system
By default, there are a bunch of errors in this repository. We do this to show off that rpglint works as expected! You can just use rpglint
inside of this directory for the linter to run!
barry$ pwd
~/Downloads/ibmi-company_system
barry$ rpglint
Linting 3 files.
/Users/barry/Downloads/ibmi-company_system/qrpglesrc/employees.pgm.sqlrpgle: 22 errors.
Line 8: expected indent of 0, got 6
Line 12: expected indent of 0, got 6
Line 38: expected indent of 0, got 6
Line 39: expected indent of 0, got 6
Line 45: expected indent of 0, got 8
Line 64: expected indent of 0, got 8
Line 4, column 0: Variable name casing does not match definition.
Line 8, column 6: Comments must be correctly formatted.
Line 10, column 0: Directives must be in uppercase.
Line 12, column 6: Comments must be correctly formatted.
Line 14, column 0: Variable name casing does not match definition.
Line 38, column 6: Comments must be correctly formatted.
Line 39, column 6: Comments must be correctly formatted.
Line 45, column 8: Comments must be correctly formatted.
Line 64, column 8: Comments must be correctly formatted.
Line 74, column 2: Variable name casing does not match definition.
Line 107, column 8: Variable name casing does not match definition.
Line 116, column 2: Variable name casing does not match definition.
Line 141, column 6: Variable name casing does not match definition.
Line 91, column 2: Same string literal used more than once. Consider using a constant instead.
Line 93, column 4: Same string literal used more than once. Consider using a constant instead.
Line 101, column 6: Same string literal used more than once. Consider using a constant instead.
rpglint simply spits out all the issues it finds with the RPGLE code in the repository folder. The intention of a linter is to enforce code standards in a code base. When the linter finds errors, it will have an exit code of 1
and 0
if there are none.
rpglint in your CI process
Because we are able to use rpglint
from the command line, this means we've opened up a totally new world to ourselves. We can now run rpglint
as part of a CI (Continuious Integration) process. For example, here's a GitHub Action .yml
which configures rpglint to run when a PR request is created or updated against the main
branch:
name: rpglint CI
on:
pull_request:
# Set your workflow to run on pull_request events that target the main branch
branches: [ "main" ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18.x]
steps:
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- run: npm i -g rpglint
- run: rpglint
The best part about the rpglint
command is that it returns exit code 1
if there are errors. CI tools (like GitHub Actions, Jenkins, GitLab Runner, etc) can use this status code to determine if the CI was successful. It makes sense that the CI fails if there are lint errors, because it doesn't match the code standard defined in the rpglint.json
.

That's it
I am so excited to share this with people. I hope lots of people have questions!
Hey Liam, This is really awesome. I am really glad to see someone push IBM i RPG modernization. To take this a step further, if the lint parser returns a success, how do we then compile the code on the actual IBM i server? That is the missing piece I can't seem to figure out. I am currently using GitHub to store the new RPG code I am writing, now I just need to figure out how to actually compile on IBM i ?