예제 #1
0
        public DeployAction TryParseDeploymentInfo(HttpRequestBase request, JObject payload, string targetBranch, out DeploymentInfo deploymentInfo)
        {
            deploymentInfo = null;
            string url = payload.Value<string>("RepositoryUrl");
            if (string.IsNullOrWhiteSpace(url) || !url.ToLowerInvariant().Contains("api.onedrive.com"))
            {
                return DeployAction.UnknownPayload;
            }

            /*
                 Expecting payload to be:
                 {
                    "RepositoryUrl": "xxx",
                    "AccessToken": "xxx"
                 }
             */
            string accessToken = payload.Value<string>("AccessToken");

            // keep email and name, so that can be re-used in later commit
            OneDriveInfo oneDriveInfo = new OneDriveInfo()
            {
                Deployer = "OneDrive",
                RepositoryUrl = url,
                AccessToken = accessToken,
                AuthorName = _settings.GetValue("authorName"),
                AuthorEmail = _settings.GetValue("authorEmail")
            };

            deploymentInfo = oneDriveInfo;

            deploymentInfo.TargetChangeset = DeploymentManager.CreateTemporaryChangeSet(
                authorName: oneDriveInfo.AuthorName,
                authorEmail: oneDriveInfo.AuthorEmail,
                message: String.Format(CultureInfo.CurrentUICulture, Resources.OneDrive_Synchronizing)
            );

            return DeployAction.ProcessDeployment;
        }
예제 #2
0
        public async Task SyncBasicTests()
        {
            var mockTracer = new Mock<ITracer>();
            mockTracer
                .Setup(m => m.Trace(It.IsAny<string>(), It.IsAny<IDictionary<string, string>>()));

            var repository = Mock.Of<IRepository>();
            var fileSystem = new Mock<IFileSystem>();
            var fileBase = new Mock<FileBase>();
            var fileInfoFactory = new Mock<IFileInfoFactory>();
            var fileInfo = new Mock<FileInfoBase>();
            var dirBase = new Mock<DirectoryBase>();
            var dirInfoFactory = new Mock<IDirectoryInfoFactory>(); // mock dirInfo to make FileSystemHelpers.DeleteDirectorySafe not throw exception
            var dirInfoBase = new Mock<DirectoryInfoBase>();
            fileSystem.Setup(f => f.File).Returns(fileBase.Object);
            fileSystem.Setup(f => f.FileInfo).Returns(fileInfoFactory.Object);
            fileInfoFactory.Setup(f => f.FromFileName(It.IsAny<string>()))
                           .Returns(() => fileInfo.Object);
            fileSystem.Setup(f => f.Directory).Returns(dirBase.Object);
            fileSystem.Setup(f => f.DirectoryInfo).Returns(dirInfoFactory.Object);
            dirInfoFactory.Setup(d => d.FromDirectoryName(It.IsAny<string>())).Returns(dirInfoBase.Object);
            fileBase.Setup(fb => fb.Exists(It.IsAny<string>())).Returns((string path) =>
            {
                return (path != null && (path.EndsWith("f-delete") || path.EndsWith("bar.txt")));
            });
            fileBase.Setup(fb => fb.SetLastWriteTimeUtc(It.IsAny<string>(), It.IsAny<DateTime>()));

            dirBase.Setup(d => d.Exists(It.IsAny<string>())).Returns((string path) =>
            {
                return (path != null && (path.EndsWith("f-delete-dir") || path.EndsWith("f2")));
            });
            FileSystemHelpers.Instance = fileSystem.Object;

            // prepare change from OneDrive
            OneDriveModel.OneDriveChange change = new OneDriveModel.OneDriveChange();
            change.IsDeleted = false;

            // prepare OneDriveInfo
            var info = new OneDriveInfo();
            info.AccessToken = "fake-token";
            info.RepositoryUrl = "https://api.onedrive.com/v1.0/drive/special/approot:/fake-folder";
            info.TargetChangeset = new ChangeSet("id", "authorName", "authorEmail", "message", DateTime.UtcNow);

            // prepare http handler
            var handler = new TestMessageHandler((HttpRequestMessage message) =>
            {
                StringContent content = null;
                if (message != null && message.RequestUri != null)
                {
                    if (message.RequestUri.AbsoluteUri.Equals(info.RepositoryUrl))
                    {
                        content = new StringContent(@"{ 'id': 'fake-id'}", Encoding.UTF8, "application/json");
                        return new HttpResponseMessage { Content = content };
                    }
                    else if (message.RequestUri.AbsoluteUri.Equals("https://api.onedrive.com/v1.0/drive/items/fake-id/view.changes"))
                    {
                        content = new StringContent(ViewChangePayload, Encoding.UTF8, "application/json");
                        return new HttpResponseMessage { Content = content };
                    }
                    else if (message.RequestUri.AbsoluteUri.EndsWith("items/A6034FFBC93398FD!331")
                        || message.RequestUri.AbsoluteUri.EndsWith("items/A6034FFBC93398FD!330"))
                    {
                        content = new StringContent(@"{ '@content.downloadUrl': 'http://site-does-not-exist.microsoft.com'}", Encoding.UTF8, "application/json");
                        return new HttpResponseMessage { Content = content };
                    }
                }

                content = new StringContent("test file content", Encoding.UTF8, "application/json");
                return new HttpResponseMessage { Content = content };
            });

            // perform action
            OneDriveHelper helper = CreateMockOneDriveHelper(handler: handler, tracer: mockTracer.Object);
            await helper.Sync(info, repository);

            // verification
            /*
             Sycing f2 to wwwroot:
             
                 There are 6 changes
                    2 deletion
                      f2\f-delete       (existed as file)
                      f2\f-delete-dir   (existed as folder)
  
                    2 file changes
                      f2\foo.txt        (not existed)
                      f2\f22\bar.txt    (existed)

                    2 folder chagnes
                      f2                (existed)
                      f2\f22            (not existed)
             */

            // deletion
            mockTracer.Verify(t => t.Trace(@"Deleted file D:\home\site\wwwroot\f-delete", It.Is<IDictionary<string, string>>(d => d.Count == 0)));
            mockTracer.Verify(t => t.Trace(@"Deleted directory D:\home\site\wwwroot\f-delete-dir", It.Is<IDictionary<string, string>>(d => d.Count == 0)));

            // file changes
            mockTracer.Verify(t => t.Trace(@"Creating file D:\home\site\wwwroot\foo.txt ...", It.Is<IDictionary<string, string>>(d => d.Count == 0)));
            mockTracer.Verify(t => t.Trace(@"Updating file D:\home\site\wwwroot\f22\bar.txt ...", It.Is<IDictionary<string, string>>(d => d.Count == 0)));

            mockTracer.Verify(t => t.Trace(@"Deleted file D:\home\site\wwwroot\f-delete", It.Is<IDictionary<string, string>>(d => d.Count == 0)));
            mockTracer.Verify(t => t.Trace(@"Deleted directory D:\home\site\wwwroot\f-delete-dir", It.Is<IDictionary<string, string>>(d => d.Count == 0)));

            // directory changes
            mockTracer.Verify(t => t.Trace(@"Ignore folder f2", It.Is<IDictionary<string, string>>(d => d.Count == 0)));
            mockTracer.Verify(t => t.Trace(@"Creating directory D:\home\site\wwwroot\f22 ...", It.Is<IDictionary<string, string>>(d => d.Count == 0)));
        }
