From f6933b771b036717daebaf874ae24473fde3d8c1 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Wed, 16 Sep 2026 09:55:00 +0200 Subject: [PATCH 01/10] ci: run template tests on macos-15 with the current Node LTS macos-12 was retired, so every run queued forever waiting for a runner that no longer exists. Node 16 predates the NativeScript 9.1 and TypeScript 6 toolchain the templates now use. --- .github/workflows/test.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 17708398..6f9f5323 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -4,7 +4,7 @@ on: push jobs: test: - runs-on: macos-12 + runs-on: macos-15 name: ${{ matrix.template }} (node ${{ matrix.node }}) @@ -33,31 +33,31 @@ jobs: - template-blank-vue - template-hello-world - template-master-detail-vue - node: [16] + node: ['lts/*'] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: path: 'templates' - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: '3' - - uses: actions/setup-java@v2 + - uses: actions/setup-java@v4 with: distribution: 'temurin' java-version: '17' - name: Install Node - uses: actions/setup-node@v2 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node }} cache: 'npm' cache-dependency-path: templates/package-lock.json - name: Cache Gradle - uses: actions/cache@v2 + uses: actions/cache@v4 with: key: ${{ runner.os }}-gradle-cache-${{ hashFiles('**/package-lock.json') }}-v1 path: | @@ -65,7 +65,7 @@ jobs: ~/.gradle/wrapper - name: Cache Python - uses: actions/cache@v2 + uses: actions/cache@v4 with: key: ${{ runner.os }}-python-cache-${{ env.pythonLocation }}-${{ hashFiles('**/package-lock.json') }} path: ${{ env.pythonLocation }} From 1b1a334561334eea82dd9b904ea85e8231e4100d Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Wed, 16 Sep 2026 09:59:23 +0200 Subject: [PATCH 02/10] ci: report every template instead of cancelling the matrix on the first failure --- .github/workflows/test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6f9f5323..c4b051bf 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -9,6 +9,7 @@ jobs: name: ${{ matrix.template }} (node ${{ matrix.node }}) strategy: + fail-fast: false matrix: template: - template-blank From 5ece1e1e6217614b5d2fe2c2e454ce636ecbf6ba Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Wed, 16 Sep 2026 10:17:42 +0200 Subject: [PATCH 03/10] ci: build only the templates a push touches A first job diffs the push against its base (the previous tip on main, the merge-base with main elsewhere) and feeds the affected templates to the build matrix. Shared inputs rebuild everything; Markdown-only changes build nothing. --- .github/workflows/test.yml | 86 ++++++++++++++++++++++++++++---------- 1 file changed, 63 insertions(+), 23 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c4b051bf..9036d525 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -3,7 +3,69 @@ name: '@nativescript/template-* -> test' on: push jobs: + # Only templates whose files changed are built; anything they all share + # (shared-mobile, prepareTemplates.js, the root package files, this + # workflow) rebuilds every template. Vision and Solid templates are not + # built here, so the list below is the universe, not the packages dir. + changes: + runs-on: ubuntu-latest + outputs: + templates: ${{ steps.list.outputs.templates }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - id: list + env: + BEFORE: ${{ github.event.before }} + ALL: | + template-blank + template-blank-vue-ts + template-hello-world-ng + template-tab-navigation + template-blank-ng + template-drawer-navigation + template-hello-world-ts + template-tab-navigation-ng + template-blank-react + template-drawer-navigation-ng + template-master-detail + template-tab-navigation-ts + template-blank-svelte + template-drawer-navigation-ts + template-master-detail-ng + template-tab-navigation-vue + template-blank-ts + template-drawer-navigation-vue + template-master-detail-ts + template-blank-vue + template-hello-world + template-master-detail-vue + run: | + if [ "$GITHUB_REF_NAME" = "main" ] && git cat-file -e "$BEFORE" 2>/dev/null; then + base=$BEFORE + else + base=$(git merge-base origin/main HEAD) + fi + changed=$(git diff --name-only "$base" HEAD | grep -vE '\.md$' || true) + + if [ -z "$changed" ]; then + selected="" + elif echo "$changed" | grep -qvE '^packages/template-[^/]+/'; then + selected=$ALL + else + changedDirs=$(echo "$changed" | grep -oE '^packages/template-[^/]+' | xargs -n1 basename | sort -u) + selected=$(comm -12 <(echo "$ALL" | sort) <(echo "$changedDirs")) + fi + + templates=$(printf '%s\n' $selected | grep . | jq -R . | jq -sc .) + echo "templates=$templates" >> "$GITHUB_OUTPUT" + echo "Building: $templates" + test: + needs: changes + if: needs.changes.outputs.templates != '[]' runs-on: macos-15 name: ${{ matrix.template }} (node ${{ matrix.node }}) @@ -11,29 +73,7 @@ jobs: strategy: fail-fast: false matrix: - template: - - template-blank - - template-blank-vue-ts - - template-hello-world-ng - - template-tab-navigation - - template-blank-ng - - template-drawer-navigation - - template-hello-world-ts - - template-tab-navigation-ng - - template-blank-react - - template-drawer-navigation-ng - - template-master-detail - - template-tab-navigation-ts - - template-blank-svelte - - template-drawer-navigation-ts - - template-master-detail-ng - - template-tab-navigation-vue - - template-blank-ts - - template-drawer-navigation-vue - - template-master-detail-ts - - template-blank-vue - - template-hello-world - - template-master-detail-vue + template: ${{ fromJSON(needs.changes.outputs.templates) }} node: ['lts/*'] steps: From d599b349cb219af299cf420e5d5c896488b3caa9 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Wed, 16 Sep 2026 10:20:11 +0200 Subject: [PATCH 04/10] ci: use the Node 24 majors of the setup actions --- .github/workflows/test.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9036d525..e65963ee 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,7 +12,7 @@ jobs: outputs: templates: ${{ steps.list.outputs.templates }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 with: fetch-depth: 0 @@ -77,28 +77,28 @@ jobs: node: ['lts/*'] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 with: path: 'templates' - - uses: actions/setup-python@v5 + - uses: actions/setup-python@v7 with: python-version: '3' - - uses: actions/setup-java@v4 + - uses: actions/setup-java@v6 with: distribution: 'temurin' java-version: '17' - name: Install Node - uses: actions/setup-node@v4 + uses: actions/setup-node@v7 with: node-version: ${{ matrix.node }} cache: 'npm' cache-dependency-path: templates/package-lock.json - name: Cache Gradle - uses: actions/cache@v4 + uses: actions/cache@v5 with: key: ${{ runner.os }}-gradle-cache-${{ hashFiles('**/package-lock.json') }}-v1 path: | @@ -106,7 +106,7 @@ jobs: ~/.gradle/wrapper - name: Cache Python - uses: actions/cache@v4 + uses: actions/cache@v5 with: key: ${{ runner.os }}-python-cache-${{ env.pythonLocation }}-${{ hashFiles('**/package-lock.json') }} path: ${{ env.pythonLocation }} From 1bf0bf07c867946b59956bcaaaa0cec5af049603 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Wed, 16 Sep 2026 10:31:25 +0200 Subject: [PATCH 05/10] fix(angular): declare NgModule components as non-standalone Angular 19 made components standalone by default, so after the move to Angular 22 the drawer, tab and master-detail templates failed to build with NG6008 for every component their modules declare. Each of the three templates is bumped a patch. --- packages/template-drawer-navigation-ng/package.json | 2 +- packages/template-drawer-navigation-ng/src/app/app.component.ts | 1 + .../src/app/browse/browse.component.ts | 1 + .../src/app/featured/featured.component.ts | 1 + .../src/app/home/home.component.ts | 1 + .../src/app/search/search.component.ts | 1 + .../src/app/settings/settings.component.ts | 1 + packages/template-master-detail-ng/package.json | 2 +- packages/template-master-detail-ng/src/app/app.component.ts | 1 + .../src/app/cars/car-detail-edit/car-detail-edit.component.ts | 1 + .../my-image-add-remove/my-image-add-remove.component.ts | 1 + .../my-list-selector/my-list-selector-modal-view.component.ts | 1 + .../my-list-selector/my-list-selector.component.ts | 1 + .../src/app/cars/car-detail/car-detail.component.ts | 1 + .../src/app/cars/car-list.component.ts | 1 + packages/template-tab-navigation-ng/package.json | 2 +- packages/template-tab-navigation-ng/src/app/app.component.ts | 1 + .../src/app/browse/browse.component.ts | 1 + .../template-tab-navigation-ng/src/app/home/home.component.ts | 1 + .../src/app/home/item-detail/item-detail.component.ts | 1 + .../src/app/search/search.component.ts | 1 + 21 files changed, 21 insertions(+), 3 deletions(-) diff --git a/packages/template-drawer-navigation-ng/package.json b/packages/template-drawer-navigation-ng/package.json index 785dece5..de61f830 100644 --- a/packages/template-drawer-navigation-ng/package.json +++ b/packages/template-drawer-navigation-ng/package.json @@ -3,7 +3,7 @@ "main": "src/main.ts", "displayName": "Navigation Drawer", "templateType": "App template", - "version": "9.1.0", + "version": "9.1.1", "description": "Side navigation template", "author": "NativeScript Team ", "license": "Apache-2.0", diff --git a/packages/template-drawer-navigation-ng/src/app/app.component.ts b/packages/template-drawer-navigation-ng/src/app/app.component.ts index 1be0b974..16f015ad 100644 --- a/packages/template-drawer-navigation-ng/src/app/app.component.ts +++ b/packages/template-drawer-navigation-ng/src/app/app.component.ts @@ -10,6 +10,7 @@ import { filter } from 'rxjs/operators' import { Application } from '@nativescript/core' @Component({ + standalone: false, selector: 'ns-app', templateUrl: 'app.component.html', }) diff --git a/packages/template-drawer-navigation-ng/src/app/browse/browse.component.ts b/packages/template-drawer-navigation-ng/src/app/browse/browse.component.ts index 007c2dac..627f747c 100644 --- a/packages/template-drawer-navigation-ng/src/app/browse/browse.component.ts +++ b/packages/template-drawer-navigation-ng/src/app/browse/browse.component.ts @@ -3,6 +3,7 @@ import { RadSideDrawer } from 'nativescript-ui-sidedrawer' import { Application } from '@nativescript/core' @Component({ + standalone: false, selector: 'Browse', templateUrl: './browse.component.html', }) diff --git a/packages/template-drawer-navigation-ng/src/app/featured/featured.component.ts b/packages/template-drawer-navigation-ng/src/app/featured/featured.component.ts index add726e9..1d27b414 100644 --- a/packages/template-drawer-navigation-ng/src/app/featured/featured.component.ts +++ b/packages/template-drawer-navigation-ng/src/app/featured/featured.component.ts @@ -3,6 +3,7 @@ import { RadSideDrawer } from 'nativescript-ui-sidedrawer' import { Application } from '@nativescript/core' @Component({ + standalone: false, selector: 'Featured', templateUrl: './featured.component.html', }) diff --git a/packages/template-drawer-navigation-ng/src/app/home/home.component.ts b/packages/template-drawer-navigation-ng/src/app/home/home.component.ts index 210179d0..9ec81cfc 100644 --- a/packages/template-drawer-navigation-ng/src/app/home/home.component.ts +++ b/packages/template-drawer-navigation-ng/src/app/home/home.component.ts @@ -3,6 +3,7 @@ import { RadSideDrawer } from 'nativescript-ui-sidedrawer' import { Application } from '@nativescript/core' @Component({ + standalone: false, selector: 'Home', templateUrl: './home.component.html', }) diff --git a/packages/template-drawer-navigation-ng/src/app/search/search.component.ts b/packages/template-drawer-navigation-ng/src/app/search/search.component.ts index 5c260182..3808c9b5 100644 --- a/packages/template-drawer-navigation-ng/src/app/search/search.component.ts +++ b/packages/template-drawer-navigation-ng/src/app/search/search.component.ts @@ -3,6 +3,7 @@ import { RadSideDrawer } from 'nativescript-ui-sidedrawer' import { Application } from '@nativescript/core' @Component({ + standalone: false, selector: 'Search', templateUrl: './search.component.html', }) diff --git a/packages/template-drawer-navigation-ng/src/app/settings/settings.component.ts b/packages/template-drawer-navigation-ng/src/app/settings/settings.component.ts index e88ca631..928d29c8 100644 --- a/packages/template-drawer-navigation-ng/src/app/settings/settings.component.ts +++ b/packages/template-drawer-navigation-ng/src/app/settings/settings.component.ts @@ -3,6 +3,7 @@ import { RadSideDrawer } from 'nativescript-ui-sidedrawer' import { Application } from '@nativescript/core' @Component({ + standalone: false, selector: 'Settings', templateUrl: './settings.component.html', }) diff --git a/packages/template-master-detail-ng/package.json b/packages/template-master-detail-ng/package.json index f11d2314..bd6550ec 100644 --- a/packages/template-master-detail-ng/package.json +++ b/packages/template-master-detail-ng/package.json @@ -3,7 +3,7 @@ "main": "src/main.ts", "displayName": "Master-Detail with Firebase", "templateType": "App template", - "version": "9.1.0", + "version": "9.1.1", "description": "Master-detail interface to display collection of items from json collection and inspect and edit selected item properties. ", "author": "NativeScript Team ", "license": "Apache-2.0", diff --git a/packages/template-master-detail-ng/src/app/app.component.ts b/packages/template-master-detail-ng/src/app/app.component.ts index 48ea41cf..8080cd4c 100644 --- a/packages/template-master-detail-ng/src/app/app.component.ts +++ b/packages/template-master-detail-ng/src/app/app.component.ts @@ -1,6 +1,7 @@ import { Component, OnInit } from '@angular/core' @Component({ + standalone: false, selector: 'ns-app', templateUrl: 'app.component.html', }) diff --git a/packages/template-master-detail-ng/src/app/cars/car-detail-edit/car-detail-edit.component.ts b/packages/template-master-detail-ng/src/app/cars/car-detail-edit/car-detail-edit.component.ts index 73c1da88..3146f327 100644 --- a/packages/template-master-detail-ng/src/app/cars/car-detail-edit/car-detail-edit.component.ts +++ b/packages/template-master-detail-ng/src/app/cars/car-detail-edit/car-detail-edit.component.ts @@ -9,6 +9,7 @@ import { CarService } from '../shared/car.service' import { carClassList, carDoorList, carSeatList, carTransmissionList } from './constants' @Component({ + standalone: false, selector: 'CarDetailEdit', templateUrl: './car-detail-edit.component.html', styleUrls: ['./car-detail-edit.component.scss'], diff --git a/packages/template-master-detail-ng/src/app/cars/car-detail-edit/my-image-add-remove/my-image-add-remove.component.ts b/packages/template-master-detail-ng/src/app/cars/car-detail-edit/my-image-add-remove/my-image-add-remove.component.ts index 25c4105c..3db998b0 100644 --- a/packages/template-master-detail-ng/src/app/cars/car-detail-edit/my-image-add-remove/my-image-add-remove.component.ts +++ b/packages/template-master-detail-ng/src/app/cars/car-detail-edit/my-image-add-remove/my-image-add-remove.component.ts @@ -17,6 +17,7 @@ const MY_IMAGE_ADD_REMOVE_CONTROL_VALUE_ACCESSOR = { * an image and provides custom logic and design to the process. *************************************************************/ @Component({ + standalone: false, selector: 'MyImageAddRemove', templateUrl: './my-image-add-remove.component.html', styleUrls: ['./my-image-add-remove.component.scss'], diff --git a/packages/template-master-detail-ng/src/app/cars/car-detail-edit/my-list-selector/my-list-selector-modal-view.component.ts b/packages/template-master-detail-ng/src/app/cars/car-detail-edit/my-list-selector/my-list-selector-modal-view.component.ts index f245514f..328a9d79 100644 --- a/packages/template-master-detail-ng/src/app/cars/car-detail-edit/my-list-selector/my-list-selector-modal-view.component.ts +++ b/packages/template-master-detail-ng/src/app/cars/car-detail-edit/my-list-selector/my-list-selector-modal-view.component.ts @@ -2,6 +2,7 @@ import { Component } from '@angular/core' import { ModalDialogParams } from '@nativescript/angular' @Component({ + standalone: false, selector: 'MyListSelectorModalView', templateUrl: './my-list-selector-modal-view.component.html', styleUrls: ['./my-list-selector-modal-view.component.scss'], diff --git a/packages/template-master-detail-ng/src/app/cars/car-detail-edit/my-list-selector/my-list-selector.component.ts b/packages/template-master-detail-ng/src/app/cars/car-detail-edit/my-list-selector/my-list-selector.component.ts index ab9dfacc..3282d928 100644 --- a/packages/template-master-detail-ng/src/app/cars/car-detail-edit/my-list-selector/my-list-selector.component.ts +++ b/packages/template-master-detail-ng/src/app/cars/car-detail-edit/my-list-selector/my-list-selector.component.ts @@ -9,6 +9,7 @@ import { MyListSelectorModalViewComponent } from './my-list-selector-modal-view. const capitalizeFirstLetter = (s) => s.charAt(0).toUpperCase() + s.slice(1) @Component({ + standalone: false, providers: [ModalDialogService], selector: 'MyListSelector', templateUrl: './my-list-selector.component.html', diff --git a/packages/template-master-detail-ng/src/app/cars/car-detail/car-detail.component.ts b/packages/template-master-detail-ng/src/app/cars/car-detail/car-detail.component.ts index 949eb715..6bcc27b1 100644 --- a/packages/template-master-detail-ng/src/app/cars/car-detail/car-detail.component.ts +++ b/packages/template-master-detail-ng/src/app/cars/car-detail/car-detail.component.ts @@ -6,6 +6,7 @@ import { Car } from '../shared/car.model' import { CarService } from '../shared/car.service' @Component({ + standalone: false, selector: 'CarDetail', templateUrl: './car-detail.component.html', }) diff --git a/packages/template-master-detail-ng/src/app/cars/car-list.component.ts b/packages/template-master-detail-ng/src/app/cars/car-list.component.ts index 25197469..db4a9fd5 100644 --- a/packages/template-master-detail-ng/src/app/cars/car-list.component.ts +++ b/packages/template-master-detail-ng/src/app/cars/car-list.component.ts @@ -9,6 +9,7 @@ import { Car } from './shared/car.model' import { CarService } from './shared/car.service' @Component({ + standalone: false, selector: 'CarsList', templateUrl: './car-list.component.html', styleUrls: ['./car-list.component.scss'], diff --git a/packages/template-tab-navigation-ng/package.json b/packages/template-tab-navigation-ng/package.json index dff0953c..623352c9 100644 --- a/packages/template-tab-navigation-ng/package.json +++ b/packages/template-tab-navigation-ng/package.json @@ -3,7 +3,7 @@ "main": "src/main.ts", "displayName": "Tabs", "templateType": "App template", - "version": "9.1.0", + "version": "9.1.1", "description": "Tabbed interface template", "author": "NativeScript Team ", "license": "Apache-2.0", diff --git a/packages/template-tab-navigation-ng/src/app/app.component.ts b/packages/template-tab-navigation-ng/src/app/app.component.ts index a1429beb..87f411a5 100644 --- a/packages/template-tab-navigation-ng/src/app/app.component.ts +++ b/packages/template-tab-navigation-ng/src/app/app.component.ts @@ -1,6 +1,7 @@ import { Component, OnInit } from '@angular/core' @Component({ + standalone: false, selector: 'ns-app', templateUrl: 'app.component.html', }) diff --git a/packages/template-tab-navigation-ng/src/app/browse/browse.component.ts b/packages/template-tab-navigation-ng/src/app/browse/browse.component.ts index 37b59b67..70f17cfc 100644 --- a/packages/template-tab-navigation-ng/src/app/browse/browse.component.ts +++ b/packages/template-tab-navigation-ng/src/app/browse/browse.component.ts @@ -1,6 +1,7 @@ import { Component, OnInit } from '@angular/core' @Component({ + standalone: false, selector: 'Browse', templateUrl: './browse.component.html', }) diff --git a/packages/template-tab-navigation-ng/src/app/home/home.component.ts b/packages/template-tab-navigation-ng/src/app/home/home.component.ts index fa1937b8..0a57542e 100644 --- a/packages/template-tab-navigation-ng/src/app/home/home.component.ts +++ b/packages/template-tab-navigation-ng/src/app/home/home.component.ts @@ -3,6 +3,7 @@ import { Component, OnInit } from '@angular/core' import { DataService, DataItem } from '../shared/data.service' @Component({ + standalone: false, selector: 'Home', templateUrl: './home.component.html', }) diff --git a/packages/template-tab-navigation-ng/src/app/home/item-detail/item-detail.component.ts b/packages/template-tab-navigation-ng/src/app/home/item-detail/item-detail.component.ts index d9998487..069f8dfb 100644 --- a/packages/template-tab-navigation-ng/src/app/home/item-detail/item-detail.component.ts +++ b/packages/template-tab-navigation-ng/src/app/home/item-detail/item-detail.component.ts @@ -5,6 +5,7 @@ import { RouterExtensions } from '@nativescript/angular' import { DataService, DataItem } from '../../shared/data.service' @Component({ + standalone: false, selector: 'ItemDetail', templateUrl: './item-detail.component.html', }) diff --git a/packages/template-tab-navigation-ng/src/app/search/search.component.ts b/packages/template-tab-navigation-ng/src/app/search/search.component.ts index 271c071f..8fdeb822 100644 --- a/packages/template-tab-navigation-ng/src/app/search/search.component.ts +++ b/packages/template-tab-navigation-ng/src/app/search/search.component.ts @@ -1,6 +1,7 @@ import { Component, OnInit } from '@angular/core' @Component({ + standalone: false, selector: 'Search', templateUrl: './search.component.html', }) From de63677ab2abbed599631d52e5b57255f5898839 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Wed, 16 Sep 2026 10:32:35 +0200 Subject: [PATCH 06/10] ci: cancel in-progress runs when the branch moves on --- .github/workflows/test.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e65963ee..0f70caea 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -2,6 +2,11 @@ name: '@nativescript/template-* -> test' on: push +# a newer push to the same branch supersedes any run still in progress +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: # Only templates whose files changed are built; anything they all share # (shared-mobile, prepareTemplates.js, the root package files, this From 0984ebf9bf965b39ca6b30082c773ab4ee6b9420 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Wed, 16 Sep 2026 10:37:35 +0200 Subject: [PATCH 07/10] fix(angular): satisfy strict template checks in the master-detail template Angular 22 type-checks templates: the door selector binds a number and a number array to inputs typed as strings, and the list tap event from a custom element is typed as Event. --- .../my-list-selector/my-list-selector.component.ts | 8 ++++---- .../src/app/cars/car-list.component.html | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/template-master-detail-ng/src/app/cars/car-detail-edit/my-list-selector/my-list-selector.component.ts b/packages/template-master-detail-ng/src/app/cars/car-detail-edit/my-list-selector/my-list-selector.component.ts index 3282d928..cd6a6022 100644 --- a/packages/template-master-detail-ng/src/app/cars/car-detail-edit/my-list-selector/my-list-selector.component.ts +++ b/packages/template-master-detail-ng/src/app/cars/car-detail-edit/my-list-selector/my-list-selector.component.ts @@ -16,9 +16,9 @@ const capitalizeFirstLetter = (s) => s.charAt(0).toUpperCase() + s.slice(1) }) export class MyListSelectorComponent implements OnInit { @Input() tag: string - @Input() items: Array - @Input() selectedValue: string - @Output() selectedValueChange = new EventEmitter() + @Input() items: Array + @Input() selectedValue: string | number + @Output() selectedValueChange = new EventEmitter() private _carEditModel: Car @@ -56,7 +56,7 @@ export class MyListSelectorComponent implements OnInit { this._modalService .showModal(MyListSelectorModalViewComponent, options) - .then((selectedValue: string) => { + .then((selectedValue: string | number) => { if (selectedValue) { this.selectedValue = selectedValue this.selectedValueChange.emit(this.selectedValue) diff --git a/packages/template-master-detail-ng/src/app/cars/car-list.component.html b/packages/template-master-detail-ng/src/app/cars/car-list.component.html index 881912b0..ccd81ffe 100644 --- a/packages/template-master-detail-ng/src/app/cars/car-list.component.html +++ b/packages/template-master-detail-ng/src/app/cars/car-list.component.html @@ -4,7 +4,7 @@ - + From 4ed9e72e576a1e387e13dc9d2aaabe93e699ab1e Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Wed, 16 Sep 2026 11:05:49 +0200 Subject: [PATCH 08/10] ci: build Android on Linux and cache npm per template Android needs nothing from macOS, so it moves to ubuntu runners where it neither costs macOS minutes nor queues behind the five-runner cap. The npm cache is keyed on the template's own package.json instead of the repo root lockfile, which the created app never installs from. --- .github/workflows/test.yml | 64 +++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 29 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0f70caea..72c4de73 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -68,29 +68,38 @@ jobs: echo "templates=$templates" >> "$GITHUB_OUTPUT" echo "Building: $templates" - test: + build: needs: changes if: needs.changes.outputs.templates != '[]' - runs-on: macos-15 + runs-on: ${{ matrix.os }} - name: ${{ matrix.template }} (node ${{ matrix.node }}) + name: ${{ matrix.template }} ${{ matrix.platform }} + # Android needs nothing from macOS, so it builds on Linux: cheaper, and + # it does not queue behind the small pool of concurrent macOS runners. strategy: fail-fast: false matrix: template: ${{ fromJSON(needs.changes.outputs.templates) }} - node: ['lts/*'] + platform: [ios, android] + include: + - platform: ios + os: macos-15 + - platform: android + os: ubuntu-latest steps: - uses: actions/checkout@v7 with: path: 'templates' - - uses: actions/setup-python@v7 + - if: matrix.platform == 'ios' + uses: actions/setup-python@v7 with: python-version: '3' - - uses: actions/setup-java@v6 + - if: matrix.platform == 'android' + uses: actions/setup-java@v6 with: distribution: 'temurin' java-version: '17' @@ -98,11 +107,21 @@ jobs: - name: Install Node uses: actions/setup-node@v7 with: - node-version: ${{ matrix.node }} - cache: 'npm' - cache-dependency-path: templates/package-lock.json + node-version: lts/* - - name: Cache Gradle + # keyed on the template's own package.json: the app created from it + # is what npm installs, not the repo root + - name: Cache npm + uses: actions/cache@v5 + with: + path: ~/.npm + key: ${{ runner.os }}-npm-${{ matrix.template }}-${{ hashFiles(format('templates/packages/{0}/package.json', matrix.template), 'templates/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-npm-${{ matrix.template }}- + ${{ runner.os }}-npm- + + - if: matrix.platform == 'android' + name: Cache Gradle uses: actions/cache@v5 with: key: ${{ runner.os }}-gradle-cache-${{ hashFiles('**/package-lock.json') }}-v1 @@ -110,30 +129,21 @@ jobs: ~/.gradle/caches ~/.gradle/wrapper - - name: Cache Python - uses: actions/cache@v5 - with: - key: ${{ runner.os }}-python-cache-${{ env.pythonLocation }}-${{ hashFiles('**/package-lock.json') }} - path: ${{ env.pythonLocation }} - - name: Setup working-directory: templates run: | - python3 -m pip install --upgrade pip six + if [ "${{ matrix.platform }}" = "ios" ]; then + python3 -m pip install --upgrade pip six + fi npm i -g nativescript@next --ignore-scripts ns usage-reporting disable ns error-reporting disable ns -v - ns doctor + ns doctor ${{ matrix.platform }} || true npm install npm run prepare-templates - # - name: "Uninstall build-tools@31.0.0" - # run: | - # SDKMANAGER=$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager - # echo y | $SDKMANAGER --uninstall "build-tools;31.0.0" - - name: Create app from template env: TEMPLATE_NAME: ${{ matrix.template }} @@ -145,10 +155,6 @@ jobs: cd myApp npm install - - name: Test iOS Build - working-directory: myApp - run: ns build ios - - - name: Test Android Build + - name: Build working-directory: myApp - run: ns build android + run: ns build ${{ matrix.platform }} From b0c94b7a9c9d461fe8b1fb8ace18dab359f831b6 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Wed, 16 Sep 2026 11:07:59 +0200 Subject: [PATCH 09/10] ci: skip the CLI environment check for Android on Linux The ubuntu image has the SDK but not the emulator package; the check treats that as fatal although compilation does not need it. --- .github/workflows/test.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 72c4de73..4a8d9107 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -157,4 +157,8 @@ jobs: - name: Build working-directory: myApp + env: + # the Linux image ships the SDK without the emulator package, which + # is all the CLI's pre-build check complains about + NS_SKIP_ENV_CHECK: ${{ matrix.platform == 'android' && '1' || '' }} run: ns build ${{ matrix.platform }} From 810b373db0618f92fb55f02aa64d7d5edd6fc4ee Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Wed, 16 Sep 2026 13:41:28 +0200 Subject: [PATCH 10/10] ci: limit the workflow token to reading contents --- .github/workflows/test.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4a8d9107..c7319933 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -2,6 +2,9 @@ name: '@nativescript/template-* -> test' on: push +permissions: + contents: read + # a newer push to the same branch supersedes any run still in progress concurrency: group: ${{ github.workflow }}-${{ github.ref }}