Skip to content
Open
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
9c737bd
Initial plan
Copilot Feb 16, 2026
d9f710a
Add check to skip delivery when no app artifacts exist
Copilot Feb 16, 2026
1570115
Add skip logic to Deploy action and update release notes
Copilot Feb 16, 2026
9596e4e
Make exit code explicit in Deploy action
Copilot Feb 16, 2026
1c00551
Merge branch 'main' into copilot/fix-deliver-to-blob-storage
mazhelez Feb 17, 2026
67494a5
Refactor delivery and deployment workflows to skip steps when no app …
mazhelez Feb 18, 2026
ae6d218
Merge branch 'main' into copilot/fix-deliver-to-blob-storage
mazhelez Feb 18, 2026
60a16fa
Update release notes and documentation to clarify automatic skip beha…
mazhelez Feb 18, 2026
463560d
Merge branch 'copilot/fix-deliver-to-blob-storage' of https://github.…
mazhelez Feb 18, 2026
7678b81
Merge branch 'main' into copilot/fix-deliver-to-blob-storage
mazhelez Mar 3, 2026
23495bc
Move release notes entry to next release section
Copilot Mar 3, 2026
5542516
Add notices when Deploy and Deliver steps are skipped due to no app a…
Copilot Mar 3, 2026
cb11b6e
Update DeliveryTargets.md to remove inaccurate statements about skip …
Copilot Mar 4, 2026
4fa1f34
Apply suggestion from @Copilot
mazhelez Mar 4, 2026
f76e075
Merge branch 'main' into copilot/fix-deliver-to-blob-storage
mazhelez Mar 4, 2026
6f63340
Merge main and move release notes entry above v9.0 section
Copilot May 1, 2026
0e71474
Merge main and update release notes to position above v9.1
Copilot Jul 9, 2026
1657635
Merge main and update release notes to position above v9.1
Copilot Jul 9, 2026
ee20979
Merge main and resolve conflicts in RELEASENOTES.md
Copilot Jul 13, 2026
de4d82a
Merge branch 'main' into copilot/fix-deliver-to-blob-storage
mazhelez Jul 13, 2026
03bee84
Merge main and move Issue 2126 to top of RELEASENOTES.md
Copilot Jul 17, 2026
6ac3d55
Merge branch 'main' into copilot/fix-deliver-to-blob-storage
mazhelez Jul 20, 2026
e8f3f7d
Revert action downgrades and fix release notes structure
Copilot Jul 20, 2026
341b320
Merge branch 'main' into copilot/fix-deliver-to-blob-storage
mazhelez Jul 23, 2026
576b9a8
Address PR review comments: fix notice injection, remove duplicate sc…
mazhelez Jul 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/agents/Documentation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Documentation Rules

## Important (Should Flag)

1. **Missing RELEASENOTES update**: User-facing changes without a release note entry
1. **Missing documentation for new settings**: New or changed AL-Go settings must be documented in `Scenarios/settings.md` (including purpose, type, default/required status, and which templates/workflows honor them) and represented in the settings schema (`Actions/.Modules/settings.schema.json`) with matching descriptions and correct metadata (`type`, `enum`, `default`, `required`).
1. **Missing documentation for new functions**: New public functions (exported from modules or used as entry points) should include comment-based help (e.g., `.SYNOPSIS`, `.DESCRIPTION`, parameter help) and be described in relevant markdown documentation when they are part of the public surface.
1. **Missing documentation for new workflows or user-facing behaviors**: New or significantly changed workflows/templates in `Templates/` must have corresponding scenario documentation (or updates) in `Scenarios/`, and new user-facing commands or actions must be documented in scenarios or `README.md`.
9 changes: 9 additions & 0 deletions .github/agents/Security.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Security Rules

## Critical (Must Flag)

1. **Missing error handling**: Scripts must start with `$errorActionPreference = "Stop"; $ProgressPreference = "SilentlyContinue"; Set-StrictMode -Version 2.0`
1. **Secret leakage**: Any path where a secret value could appear in logs, error messages, or output without being masked via `::add-mask::`
1. **Path traversal**: File operations that don't validate paths stay within the workspace
1. **Missing `-recurse` on ConvertTo-HashTable**: After `ConvertFrom-Json`, always chain `| ConvertTo-HashTable -recurse` for case-insensitive access
1. **Deprecated settings**: Flag usage of settings listed in `DEPRECATIONS.md`
13 changes: 13 additions & 0 deletions .github/agents/Style.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Style Rules

## Important (Should Flag)

1. **Missing tests**: New or modified functions should have corresponding Pester tests in `Tests/`
1. **Cross-platform issues**: Hardcoded path separators, PS5-only or PS7-only constructs
1. **Encoding omissions**: File read/write without explicit `-Encoding UTF8`
1. **YAML permissions**: Workflows without minimal permission declarations

