From 45e97d64aae26468cf45738400cdf64b7a48e41c Mon Sep 17 00:00:00 2001 From: "Kristian D. Dimitrov" Date: Fri, 18 Oct 2019 13:23:03 +0300 Subject: [PATCH 01/11] chore:bump version to 6.2.1 --- npm-shrinkwrap.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 8eddd47080..f51552202e 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,6 +1,6 @@ { "name": "nativescript", - "version": "6.2.0", + "version": "6.2.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 9eb590f2e0..06cd007e91 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "nativescript", "preferGlobal": true, - "version": "6.2.0", + "version": "6.2.1", "author": "Telerik ", "description": "Command-line interface for building NativeScript projects", "bin": { From 1e9a55e2259a7fcdae679bd44d9073b4e33bd863 Mon Sep 17 00:00:00 2001 From: Kristian Dimitrov Date: Wed, 23 Oct 2019 13:39:38 +0300 Subject: [PATCH 02/11] chore: add trace for shouldMigrate caching --- lib/controllers/migrate-controller.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/controllers/migrate-controller.ts b/lib/controllers/migrate-controller.ts index 0b7d041408..ec49989a85 100644 --- a/lib/controllers/migrate-controller.ts +++ b/lib/controllers/migrate-controller.ts @@ -163,11 +163,14 @@ Running this command will ${MigrateController.COMMON_MIGRATE_MESSAGE}`; const cachedResult = await this.getCachedShouldMigrate(projectDir, platform); if (cachedResult !== false) { remainingPlatforms.push(platform); + } else { + this.$logger.trace(`Got cached result for shouldMigrate for platform: ${platform}`); } } if (remainingPlatforms.length > 0) { shouldMigrate = await this._shouldMigrate({ projectDir, platforms: remainingPlatforms, allowInvalidVersions }); + this.$logger.trace(`Executed shouldMigrate for platforms: ${remainingPlatforms}. Result is: ${shouldMigrate}`); if (!shouldMigrate) { for (const remainingPlatform of remainingPlatforms) { From 516fd310d4b7953c9448ca34bfb429a55b99c50d Mon Sep 17 00:00:00 2001 From: fatme Date: Tue, 29 Oct 2019 09:40:36 +0200 Subject: [PATCH 03/11] fix: handle correctly the situation when the compilation hash is the same as the previous one MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently CLI considers the hash that is the same as the previous as invalid and this way the application is restarted on device. As that hash is already handled, we should consider it as a valid hash. Steps to reproduce : ``` `tns create ts_proj` - choose ts tabs project npm i tns-core-modules@rc --save --save-exact npm i nativescript-dev-webpack@rc --save-dev --save-exact node_modules/.bin/update-ns-webpack --deps –configs tns run android Change something in app.android.scss - the change is applied, no restart Change something in app.ios.scss - application restarts ``` --- lib/services/webpack/webpack-compiler-service.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/services/webpack/webpack-compiler-service.ts b/lib/services/webpack/webpack-compiler-service.ts index 4f0dd015da..297e306bef 100644 --- a/lib/services/webpack/webpack-compiler-service.ts +++ b/lib/services/webpack/webpack-compiler-service.ts @@ -46,6 +46,11 @@ export class WebpackCompilerService extends EventEmitter implements IWebpackComp return; } + // the hash of the compilation is the same as the previous one + if (this.expectedHashes[platformData.platformNameLowerCase] === message.hash) { + return; + } + let result; if (prepareData.hmr) { From 61237bb9bbaa0b759d9d155324efc419c3ac9b79 Mon Sep 17 00:00:00 2001 From: fatme Date: Fri, 1 Nov 2019 11:24:31 +0200 Subject: [PATCH 04/11] chore: create changelog for 6.2.0 release --- CHANGELOG.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 32ae3f35d6..c81f75fbc9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,33 @@ NativeScript CLI Changelog ================ +6.2.0 (2019, November 1) +== + +### New +* [Implemented #5038](https://github.com/NativeScript/nativescript-cli/issues/5038): Deprecate support for markingMode:full +* [Implemented #5049](https://github.com/NativeScript/nativescript-cli/issues/5049): Android App Bundle Improvements +* [Implemented #5060](https://github.com/NativeScript/nativescript-cli/issues/5060): Kotlin usage tracking in android builds +* [Implemented #5096](https://github.com/NativeScript/nativescript-cli/issues/5096): Reduce the npm requests when checking if the project should be migrated +* [Implemented #5104](https://github.com/NativeScript/nativescript-cli/pull/5104): Allow tag and range versions in the preview app plugin versions validation +* [Implemented #5107](https://github.com/NativeScript/nativescript-cli/issues/5107): Support V8 Snapshots on Windows + +### Fixed +* [Fixed #3785](https://github.com/NativeScript/nativescript-cli/issues/3785): NativeScript CLI doesn't pause on webpack compilation errors +* [Fixed #4681](https://github.com/NativeScript/nativescript-cli/issues/4681): `tns update ios` is not working +* [Fixed #4963](https://github.com/NativeScript/nativescript-cli/issues/4963): Difference in hookArgs.prepareData.platform on prepare and run command +* [Fixed #4995](https://github.com/NativeScript/nativescript-cli/issues/4995): Building plugin and running demo app fails if plugins has a surrounding gradle build +* [Fixed #5005](https://github.com/NativeScript/nativescript-cli/issues/5005): Apple Watch extension with space in the name of `.entitlements` file is not working +* [Fixed #5020](https://github.com/NativeScript/nativescript-cli/issues/5020): Stuck at "Restarting application on device" on Windows 10, iPad mini 2, compiled with NativeScript Sidekick cloud service. +* [Fixed #5030](https://github.com/NativeScript/nativescript-cli/issues/5030): The `tns devices` command lists appletv as iOS platform +* [Fixed #5034](https://github.com/NativeScript/nativescript-cli/issues/5034): Broken build when passing --i-cloud-container-environment +* [Fixed #5056](https://github.com/NativeScript/nativescript-cli/issues/5056): Unable to process native iOS files and frameworks from scoped packages +* [Fixed #5061](https://github.com/NativeScript/nativescript-cli/issues/5061): Unable to resolve cocoapods version conflicts +* [Fixed #5063](https://github.com/NativeScript/nativescript-cli/issues/5063): Splash Screen asset generation fails for iOS +* [Fixed #5070](https://github.com/NativeScript/nativescript-cli/issues/5070): The `tns test` command cannot work if the source code is not in `src` or `app` folder +* [Fixed #5077](https://github.com/NativeScript/nativescript-cli/pull/5077): Pass allowProvisioningUpdates to xcodebuild only when building for device +* [Fixed #5094](https://github.com/NativeScript/nativescript-cli/issues/5094): Add Theme v2 name to non-extenal modules when starting webpack + 6.1.2 (2019, September 18) == From 5ccfba6f3f7e4e7f66007e60518e29f48e02053d Mon Sep 17 00:00:00 2001 From: rosen-vladimirov Date: Fri, 8 Nov 2019 09:27:48 +0200 Subject: [PATCH 05/11] fix: values-v directories are not prepared correctly In Android's resources you can have different `values-v` directories which are used at runtime to differentiate resources for API levels. In CLI we had a logic to include in native build only the `values-v` directories which are equal or lower to the SDK used for building the application. This means that if you are using compileSdk 28, but you have `values-v29` directory in your resources it shouldn't be included in the native build. Due to many changes in the structure of App_Resources/Android and the gradle template in NativeScript 4.0, this logic has been broken. Fix it and execute it on every prepare of App_Resources. --- lib/services/android-project-service.ts | 45 +++++- test/services/android-project-service.ts | 185 ++++++++++++++++++++++- 2 files changed, 219 insertions(+), 11 deletions(-) diff --git a/lib/services/android-project-service.ts b/lib/services/android-project-service.ts index d8efcf13e5..e33ee726be 100644 --- a/lib/services/android-project-service.ts +++ b/lib/services/android-project-service.ts @@ -142,11 +142,23 @@ export class AndroidProjectService extends projectServiceBaseLib.PlatformProject this.copy(this.getPlatformData(projectData).projectRoot, frameworkDir, "*", "-R"); + // TODO: Check if we actually need this and if it should be targetSdk or compileSdk this.cleanResValues(targetSdkVersion, projectData); } + private getResDestinationDir(projectData: IProjectData): string { + const appResourcesDirStructureHasMigrated = this.$androidResourcesMigrationService.hasMigrated(projectData.getAppResourcesDirectoryPath()); + + if (appResourcesDirStructureHasMigrated) { + const appResourcesDestinationPath = this.getUpdatedAppResourcesDestinationDirPath(projectData); + return path.join(appResourcesDestinationPath, constants.MAIN_DIR, constants.RESOURCES_DIR); + } else { + return this.getLegacyAppResourcesDestinationDirPath(projectData); + } + } + private cleanResValues(targetSdkVersion: number, projectData: IProjectData): void { - const resDestinationDir = this.getAppResourcesDestinationDirectoryPath(projectData); + const resDestinationDir = this.getResDestinationDir(projectData); const directoriesInResFolder = this.$fs.readDirectory(resDestinationDir); const directoriesToClean = directoriesInResFolder .map(dir => { @@ -283,7 +295,7 @@ export class AndroidProjectService extends projectServiceBaseLib.PlatformProject const projectAppResourcesPath = projectData.getAppResourcesDirectoryPath(projectData.projectDir); const platformsAppResourcesPath = this.getAppResourcesDestinationDirectoryPath(projectData); - this.cleanUpPreparedResources(projectAppResourcesPath, projectData); + this.cleanUpPreparedResources(projectData); this.$fs.ensureDirectoryExists(platformsAppResourcesPath); @@ -296,6 +308,10 @@ export class AndroidProjectService extends projectServiceBaseLib.PlatformProject // App_Resources/Android/libs is reserved to user's aars and jars, but they should not be copied as resources this.$fs.deleteDirectory(path.join(platformsAppResourcesPath, "libs")); } + + const androidToolsInfo = this.$androidToolsInfo.getToolsInfo({ projectDir: projectData.projectDir }); + const compileSdkVersion = androidToolsInfo && androidToolsInfo.compileSdkVersion; + this.cleanResValues(compileSdkVersion, projectData); } public async preparePluginNativeCode(pluginData: IPluginData, projectData: IProjectData): Promise { @@ -431,18 +447,31 @@ export class AndroidProjectService extends projectServiceBaseLib.PlatformProject return path.join(this.getPlatformData(projectData).projectRoot, ...resourcePath); } - private cleanUpPreparedResources(appResourcesDirectoryPath: string, projectData: IProjectData): void { - let resourcesDirPath = path.join(appResourcesDirectoryPath, this.getPlatformData(projectData).normalizedPlatformName); + /** + * The purpose of this method is to delete the previously prepared user resources. + * The content of the `/android/.../res` directory is based on user's resources and gradle project template from android-runtime. + * During preparation of the `/Android` we want to clean all the users files from previous preparation, + * but keep the ones that were introduced during `platform add` of the android-runtime. + * Currently the Gradle project template contains resources only in values and values-v21 directories. + * So the current logic of the method is cleaning al resources from `/android/.../res` that are not in `values.*` directories + * and that exist in the `/Android/.../res` directory + * This means that if user has a resource file in values-v29 for example, builds the project and then deletes this resource, + * it will be kept in platforms directory. Reference issue: `https://github.com/NativeScript/nativescript-cli/issues/5083` + * Same is valid for files in `drawable-` directories - in case in user's resources there's drawable-hdpi directory, + * which is deleted after the first build of app, it will remain in platforms directory. + */ + private cleanUpPreparedResources(projectData: IProjectData): void { + let resourcesDirPath = path.join(projectData.appResourcesDirectoryPath, this.getPlatformData(projectData).normalizedPlatformName); if (this.$androidResourcesMigrationService.hasMigrated(projectData.appResourcesDirectoryPath)) { - resourcesDirPath = path.join(resourcesDirPath, constants.MAIN_DIR, constants.RESOURCES_DIR); + resourcesDirPath = path.join(resourcesDirPath, constants.SRC_DIR, constants.MAIN_DIR, constants.RESOURCES_DIR); } const valuesDirRegExp = /^values/; if (this.$fs.exists(resourcesDirPath)) { const resourcesDirs = this.$fs.readDirectory(resourcesDirPath).filter(resDir => !resDir.match(valuesDirRegExp)); - const appResourcesDestinationDirectoryPath = this.getAppResourcesDestinationDirectoryPath(projectData); - _.each(resourcesDirs, resourceDir => { - this.$fs.deleteDirectory(path.join(appResourcesDestinationDirectoryPath, resourceDir)); + const resDestinationDir = this.getResDestinationDir(projectData); + _.each(resourcesDirs, currentResource => { + this.$fs.deleteDirectory(path.join(resDestinationDir, currentResource)); }); } } diff --git a/test/services/android-project-service.ts b/test/services/android-project-service.ts index d25b51982f..b541c182a4 100644 --- a/test/services/android-project-service.ts +++ b/test/services/android-project-service.ts @@ -3,6 +3,7 @@ import { Yok } from "../../lib/common/yok"; import * as stubs from "../stubs"; import { assert } from "chai"; import * as sinon from "sinon"; +import * as path from "path"; import { GradleCommandService } from "../../lib/services/android/gradle-command-service"; import { GradleBuildService } from "../../lib/services/android/gradle-build-service"; import { GradleBuildArgsService } from "../../lib/services/android/gradle-build-args-service"; @@ -42,7 +43,7 @@ const createTestInjector = (): IInjector => { testInjector.register("gradleBuildService", GradleBuildService); testInjector.register("gradleBuildArgsService", GradleBuildArgsService); testInjector.register("analyticsService", stubs.AnalyticsService); - testInjector.register("staticConfig", {TRACK_FEATURE_USAGE_SETTING_NAME: "TrackFeatureUsage"}); + testInjector.register("staticConfig", { TRACK_FEATURE_USAGE_SETTING_NAME: "TrackFeatureUsage" }); return testInjector; }; @@ -59,7 +60,7 @@ const getDefautlBuildConfig = (): IBuildConfig => { }; }; -describe("androidDeviceDebugService", () => { +describe("androidProjectService", () => { let injector: IInjector; let androidProjectService: IPlatformProjectService; let sandbox: sinon.SinonSandbox = null; @@ -74,7 +75,7 @@ describe("androidDeviceDebugService", () => { sandbox.restore(); }); - describe("buildPlatform", () => { + describe("buildProject", () => { let projectData: IProjectData; let childProcess: stubs.ChildProcessStub; @@ -138,4 +139,182 @@ describe("androidDeviceDebugService", () => { assert.include(childProcess.lastCommandArgs, "bundleDebug"); }); }); + + describe("prepareAppResources", () => { + const projectDir = "testDir"; + const pathToAppResourcesDir = path.join(projectDir, "app", "App_Resources"); + const pathToAppResourcesAndroid = path.join(pathToAppResourcesDir, "Android"); + const pathToPlatformsAndroid = path.join(projectDir, "platforms", "android"); + const pathToResDirInPlatforms = path.join(pathToPlatformsAndroid, "app", "src", "main", "res"); + const valuesV27Path = path.join(pathToResDirInPlatforms, "values-v27"); + const valuesV28Path = path.join(pathToResDirInPlatforms, "values-v28"); + const libsPath = path.join(pathToResDirInPlatforms, "libs"); + const drawableHdpiPath = path.join(pathToResDirInPlatforms, "drawable-hdpi"); + const drawableLdpiPath = path.join(pathToResDirInPlatforms, "drawable-ldpi"); + let deletedDirs: string[] = []; + let copiedFiles: { sourceFileName: string, destinationFileName: string }[] = []; + let readDirectoryResults: IDictionary = {}; + let fs: IFileSystem = null; + let projectData: IProjectData = null; + let compileSdkVersion = 29; + + beforeEach(() => { + projectData = injector.resolve("projectData"); + projectData.projectDir = projectDir; + projectData.appResourcesDirectoryPath = pathToAppResourcesDir; + + deletedDirs = []; + copiedFiles = []; + readDirectoryResults = {}; + + fs = injector.resolve("fs"); + fs.deleteDirectory = (directory: string): void => { + deletedDirs.push(directory); + }; + fs.copyFile = (sourceFileName: string, destinationFileName: string): void => { + copiedFiles.push({ sourceFileName, destinationFileName }); + }; + fs.readDirectory = (dir: string): string[] => { + return readDirectoryResults[dir] || []; + }; + + compileSdkVersion = 29; + + const androidToolsInfo = injector.resolve("androidToolsInfo"); + androidToolsInfo.getToolsInfo = (config?: IProjectDir): IAndroidToolsInfoData => { + return { + compileSdkVersion + }; + }; + + }); + + describe("when new Android App_Resources structure is detected (post {N} 4.0 structure)", () => { + const pathToSrcDirInAppResources = path.join(pathToAppResourcesAndroid, "src"); + beforeEach(() => { + const androidResourcesMigrationService = injector.resolve("androidResourcesMigrationService"); + androidResourcesMigrationService.hasMigrated = () => true; + }); + + it("copies everything from App_Resources/Android/src to correct location in platforms", async () => { + await androidProjectService.prepareAppResources(projectData); + + assert.deepEqual(copiedFiles, [{ sourceFileName: path.join(pathToSrcDirInAppResources, "*"), destinationFileName: path.join(projectData.projectDir, "platforms", "android", "app", "src") }]); + }); + + it("deletes correct values- directories based on the compileSdk", async () => { + readDirectoryResults = { + [`${pathToResDirInPlatforms}`]: [ + "values", + "values-v21", + "values-v26", + "values-v27", + "values-v28" + ] + }; + + compileSdkVersion = 26; + await androidProjectService.prepareAppResources(projectData); + assert.deepEqual(deletedDirs, [ + valuesV27Path, + valuesV28Path + ]); + }); + + it("deletes drawable directories when they've been previously prepared", async () => { + readDirectoryResults = { + [path.join(pathToSrcDirInAppResources, "main", "res")]: [ + "drawable-hdpi", + "drawable-ldpi", + "values", + "values-v21", + "values-v29" + ], + [`${pathToResDirInPlatforms}`]: [ + "drawable-hdpi", + "drawable-ldpi", + "drawable-mdpi", + "values", + "values-v21", + "values-v29" + ] + }; + + await androidProjectService.prepareAppResources(projectData); + + // NOTE: Currently the drawable-mdpi directory is not deleted from prepared App_Resources as it does not exist in the currently prepared App_Resources + // This is not correct behavior and it should be fixed in a later point. + assert.deepEqual(deletedDirs, [ + drawableHdpiPath, + drawableLdpiPath + ]); + }); + }); + + describe("when old Android App_Resources structure is detected (post {N} 4.0 structure)", () => { + beforeEach(() => { + const androidResourcesMigrationService = injector.resolve("androidResourcesMigrationService"); + androidResourcesMigrationService.hasMigrated = () => false; + }); + + it("copies everything from App_Resources/Android to correct location in platforms", async () => { + await androidProjectService.prepareAppResources(projectData); + + assert.deepEqual(copiedFiles, [{ sourceFileName: path.join(pathToAppResourcesAndroid, "*"), destinationFileName: pathToResDirInPlatforms }]); + }); + + it("deletes correct values- directories based on the compileSdk", async () => { + readDirectoryResults = { + [`${pathToResDirInPlatforms}`]: [ + "values", + "values-v21", + "values-v26", + "values-v27", + "values-v28" + ] + }; + + compileSdkVersion = 26; + + await androidProjectService.prepareAppResources(projectData); + + // During preparation of old App_Resources, CLI copies all of them in platforms and after that deletes the libs directory. + assert.deepEqual(deletedDirs, [ + libsPath, + valuesV27Path, + valuesV28Path + ]); + }); + + it("deletes drawable directories when they've been previously prepared", async () => { + readDirectoryResults = { + [`${pathToAppResourcesAndroid}`]: [ + "drawable-hdpi", + "drawable-ldpi", + "values", + "values-v21", + "values-v29" + ], + [`${pathToResDirInPlatforms}`]: [ + "drawable-hdpi", + "drawable-ldpi", + "drawable-mdpi", + "values", + "values-v21", + "values-v29" + ] + }; + + await androidProjectService.prepareAppResources(projectData); + // NOTE: Currently the drawable-mdpi directory is not deleted from prepared App_Resources as it does not exist in the currently prepared App_Resources + // This is not correct behavior and it should be fixed in a later point. + // During preparation of old App_Resources, CLI copies all of them in platforms and after that deletes the libs directory. + assert.deepEqual(deletedDirs, [ + drawableHdpiPath, + drawableLdpiPath, + libsPath + ]); + }); + }); + }); }); From a6d5eb52eae1c7a9773d638674dbced7eb4aa6dd Mon Sep 17 00:00:00 2001 From: fatme Date: Fri, 15 Nov 2019 09:51:58 +0200 Subject: [PATCH 06/11] fix: fix livesync when `--no-hmr` option is provided and changes are reverted to the initial state of application Livesync doesn't work when `tns run ios --no-hmr` command is executed, same changes are synced and the application is reverted to its initial state. On first webpack compilation CLI stores the initial hash of the compilation but the stored hash is updated only in `hmr` mode. On the other side, CLI has a logic to return when the stored hash is the same as the current hash. So, when the changes are reverted to the initial state of the application, the current hash is the same as the first reported hash. This way, CLI doesn't execute any livesync logic after the reported changes from webpack process. Rel to: https://github.com/NativeScript/nativescript-cli/issues/5132 --- lib/services/webpack/webpack-compiler-service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/services/webpack/webpack-compiler-service.ts b/lib/services/webpack/webpack-compiler-service.ts index 297e306bef..e46474bdf8 100644 --- a/lib/services/webpack/webpack-compiler-service.ts +++ b/lib/services/webpack/webpack-compiler-service.ts @@ -42,7 +42,7 @@ export class WebpackCompilerService extends EventEmitter implements IWebpackComp if (message.emittedFiles) { if (isFirstWebpackWatchCompilation) { isFirstWebpackWatchCompilation = false; - this.expectedHashes[platformData.platformNameLowerCase] = message.hash; + this.expectedHashes[platformData.platformNameLowerCase] = prepareData.hmr ? message.hash : ""; return; } From f3171a8ed63b681118aa729f4876e619d25306b3 Mon Sep 17 00:00:00 2001 From: rosen-vladimirov Date: Fri, 15 Nov 2019 18:45:04 +0200 Subject: [PATCH 07/11] fix: generate iOS images when we have their sizes In case we do not have some of iOS Resource images in our image-definitions.json file, we do not generate images for them. This was not the case prior 6.2.0 release, so fix the behavior by getting back the old logic - get the image size from the Contents.json and generate image for it. Also add the images from the templates that are currently missing from our `image-definitions.json` file. --- lib/services/project-data-service.ts | 11 ++- resources/assets/image-definitions.json | 21 ++++++ test/services/project-data-service.ts | 97 +++++++++++++++++++++++++ 3 files changed, 127 insertions(+), 2 deletions(-) diff --git a/lib/services/project-data-service.ts b/lib/services/project-data-service.ts index db02f78245..30dc8b0cd3 100644 --- a/lib/services/project-data-service.ts +++ b/lib/services/project-data-service.ts @@ -282,8 +282,15 @@ export class ProjectDataService implements IProjectDataService { } }); - if (!foundMatchingDefinition && image.filename) { - this.$logger.warn(`Didn't find a matching image definition for file ${path.join(path.basename(dirPath), image.filename)}. This file will be skipped from reources generation.`); + if (!foundMatchingDefinition) { + if (image.height && image.width) { + this.$logger.trace("Missing data for image", image, " in CLI's resource file, but we will try to generate images based on the size from Contents.json"); + finalContent.images.push(image); + } else if (image.filename) { + this.$logger.warn(`Didn't find a matching image definition for file ${path.join(path.basename(dirPath), image.filename)}. This file will be skipped from resources generation.`); + } else { + this.$logger.trace(`Unable to detect data for image generation of image`, image); + } } }); diff --git a/resources/assets/image-definitions.json b/resources/assets/image-definitions.json index 7777b0ec04..78e1e7eb5b 100644 --- a/resources/assets/image-definitions.json +++ b/resources/assets/image-definitions.json @@ -1,6 +1,27 @@ { "ios": { "icons": [ + { + "width": 20, + "height": 20, + "directory": "Assets.xcassets/AppIcon.appiconset", + "filename": "icon-20@3x.png", + "scale": "3x" + }, + { + "width": 20, + "height": 20, + "directory": "Assets.xcassets/AppIcon.appiconset", + "filename": "icon-20@2x.png", + "scale": "2x" + }, + { + "width": 20, + "height": 20, + "directory": "Assets.xcassets/AppIcon.appiconset", + "filename": "icon-20.png", + "scale": "1x" + }, { "width": 60, "height": 60, diff --git a/test/services/project-data-service.ts b/test/services/project-data-service.ts index 35c4c919c2..9b4da40ea7 100644 --- a/test/services/project-data-service.ts +++ b/test/services/project-data-service.ts @@ -366,6 +366,103 @@ describe("projectDataService", () => { assert.deepEqual(assetStructure, { ios: emptyAssetStructure, android: _.merge(_.cloneDeep(emptyAssetStructure), { splashImages: null }) }); }); + + it("generates iOS resources for files, which are not declared in image-definitions.json, but we have their size from resource's Contents.json", async () => { + const defaultEmptyData: any = {}; + defaultEmptyData[CLIENT_NAME_KEY_IN_PROJECT_FILE] = {}; + const testInjector = createTestInjector(JSON.stringify(defaultEmptyData)); + const fs = testInjector.resolve("fs"); + fs.exists = () => true; + fs.readJson = (filePath: string): any => { + if (basename(filePath) === AssetConstants.imageDefinitionsFileName) { + return { + android: {}, + ios: { + "icons": [ + { + "width": 20, + "height": 20, + "directory": "Assets.xcassets/AppIcon.appiconset", + "filename": "icon-20@3x.png", + "scale": "3x" + }] + } + }; + } + + if (basename(filePath) === AssetConstants.iOSResourcesFileName && filePath.indexOf(AssetConstants.iOSIconsDirName) !== -1) { + return { + "images": [ + { + "size": "20x20", + "idiom": "iphone", + "filename": "icon-20@2x.png", + "scale": "2x" + }, + { + "size": "20x20", + "idiom": "iphone", + "filename": "icon-20@3x.png", + "scale": "3x" + } + ] + }; + } + }; + + const projectDataService = testInjector.resolve("projectDataService"); + const assetStructure = await projectDataService.getAssetsStructure({ projectDir: "." }); + const emptyAssetStructure: IAssetGroup = { + icons: { + images: [] + }, + splashBackgrounds: { + images: [] + }, + splashCenterImages: { + images: [] + }, + splashImages: { + images: [] + } + }; + + const expectedIOSStructure = _.merge({}, emptyAssetStructure, { + icons: { + "images": [ + { + "filename": "icon-20@2x.png", + "height": 20, + "idiom": "iphone", + "scale": "2x", + "size": "20x20", + "width": 20 + }, + { + "filename": "icon-20@3x.png", + "height": 20, + "idiom": "iphone", + "overlayImageScale": undefined, + "resizeOperation": undefined, + "rgba": undefined, + "scale": "3x", + "size": "20x20", + "width": 20 + } + ] + } + }); + + _.each(assetStructure.ios.icons.images, icon => { + // as path is generated from the current directory, skip it from the validation + delete icon.path; + }); + + assert.deepEqual(assetStructure, { + ios: expectedIOSStructure, + android: _.merge(_.cloneDeep(emptyAssetStructure), { splashImages: null }) + }); + }); }); describe("getAppExecutableFiles", () => { From 27375b67ad37e5d7b9e4469c3d27de95a2899ee5 Mon Sep 17 00:00:00 2001 From: endarova Date: Mon, 18 Nov 2019 11:34:41 +0200 Subject: [PATCH 08/11] chore: create changelog for 6.2.1 release --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c81f75fbc9..c6719f027e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,13 @@ NativeScript CLI Changelog ================ +6.2.1 (2019, November 18) +== + +### Fixed +* [Fixed #5120](https://github.com/NativeScript/nativescript-cli/issues/5120): Android resource directories are not prepared correctly +* [Fixed #5105](https://github.com/NativeScript/nativescript-cli/issues/5105): App restarts when changing platform specific scss + 6.2.0 (2019, November 1) == From 60fc024a45778f3c7d750595e75eb0d466416e50 Mon Sep 17 00:00:00 2001 From: rosen-vladimirov Date: Mon, 18 Nov 2019 12:05:44 +0200 Subject: [PATCH 09/11] chore: set version to 6.2.2 --- npm-shrinkwrap.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index f51552202e..969d5d63d6 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,6 +1,6 @@ { "name": "nativescript", - "version": "6.2.1", + "version": "6.2.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 06cd007e91..4f1bd0f4b4 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "nativescript", "preferGlobal": true, - "version": "6.2.1", + "version": "6.2.2", "author": "Telerik ", "description": "Command-line interface for building NativeScript projects", "bin": { From d2aceaa48ce282e4f764af215d88ec785c3a9651 Mon Sep 17 00:00:00 2001 From: rosen-vladimirov Date: Thu, 21 Nov 2019 08:57:23 +0200 Subject: [PATCH 10/11] chore: add script for automatic changelog generation Add script to generate the changelog automatically. The script should be called from the root of the repository in the following way: ``` node generate_changelog.js ``` For example: ``` node generate_changelog.js 6.2.2 2d2156c261bb1494f7a6e22f11fa446c7ca0e6b7 ``` The script uses GitHub's GraphQL API v4. More information about it can be found [here](https://developer.github.com/v4/). The script is designed to work with current NativeScript CLI workflow: - it generates changelog based on CLI's Changelog.md format - it generates changelog only for issues, PR's added in the milestone are not included in the changelog - issues with no-changelog label are not added to the milestone. A warning is shown for them. - issues with feature label are added to the "New" section of the changelog. All other issues are added to the "Fixed" section. - issues, which are not in state "Ready for Test", "In testing" or "Done" are not added to the changelog. A warning is shown for them. --- .npmignore | 3 +- generate_changelog.js | 195 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 197 insertions(+), 1 deletion(-) create mode 100644 generate_changelog.js diff --git a/.npmignore b/.npmignore index b724e00efa..4d66a58b90 100644 --- a/.npmignore +++ b/.npmignore @@ -31,4 +31,5 @@ scratch/ docs/html/ dev/ -.travis/**/* \ No newline at end of file +.travis/**/* +generate_changelog.js \ No newline at end of file diff --git a/generate_changelog.js b/generate_changelog.js new file mode 100644 index 0000000000..1b5f9588ba --- /dev/null +++ b/generate_changelog.js @@ -0,0 +1,195 @@ +"use strict"; + +const _ = require("lodash"); +const request = require("request"); +const fs = require("fs"); +const path = require("path"); +require("colors"); + +const argv = process.argv; +if (argv.length < 3 || argv.length > 4) { + console.error(`Incorrect usage. You need to pass the milestone and optionally the Authorization token.\n`.red + + `### Example: +node generate_changelog.js 6.2.2 2d2156c261bb1494f7a6e22f11fa446c7ca0e6b7\n`.yellow); + process.exit(127); +} + +const selectedMilestone = process.argv[2]; +const token = process.argv[3] || process.env.NS_CLI_CHANGELOG_AUTHORIZATION; +if (!token) { + console.error(`Unable to find Authorization token.\n`.red + + `You must either set NS_CLI_CHANGELOG_AUTHORIZATION environment variable or pass the token as an argument to the script:\n`.yellow + + `node generate_changelog.js 6.2.2 2d2156c261bb1494f7a6e22f11fa446c7ca0e6b7\n`.green); + process.exit(127); +} + +const sendRequest = (query) => { + return new Promise((resolve, reject) => { + request.post("https://api.github.com/graphql", { + headers: { + "Accept": "application/json", + "Authorization": `Bearer ${token}`, + "User-Agent": "NativeScript CLI Changelog Generator" + }, + body: JSON.stringify(query), + followAllRedirects: true + }, (err, response, body) => { + if (err) { + reject(err); + return; + } + resolve(JSON.parse(body)); + }); + }); +}; + +const getMilestonesInfoQuery = { + query: `{ + repository(owner:"NativeScript", name:"nativescript-cli") { + milestones(first: 100, states: OPEN) { + nodes { + number + id + title + url + } + } + } +}` +}; + +sendRequest(getMilestonesInfoQuery) + .then(result => { + const milestones = result && result.data && result.data.repository && result.data.repository.milestones && result.data.repository.milestones.nodes || []; + const matchingMilestone = _.find(milestones, m => m.title === selectedMilestone); + if (!matchingMilestone) { + throw new Error(`Unable to find milestone ${selectedMilestone} in the milestones. Current milestones info is: ${JSON.stringify(milestones, null, 2)}`); + } + return matchingMilestone.number; + }) + .then((milestone) => { + const getItemsForMilestoneQuery = { + query: `{ + repository(owner:"NativeScript", name:"nativescript-cli") { + milestone(number: ${milestone}) { + number + id + issuePrioritiesDebug + url + issues(first: 100) { + nodes { + title + url + number + labels(first:100) { + edges { + node { + name + } + } + } + projectCards(first: 100) { + nodes { + column { + name + } + project { + name + number + } + state + } + } + } + } + } + } +}` + }; + return sendRequest(getItemsForMilestoneQuery); + }) + .then((milestoneQueryResult) => { + const issues = (milestoneQueryResult && milestoneQueryResult.data && milestoneQueryResult.data.repository && + milestoneQueryResult.data.repository.milestone && milestoneQueryResult.data.repository.milestone.issues && + milestoneQueryResult.data.repository.milestone.issues.nodes) || []; + const finalIssuesForChangelog = []; + issues.forEach((issue) => { + const labels = ((issue.labels && issue.labels.edges) || []).map((lblObj) => lblObj && lblObj.node && lblObj.node.name); + const isFeature = labels.indexOf("feature") !== -1; + const isBug = labels.indexOf("bug") !== -1; + const shouldBeSkipped = labels.indexOf("no-changelog") !== -1; + if (isFeature && isBug) { + console.error(`The item '${issue.title}' has both bug and feature label. Clear one of them and try again.`.red); + process.exit(1); + } else if (shouldBeSkipped) { + console.log(`Item ${issue && issue.url}(${issue && issue.title}) will not be included in changelog as it has no-changelog label`.yellow); + } else { + // check if we have resolved it: + const columns = (issue && issue.projectCards && issue.projectCards.nodes || []).map(c => c && c.column && c.column.name); + // There shouldn't be more than one columns. + const column = _.first(columns); + if (columns && column === "Ready for Test" || column === "In Testing" || column === "Done") { + finalIssuesForChangelog.push({ + type: isFeature ? "feature" : "bug", + number: issue && issue.number, + title: issue && issue.title, + url: issue && issue.url + }); + } else { + console.log(`Item ${issue && issue.url}(${issue && issue.title}) will not be included in changelog as its status is ${columns}`.yellow); + } + } + }); + + return finalIssuesForChangelog; + }) + .then(data => { + const features = []; + const bugs = []; + + _.sortBy(data, (d) => d.number) + .forEach(d => { + if (d.type === "feature") { + features.push(`* [Implemented #${d.number}](${d.url}): ${d.title}`); + } else { + bugs.push(`* [Fixed #${d.number}](${d.url}): ${d.title}`); + } + }); + + const pathToChangelog = path.join(__dirname, "CHANGELOG.md"); + let changelogContent = fs.readFileSync(pathToChangelog).toString(); + + if (features.length === 0 && bugs.length === 0) { + console.error(`Unable to find anything ready for milestone ${selectedMilestone}`.red); + process.exit(2); + } + + const monthNames = ["January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December" + ]; + const currentDate = new Date(); + + let newChangelogContent = `\n${selectedMilestone} (${currentDate.getFullYear()}, ${monthNames[currentDate.getMonth()]} ${currentDate.getDate()}) +=== +`; + if (features.length > 0) { + newChangelogContent += ` +### New + +${features.join("\n")} +`; + } + if (bugs.length) { + newChangelogContent += ` +### Fixed + +${bugs.join("\n")} +`; + } + + changelogContent = changelogContent.replace(/(NativeScript CLI Changelog\r?\n=+\r?\n)([\s\S]*)/m, `$1${newChangelogContent}\n$2`); + fs.writeFileSync(pathToChangelog, changelogContent); + console.log(`Successfully added Changelog for ${selectedMilestone}`.green); + console.log("Commit the local changes and send a PR.".magenta); + }) + .catch(error => console.error(error)); \ No newline at end of file From 425a32d3ff0ca7f37997f753c36c1ce49e6f1174 Mon Sep 17 00:00:00 2001 From: miroslavaivanova Date: Fri, 22 Nov 2019 10:53:46 +0200 Subject: [PATCH 11/11] Update CHANGELOG.md --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c6719f027e..18aa3ae739 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ NativeScript CLI Changelog ================ +6.2.2 (2019, November 22) +== + +### Fixed +* [Fixed #5126](https://github.com/NativeScript/nativescript-cli/issues/5126): CLI does not generate all icons 6.2.1 (2019, November 18) ==