You will learn and create an application-level library in COBOL. You will structure the package, implement automatic tests, deploy on GitHub and enable Continuous Integration workflow. Finally, you will publish the package in the COBOL package registry.
Preconditions
You have learned basic principles, methods and standards of COBOL. In this tutorial we’ll use GnuCOBOL — a free COBOL compiler which implements a substantial part of the COBOL 85, COBOL 2002 and COBOL 2014 standards and X/Open COBOL, as well as many extensions included in other COBOL compilers.
You have Docker, a command-line virtualization tool, installed.
You have NPM, a package manager for JavaScript programming language, installed.
You have Git, an open source distributed version control client, installed.
You have GitHub account for publishing of the package.
You may use any text editor you like, but I recommend Visual Studio Code (or its open-source version VSCodium) with COBOL-syntax extension bitlang.cobol
installed.
Package vs Library
Each programming language has standard set of functions or operators provided by default and included into installation package. In COBOL we call them Intrinsic functions. Intrinsics cover basic programming needs, but we’ve used to extend default set by own functions every time writing something smarter than ´Hello, world!´.
Gradually, custom functions form reusable COBOL libraries, Copybooks, for inclusion into other programs and services on-demand. Thanks to Version Control Systems, contributors are able to effectively cooperate and deliver the libraries to the programmers. The only problem was an integration with external source-code that might be casually written in other COBOL dialect, coding standard or approach. And package management is a solution here.
Similar to other application-level package managers, such as Yarn for JavaScript, Maven for Java, Packagist for PHP, NuGet for C# etc., in 2020 COBOL obtained its own public package manager that standardizes the way the contributors should treat the libraries — COBOLget. The tutorial explains how to create and publish your first COBOL package the modern way.
Specifications
For financial applications we’ll implement banking
package which exposes single iban-checksum
function — an IBAN validator. The function accepts alphanumeric argument and returns numeric value 1
in case of success. The algorithm is as follows:
- Check IBAN length.
- Move the first 4 characters to the end.
- Replace each letter with two digits, where A = 10, B = 11, …, Z = 35.
- Compute the remainder by MOD97 intrinsic function. If the remainder is 1, the checksum is valid.
Structuring
Please create new GitHub repository demo-banking
and copy template of the package to your local copy of the repository. Here’s a structure of the package:
├── Dockerfile
├── .github
│ └── workflows
│ └── docker-image.yml
├── .gitignore
├── modules.json
├── modules-lock.json
├── README.md
├── src
│ └── banking.cbl
└── tests
└── banking-test.cbl
For COBOLget packages Dockerfile, README.md, .gitignore and .workflows are optional, but our library follows Continuous Integration practices, where each modification of the source-code is getting tested on the repository. On each push or pull request GitHub will trigger docker-ci
workflow. In its turn, Docker will download GnuCOBOL image gnucobol2.2
, install COBOLget dependencies from modules-lock.json
and will execute GCBLUnit tests in banking-test.cbl
.
The file modules.json
is a Manifest of the package which describes the library and its dependencies:
{
"name": "demo-banking-FIXME",
"description": "Demo banking package",
"modules": [
"src/banking.cbl"
],
"dialect": "gnucobol",
"licenses": [
"MIT"
],
"authors": [
"FIXME"
],
"dependencies": {},
"dependencies-debug": {
"gcblunit": "*"
}
}
The properties are speaking enough and similar to other package managers. Our package does not use any dependencies, but requires gcblunit
package at any version (by default, the latest available) for development and debugging purposes. Property modules
must contain COBOL modules (programs and functions) for inclusion as a Copybook. Full schema of the Manifest you may find on https://cobolget.com/schema.json.
Let’s install cobolget
command-line tool and validate our package:
$ npm install -g cobolget
$ cobolget validate
An error occurred: Error: "demo-banking-FIXME" does not match to ^[a-z0-9\-]+$
Oops! Please replace FIXME with your GitHub username in README.md, as well as in the Manifest in lower-case, making the package valid and unique in the COBOLget registry. Don’t forget to replace FIXME in the command below as well:
$ cobolget validate
Manifest modules.json is valid.
$ cobolget list demo-banking-FIXME
No matching results.
Well done! The structure of the package is finished. We’ll test our library in the next step.
Testing
The file banking-test.cbl
has 8 GCBLUnit assertions that expect “1” returned by iban-checksum
function. Let’s execute docker-ci
workflow locally, an one-liner
$ docker build --tag package .
As you can see, creation of the Docker image fails on testing phase.
....FFFF
Time: 00:00:00
There was 0000000004 failure(s):
F banking-test #05 assert-equals 1 <> 0
F banking-test #06 assert-equals 1 <> 0
F banking-test #07 assert-equals 1 <> 0
F banking-test #08 assert-equals 1 <> 0
FAILURES!
Tests: 0000000001, Skipped: 0000000000
Assertions: 0000000008, Failures: 0000000004, Exceptions: 0000000000
The command '/bin/sh -c cobc -x -debug modules/gcblunit/gcblunit.cbl tests/* --job='banking-test'' returned a non-zero code: 1
The last 4 of 8 assertions returned “0” instead of expected “1”. Definitely, it’s a false negative result because these numbers have been carefully copied from Wikipedia. :) You may remove inner spaces and try again, but I suggest you to improve iban-checksum
function instead. Spaces are generally acceptable in IBAN and must pass the validation. The best implementation will be included into core COBOLget package under your name. Nevertheless, you may commit and push the package on GitHub and proceed to the next step.
Publishing
Please “release” your package on GitHub by attaching a version tag e.g. 1.2.3
to the commit. COBOLget implements SemVer versioning standard, any other tags will be skipped during the import. Now you can import your package into COBOLget Registry by using index
command, from the command-line or on the website.
$ cobolget index -h
Usage: index [options] <name|url>
Import or update the package in the registry
Options:
-t, --token <token> Repository token for private package
-o, --organization <organization> Organization name for private package
-h, --help output usage information
Newborn packages we index by URL of the repository. Further releases we can index by the name.
$ cobolget index https://github.com/FIXME/demo-banking
Package 'demo-banking-FIXME' has been indexed in the registry.
Your first COBOL package is published on cobolget.com and ready for integration into applications and microservices.
Conclusion
You have created and successfully published your application-level COBOL library in COBOLget format by using Git, Docker, Unit-Testing and Continuous Integration practices. 60-years old COBOL fits modern software engineering.
Are you Wikipedia editor? Please help publish missing article from the sandbox.