Пример #1
0
        // Generate a standard error message for project manifest field checks. This is also used during tests
        internal string CreateFieldErrorMessage(string fieldName)
        {
            string docsLink = ErrorDocumentation.GetLinkMessage(k_DocsFilePath,
                                                                "The-{fieldName}-field-in-the-project-manifest-is-not-a-valid-field-for-template-packages");

            return($"The `{fieldName}` field in the project manifest is not a valid field for template packages. Please remove this field from {Context.ProjectInfo.ManifestPath}. {docsLink}");
        }
Пример #2
0
        // Require a minor bump of the package version when the minimum Unity version requirement becomes more strict.
        // This is to ensure that we have patch versions available for the previous version of the package.
        void ValidateUnityVersionBump(ManifestData previousManifest, ManifestData currentManifest)
        {
            // This is the first version of the package.
            if (previousManifest == null)
            {
                return;
            }

            // Minimum Unity version requirement did not change.
            var currentPackageUnityVersion  = GetPackageUnityVersion(currentManifest);
            var previousPackageUnityVersion = GetPackageUnityVersion(previousManifest);

            if (currentPackageUnityVersion == previousPackageUnityVersion)
            {
                return;
            }

            // Minimum Unity version requirement became less strict.
            if (currentPackageUnityVersion < previousPackageUnityVersion)
            {
                AddWarning(
                    "The Unity version requirement is less strict than in the previous version of the package. " +
                    "Please confirm that this change is deliberate and intentional. " +
                    ErrorDocumentation.GetLinkMessage(k_DocsFilePath, k_DocsLessStrictSection));
                return;
            }

            // Major or minor version of package was bumped.
            var previousPackageVersion = SemVersion.Parse(previousManifest.version);
            var currentPackageVersion  = SemVersion.Parse(currentManifest.version);

            if (currentPackageVersion.Major > previousPackageVersion.Major ||
                currentPackageVersion.Minor > previousPackageVersion.Minor)
            {
                return;
            }

            AddUnityAuthoredConditionalError(currentManifest,
                                             "The Unity version requirement is more strict than in the previous version of the package. " +
                                             "Increment the minor version of the package to leave patch versions available for previous version. " +
                                             ErrorDocumentation.GetLinkMessage(k_DocsFilePath, k_DocsMoreStrictSection));
        }
        /**
         * Can't promote if it's a release or RC
         * Can promote -preview, -pre (unless it is the first one, but that is verified somewhere else) and -exp
         * Error in Promotion
         * Only warn when in CI
         */
        private void ValidateVersionAbilityToPromote(SemVersion packageVersionNumber, VersionTag versionTag, ManifestData manifestData)
        {
            // Make this check only in promotion, to avoid network calls
            if (Context.PackageVersionExistsOnProduction)
            {
                AddPromotionConditionalError("Version " + Context.ProjectPackageInfo.version + " of this package already exists in production.");
            }

            var message = String.Empty;

            if (PackageLifecyclePhase.IsReleasedVersion(packageVersionNumber, versionTag) ||
                PackageLifecyclePhase.IsRCForThisEditor(manifestData.name, Context))
            {
                message = $"Automated promotion of Release or Release Candidate packages is not allowed. Release Management are the only ones that can promote Release and Release Candidate packages to production, if you need this to happen, please go to #devs-pkg-promotion. {ErrorDocumentation.GetLinkMessage(k_DocsFilePath, "a-release-package-must-be-manually-promoted-by-release-management")}";
            }
            else
            {
                // We send a message if this is the first version of the package being promoted
                if (!Context.PackageExistsOnProduction)
                {
                    message = $"{Context.PublishPackageInfo.name} has never been promoted to production before. Please contact Release Management through slack in #devs-pkg-promotion to promote the first version of your package before trying to use this automated pipeline. {ErrorDocumentation.GetLinkMessage(k_DocsFilePath, "the-very-first-version-of-a-package-must-be-promoted-by-release-management")}";
                }
            }

            if (message != String.Empty)
            {
                AddPromotionConditionalError(message);
            }
        }
        private void ValidateDependenciesLifecyclePhase(Dictionary <string, string> dependencies)
        {
            // No dependencies, exit early
            if (!dependencies.Any())
            {
                return;
            }

            // Extract the current track, since otherwise we'd be potentially parsing the version
            // multiple times
            var currentTrack = PackageLifecyclePhase.GetLifecyclePhaseOrRelation(Context.ProjectPackageInfo.version, Context.ProjectPackageInfo.name, Context);

            var supportedVersions = PackageLifecyclePhase.GetPhaseSupportedVersions(currentTrack);

            // Check each dependency against supported versions
            foreach (var dependency in dependencies)
            {
                // Skip invalid dependencies from this check
                SemVersion depVersion;
                if (!SemVersion.TryParse(dependency.Value, out depVersion))
                {
                    continue;
                }

                LifecyclePhase dependencyTrack = PackageLifecyclePhase.GetLifecyclePhaseOrRelation(dependency.Value.ToLower(), dependency.Key.ToLower(), Context);
                var            depId           = Utilities.CreatePackageId(dependency.Key, dependency.Value);
                if (!supportedVersions.HasFlag(dependencyTrack))
                {
                    AddError($"Package {Context.ProjectPackageInfo.Id} depends on package {depId} which is in an invalid track for release purposes. {currentTrack} versions can only depend on {supportedVersions.ToString()} versions. {ErrorDocumentation.GetLinkMessage(k_DocsFilePath, "package-depends-on-a-package-which-is-in-an-invalid-track-for-release-purposes")}");
                }
            }
        }
        private void LifecycleV2VersionValidator(SemVersion packageVersionNumber, VersionTag versionTag)
        {
            if (versionTag.IsEmpty())
            {
                return;
            }

            if (versionTag.Tag == "preview")
            {
                AddError("In package.json, \"version\" cannot be tagged \"preview\" in lifecycle v2, please use \"exp\". " + ErrorDocumentation.GetLinkMessage(ErrorTypes.InvalidLifecycleV2));
                return;
            }

            if (packageVersionNumber.Major < 1)
            {
                AddError("In package.json, \"version\" cannot be tagged \"" + packageVersionNumber.Prerelease + "\" while the major version less than 1. " + ErrorDocumentation.GetLinkMessage(ErrorTypes.InvalidLifecycleV2));
                return;
            }

            if (versionTag.Tag != "exp" && versionTag.Tag != "pre")
            {
                AddError("In package.json, \"version\" must be a valid tag. \"" + versionTag.Tag + "\" is invalid, try either \"pre\" or \"exp\". " + ErrorDocumentation.GetLinkMessage(ErrorTypes.InvalidLifecycleV2));
                return;
            }

            if (versionTag.Tag != "exp" && versionTag.Feature != "")
            {
                AddError("In package.json, \"version\" must be a valid tag. Custom tag \"" + versionTag.Feature + "\" only allowed with \"exp\". " + ErrorDocumentation.GetLinkMessage(ErrorTypes.InvalidLifecycleV2));
                return;
            }

            if (versionTag.Tag == "exp" && versionTag.Feature.Length > 10)
            {
                AddError("In package.json, \"version\" must be a valid tag. Custom tag \"" + versionTag.Feature + "\" is too long, must be 10 characters long or less. " + ErrorDocumentation.GetLinkMessage(ErrorTypes.InvalidLifecycleV2));
                return;
            }

            if (versionTag.Iteration < 1)
            {
                AddError("In package.json, \"version\" must be a valid tag. Iteration is required to be 1 or greater. " + ErrorDocumentation.GetLinkMessage(ErrorTypes.InvalidLifecycleV2));
                return;
            }
        }
