Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .github/workflows/github-action-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ jobs:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5.3.0
uses: actions/setup-python@v5.3.1
with:
# Version range or exact version of Python to use, using SemVer's version range syntax. Reads from .python-version if unset.
python-version: '3.10'
Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
rev: v5.0.0
hooks:
- id: check-json
- id: check-yaml
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ It requires the `az bicep` toolchain installed, and uses [`az bicep`](https://gi
## Demo

Example usage of `pre-commit run --all-files` and
`git commit` after hook innstall in git repository `pre-commit install`
`git commit` after hook install in git repository `pre-commit install`

![alt text](https://raw.githubusercontent.com/Azure4DevOps/check-azure-bicep.example/master/example.gif)

Expand Down
9 changes: 7 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@
import sys

def get_project_requirements() -> str:
with open(f"requirements.txt", "r") as f:
with open("requirements.txt", "r") as f:
return f.read()

def get_long_description() -> str:
with open("README.md", "r", encoding="utf-8") as f:
return f.read()

def az_bicep_build():
Expand Down Expand Up @@ -45,7 +49,8 @@ def az_bicep_format():

setuptools.setup(
name="check-azure-bicep-python",
description="check-azure-bicep-python",
description="Pre-commit hooks for Azure Bicep validation with built-in support for GitHub Workflows and Azure Pipelines",
long_description=get_long_description(),
long_description_content_type="text/markdown",
url="https://github.com/Azure4DevOps/check-azure-bicep",
python_requires=">=3.10",
Expand Down
88 changes: 88 additions & 0 deletions tests/test_az_bicep_build.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#!/usr/bin/env python
"""Unit tests for az_bicep_build function."""
import unittest
import sys
Copy link

Copilot AI Nov 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Import of 'sys' is not used.

Suggested change
import sys

Copilot uses AI. Check for mistakes.
from unittest.mock import patch, MagicMock
from checkazurebiceppython import az_bicep_build


class TestAzBicepBuild(unittest.TestCase):
"""Test cases for az_bicep_build function."""

@patch('checkazurebiceppython.subprocess.run')
@patch('checkazurebiceppython.glob.glob')
def test_bicep_build_no_files(self, mock_glob, mock_run):
"""Test bicep build when no bicep files are found."""
mock_glob.return_value = []
mock_run.return_value = MagicMock(stdout="Bicep CLI version 0.4.1008", stderr=b"")
Copy link

Copilot AI Nov 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mock for the version check incorrectly uses stderr=b"" (bytes). Since the actual subprocess.run call uses text=True, stderr should be an empty string "" instead of bytes b"".

Copilot uses AI. Check for mistakes.

# Should not raise any exception when no files found
az_bicep_build()

# Verify version check was called
mock_run.assert_any_call(
["az", "bicep", "version"],
stdout=unittest.mock.ANY,
text=True,
shell=True
)

@patch('checkazurebiceppython.subprocess.run')
@patch('checkazurebiceppython.glob.glob')
def test_bicep_build_successful(self, mock_glob, mock_run):
"""Test bicep build with successful validation."""
mock_glob.return_value = ['./test.bicep']

# Mock version and build calls (no upgrade because -noupgrade is hardcoded)
mock_run.side_effect = [
MagicMock(stdout="Bicep CLI version 0.4.1008", stderr=b""),
Copy link

Copilot AI Nov 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mock for the version check in the side_effect list incorrectly uses stderr=b"" (bytes). Since the actual subprocess.run call uses text=True, stderr should be an empty string "" instead of bytes b"".

Copilot uses AI. Check for mistakes.
MagicMock(stdout=b"Build successful", stderr=b"")
]

# Should complete without error
az_bicep_build()

# Verify build was called for the file
self.assertEqual(mock_run.call_count, 2)

@patch('checkazurebiceppython.subprocess.run')
@patch('checkazurebiceppython.glob.glob')
@patch('builtins.print')
def test_bicep_build_with_errors(self, mock_print, mock_glob, mock_run):
"""Test bicep build with validation errors."""
mock_glob.return_value = ['./test.bicep']

# Mock version and failed build (no upgrade because -noupgrade is hardcoded)
mock_run.side_effect = [
MagicMock(stdout="Bicep CLI version 0.4.1008", stderr=b""),
Copy link

Copilot AI Nov 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mock for the version check in the side_effect list incorrectly uses stderr=b"" (bytes). Since the actual subprocess.run call uses text=True, stderr should be an empty string "" instead of bytes b"".

Copilot uses AI. Check for mistakes.
MagicMock(stdout=b"", stderr=b"Error: Invalid syntax")
]

# Should exit with code 25
with self.assertRaises(SystemExit) as cm:
az_bicep_build()

self.assertEqual(cm.exception.code, 25)

@patch('checkazurebiceppython.subprocess.run')
@patch('checkazurebiceppython.glob.glob')
def test_bicep_build_multiple_files(self, mock_glob, mock_run):
"""Test bicep build with multiple files."""
mock_glob.return_value = ['./test1.bicep', './test2.bicep']

# Mock version and two successful builds (no upgrade because -noupgrade is hardcoded)
mock_run.side_effect = [
MagicMock(stdout="Bicep CLI version 0.4.1008", stderr=b""),
Copy link

Copilot AI Nov 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mock for the version check in the side_effect list incorrectly uses stderr=b"" (bytes). Since the actual subprocess.run call uses text=True, stderr should be an empty string "" instead of bytes b"".

Copilot uses AI. Check for mistakes.
MagicMock(stdout=b"Build successful", stderr=b""),
MagicMock(stdout=b"Build successful", stderr=b"")
]

# Should complete without error
az_bicep_build()

# Verify build was called for both files
self.assertEqual(mock_run.call_count, 3)


if __name__ == '__main__':
unittest.main()
88 changes: 88 additions & 0 deletions tests/test_az_bicep_format.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#!/usr/bin/env python
"""Unit tests for az_bicep_format function."""
import unittest
import sys
Copy link

Copilot AI Nov 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Import of 'sys' is not used.

Suggested change
import sys

Copilot uses AI. Check for mistakes.
from unittest.mock import patch, MagicMock
from checkazurebiceppython import az_bicep_format


class TestAzBicepFormat(unittest.TestCase):
"""Test cases for az_bicep_format function."""

@patch('checkazurebiceppython.subprocess.run')
@patch('checkazurebiceppython.glob.glob')
def test_bicep_format_no_files(self, mock_glob, mock_run):
"""Test bicep format when no bicep files are found."""
mock_glob.return_value = []
mock_run.return_value = MagicMock(stdout="Bicep CLI version 0.4.1008", stderr=b"")
Copy link

Copilot AI Nov 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mock for the version check incorrectly uses stderr=b"" (bytes). Since the actual subprocess.run call uses text=True, stderr should be an empty string "" instead of bytes b"".

Copilot uses AI. Check for mistakes.

# Should not raise any exception when no files found
az_bicep_format()

# Verify version check was called
mock_run.assert_any_call(
["az", "bicep", "version"],
stdout=unittest.mock.ANY,
text=True,
shell=True
)

@patch('checkazurebiceppython.subprocess.run')
@patch('checkazurebiceppython.glob.glob')
def test_bicep_format_successful(self, mock_glob, mock_run):
"""Test bicep format with successful formatting."""
mock_glob.return_value = ['./test.bicep']

# Mock version and format calls (no upgrade because --noupgrade is hardcoded)
mock_run.side_effect = [
MagicMock(stdout="Bicep CLI version 0.4.1008", stderr=b""),
Copy link

Copilot AI Nov 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mock for the version check in the side_effect list incorrectly uses stderr=b"" (bytes). Since the actual subprocess.run call uses text=True, stderr should be an empty string "" instead of bytes b"".

Copilot uses AI. Check for mistakes.
MagicMock(stdout=b"Format successful", stderr=b"")
]

# Should complete without error
az_bicep_format()

# Verify format was called for the file
self.assertEqual(mock_run.call_count, 2)

@patch('checkazurebiceppython.subprocess.run')
@patch('checkazurebiceppython.glob.glob')
@patch('builtins.print')
def test_bicep_format_with_errors(self, mock_print, mock_glob, mock_run):
"""Test bicep format with errors."""
mock_glob.return_value = ['./test.bicep']

# Mock version and failed format (no upgrade because --noupgrade is hardcoded)
mock_run.side_effect = [
MagicMock(stdout="Bicep CLI version 0.4.1008", stderr=b""),
Copy link

Copilot AI Nov 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mock for the version check in the side_effect list incorrectly uses stderr=b"" (bytes). Since the actual subprocess.run call uses text=True, stderr should be an empty string "" instead of bytes b"".

Copilot uses AI. Check for mistakes.
MagicMock(stdout=b"", stderr=b"Error: Invalid file")
]

# Should exit with code 25
with self.assertRaises(SystemExit) as cm:
az_bicep_format()

self.assertEqual(cm.exception.code, 25)

@patch('checkazurebiceppython.subprocess.run')
@patch('checkazurebiceppython.glob.glob')
def test_bicep_format_multiple_files(self, mock_glob, mock_run):
"""Test bicep format with multiple files."""
mock_glob.return_value = ['./test1.bicep', './test2.bicep']

# Mock version and two successful formats (no upgrade because --noupgrade is hardcoded)
mock_run.side_effect = [
MagicMock(stdout="Bicep CLI version 0.4.1008", stderr=b""),
Copy link

Copilot AI Nov 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mock for the version check in the side_effect list incorrectly uses stderr=b"" (bytes). Since the actual subprocess.run call uses text=True, stderr should be an empty string "" instead of bytes b"".

Copilot uses AI. Check for mistakes.
MagicMock(stdout=b"Format successful", stderr=b""),
MagicMock(stdout=b"Format successful", stderr=b"")
]

# Should complete without error
az_bicep_format()

# Verify format was called for both files
self.assertEqual(mock_run.call_count, 3)


if __name__ == '__main__':
unittest.main()
Loading