## Informational (May Flag)

1. Opportunities to use existing helper functions from `AL-Go-Helper.ps1` or shared modules
1. Inconsistent naming (should be PascalCase functions, camelCase variables)
42 changes: 42 additions & 0 deletions .github/agents/code-review.agent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# AL-Go Code Review Agent

You are a code review agent specialized in the AL-Go for GitHub repository. Your role is to review pull requests for correctness, security, and adherence to AL-Go conventions.

## Your Expertise

You are an expert in:

- PowerShell scripting (PS5 and PS7 compatibility)
- GitHub Actions workflows (YAML)
- Business Central extension development patterns
- AL-Go's architecture: actions in `Actions/`, reusable workflows in `Templates/`, tests in `Tests/`

## Review Focus Areas

Detailed rules are organized in separate files:

- **[Security.md](./Security.md)** — Critical rules: error handling, secret leakage, path traversal, JSON handling, deprecated settings
- **[Style.md](./Style.md)** — Style/quality rules: tests, cross-platform, encoding, YAML permissions, naming conventions
- **[Documentation.md](./Documentation.md)** — Documentation rules: RELEASENOTES, settings docs, function docs, workflow/scenario docs

## How to Review

When reviewing changes:

1. Read the PR description to understand intent
1. Check each changed file against the critical and important rules in [Security.md](./Security.md) and [Style.md](./Style.md)
1. Verify that test coverage exists for logic changes
1. Check for deprecated setting usage against `DEPRECATIONS.md`, and ensure any deprecations are documented there with clear replacement guidance and reflected in settings documentation/schema descriptions.
1. Validate that workflows follow the existing patterns in `Templates/`
1. Confirm that any new or modified settings are both documented and added to the schema, with aligned descriptions and correct metadata (type/default/enum/required). See [Documentation.md](./Documentation.md).
1. Confirm that new public functions have appropriate documentation, including accurate comment-based help (parameter names and descriptions kept in sync with the implementation).
1. Confirm that new or significantly changed workflows/templates and other user-facing behaviors are documented in the appropriate scenario files and/or `README.md`, and that any breaking changes are called out in `RELEASENOTES.md`.

## Key Repository Knowledge

- **Settings reference**: `Scenarios/settings.md` describes all AL-Go settings
- **Settings schema**: `Actions/.Modules/settings.schema.json` defines the JSON schema for AL-Go settings
- **Action pattern**: Each action lives in `Actions/<ActionName>/` with an `action.yaml` and PowerShell scripts
- **Template workflows**: `Templates/Per Tenant Extension/` and `Templates/AppSource App/` contain the workflow templates shipped to users
- **Shared modules**: `Actions/.Modules/` contains reusable PowerShell modules
- **Security checks**: `Actions/VerifyPRChanges/` validates that fork PRs don't modify protected files (.ps1, .psm1, .yml, .yaml, CODEOWNERS)
111 changes: 111 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# Copilot Instructions for AL-Go

## Project Overview

AL-Go for GitHub is a set of GitHub Actions and Templates for building, testing, and deploying Business Central extensions using GitHub workflows. It consists of PowerShell actions, reusable YAML workflows, and Pester-based unit tests.

## PowerShell Conventions

### Error Handling

- Every action script must start with the standard header:
```powershell
$errorActionPreference = "Stop"; $ProgressPreference = "SilentlyContinue"; Set-StrictMode -Version 2.0
```
- Use `try/catch/finally` with structured error propagation.
- Check `$LASTEXITCODE` after running external commands.
- Use `Write-Host "::Error::<message>"` for GitHub Actions error annotations.
- Use `Write-Host "::Warning::<message>"` for non-blocking warnings.

### JSON Processing

- Always use `ConvertTo-HashTable -recurse` after `ConvertFrom-Json` to ensure nested objects and arrays are converted to hashtables for consistent access.
- Always specify `-Encoding UTF8` when reading or writing JSON files.

### Function Declarations

- Use PascalCase for function names and camelCase for variables.

### Module Loading

- Import modules with explicit paths: `Join-Path $PSScriptRoot` pattern.
- Use `-Force -DisableNameChecking` for re-imports.

## Security Patterns

### Secret Handling

- Mask secrets with `Write-Host "::add-mask::$secret"` before any output.
- Never log raw secrets; use clean/placeholder URLs in error messages.
- Be aware that secrets in URLs use `${{ secretName }}` syntax — replacement is done before use.
- URL-encode secret values when injecting into URLs.

### Input Sanitization

- Sanitize filenames using `[System.IO.Path]::GetInvalidFileNameChars()`.
- Check for path traversal using `Test-PathWithinWorkspace` or equivalent.
- Sanitize container names with `-replace "[^a-z0-9\-]"`.

### Authentication

- Never hardcode credentials or tokens in source code.
- Use GitHub secrets or Azure KeyVault for credential storage.

