Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
125 commits
Select commit Hold shift + click to select a range
f45f491
[WIP] Submitting new properties during upgrade
Dec 10, 2025
52de907
fix(ui): Handle conditional properties in upgrade form
google-labs-jules[bot] Dec 10, 2025
25ded79
fix(ui): Handle conditional properties in upgrade form
google-labs-jules[bot] Dec 10, 2025
27552bc
Merge pull request #1 from JC-wk/fix/upgrade-conditional-properties-1…
JC-wk Dec 10, 2025
59bbaa4
support all types of template
Dec 11, 2025
1797f33
show properties to be removed
Dec 11, 2025
01f3245
remove logging
Dec 11, 2025
4b66ea5
update warning message
Dec 12, 2025
f6c044e
add capability to remove properties that no longer exist in the template
Dec 12, 2025
d06037d
add tests and resolve issue causing failing test
Dec 15, 2025
7ad0a7a
update changelog
Dec 16, 2025
a272677
cache currrent template
Dec 16, 2025
0d9313c
Merge branch 'main' into template-upgrade-properties
JC-wk Dec 16, 2025
b02794e
Add test
Dec 19, 2025
e99a78f
fix ws template auth
Dec 22, 2025
31f3dfb
Merge branch 'main' into template-upgrade-properties
JC-wk Dec 24, 2025
1d0b51b
ui version bump
Dec 24, 2025
ce1f5b2
Merge branch 'main' into template-upgrade-properties
JC-wk Jan 5, 2026
2ec1049
bump version
Jan 5, 2026
89747c5
Merge branch 'main' into template-upgrade-properties
JC-wk Jan 9, 2026
d6b61c8
fix: use correct auth
Jan 13, 2026
aa48f11
test: enhance ConfirmUpgradeResource tests for template fetching and …
Jan 14, 2026
62af590
update test
Jan 15, 2026
fdf3589
add method to extract pipeline properties for resource validation
Jan 16, 2026
e85b25c
add tests
Jan 16, 2026
9f733ab
update api version
Jan 16, 2026
710fb3c
Add ESLint config file paths for validation
JC-wk Jan 20, 2026
43b5b02
Merge branch 'microsoft:main' into main
JC-wk Jan 22, 2026
ef84720
allow property substitution without an update to the parent workspace…
Jan 27, 2026
7b9025a
use .allOf property
Jan 27, 2026
76854fb
Merge branch 'microsoft:main' into main
JC-wk Jan 27, 2026
57e1f48
Merge remote-tracking branch 'TREfork/main' into template-upgrade-pro…
Jan 27, 2026
78d2142
Merge remote-tracking branch 'TREfork/main' into template-upgrade-pro…
Jan 29, 2026
c2cfe44
Merge branch 'main' into template-upgrade-properties
JC-wk Feb 3, 2026
dbaef80
update versions
Feb 3, 2026
47c941d
filter out properties set via pipeliine
Feb 3, 2026
9b37fe6
revert allOf change
Feb 3, 2026
675418b
revert tests
Feb 3, 2026
9151b26
correctly revert tests
Feb 3, 2026
e7ac285
Merge branch 'main' into template-upgrade-properties
JC-wk Feb 6, 2026
4c9235e
changelog
Feb 6, 2026
519d21f
api ver
Feb 6, 2026
a58e209
fix lint
Feb 6, 2026
6cf3d32
Merge branch 'main' into template-upgrade-properties
JC-wk May 22, 2026
3310542
update version
May 22, 2026
be4d3c6
Fix PR suggestions from copilot
Jun 9, 2026
abf2088
apply copilot sec fix
Jun 9, 2026
4eca9fe
implplement copilot suggestions
Jun 9, 2026
8d0dca0
Guarded the allOf attribute lookup in resources.py using Python's …
Jun 9, 2026
dc1714f
Merge branch 'main' into template-upgrade-properties
JC-wk Jun 9, 2026
d8a9faf
Merge branch 'main' into template-upgrade-properties
JC-wk Jun 24, 2026
61ed43d
Merge branch 'main' into template-upgrade-properties
JC-wk Jun 30, 2026
deb79af
Merge branch 'main' into template-upgrade-properties
JC-wk Jul 3, 2026
4ee4ddd
Bump version to 0.25.27
JC-wk Jul 3, 2026
92f06c9
Merge branch 'main' into template-upgrade-properties
JC-wk Jul 3, 2026
f73c2d4
Bump version to 0.8.28 in package.json and package-lock.json
Jul 7, 2026
6f3cf2b
Merge branch 'main' into template-upgrade-properties
JC-wk Jul 21, 2026
61c5e2c
formatting
Jul 24, 2026
ba7230e
Merge remote-tracking branch 'TREfork/main' into template-upgrade-pro…
Jul 24, 2026
899204c
address pr feedback
Jul 24, 2026
c388e14
bump version to 0.25.30
Jul 24, 2026
05f9cd8
Updated test_resource_repository.py to align template os_image optio…
Jul 24, 2026
f454fc3
1. Comprehensive old_template_properties Extraction:
Jul 24, 2026
10f1c5d
Enhance resource template property handling during upgrades
Jul 24, 2026
9f68ee7
Refactor schema upgrade utilities and enhance ConfirmUpgradeResource …
Jul 24, 2026
9dd4dab
Implement nested property removal in patch_resource and add E2E tests…
Jul 24, 2026
f51fda5
Enhance resource patch validation to support nested properties and im…
Jul 24, 2026
77f3e08
Update test to validate patch with Windows 11 OS image for resource p…
Jul 24, 2026
80de092
updated the test to use an admin token when fetching the workspace se…
Jul 24, 2026
a71aca2
fix copilot suggestions
Jul 24, 2026
0747d45
address copilot comments
Jul 24, 2026
ecf8fbf
Refactor tests to remove unnecessary mocks for resource template repo…
Jul 24, 2026
14b568a
Refactor collectConditionalKeys to use type guard for required proper…
Jul 24, 2026
5d7c845
rem e2e
Jul 24, 2026
674c059
copilot suggestion
Jul 24, 2026
efb8e91
Merge branch 'main' into template-upgrade-properties
JC-wk Jul 30, 2026
2c19f23
Merge branch 'main' into template-upgrade-properties
JC-wk Jul 31, 2026
ef38d82
Merge branch 'main' into template-upgrade-properties
JC-wk Jul 31, 2026
e01580e
### Summary of Changes
Jul 31, 2026
530400f
address copilot review
Jul 31, 2026
d5995d7
1. Enum Property Value Prefilling (ConfirmUpgradeResource.tsx):
Jul 31, 2026
5b437bd
feat: implement deep dictionary update method and add corresponding t…
Jul 31, 2026
5a34c22
1. ui/app/src/components/shared/ConfirmUpgradeResource.tsx & ui/app/…
Jul 31, 2026
b54c4d7
add test
Jul 31, 2026
1a5bffd
fix: handle component unmount during schema fetch to prevent state up…
Jul 31, 2026
8cd5ab1
fix: enhance validation for resource patch properties to distinguish …
Jul 31, 2026
8df8554
fix: update modal blocking behavior and enhance effect dependencies f…
Jul 31, 2026
0a7a287
fix: enhance logic for identifying removed properties in resource upg…
Jul 31, 2026
126752d
fix: update get_nested_val return type and enhance validation logic f…
Aug 3, 2026
51904a0
fix: implement deep merge for resource patch properties and enhance v…
Aug 3, 2026
7d59ead
fix: enhance property merging logic to include system properties and …
Aug 3, 2026
62ae961
fix: enhance validation logic to reject modifications of system prope…
Aug 3, 2026
dd06b7f
test: add validation for enum property updates during template upgrades
Aug 3, 2026
77101bd
fix: update _get_pipeline_properties to use set for unique property n…
Aug 3, 2026
df8b369
fix: enhance resource patch validation to allow retained system prope…
Aug 3, 2026
c858ab2
test: add validation to reject empty object for non-updateable proper…
Aug 3, 2026
68d9b20
feat: enhance resource upgrade logic and validation for new propertie…
Aug 3, 2026
7f475fb
feat: add form error handling and validation for resource upgrade pro…
Aug 3, 2026
d040f3a
fix: update nested value setting logic to handle required properties …
Aug 3, 2026
8cd29d5
feat: add additional fields to resource template schema for enhanced …
Aug 3, 2026
ee417c6
feat: enhance property validation logic in ConfirmUpgradeResource com…
Aug 3, 2026
de8ef84
feat: enhance schema property handling and pruning logic in resource …
Aug 3, 2026
554d1b4
feat: enhance resource upgrade logic to correctly prune empty contain…
Aug 3, 2026
f8611ca
copilot fixes
Aug 3, 2026
ae33eed
feat: simplify property extraction logic in ConfirmUpgradeResource an…
Aug 3, 2026
b4f7cc6
feat: enhance ConfirmUpgradeResource form with live validation
Aug 3, 2026
2227ccf
feat: update ConfirmUpgradeResource to enhance property handling and …
Aug 4, 2026
596167f
feat: update version numbers and enhance ConfirmUpgradeResource funct…
Aug 4, 2026
8237f81
feat: enhance resource patching to support full array items during up…
Aug 4, 2026
fff3447
feat: enhance schema upgrade logic to support pruning of undeclared n…
Aug 4, 2026
e5cc5dc
feat: enhance resource handling by improving array property indexing …
Aug 4, 2026
257e465
feat: enhance resource patch validation to support newly required arr…
Aug 4, 2026
f35a7b8
Potential fix for pull request finding
JC-wk Aug 17, 2026
713aee6
Potential fix for pull request finding
JC-wk Aug 17, 2026
2506751
feat: improve conditional property handling during template upgrades
Aug 18, 2026
d2caf70
Merge branch 'template-upgrade-properties' of https://github.com/JC-w…
Aug 18, 2026
07f2f30
feat: enhance template upgrade validation and property handling
Aug 19, 2026
d49589c
feat: enhance resource upgrade handling and schema property resolution
Aug 19, 2026
44d067c
Merge branch 'main' into template-upgrade-properties
Aug 19, 2026
f6ecbbd
fix changelog
Aug 19, 2026
e3633cf
fix: preserve array item properties during template upgrades
Aug 20, 2026
5ed728b
Merge branch 'main' into template-upgrade-properties
JC-wk Aug 20, 2026
d5c9ba6
fix: handle nested conditional properties during template upgrades
Aug 20, 2026
56e4d80
Merge branch 'template-upgrade-properties' of https://github.com/JC-w…
Aug 20, 2026
b17e21d
fix: preserve nested properties during template upgrades
Aug 21, 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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
**BREAKING CHANGES**

