This is part 4 of 5 TRM related blog articles: Part 1: Introduction Part 2: Install your first package Part 3: Publish your first package Part 4: Dependencies Part 5: Setup a CI/CD pipeline with Github Actions What's a dependency? A dependency is a term used to describe the usage of an external package. Here's an example in the ABAP world: In this example, I created a new package called ZTRM_DEPENDANT and, as you can see, it contains a simple program with a write statement. The problem with this package is that, by itself, it won't work because it's using a method from a class in another package (ZCL_TRM_DEPENDENCY). So if I want to share the source code of this report, I also have to share the source code of the class used, otherwise you'd get a syntax error. The same goes if I have to transport this package to another SAP system. Can you imagine what happens when you have MANY dependencies? I'm sure you too spent some time in STMS logs finding the correct order of packages to transport... To solve this problem, developers declare a list of dependencies - packages needed (beforehand) in order to guarantee the software works as expected. Declaring package dependencies with TRM As explained in the earlier articles, TRM introduces manifests (package descriptors) in ABAP. Although you can always make manual changes, for some objects, dependency recognition is done automatically. I'll try to publish this package, but notice that TRM will not let me continue. In order to declare a dependency, you first have to publish that dependency. To fix the error, I'll first publish the package that contains the class ZCL_TRM_DEPENDENCY, and I'll name this TRM package trm-dependency, version 1.0.0. Now that the class ZCL_TRM_DEPENDENCY is contained in a TRM package, the dependency will be detected, and I can finally publish my package, trm-dependant. Installing a package with dependencies When you install a package with dependencies, TRM will first check if a release within the declared version range exists in the registry (or is already installed in the system) and will try to install that before any other operation. With TRM setup on your system, you can try installing this demo package yourself: run the command trm install trm-dependant you should see a message that explains what dependencies are needed One of the problems that may occur is circular dependencies (which means package A has a dependency with package B, and package B also has a dependency with package A): these situations should be avoided, but steps can always be skipped manually in order to fix this issue. Another scenario is two distinct packages with the same dependency but different version ranges: this is not an easy topic, and it's best discussed in the official documentation. Understanding dependency version costraints In the example above, the dependency with trm-dependency is automatically detected and set to require the package with a release in the constraint ^1.0.0. TRM uses Semantic Versioning, and this constraint means that upon installing trm-dependant, the system needs trm-dependency with a version between 1.0.0 and 2.0.0 (excluded). The reason why "^1.0.0" was chosen during the automatic detection is because TRM assumes that every non major release after 1.0.0 (the version installed on the system during publish of the dependant) doesn't have any breaking changes but rather fixes and minor features. This is to ensure that whenever you install trm-dependant version 1.0.0 you'll have the expected functionalities during its release, but you'll also have the latest non breaking changes version of trm-dependency. It's worth mentioning that dependency version ranges can be changed manually. Verifying dependencies Installing dependencies can be a scary task. In a situation where there are multiple packages required, you may not have the time to check every single one of them and their content. Checksums are introduced to basically ensure that the content of the dependency during the publish is the same during the install. Once a package is published, its checksum cannot be changed. This allows you to install in "safe mode" (perhaps installing open source projects): TRM will install the minimum version of the dependency within the range provided that will match the checksum declared during publish. This, however, is not done by default, as the expected behavior during the installation of dependencies is getting the best match within the declared range, as explained earlier. Dependencies with SAP packages But, are dependency declarations limited to other custom packages? No, they are not! Every time you use an SAP standard object, you are essentially creating a dependency. Because of how complex SAP standard objects are delivered, you can't just assume all the standard objects used by a third-party custom package are available on your target system. These dependencies are called, in TRM, SAP entries: Similar to dependencies, they can be automatically detected, but the only check executed is their availability on the system. Let's make an example: Here I'm using a method from the class /UI2/CL_JSON. This is a standard class, and if we dig into its documentation, we'll find out that it's delivered with the UI2 Add-on for SAP_BASIS 740 – 76X (lucky for us, this has clear documentation, but it's not always this easy 😅). Unfortunately, semantic version is not something in use with SAP standard packages, so all we know is that the UI2 Add-on is required in order to use this class, but setting a range for it would be a challenge. After understanding what dependencies are, we can say that: If I were to copy and paste the source code of this program on a system without the UI2 Add-on, I would get a syntax error because I'm missing the required class. Even if the add-on is installed, we can't guarantee the expected behavior because the versioning used by add-ons is not compatible with semantic versioning. TRM solves point 1 by adding the class /UI2/CL_JSON to the required SAP entries: the expected manifest is ...
"sapEntries": {
"TADIR": [
{
"PGMID": "R3TR",
"OBJECT": "CLAS",
"OBJ_NAME": "/UI2/CL_JSON"
}
]
}
... so during install, a check on the existence of the class is performed. It's not enough, as explained in point 2: the example uses the constant /ui2/cl_json=>pretty_mode-camel_case which was introduced in one of the rather newer versions of the add-on. To fix point 2, you would need to manually fine-tune the JSON in order to execute deeper checks during install of the package. Next blog post: Setting up CI/CD workflows with Github Actions (Part 5). If you want to know more about TRM, check out the official documentation.
... View more