예제 #3
0
        internal async Task <ChangeSet> Sync(OneDriveInfo info, IRepository repository, ITracer tracer)
        {
            ChangeSet     changeSet = null;
            string        cursor    = _settings.GetValue(CursorKey);
            ChangesResult changes   = null;

            // use incoming tracer since it is background work
            _tracer = tracer;

            // We truncate cursor value in filename but keep it unharmed in the trace content
            using (_tracer.Step("Getting delta changes with cursor: {0}...", cursor.Truncate(5)))
                using (_tracer.Step("cursor: {0}", cursor))
                {
                    changes = await GetChanges(info.TargetChangeset.Id, info.AccessToken, info.RepositoryUrl, cursor);
                }

            if (changes == null || changes.Count == 0)
            {
                _tracer.Trace("No changes need to be applied.");
                LogMessage(Resources.OneDriveNoChangesFound);
                return(changeSet);
            }

            // for simplicity, use file changes as effective total
            _totals = changes.FileChanges.Count > 0 ? changes.FileChanges.Count : changes.Count;

            string hoststarthtml = Path.Combine(_environment.WebRootPath, Constants.HostingStartHtml);

            FileSystemHelpers.DeleteFileSafe(hoststarthtml);

            using (new Timer(UpdateStatusFile, state: info.TargetChangeset.Id, dueTime: TimeSpan.FromSeconds(5), period: TimeSpan.FromSeconds(5)))
                using (_tracer.Step("Applying {0} changes ...", _totals))
                {
                    LogMessage(Resources.OneDriveApplyingChanges, _totals);

                    // perform action seperately, so that can ensure timestamp on directory
                    // e.g two changes:
                    //  (new) file /a/b/c.txt
                    //  (new) dir  /a/b
                    //  if created dir first then create file. file creation will trigger folder timestamp change.
                    //  which will result in "/a/b" has timestamp from the monent of file creation instead of the timestamp value from server, where value supposed to be set by code specifically.
                    await ApplyChangesParallel(changes.DeletionChanges, info.AccessToken, maxParallelCount : 1, countSuccess : changes.FileChanges.Count == 0);
                    await ApplyChangesParallel(changes.FileChanges, info.AccessToken, maxParallelCount : MaxConcurrentRequests, countSuccess : true);

                    // apply folder changes at last to maintain same timestamp as in OneDrive
                    await ApplyChangesParallel(changes.DirectoryChanges, info.AccessToken, maxParallelCount : 1, countSuccess : changes.FileChanges.Count == 0);

                    _tracer.Trace("{0} succeeded, {1} failed", _successCount, _failedCount);
                    LogMessage(Resources.OneDriveApplyResult, _successCount, _failedCount);

                    string message = _failedCount > 0 ?
                                     string.Format(CultureInfo.CurrentCulture, Resources.OneDrive_SynchronizedWithFailure, _successCount, _totals, _failedCount) :
                                     string.Format(CultureInfo.CurrentCulture, Resources.OneDrive_Synchronized, _totals);

                    // Commit anyway even partial change
                    if (repository.Commit(message, info.AuthorName, info.AuthorEmail))
                    {
                        changeSet = repository.GetChangeSet("HEAD");
                    }

                    if (_failedCount > 0)
                    {
                        // signal deployment failied
                        throw new Exception(string.Format(CultureInfo.CurrentCulture, Resources.OneDriveApplyResult, _successCount, _failedCount));
                    }
                }

            // finally keep a copy of the new cursor
            _settings.SetValue(CursorKey, changes.Cursor);

            return(changeSet);
        }