ENHANCEMENTS:
* Allow new template properties to be specified during template upgrades. Remove Template properties that no longer exist. ([#4783](https://github.com/microsoft/AzureTRE/pull/4783))

## (0.29.0) (August 14, 2026)
**BREAKING CHANGES**
Expand Down
2 changes: 1 addition & 1 deletion api_app/_version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.26.5"
__version__ = "0.27.0"
657 changes: 620 additions & 37 deletions api_app/db/repositories/resources.py

Large diffs are not rendered by default.

10 changes: 6 additions & 4 deletions api_app/tests_ma/test_api/test_routes/test_shared_services.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from models.domain.resource import ResourceHistoryItem

from tests_ma.test_api.conftest import create_admin_user, create_test_user
from .test_workspaces import FAKE_CREATE_TIMESTAMP, FAKE_UPDATE_TIMESTAMP, OPERATION_ID, sample_resource_operation
from .test_workspaces import FAKE_CREATE_TIMESTAMP, FAKE_UPDATE_TIMESTAMP, OPERATION_ID, sample_resource_operation, sample_resource_template

from db.errors import EntityDoesNotExist
from models.domain.shared_service import SharedService
Expand Down Expand Up @@ -44,7 +44,9 @@ def sample_shared_service(shared_service_id=SHARED_SERVICE_ID):
'description': 'desc here',
'overview': 'overview here',
'private_field_1': 'value_1',
'private_field_2': 'value_2'
'private_field_2': 'value_2',
'title': 'A display name',
'os_image': 'Windows 11'
},
resourcePath=f'/shared-services/{shared_service_id}',
updatedWhen=FAKE_CREATE_TIMESTAMP,
Expand Down Expand Up @@ -220,7 +222,7 @@ async def test_patch_shared_service_patches_shared_service(self, _, update_item_
@patch("api.routes.shared_services.ResourceHistoryRepository.save_item", return_value=AsyncMock())
@patch("api.routes.shared_services.SharedServiceRepository.get_timestamp", return_value=FAKE_UPDATE_TIMESTAMP)
@patch("api.dependencies.shared_services.SharedServiceRepository.get_shared_service_by_id", return_value=sample_shared_service(SHARED_SERVICE_ID))
@patch("api.routes.shared_services.ResourceTemplateRepository.get_template_by_name_and_version", return_value=sample_shared_service())
@patch("api.routes.shared_services.ResourceTemplateRepository.get_template_by_name_and_version", return_value=sample_resource_template())
@patch("api.routes.shared_services.SharedServiceRepository.update_item_with_etag", return_value=sample_shared_service())
@patch("api.routes.shared_services.send_resource_request_message", return_value=sample_resource_operation(resource_id=SHARED_SERVICE_ID, operation_id=OPERATION_ID))
async def test_patch_shared_service_with_upgrade_minor_version_patches_shared_service(self, _, update_item_mock, __, ___, ____, _____, app, client):
Expand All @@ -242,7 +244,7 @@ async def test_patch_shared_service_with_upgrade_minor_version_patches_shared_se
@patch("api.routes.shared_services.ResourceHistoryRepository.save_item", return_value=AsyncMock())
@patch("api.routes.shared_services.SharedServiceRepository.get_timestamp", return_value=FAKE_UPDATE_TIMESTAMP)
@patch("api.dependencies.shared_services.SharedServiceRepository.get_shared_service_by_id", return_value=sample_shared_service(SHARED_SERVICE_ID))
@patch("api.routes.shared_services.ResourceTemplateRepository.get_template_by_name_and_version", return_value=sample_shared_service())
@patch("api.routes.shared_services.ResourceTemplateRepository.get_template_by_name_and_version", return_value=sample_resource_template())
@patch("api.routes.shared_services.SharedServiceRepository.update_item_with_etag", return_value=sample_shared_service())
@patch("api.routes.shared_services.send_resource_request_message", return_value=sample_resource_operation(resource_id=SHARED_SERVICE_ID, operation_id=OPERATION_ID))
async def test_patch_shared_service_with_upgrade_major_version_and_force_update_patches_shared_service(self, _, update_item_mock, __, ___, ____, _____, app, client):
Expand Down
51 changes: 43 additions & 8 deletions api_app/tests_ma/test_api/test_routes/test_workspaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,11 @@ def sample_workspace(workspace_id=WORKSPACE_ID, auth_info: dict = {}) -> Workspa
properties={
"client_id": "12345",
"scope_id": "test_scope_id",
"sp_id": "test_sp_id"
"sp_id": "test_sp_id",
"display_name": "Test Name",
"description": "desc here",
"title": "Test Title",
"os_image": "Windows 11"
},
resourcePath=f'/workspaces/{workspace_id}',
updatedWhen=FAKE_CREATE_TIMESTAMP,
Expand Down Expand Up @@ -164,12 +168,12 @@ def sample_deployed_workspace(workspace_id=WORKSPACE_ID, authInfo={}):
templateName="tre-workspace-base",
templateVersion="0.1.0",
etag="",
properties={},
properties={'display_name': 'Test Name', 'description': 'desc here', 'title': 'Test Title', 'os_image': 'Windows 11'},
resourcePath="test",
updatedWhen=FAKE_CREATE_TIMESTAMP
)
if authInfo:
workspace.properties = {**authInfo}
workspace.properties.update(authInfo)
return workspace


Expand All @@ -180,7 +184,7 @@ def sample_workspace_service(workspace_service_id=SERVICE_ID, workspace_id=WORKS
templateName="tre-workspace-base",
templateVersion="0.1.0",
etag="",
properties={},
properties={'display_name': 'Test Name', 'description': 'desc here', 'title': 'Test Title', 'os_image': 'Windows 11'},
resourcePath=f'/workspaces/{workspace_id}/workspace-services/{workspace_service_id}',
updatedWhen=FAKE_CREATE_TIMESTAMP,
user=create_workspace_owner_user().model_dump()
Expand All @@ -195,7 +199,7 @@ def sample_user_resource_object(user_resource_id=USER_RESOURCE_ID, workspace_id=
templateName="tre-user-resource",
templateVersion="0.1.0",
etag="",
properties={},
properties={'display_name': 'Test Name', 'description': 'desc here', 'title': 'Test Title', 'os_image': 'Windows 11'},
resourcePath=f'/workspaces/{workspace_id}/workspace-services/{parent_workspace_service_id}/user-resources/{user_resource_id}',
updatedWhen=FAKE_CREATE_TIMESTAMP,
user=create_workspace_researcher_user().model_dump()
Expand All @@ -213,6 +217,14 @@ def sample_resource_template() -> ResourceTemplate:
current=True,
required=['os_image', 'title'],
properties={
'display_name': {
'type': 'string',
'title': 'Display Name'
},
'description': {
'type': 'string',
'title': 'Description'
},
'title': {
'type': 'string',
'title': 'Title of the resource'
Expand All @@ -237,6 +249,30 @@ def sample_resource_template() -> ResourceTemplate:
'large'
],
'updateable': True
},
'overview': {
'type': 'string',
'title': 'Overview'
},
'private_field_1': {
'type': 'string',
'title': 'Private Field 1'
},
'private_field_2': {
'type': 'string',
'title': 'Private Field 2'
},
'client_id': {
'type': 'string',
'title': 'Client ID'
},
'scope_id': {
'type': 'string',
'title': 'Scope ID'
},
'sp_id': {
'type': 'string',
'title': 'SP ID'
}
},
actions=[])
Expand Down Expand Up @@ -597,7 +633,7 @@ async def test_patch_workspaces_with_upgrade_major_version_returns_bad_request(s
@patch("api.routes.workspaces.send_resource_request_message", return_value=sample_resource_operation(resource_id=WORKSPACE_ID, operation_id=OPERATION_ID))
@patch("api.dependencies.workspaces.WorkspaceRepository.get_workspace_by_id", return_value=sample_workspace())
@patch("api.routes.workspaces.WorkspaceRepository.update_item_with_etag", return_value=sample_workspace())
@patch("api.routes.workspaces.ResourceTemplateRepository.get_template_by_name_and_version", return_value=sample_workspace())
@patch("api.routes.workspaces.ResourceTemplateRepository.get_template_by_name_and_version", return_value=sample_resource_template())
@patch("api.routes.workspaces.WorkspaceRepository.get_timestamp", return_value=FAKE_UPDATE_TIMESTAMP)
async def test_patch_workspaces_with_upgrade_major_version_and_force_update_returns_patched_workspace(self, _, __, update_item_mock, ___, ____, _____, ______, app, client):
workspace_patch = {"templateVersion": "2.0.0"}
Expand Down Expand Up @@ -644,7 +680,7 @@ async def test_patch_workspaces_with_downgrade_version_returns_bad_request(self,
@patch("api.routes.workspaces.send_resource_request_message", return_value=sample_resource_operation(resource_id=WORKSPACE_ID, operation_id=OPERATION_ID))
@patch("api.dependencies.workspaces.WorkspaceRepository.get_workspace_by_id", return_value=sample_workspace())
@patch("api.routes.workspaces.WorkspaceRepository.update_item_with_etag", return_value=sample_workspace())
@patch("api.routes.workspaces.ResourceTemplateRepository.get_template_by_name_and_version", return_value=sample_workspace())
@patch("api.routes.workspaces.ResourceTemplateRepository.get_template_by_name_and_version", return_value=sample_resource_template())
@patch("api.routes.workspaces.WorkspaceRepository.get_timestamp", return_value=FAKE_UPDATE_TIMESTAMP)
async def test_patch_workspaces_with_upgrade_minor_version_patches_workspace(self, _, __, update_item_mock, ___, ____, _____, ______, app, client):
workspace_patch = {"templateVersion": "0.2.0"}
Expand All @@ -658,7 +694,6 @@ async def test_patch_workspaces_with_upgrade_minor_version_patches_workspace(sel
modified_workspace.templateVersion = "0.2.0"

response = await client.patch(app.url_path_for(strings.API_UPDATE_WORKSPACE, workspace_id=WORKSPACE_ID), json=workspace_patch, headers={"etag": etag})

update_item_mock.assert_called_once_with(modified_workspace, etag)
assert response.status_code == status.HTTP_202_ACCEPTED

Expand Down
Loading
Loading