Overview
AL-Go supports delivery to multiple target types:GitHub Packages
Free NuGet feed provided by GitHub for each organization. Ideal for internal distribution and dependency management.
Custom NuGet Feeds
Azure DevOps Artifacts, private NuGet servers, or other custom NuGet v3 feeds.
Azure Storage
Publish artifacts to Azure Storage accounts for archival or custom distribution workflows.
Microsoft AppSource
Submit applications to Microsoft AppSource for public distribution.
NuGet and GitHub Packages delivery is currently experimental. While stable and used in production, the package structure and configuration may change in future versions.
Delivery Targets Concept
Each delivery target is configured through:- Context Secret: A secret named
<DeliveryTarget>Contextcontaining connection information - Delivery Script: An optional PowerShell script named
DeliverTo<DeliveryTarget>.ps1for custom logic - Settings: Optional configuration in AL-Go settings files
Supported Targets
| Target | Purpose | Context Secret | Status |
|---|---|---|---|
| GitHubPackages | GitHub Packages NuGet feed | GitHubPackagesContext | ✅ Experimental |
| NuGet | Custom NuGet feed | NuGetContext | ✅ Experimental |
| Storage | Azure Storage Account | StorageContext | ✅ Stable |
| AppSource | Microsoft AppSource | AppSourceContext | ✅ Stable |
GitHub Packages Setup
GitHub Packages provides a free NuGet feed for each GitHub organization, making it the recommended approach for most Per-Tenant Extension (PTE) scenarios.Create Personal Access Token
Generate a token with package permissions:
- Navigate to GitHub Personal Access Tokens
- Create a Classic Personal Access Token (fine-grained tokens don’t support packages yet)
- Select the following scopes:
write:packages- Required for publishing packagesread:packages- Required for consuming packagesrepo- Required if your repositories are private
- Set an appropriate expiration date
- Generate and copy the token
Create GitHubPackagesContext Secret
Create an organizational or repository secret:Replace:
- Navigate to Settings → Secrets and variables → Actions
- Click New organization secret (or New repository secret)
- Name:
GitHubPackagesContext - Value: Compressed JSON with token and server URL
<your_token>: Your personal access token<your_org>: Your GitHub organization name
Use the BcContainerHelper function
New-ALGoNuGetContext to generate correctly formatted JSON:Configure Repository Settings (Optional)
Control delivery behavior in your AL-Go settings file:Configuration options:
ContinuousDelivery: Enable automatic delivery on successful buildsBranches: Array of branch patterns that trigger delivery
Consuming GitHub Packages
GitHub Packages are automatically available for dependency resolution. When your apps reference dependencies published to your organization’s GitHub Packages feed, AL-Go will automatically resolve and download them. No additional configuration required - AL-Go uses theGitHubPackagesContext secret for both publishing and consuming packages.
Custom NuGet Feed Setup
For Azure DevOps Artifacts, private NuGet servers, or other custom feeds:Obtain Feed Credentials
Get authentication credentials for your NuGet feed:Azure DevOps:
- Navigate to User Settings → Personal Access Tokens
- Create new token with Packaging: Read & write scope
- Copy the token value
- Use API key or credentials provided by your server administrator
Get Feed URL
Locate your NuGet v3 feed URL:Common formats:
- Azure DevOps:
https://pkgs.dev.azure.com/<org>/<project>/_packaging/<feedName>/nuget/v3/index.json - GitHub Packages:
https://nuget.pkg.github.com/<org>/index.json - NuGet.org:
https://api.nuget.org/v3/index.json - Private server: Contact your administrator
Create NuGetContext Secret
Create a repository or organization secret:Name: Example for Azure DevOps:
NuGetContextValue: Compressed JSON with credentialsConfigure Dependency Resolution (Optional)
Unlike GitHub Packages, custom NuGet feeds are not automatically used for dependency resolution. Add your feed to Parameters:
trustedNuGetFeeds:url: NuGet feed URLauthTokenSecret: Name of the secret containing credentialspatterns: Array of package name patterns (e.g.,["Contoso.*", "Fabrikam.*"])
Configuration Examples
Example 1: GitHub Packages for PTE Organization
Scenario: A company developing Per-Tenant Extensions wants to automatically publish apps to GitHub Packages for internal distribution. Organizational Secret:GitHubPackagesContext
main branch automatically publishes packages to GitHub Packages.
Example 2: Azure DevOps Artifacts for PTE Development
Scenario: A partner with existing Azure DevOps infrastructure wants to deliver PTEs to Azure DevOps Artifacts. Repository Secret:NuGetContext
Example 3: Multi-Environment PTE Setup
Scenario: Publish development builds to GitHub Packages and production releases to a private NuGet feed. Secrets:GitHubPackagesContext: For development buildsNuGetContext: For production releases
- Development branches → GitHub Packages
- Main branch → Private NuGet feed
Example 4: Multiple Feed Configuration
Scenario: Use multiple NuGet feeds for different package sources. AL-Go-Settings.json:Custom Delivery Scripts
For advanced scenarios, create custom delivery scripts to implement specialized delivery logic.Create Delivery Script
Create a PowerShell script in your
.github folder:File: .github/DeliverToCustomFeed.ps1Create Context Secret
Create a secret named Access the secret in your script:
CustomFeedContext with your custom configuration:Script Parameters
Your delivery script receives a hashtable with the following parameters:| Parameter | Type | Description |
|---|---|---|
project | string | Project path (escaped for artifact naming) |
projectName | string | Project name (sanitized for paths) |
type | string | Delivery type: “CD” or “Release” |
appsFolder | string | Path to folder containing .app files |
testAppsFolder | string | Path to test app files (if available) |
dependenciesFolder | string | Path to dependency files (if available) |
appsFolders | string[] | Array of all app folders from different build modes |
testAppsFolders | string[] | Array of all test app folders |
dependenciesFolders | string[] | Array of all dependency folders |
Folder parameters may be
$null if no artifacts of that type were found. Use null checks before accessing folders.Branch-Specific Delivery
Configure different delivery targets for different branches:- Feature branches: Deliver to development feed for testing
- Main branch: Deliver to production feed
- Release branches: Deliver to staging feed for validation
Troubleshooting
Missing Context Secret
Error:
Secret 'GitHubPackagesContext' not foundSolutions:- Verify secret exists at organization or repository level
- Check secret name matches exactly (case-sensitive)
- Ensure repository has access to organization secrets
- Confirm secret is not expired (for PATs)
Authentication Failed
Error:
401 Unauthorized when publishing packagesSolutions:- Verify PAT has correct scopes (
write:packages,read:packages) - Check if token has expired
- Ensure token has access to target organization
- Confirm server URL is correct
- Validate JSON format (must be compressed)
Package Not Found
Error: Unable to find package during dependency resolutionSolutions:
- Verify package was published successfully
- Check
trustedNuGetFeedsconfiguration - Ensure package name matches app.json dependencies
- Confirm package version exists
- Verify feed URL is accessible
Curly Brackets Masked
Error: Seeing
*** instead of JSON in logsSolutions:- Ensure JSON is compressed (single line)
- Remove all newlines and extra whitespace
- Use
New-ALGoNuGetContextto generate correct format - Validate JSON syntax before creating secret
Debugging Steps
Check Workflow Logs
Review the CI/CD workflow for delivery job:
- Navigate to Actions → Select workflow run
- Look for “Deliver to [Target]” job
- Review step outputs for errors
- Check for authentication failures
Verify Package Publication
Confirm packages were published:
- GitHub Packages: Organization → Packages tab
- Azure DevOps: Artifacts → Feed → Packages
- Custom feed: Use feed’s web interface
Test Dependency Resolution
Verify dependency resolution works:
- Check workflow logs for “Resolving Dependencies”
- Look for “Installing app dependencies” messages
- Verify correct package versions are downloaded
- Check for authentication errors
Security Best Practices
Token Scopes
Grant minimum permissions:
- GitHub Packages:
write:packages,read:packagesonly - Azure DevOps: Packaging (Read & Write) scope
- Avoid granting
reposcope unless necessary - Use fine-grained tokens when available
Secret Storage
Use appropriate secret levels:
- Organization secrets for shared feeds
- Repository secrets for project-specific feeds
- Environment secrets for environment-specific delivery
- Azure Key Vault for sensitive credentials
Token Rotation
Regular credential updates:
- Rotate PATs every 90 days
- Set expiration dates on all tokens
- Monitor token usage
- Revoke unused tokens
Access Control
Limit feed access:
- Use dedicated service accounts
- Implement feed permissions
- Audit package access
- Monitor download patterns
Limitations and Considerations
Best Practices
- Use semantic versioning: Follow semver (e.g., 1.2.3) for all packages
- Test in isolation: Validate delivery configuration in test repositories first
- Monitor package sizes: Be aware of feed storage limits
- Document dependencies: Maintain clear dependency documentation
- Implement cleanup: Set up package retention and cleanup policies
- Version consistency: Ensure app.json versions match package versions
- Feed organization: Use separate feeds for dev, test, and production
Next Steps
Continuous Deployment
Learn about automated deployment strategies
Sandbox Environment
Set up sandbox environments for testing
AL-Go Settings
Explore all configuration options
AL-Go Secrets
Learn about secret management