Too bad AppSource rules don’t work for all targets!

In this video, I show how to make Visual Studio Code check your code against a released version to ensure that you’re not creating breaking changes.

https://youtu.be/bHlkspGXXHM

In this video, Erik demonstrates how AppSource’s breaking change validation rules work in AL development for Business Central, and shows how you can leverage these same checks locally during development — even before submitting to AppSource. He also raises an important question: why aren’t these rules available for all targets, not just AppSource apps?

What Is a Breaking Change?

One of the key rules enforced when submitting an app to AppSource is that your update cannot contain a breaking change. A breaking change is any modification to your app that would cause another app — one that has taken a dependency on yours — to break.

This is more intrusive than you might initially think. For example, if someone takes a dependency on any UI component in your app (using addafter, addbefore, addfirst, or addlast), then you cannot remove that UI component once it has been published. The same principle applies to procedures, fields, and many other elements of your app’s public interface.

You might think a change you’re making has no impact, but it very well might. Microsoft checks for these issues during AppSource validation, but you can actually perform these checks yourself during development.

Setting Up Baseline Validation with AppSourceCop

The key to local breaking change detection lies in the appsourcecop.json configuration file. Erik demonstrates this while working on the next version of his Simple Object Designer extension.

The configuration requires four additional properties beyond what you’d normally have:

{
    "baselinePackageCachePath": "./.baseline",
    "name": "Simple Object Designer",
    "publisher": "Your Publisher Name",
    "version": "3.0.0.72"
}

The baselinePackageCachePath points to a folder containing:

  • The latest released AppSource app file
  • All the dependencies that the app has

The name, publisher, and version properties identify the specific baseline release to compare against — in this case, the latest version live on AppSource.

Breaking Change Detection in Action

Deleting a Field

Erik demonstrates by deleting a field from a table. Immediately, the AppSource cop raises an error:

“Field with name ‘Hash Algorithm’ and ID 14 was found in the previous version but is missing in the current version. This might break the upgrade or install of existing installations.”

Changing a Field Type

Even if you don’t delete a field, changing its type is also caught. Erik changes a field from Integer to Text[100], and receives an error indicating that changing the type of a field is not allowed.

Removing an Action from a Page

Erik removes an action called “Config Package” from a setup page. The analyzer catches this as well:

“The action with name ‘Config Package’ defined in page ‘Simple Field Setup’ was found in the previous version but is missing in the current extension. This will break dependencies.”

The reason is straightforward: another extension might be using addafter('Config Package') to anchor their own actions. If that anchor disappears, their app fails. The correct approach is to keep the action but mark it as not visible and obsolete.

Changing Procedure Scope

Erik has a public procedure called CreateRapidStartPackage. Changing its scope from public to local triggers an error — someone might have taken a dependency on your app and be calling that procedure.

Changing Function Signatures

Adding a parameter to an existing public procedure is also detected:

“The number of parameters in this function has changed from 0 to 1. This will break dependencies.”

The correct approach is to keep the original procedure (potentially marking it as obsolete) and add a new overload with the additional parameter:

// Keep the original for backward compatibility
[Obsolete('Use the overload with name parameter instead.')]
procedure CreateRapidStartPackage()
begin
    // Original implementation
end;

// New version with additional parameter
procedure CreateRapidStartPackage(Name: Text)
begin
    // New implementation
end;

This way, the dependency rules are satisfied and you’ve added the new functionality through an overload.

Automating Baseline Updates in Your Pipeline

Erik explains that he has integrated this into his build pipeline. Whenever he runs a release that is tagged to be uploaded to AppSource, the build procedure automatically:

  1. Populates the baseline folder with the newly released artifacts
  2. Updates the appsourcecop.json with the new version number

This means he catches breaking changes during development rather than receiving validation errors from AppSource after submission — saving significant time and frustration.

Design Philosophy: Public First vs. Internal First

This validation has also influenced Erik’s design approach. He admits to historically designing “liberally” — making procedures public by default, thinking they might be useful to others. However, once something is public and released, you can never take it back without introducing a breaking change.

This experience has led him to reconsider: perhaps starting with internal scope (available only within the extension) is a better default, promoting a more deliberate approach to your public API surface.

Why Only AppSource?

The central question Erik raises is: why are these breaking change rules limited to the AppSource target? Per-Tenant Extensions (PTEs) and on-premises apps would benefit equally from this validation. Even if an app isn’t destined for AppSource, it should still be a well-behaving app that avoids nasty upgrade surprises for anyone depending on it.

Erik notes that it would be interesting to explore whether the ruleset.json mechanism could be used to selectively enable or disable specific AppSource cop rules for non-AppSource targets — allowing developers to pick and choose which breaking change checks to enforce regardless of their deployment target.

Conclusion

Setting up baseline validation with AppSourceCop is a powerful technique that catches breaking changes during development rather than during AppSource submission. By pointing your appsourcecop.json to a folder containing your latest released artifacts, you get immediate feedback when you inadvertently modify your app’s public interface. Whether you’re building for AppSource or not, these checks help ensure your apps are well-behaved and upgrade-safe. Give it a try — it could save you a lot of time and headaches.