Exemple #1
0
 public LibGit2Sharp.RepositoryStatus GetModifiedFileList()
 {
     LibGit2Sharp.StatusOptions option = new LibGit2Sharp.StatusOptions();
     return repository_.RetrieveStatus(option);
 }
        private static void CleanRepoAndSubmodules(LibGit2Sharp.Repository repo, ILogger log)
        {
            using (log.BeginScope($"Beginning clean of {repo.Info.WorkingDirectory} and {repo.Submodules.Count()} submodules"))
            {
                log.LogDebug($"Beginning clean of {repo.Info.WorkingDirectory} and {repo.Submodules.Count()} submodules");
                LibGit2Sharp.StatusOptions options = new LibGit2Sharp.StatusOptions
                {
                    IncludeUntracked     = true,
                    RecurseUntrackedDirs = true,
                };
                int count = 0;
                foreach (LibGit2Sharp.StatusEntry item in repo.RetrieveStatus(options))
                {
                    if (item.State == LibGit2Sharp.FileStatus.NewInWorkdir)
                    {
                        File.Delete(Path.Combine(repo.Info.WorkingDirectory, item.FilePath));
                        ++count;
                    }
                }
                log.LogDebug($"Deleted {count} untracked files");

                foreach (LibGit2Sharp.Submodule sub in repo.Submodules)
                {
                    string normalizedSubPath  = sub.Path.Replace('\\', Path.DirectorySeparatorChar).Replace('/', Path.DirectorySeparatorChar);
                    string subRepoPath        = Path.Combine(repo.Info.WorkingDirectory, normalizedSubPath);
                    string subRepoGitFilePath = Path.Combine(subRepoPath, ".git");
                    if (!File.Exists(subRepoGitFilePath))
                    {
                        log.LogDebug($"Submodule {sub.Name} in {subRepoPath} does not appear to be initialized (no file at {subRepoGitFilePath}), attempting to initialize now.");
                        // hasn't been initialized yet, can happen when different hashes have new or moved submodules
                        try
                        {
                            repo.Submodules.Update(sub.Name, new LibGit2Sharp.SubmoduleUpdateOptions {
                                Init = true
                            });
                        }
                        catch
                        {
                            log.LogDebug($"Submodule {sub.Name} in {subRepoPath} is already initialized, trying to adopt from super-repo {repo.Info.Path}");

                            // superrepo thinks it is initialized, but it's orphaned.  Go back to the master repo to find out where this is supposed to point.
                            using (LibGit2Sharp.Repository masterRepo = new LibGit2Sharp.Repository(repo.Info.WorkingDirectory))
                            {
                                LibGit2Sharp.Submodule masterSubModule = masterRepo.Submodules.Single(s => s.Name == sub.Name);
                                string masterSubPath = Path.Combine(repo.Info.Path, "modules", masterSubModule.Path);
                                log.LogDebug($"Writing .gitdir redirect {masterSubPath} to {subRepoGitFilePath}");
                                Directory.CreateDirectory(Path.GetDirectoryName(subRepoGitFilePath));
                                File.WriteAllText(subRepoGitFilePath, $"gitdir: {masterSubPath}");
                            }
                        }
                    }

                    using (log.BeginScope($"Beginning clean of submodule {sub.Name}"))
                    {
                        log.LogDebug($"Beginning clean of submodule {sub.Name} in {subRepoPath}");

                        // The worktree is stored in the .gitdir/config file, so we have to change it
                        // to get it to check out to the correct place.
                        LibGit2Sharp.ConfigurationEntry <string> oldWorkTree = null;
                        using (LibGit2Sharp.Repository subRepo = new LibGit2Sharp.Repository(subRepoPath))
                        {
                            oldWorkTree = subRepo.Config.Get <string>("core.worktree");
                            if (oldWorkTree != null)
                            {
                                log.LogDebug($"{subRepoPath} old worktree is {oldWorkTree.Value}, setting to {subRepoPath}");
                                subRepo.Config.Set("core.worktree", subRepoPath);
                            }
                            // This branch really shouldn't happen but just in case.
                            else
                            {
                                log.LogDebug($"{subRepoPath} has default worktree, leaving unchanged");
                            }
                        }

                        using (LibGit2Sharp.Repository subRepo = new LibGit2Sharp.Repository(subRepoPath))
                        {
                            log.LogDebug($"Resetting {sub.Name} to {sub.HeadCommitId.Sha}");
                            subRepo.Reset(LibGit2Sharp.ResetMode.Hard, subRepo.Commits.QueryBy(new LibGit2Sharp.CommitFilter {
                                IncludeReachableFrom = subRepo.Refs
                            }).Single(c => c.Sha == sub.HeadCommitId.Sha));
                            // Now we reset the worktree back so that when we can initialize a Repository
                            // from it, instead of having to figure out which hash of the repo was most recently checked out.
                            if (oldWorkTree != null)
                            {
                                log.LogDebug($"resetting {subRepoPath} worktree to {oldWorkTree.Value}");
                                subRepo.Config.Set("core.worktree", oldWorkTree.Value);
                            }
                            else
                            {
                                log.LogDebug($"leaving {subRepoPath} worktree as default");
                            }
                            log.LogDebug($"Done resetting {subRepoPath}, checking submodules");
                            CleanRepoAndSubmodules(subRepo, log);
                        }
                    }

                    if (File.Exists(subRepoGitFilePath))
                    {
                        log.LogDebug($"Deleting {subRepoGitFilePath} to orphan submodule {sub.Name}");
                        File.Delete(subRepoGitFilePath);
                    }
                    else
                    {
                        log.LogDebug($"{sub.Name} doesn't have a .gitdir redirect at {subRepoGitFilePath}, skipping delete");
                    }
                }
            }
        }
        public override void ExecuteBuild()
        {
            DLCName = ParseParamValue("Plugin", "");
            DLCDir = CombinePaths(CmdEnv.LocalRoot, "UnrealTournament", "Plugins", DLCName);
            PluginsDir = CombinePaths(CmdEnv.LocalRoot, "UnrealTournament", "Plugins");
            PublishDir = CombinePaths(DLCDir, "Releases");

            // Right now all platform asset registries seem to be the exact same, this may change in the future
            AssetRegistry = ParseParamValue("ReleaseVersion", "UTVersion0");
            VersionString = ParseParamValue("Version", "NOVERSION");

            FileVersionName = VERSION_NAME;

            // prevent processing automation process for the wrong plugin (if mutliple PluginPackageZip commands exist)
            if (!DLCName.Equals(PLUGIN_NAME, StringComparison.InvariantCultureIgnoreCase))
            {
                // no Expception as other plugins need to be processed
                return;
            }

            // Check parms
            if (!DirectoryExists(DLCDir))
            {
                throw new AutomationException("Plugin folder '{0}' does not exist. Verify that '-plugin={1}' is set up properly.", DLCDir, DLCName);
            }
            if (new DirectoryInfo(PluginsDir).FullName.Equals(new DirectoryInfo(DLCDir).FullName, StringComparison.InvariantCultureIgnoreCase))
            {
                throw new AutomationException("No Plugin given. Verify that '-plugin=PLUGINNAME' is set.");
            }

            // Check for changed files in the git repo and abort
            if (!ParseParam("NoGitCheck"))
            {
                string GitFolder = CombinePaths(DLCDir, GIT_FOLDER_NAME);
                if (DirectoryExists(GitFolder))
                {
                    using (var repo = new LibGit2Sharp.Repository(GitFolder))
                    {
                        LibGit2Sharp.StatusOptions check = new LibGit2Sharp.StatusOptions();
                        check.ExcludeSubmodules = true;

                        LibGit2Sharp.RepositoryStatus status = repo.RetrieveStatus(check);
                        if (status.IsDirty)
                        {
                            throw new AutomationException("Git code repository has uncommited changes.");
                        }

                        foreach (LibGit2Sharp.Submodule submodule in repo.Submodules)
                        {
                            LibGit2Sharp.SubmoduleStatus substatus = submodule.RetrieveStatus();
                            if (!substatus.HasFlag(LibGit2Sharp.SubmoduleStatus.Unmodified))
                            {
                                throw new AutomationException("Git sub module '{0}' has uncommited changes.", submodule.Name);
                            }
                        }
                    }
                }
            }

            // Check if binaries exist
            {
                string BinariesFolder = CombinePaths(DLCDir, "Binaries");
                if (!DirectoryExists(BinariesFolder))
                {
                    throw new AutomationException("No Binaries folder. Please, recompile the plugin from source files");
                }

                // TODO: Check for specific files (SO for linux and DLL for windows)
                if (FindFiles("*", true, BinariesFolder).Length == 0)
                {
                    throw new AutomationException("No binary files. Please, recompile the plugin from source files");
                }
            }

            //
            // Create filter list to exclude folder/files from zip
            //

            FileFilter Filter = new FileFilter();
            Filter.ExcludeConfidentialFolders();
            Filter.ExcludeConfidentialPlatforms();

            // read git ignore file and add these to the filder
            var FilterInclude = new List<string>();
            var FilterExclude = new List<string>();
            {
                string GitFolder = CombinePaths(DLCDir, GIT_FOLDER_NAME);
                if (DirectoryExists(GitFolder))
                {
                    using (var repo = new LibGit2Sharp.Repository(GitFolder))
                    {
                        var subrepos = new List<LibGit2Sharp.Repository>();
                        foreach (LibGit2Sharp.Submodule submodule in repo.Submodules)
                        {
                            string SubFolder = CombinePaths(DLCDir, submodule.Path);
                            if (DirectoryExists(SubFolder))
                            {
                                string relpath = SubFolder.Substring(DLCDir.Length).Replace("\\", "/").Trim('/');
                                FilterExclude.Add("/" + relpath + "/**");
                                subrepos.Add(new LibGit2Sharp.Repository(SubFolder));
                            }
                        }

                        foreach (var file in FindFiles("*", true, DLCDir))
                        {
                            bool subuntracked = false;
                            foreach (var subrepo in subrepos)
                            {
                                if (file.StartsWith(subrepo.Info.WorkingDirectory))
                                {
                                    LibGit2Sharp.FileStatus substatus = subrepo.RetrieveStatus(file);
                                    if (substatus == LibGit2Sharp.FileStatus.Untracked)
                                    {
                                        subuntracked = true;
                                        string relpath = file.Substring(DLCDir.Length).Replace("\\", "/").TrimStart('/');
                                        FilterInclude.Add(relpath);
                                        break;
                                    }
                                }
                            }

                            if (!subuntracked)
                            {
                                LibGit2Sharp.FileStatus status = repo.RetrieveStatus(file);

                                if (status == LibGit2Sharp.FileStatus.Untracked)
                                {
                                    string relpath = file.Substring(DLCDir.Length).Replace("\\", "/").TrimStart('/');
                                    FilterInclude.Add(relpath);
                                }
                            }
                        }

                        foreach (var subrepo in subrepos)
                        {
                            subrepo.Dispose();
                        }
                        subrepos.Clear();
                    }
                }

                string GitIgnoreFile = CombinePaths(DLCDir, GIT_IGNORE_FILE);
                if (FileExists(GitIgnoreFile))
                {
                    //HasGitIgnore = true;
                    var GitIgnores = GitIgnoreParser.ReadFromFile(GitIgnoreFile);

                    foreach (var entry in GitIgnores.Entries)
                    {
                        string pattern = entry.Pattern;
                        if (entry.Pattern.EndsWith("/")) pattern += "**";
                        if (entry.Type == GitIgnoreParser.GitIgnoreTypInfo.Include)
                        {
                            FilterInclude.Add(pattern);
                        }
                        else if (entry.Type == GitIgnoreParser.GitIgnoreTypInfo.Exclude)
                        {
                            FilterExclude.Add(pattern);
                        }
                    }
                }
            }

            // TODO: Add build file for includes

            // include bin and plugin content but only valid editor files
            foreach (var f in FilterExclude)
            {
                Filter.Include(f.Replace("**", "..."));
            }

            if (FilterInclude.Count == 0)
            {
                Filter.Include("Readme*");
                Filter.Include("*.txt");
                Filter.Include("*.md");
                Filter.Include("*.pod");
            }
            else
            {
                Filter.Include("/*.*");
            }

            // Add source if required
            if (ParseParam("source"))
            {
                Filter.Include("/Source/...");
                Filter.Include("/Build/...");
                Filter.Exclude("/Build/.../Obj/...");
            }
            else
            {
                Filter.Exclude("/Build/...");
            }

            foreach (var f in FilterInclude)
            {
                Filter.Exclude(f.Replace("**", "..."));
            }

            Filter.Include("/Binaries/...");

            // ignore debug symbols
            Filter.Exclude("/Binaries/.../*.pdb");

            // ignore git files
            Filter.Exclude(".git*");
            Filter.Exclude(".git/...");

            // always include plugin descriptor file
            Filter.Include("*.uplugin");

            // exclude releaes foldre
            Filter.Exclude("/Releases/...");
            Filter.Exclude("/Releases/.../...");

            // read current version info from file
            CreateVersionInfo();

            // create meta info which is stored in BuildMeta
            CreateMetaInfo();

            // create file name
            string ZipFileName = GenerateFileName() + ".zip";
            string ZipFile = CombinePaths(PublishDir, ZipFileName);
            string ZipDir = CombinePaths(CmdEnv.LocalRoot, "UnrealTournament", "Plugins", DLCName);

            // check if file exists and abort...
            if (FileExists(ZipFile) && !ParseParam("overwrite"))
            {
                throw new AutomationException("Release file {0} already exists.", ZipFileName);
            }

            string zipfolder = Packager.CopyFilesToZip(PublishDir, ZipDir, DLCName, Filter, NoConversion: HasParam("source"), ParseTextOnly: HasParam("ParseTextOnly"));
            ZipFiles(ZipFile, zipfolder, new FileFilter(FileFilterType.Include));

            if (ParseParam("publish") && BuildVersion.IsValid())
            {
                bool IsInternal = false;
                if (ParseParam("release"))
                {
                    // remove internal build (public release) ... just in case
                    DataWriteToFile(FileVersionName, BuildVersion.ToData(true));
                }
                else
                {
                    IsInternal = true;

                    // increase internal build
                    BuildVersion.BuildAsNumber += 1;
                    DataWriteToFile(FileVersionName, BuildVersion.ToData());
                }

                string GitFolder = CombinePaths(DLCDir, GIT_FOLDER_NAME);
                if (ParseParam("commit") && DirectoryExists(GitFolder))
                {
                    using (var repo = new LibGit2Sharp.Repository(GitFolder))
                    {
                        string commmessage;
                        if (IsInternal)
                            commmessage = string.Format(COMMIT_TITLE_VERSION_INTERNAL, BuildVersion.ToString());
                        else
                            commmessage = string.Format(COMMIT_TITLE_VERSION_PUBLISH, BuildVersion.ToShortVersion());

                        commmessage += Environment.NewLine;
                        commmessage += Environment.NewLine;

                        commmessage += BuildMeta.ToExtendedString();

                        // Stage the file
                        LibGit2Sharp.StageOptions stageoptions = new LibGit2Sharp.StageOptions();
                        repo.Stage(FileVersionName, stageoptions);

                        // Create the committer's signature and commit
                        LibGit2Sharp.Signature author = repo.Config.BuildSignature(DateTime.Now);
                        LibGit2Sharp.Signature committer = author;

                        // Commit to the repository
                        LibGit2Sharp.CommitOptions options = new LibGit2Sharp.CommitOptions();
                        LibGit2Sharp.Commit commit = repo.Commit(commmessage, author, committer, options);

                        // Commit new tag
                        LibGit2Sharp.Tag t = repo.Tags.Add(string.Format("v{0}", BuildVersion.ToShortVersion()), repo.Head.Tip);
                    }
                }
            }
        }