## YAML Workflow Conventions

- Declare minimal required permissions (e.g., `contents: read`, `actions: read`).
- Use `defaults.run.shell: pwsh` for cross-platform compatibility.
- Prefix internal environment variables with `_` to distinguish from GitHub context.
- Use `${{ needs.JobName.outputs.key }}` for cross-job communication.
- Add `::Notice::` steps when conditionally skipping workflow steps.

## Testing Requirements

- All new functions must have Pester unit tests in the `Tests/` folder.
- Test files follow the naming convention `*.Test.ps1`.
- Use `Describe`/`It` blocks with descriptive names.
- Mock external dependencies to isolate units under test.
- Tests must pass on both Windows (PowerShell 5) and Linux (PowerShell 7).
- Use `InModuleScope` for testing private module functions.

## Documentation Requirements

- All new or modified AL-Go settings must be:
- Documented in `Scenarios/settings.md` with a clear description, type, default/required status, valid values (e.g., enum), and which templates/workflows honor the setting.
- Added or updated in the settings schema (`Actions/.Modules/settings.schema.json`) with aligned `description`, `type`, `enum`, `default`, and `required` metadata.
- Marked as deprecated in both `Scenarios/settings.md` and the schema description when applicable, with guidance on the replacement setting, and listed in `DEPRECATIONS.md`.
- New public functions (in `.ps1` / `.psm1` files, or used as entry points from workflows) should include comment-based help with at least `.SYNOPSIS` and, when appropriate, `.DESCRIPTION`, `.PARAMETER`, and `.EXAMPLE` blocks. Parameter names and descriptions in the help should stay in sync with the function signature.
- When adding new user-facing behaviors, workflows, or commands:
- Update the relevant scenario(s) under `Scenarios/` or the appropriate `README.md` so users can discover and understand the change.
- Call out breaking changes and notable new capabilities in `RELEASENOTES.md`.

## Deprecated Features

Before using or accepting settings, check `DEPRECATIONS.md` for deprecated settings:

- `unusedALGoSystemFiles` → use `customALGoFiles.filesToExclude`
- `alwaysBuildAllProjects` → use `incrementalBuilds.onPull_Request`
- `<workflow>Schedule` → use `workflowSchedule` with conditional settings
- `cleanModePreprocessorSymbols` → use `preprocessorSymbols` with conditional settings

## Cross-Platform Considerations

- Use `[System.IO.Path]::DirectorySeparatorChar` instead of hardcoded separators.
- Account for PowerShell 5 vs 7 differences (e.g., encoding parameters, `$IsWindows`).
- Use `Replace('\', '/')` for path normalization in URLs and artifact names.

## Pull Request Checklist

When reviewing PRs, verify:

- [ ] Standard error handling header is present in new scripts
- [ ] Secrets are masked before any output
- [ ] JSON is converted with `ConvertTo-HashTable -recurse`
- [ ] File encoding is explicitly specified
- [ ] Unit tests are added or updated
- [ ] RELEASENOTES.md is updated for user-facing changes
- [ ] No deprecated settings are introduced
- [ ] YAML workflows declare minimal permissions
- [ ] Cross-platform compatibility is maintained
- [ ] New or changed settings are documented in `Scenarios/settings.md` and reflected in `Actions/.Modules/settings.schema.json` with consistent metadata
- [ ] New public functions have appropriate comment-based help and any new workflows/user-facing behaviors are documented in scenarios/READMEs
2 changes: 1 addition & 1 deletion .github/workflows/AiIssueTriager.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Setup Node.js
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0

- name: Run AI assessment
id: ai-assessment
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/CI.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
steps:
- name: Harden Runner
if: github.repository_owner == 'microsoft'
uses: step-security/harden-runner@a90bcbc6539c36a85cdfeb73f7e2f433735f215b # v2.15.0
uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0
with:
egress-policy: audit

Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/CleanupTempRepos.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
steps:
- name: Harden Runner
if: github.repository_owner == 'microsoft'
uses: step-security/harden-runner@a90bcbc6539c36a85cdfeb73f7e2f433735f215b # v2.15.0
uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0
with:
egress-policy: audit

Expand All @@ -47,7 +47,7 @@ jobs:
run: |
${{ github.workspace }}/Internal/Scripts/GetOwnerForE2ETests.ps1 -githubOwner $env:githubOwner

- uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1
- uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1
id: app-token
if: ${{ vars.E2E_APP_ID != '' }}
with:
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/Deploy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ jobs:
steps:
- name: Harden Runner
if: github.repository_owner == 'microsoft'
uses: step-security/harden-runner@a90bcbc6539c36a85cdfeb73f7e2f433735f215b # v2.15.0
uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0
with:
egress-policy: audit