Пример #6
0
        /// <summary>
        /// For templates, we want to make sure that Show Preview Packages or Show Pre-Release packages
        /// are not enabled.
        /// For <=2019.4 this is saved on the profile preferences and is not bound to be
        /// pre-enabled. For >2019.4 this is saved in ProjectSettings/PackageManagerSettings.asset
        /// </summary>
        private void ValidatePackageManagerSettings()
        {
            if (Context.ProjectInfo.PackageManagerSettingsValidation == null)
            {
                return;
            }

            if (Context.ProjectInfo.PackageManagerSettingsValidation.m_EnablePreviewPackages)
            {
                AddError($"Preview packages are not allowed to be enabled on template packages. Please disable the `Enable Preview Packages` option in ProjectSettings > PackageManager > Advanced Settings. {ErrorDocumentation.GetLinkMessage(k_DocsFilePath, "preview|prerelease-packages-are-not-allowed-to-be-enabled-on-template-packages")}");
            }

            if (Context.ProjectInfo.PackageManagerSettingsValidation.m_EnablePreReleasePackages)
            {
                AddError($"PreRelease packages are not allowed to be enabled on template packages. Please disable the `Enable PreRelease Packages` option in ProjectSettings > PackageManager > Advanced Settings. {ErrorDocumentation.GetLinkMessage(k_DocsFilePath, "preview|prerelease-packages-are-not-allowed-to-be-enabled-on-template-packages")}");
            }
        }
        private void CheckApiDiff(AssemblyInfo[] assemblyInfo)
        {
#if UNITY_2018_1_OR_NEWER && !UNITY_2019_1_OR_NEWER
            TestState = TestState.NotRun;
            AddInformation("Api breaking changes validation only available on Unity 2019.1 or newer.");
            return;
#else
            var diff = new ApiDiff();
            var assembliesForPackage = assemblyInfo.Where(a => !validationAssemblyInformation.IsTestAssembly(a)).ToArray();
            if (Context.PreviousPackageBinaryDirectory == null)
            {
                TestState = TestState.NotRun;
                AddInformation("Previous package binaries must be present on artifactory to do API diff.");
                return;
            }

            var oldAssemblyPaths = Directory.GetFiles(Context.PreviousPackageBinaryDirectory, "*.dll");

            //Build diff
            foreach (var info in assembliesForPackage)
            {
                var assemblyDefinition = info.assemblyDefinition;
                var oldAssemblyPath    = oldAssemblyPaths.FirstOrDefault(p => Path.GetFileNameWithoutExtension(p) == assemblyDefinition.name);

                if (info.assembly != null)
                {
                    var extraSearchFolder    = Path.GetDirectoryName(typeof(System.ObsoleteAttribute).Assembly.Location);
                    var assemblySearchFolder = new[]
                    {
                        extraSearchFolder,                                                              // System assemblies folder
                        Path.Combine(EditorApplication.applicationContentsPath, "Managed"),             // Main Unity assemblies folder.
                        Path.Combine(EditorApplication.applicationContentsPath, "Managed/UnityEngine"), // Module assemblies folder.
                        Path.GetDirectoryName(info.assembly.outputPath),                                // TODO: This is not correct. We need to keep all dependencies for the previous binaries. For now, use the same folder as the current version when resolving dependencies.
                        Context.ProjectPackageInfo.path                                                 // make sure to add the package folder as well, because it may contain .dll files
                    };

                    const string logsDirectory = "Logs";
                    if (!Directory.Exists(logsDirectory))
                    {
                        Directory.CreateDirectory(logsDirectory);
                    }

                    File.WriteAllText($"{logsDirectory}/ApiValidationParameters.txt", $"previous: {oldAssemblyPath}\ncurrent: {info.assembly.outputPath}\nsearch path: {string.Join("\n", assemblySearchFolder)}");
                    var apiChangesAssemblyInfo = new APIChangesCollector.AssemblyInfo()
                    {
                        BaseAssemblyPath = oldAssemblyPath,
                        BaseAssemblyExtraSearchFolders = assemblySearchFolder,
                        CurrentAssemblyPath            = info.assembly.outputPath,
                        CurrentExtraSearchFolders      = assemblySearchFolder
                    };

                    List <IAPIChange> entityChanges;
                    try
                    {
                        entityChanges = APIChangesCollector.Collect(apiChangesAssemblyInfo)
                                        .SelectMany(c => c.Changes).ToList();
                    }
                    catch (AssemblyResolutionException exception)
                    {
                        if (exception.AssemblyReference.Name == "UnityEditor.CoreModule" ||
                            exception.AssemblyReference.Name == "UnityEngine.CoreModule")
                        {
                            AddError(
                                "Failed comparing against assemblies of previously promoted version of package. \n" +
                                "This is most likely because the assemblies that were compared against were built with a different version of Unity. \n" +
                                "If you are certain that there are no API changes warranting bumping the package version then you can add an exception for this error:\n" +
                                ErrorDocumentation.GetLinkMessage("validation_exceptions.html", ""));
                            AddInformation($"APIChangesCollector.Collect threw exception:\n{exception}");
                            return;
                        }

                        throw;
                    }

                    var assemblyChange = new AssemblyChange(info.assembly.name)
                    {
                        additions = entityChanges.Where(c => c.IsAdd()).Select(c => c.ToString()).ToList(),
                        // Among all attribute changes, only the Obsolete attribute should be considered a breaking change
                        breakingChanges = entityChanges.Where(c => !c.IsAdd() && !((c.GetType()).Equals(typeof(AttributeChange)))).Select(c => c.ToString()).ToList()
                    };

                    if (entityChanges.Count > 0)
                    {
                        diff.assemblyChanges.Add(assemblyChange);
                    }
                }

                if (oldAssemblyPath == null)
                {
                    diff.newAssemblies.Add(assemblyDefinition.name);
                }
            }

            foreach (var oldAssemblyPath in oldAssemblyPaths)
            {
                var oldAssemblyName = Path.GetFileNameWithoutExtension(oldAssemblyPath);
                if (assembliesForPackage.All(a => a.assemblyDefinition.name != oldAssemblyName))
                {
                    diff.missingAssemblies.Add(oldAssemblyName);
                }
            }

            //separate changes
            diff.additions            = diff.assemblyChanges.Sum(v => v.additions.Count);
            diff.removedAssemblyCount = diff.missingAssemblies.Count;
            diff.breakingChanges      = diff.assemblyChanges.Sum(v => v.breakingChanges.Count);

            AddInformation("Tested against version {0}", Context.PreviousPackageInfo.Id);
            AddInformation("API Diff - Breaking changes: {0} Additions: {1} Missing Assemblies: {2}",
                           diff.breakingChanges,
                           diff.additions,
                           diff.removedAssemblyCount);

            if (diff.breakingChanges > 0 || diff.additions > 0)
            {
                TestOutput.AddRange(diff.assemblyChanges.Select(c => new ValidationTestOutput()
                {
                    Type = TestOutputType.Information, Output = JsonUtility.ToJson(c, true)
                }));
            }

            string json = JsonUtility.ToJson(diff, true);
            Directory.CreateDirectory(ValidationSuiteReport.ResultsPath);
            File.WriteAllText(Path.Combine(ValidationSuiteReport.ResultsPath, "ApiValidationReport.json"), json);

            //Figure out type of version change (patch, minor, major)
            //Error if changes are not allowed
            var changeType = Context.VersionChangeType;

            if (changeType == VersionChangeType.Unknown)
            {
                return;
            }

            if (Context.ProjectPackageInfo.LifecyclePhase == LifecyclePhase.Preview || Context.ProjectPackageInfo.LifecyclePhase == LifecyclePhase.Experimental)
            {
                ExperimentalPackageValidateApiDiffs(diff, changeType);
            }
            else
            {
                ReleasePackageValidateApiDiffs(diff, changeType);
            }
#endif
        }