Expand Down Expand Up @@ -87,7 +87,7 @@ jobs:
steps:
- name: Harden Runner
if: github.repository_owner == 'microsoft'
uses: step-security/harden-runner@a90bcbc6539c36a85cdfeb73f7e2f433735f215b # v2.15.0
uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0
with:
egress-policy: audit

Expand Down Expand Up @@ -129,7 +129,7 @@ jobs:
steps:
- name: Harden Runner
if: github.repository_owner == 'microsoft'
uses: step-security/harden-runner@a90bcbc6539c36a85cdfeb73f7e2f433735f215b # v2.15.0
uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0
with:
egress-policy: audit

Expand All @@ -154,7 +154,7 @@ jobs:

- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1
- uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1
id: app-token
if: ${{ vars.APP_ID != '' }}
with:
Expand Down Expand Up @@ -214,7 +214,7 @@ jobs:

- name: Create release
if: github.repository_owner == 'microsoft' && needs.Inputs.outputs.createRelease == 'true'
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
id: createrelease
env:
branch: ${{ needs.Inputs.outputs.branch }}
Expand Down
20 changes: 10 additions & 10 deletions .github/workflows/E2E.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ jobs:
steps:
- name: Harden Runner
if: github.repository_owner == 'microsoft'
uses: step-security/harden-runner@a90bcbc6539c36a85cdfeb73f7e2f433735f215b # v2.15.0
uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0
with:
egress-policy: audit

Expand Down Expand Up @@ -120,15 +120,15 @@ jobs:
steps:
- name: Harden Runner
if: github.repository_owner == 'microsoft'
uses: step-security/harden-runner@a90bcbc6539c36a85cdfeb73f7e2f433735f215b # v2.15.0
uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0
with:
egress-policy: audit

- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: ${{ github.event.inputs.ref }}

- uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1
- uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1
id: app-token
with:
app-id: ${{ vars.E2E_APP_ID }}
Expand All @@ -155,15 +155,15 @@ jobs:
steps:
- name: Harden Runner
if: github.repository_owner == 'microsoft'
uses: step-security/harden-runner@a90bcbc6539c36a85cdfeb73f7e2f433735f215b # v2.15.0
uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0
with:
egress-policy: audit

- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: ${{ github.event.inputs.ref }}

- uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1
- uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1
id: app-token
with:
app-id: ${{ vars.E2E_APP_ID }}
Expand Down Expand Up @@ -281,7 +281,7 @@ jobs:
steps:
- name: Harden Runner
if: github.repository_owner == 'microsoft'
uses: step-security/harden-runner@a90bcbc6539c36a85cdfeb73f7e2f433735f215b # v2.15.0
uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0
with:
egress-policy: audit

Expand Down Expand Up @@ -318,7 +318,7 @@ jobs:
steps:
- name: Harden Runner
if: github.repository_owner == 'microsoft'
uses: step-security/harden-runner@a90bcbc6539c36a85cdfeb73f7e2f433735f215b # v2.15.0
uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0
with:
egress-policy: audit

Expand Down Expand Up @@ -355,7 +355,7 @@ jobs:
steps:
- name: Harden Runner
if: github.repository_owner == 'microsoft'
uses: step-security/harden-runner@a90bcbc6539c36a85cdfeb73f7e2f433735f215b # v2.15.0
uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0
with:
egress-policy: audit

Expand Down Expand Up @@ -404,7 +404,7 @@ jobs:
steps:
- name: Harden Runner
if: github.repository_owner == 'microsoft'
uses: step-security/harden-runner@a90bcbc6539c36a85cdfeb73f7e2f433735f215b # v2.15.0
uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0
with:
egress-policy: audit

Expand Down Expand Up @@ -453,7 +453,7 @@ jobs:
steps:
- name: Harden Runner
if: github.repository_owner == 'microsoft'
uses: step-security/harden-runner@a90bcbc6539c36a85cdfeb73f7e2f433735f215b # v2.15.0
uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0
with:
egress-policy: audit

Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/powershell.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
steps:
- name: Harden Runner
if: github.repository_owner == 'microsoft'
uses: step-security/harden-runner@a90bcbc6539c36a85cdfeb73f7e2f433735f215b # v2.15.0
uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0
with:
egress-policy: audit

Expand All @@ -38,6 +38,6 @@ jobs:

# Upload the SARIF file generated in the previous step
- name: Upload SARIF results file
uses: github/codeql-action/upload-sarif@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4.32.4
uses: github/codeql-action/upload-sarif@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2
with:
sarif_file: results.sarif
2 changes: 1 addition & 1 deletion .github/workflows/pre-commit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
steps:
- name: Harden Runner
if: github.repository_owner == 'microsoft'
uses: step-security/harden-runner@a90bcbc6539c36a85cdfeb73f7e2f433735f215b # v2.15.0
uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0
with:
egress-policy: audit

Expand Down
Loading