implemented uploading template from URL - home page (#196)

* implemented uploading template from URL - home page

* added comments

* setting the default template once the process completes

* setting default template after the process completes

* validating extension for private tempalte

* Handled pull request error

* changed querystring parameter
showing template name without GUID

* hiding choose template button when template is submitted in URL

* adding note about private template

* updated the document

* updated doc
This commit is contained in:
Akshay H 2020-01-07 18:20:40 +05:30 коммит произвёл GitHub
Родитель bb050c75bd
Коммит 00ea7b2fe2
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
13 изменённых файлов: 214 добавлений и 46 удалений

1
.gitignore поставляемый
Просмотреть файл

@ -148,3 +148,4 @@ UpgradeLog.htm
.cr/
/src/VstsDemoBuilder/Logs
/src/VstsDemoBuilder/ExtractedTemplate/adqw
/src/AzureDevOpsDemoBuilder/log

Просмотреть файл

@ -0,0 +1,27 @@
# Using Private template URL
Once you generate the custom tempalte using [Azure DevOps Demo Generator - Tempalte Builder](https://azuredevopsdemogenerator.azurewebsites.net/), you can use the same template as a master copy to provision the sample projects.
## Provisioning your project from your custom template using public URL
Using private template URL you can provisoin the project. You have multiple options here
1. Using the template URL from public GitHub repository, refer [Provisioning the project from your custom template](./Using-The-Template-Extractor.md)
1. Use the template URL in the home page of [Azure DevOps Demo Generator](https://azuredevopsdemogenerator.azurewebsites.net/) with querystring parameter **?templateurl**. This supports only the public URL
>```Ex: https://azuredevopsdemogenerator.azurewebsites.net/?templateurl=public_url ```
Once you format the URL, press enter to reload the page.
1. Click on **Sign In** button
1. Once you navigate to **Create Project** page, you should see the private tempalte selected by default
1. Select the **Organization**. Provide the **Project Name**. Choose **Create Project** to start provisioning a project
> **Note**: Once the process completes, the template will be discarded by the system. If you want to reuse the tempalte, you can use the **Private** option in the **Choose Template** dialog box
You can refer the document [Provisioning your project from your custom template](./Using-The-Template-Extractor.md)
Previous: [Using the Extractor](./Using-The-Template-Extractor.md)

Просмотреть файл

@ -44,10 +44,20 @@ Setup an Azure DevOps project and make sure it is ready to be extracted. The ext
1. You will see a new tab labelled **Private**. Select the tab.
1. Select **Browse** and select the zip file you downloaded zip file.
Here you have three option
1. Click **OK** to close the dialog. Choose **Create Project** to start provisioning a project
1. Select **Browse** and select the zip file you downloaded zip file.
1. Use the radio button **GitHub** to consume the private template from a github raw URL
1. Use the radio button **URL** to consume the private template from other sources
1. Once you point the right template, click **Submit** to validate and pick the template for provisoning the project
1. Choose **Create Project** to start provisioning a project
-------------
Previous: [Using the Generator](./Using-The-Generator.md)
Next: [Using Private template URL](./Using-Private-template-URL.md)

Просмотреть файл

@ -2,6 +2,8 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.IO;
using System.Web.Hosting;
using System.Web.Mvc;
using VstsDemoBuilder.Models;
using VstsDemoBuilder.ServiceInterfaces;
@ -16,10 +18,12 @@ namespace VstsDemoBuilder.Controllers
private TemplateSelection.Templates templates = new TemplateSelection.Templates();
private ILog logger = LogManager.GetLogger("ErrorLog");
private IProjectService projectService;
private ITemplateService templateService;
public AccountController(IProjectService _projectService)
public AccountController(IProjectService _projectService, ITemplateService _templateService)
{
projectService = _projectService;
templateService = _templateService;
}
[HttpGet]
@ -49,6 +53,7 @@ namespace VstsDemoBuilder.Controllers
{
Session["EnableExtractor"] = model.EnableExtractor;
}
var browser = Request.Browser.Type;
if (browser.Contains("InternetExplorer"))
{
@ -101,6 +106,25 @@ namespace VstsDemoBuilder.Controllers
}
}
}
if (!string.IsNullOrEmpty(model.TemplateURL))
{
if (model.TemplateURL.EndsWith(".zip"))
{
PrivateTemplate _privateTemplate = UploadPrivateTempalteFromHome(model.TemplateURL);
if (_privateTemplate.IsTemplateValid)
{
Session["PrivateTemplateURL"] = _privateTemplate.privateTemplatePath;
Session["PrivateTemplateName"] = _privateTemplate.privateTemplateName;
Session["PrivateTemplateOriginalName"] = _privateTemplate.privateTemplateOriginalName;
}
else
{
ViewBag.resMessage = _privateTemplate.responseMessage;
return View(new LoginModel());
}
}
}
}
catch (Exception ex)
{
@ -172,5 +196,48 @@ namespace VstsDemoBuilder.Controllers
{
return View();
}
public PrivateTemplate UploadPrivateTempalteFromHome(string TemplateURL)
{
PrivateTemplate privateTemplate = new PrivateTemplate();
string templatePath = string.Empty;
try
{
privateTemplate.IsTemplateValid = false;
string templateName = "";
string fileName = Path.GetFileName(TemplateURL);
string extension = Path.GetExtension(TemplateURL);
privateTemplate.privateTemplateOriginalName = fileName.ToLower().Replace(".zip", "").Trim();
templateName = fileName.ToLower().Replace(".zip", "").Trim() + "-" + Guid.NewGuid().ToString().Substring(0, 6) + extension.ToLower();
privateTemplate.privateTemplateName = templateName.ToLower().Replace(".zip", "").Trim();
privateTemplate.privateTemplatePath = templateService.GetTemplateFromPath(TemplateURL, templateName, "", "", "");
if (privateTemplate.privateTemplatePath != "")
{
privateTemplate.responseMessage = templateService.checkSelectedTemplateIsPrivate(privateTemplate.privateTemplatePath);
if (privateTemplate.responseMessage != "SUCCESS")
{
var templatepath = HostingEnvironment.MapPath("~") + @"\PrivateTemplates\" + templateName.ToLower().Replace(".zip", "").Trim();
if (Directory.Exists(templatepath))
Directory.Delete(templatepath, true);
}
if (privateTemplate.responseMessage == "SUCCESS")
{
privateTemplate.IsTemplateValid = true;
}
}
else
{
privateTemplate.responseMessage = "Unable to download file, please check the provided URL";
privateTemplate.IsTemplateValid = false;
}
}
catch (Exception ex)
{
ProjectService.logger.Info(DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss") + "\t" + "\t" + ex.Message + "\t" + "\n" + ex.StackTrace + "\n");
}
return privateTemplate;
}
}
}

Просмотреть файл

@ -168,11 +168,16 @@ namespace VstsDemoBuilder.Controllers
model.TemplateName = Session["templateName"].ToString();
TemplateSelected = model.TemplateName;
}
else if (Session["PrivateTemplateName"] != null)
{
model.TemplateName = Session["PrivateTemplateName"].ToString();
TemplateSelected = model.TemplateName;
}
else
{
TemplateSelected = System.Configuration.ConfigurationManager.AppSettings["DefaultTemplate"];
model.TemplateName = TemplateSelected;
}
if (Session["PAT"] != null)
{
_accessDetails.access_token = Session["PAT"].ToString();
@ -229,25 +234,37 @@ namespace VstsDemoBuilder.Controllers
//if exist, will append the template name to Selected template textbox, else will append the SmartHotel360 template
if (!string.IsNullOrEmpty(TemplateSelected))
{
foreach (var grpTemplate in templates.GroupwiseTemplates)
if (Session["PrivateTemplateName"] == null)
{
foreach (var template in grpTemplate.Template)
foreach (var grpTemplate in templates.GroupwiseTemplates)
{
if (template.Name != null)
foreach (var template in grpTemplate.Template)
{
if (template.Name.ToLower() == TemplateSelected.ToLower())
if (template.Name != null)
{
model.SelectedTemplate = template.Name;
model.Templates.Add(template.Name);
model.selectedTemplateDescription = template.Description == null ? string.Empty : template.Description;
model.selectedTemplateFolder = template.TemplateFolder == null ? string.Empty : template.TemplateFolder;
model.Message = template.Message == null ? string.Empty : template.Message;
model.ForkGitHubRepo = template.ForkGitHubRepo.ToString();
model.templateImage = template.Image ?? "/Templates/TemplateImages/CodeFile.png";
if (template.Name.ToLower() == TemplateSelected.ToLower())
{
model.SelectedTemplate = template.Name;
model.Templates.Add(template.Name);
model.selectedTemplateDescription = template.Description == null ? string.Empty : template.Description;
model.selectedTemplateFolder = template.TemplateFolder == null ? string.Empty : template.TemplateFolder;
model.Message = template.Message == null ? string.Empty : template.Message;
model.ForkGitHubRepo = template.ForkGitHubRepo.ToString();
model.templateImage = template.Image ?? "/Templates/TemplateImages/CodeFile.png";
}
}
}
}
}
else
{
model.SelectedTemplate = Session["PrivateTemplateOriginalName"].ToString();
model.Templates.Add(model.SelectedTemplate);
model.selectedTemplateDescription = "<p style='color:red;fontsize:10px'><b>Note</b>: Template will be discarded once the process completes. Please refersh the page to select other templates </p>";
model.selectedTemplateFolder = Session["PrivateTemplateName"].ToString();
model.ForkGitHubRepo = "false";
model.templateImage = "/Templates/TemplateImages/CodeFile.png";
}
}
return View(model);
}
@ -518,9 +535,18 @@ namespace VstsDemoBuilder.Controllers
{
model.GitHubToken = Session["GitHubToken"].ToString();
}
if (Session["PrivateTemplateURL"] != null && Session["PrivateTemplateName"] != null)
{
model.PrivateTemplatePath = Session["PrivateTemplateURL"].ToString();
Session["PrivateTemplateURL"] = null;
Session["PrivateTemplateName"] = null;
Session["PrivateTemplateOriginalName"] = null;
Session["templateName"] = System.Configuration.ConfigurationManager.AppSettings["DefaultTemplate"];
}
projectService.AddMessage(model.id, string.Empty);
projectService.AddMessage(model.id.ErrorId(), string.Empty);
if (!string.IsNullOrEmpty(model.PrivateTemplatePath))
bool whereIsTemplate = projectService.WhereDoseTemplateBelongTo(model.SelectedTemplate); // checking for private template existance
if (!string.IsNullOrEmpty(model.PrivateTemplatePath) && whereIsTemplate) // if the template path exist and tempalte is present in private fodler
{
model.IsPrivatePath = true;
}
@ -620,6 +646,7 @@ namespace VstsDemoBuilder.Controllers
{
try
{
bool isTemplateBelongToPrivateFolder = projectService.WhereDoseTemplateBelongTo(selectedTemplate);
if (!string.IsNullOrEmpty(selectedTemplate) && !string.IsNullOrEmpty(account) && !string.IsNullOrEmpty(token))
{
string accountName = string.Empty;
@ -629,7 +656,12 @@ namespace VstsDemoBuilder.Controllers
pat = token;
string templatesFolder = string.Empty;
string extensionJsonFile = string.Empty;
if (string.IsNullOrEmpty(PrivatePath))
if (isTemplateBelongToPrivateFolder)
{
templatesFolder = Session["PrivateTemplateURL"].ToString();
extensionJsonFile = string.Format(templatesFolder + @"\Extensions.json");
}
else if (string.IsNullOrEmpty(PrivatePath))
{
templatesFolder = Server.MapPath("~") + @"\Templates\";
extensionJsonFile = string.Format(templatesFolder + @"\{0}\Extensions.json", selectedTemplate);
@ -640,8 +672,6 @@ namespace VstsDemoBuilder.Controllers
extensionJsonFile = string.Format(templatesFolder + @"\Extensions.json");
}
if (!(System.IO.File.Exists(extensionJsonFile)))
{
return Json(new { message = "Template not found", status = "false" }, JsonRequestBehavior.AllowGet);

Просмотреть файл

@ -13,5 +13,6 @@
public string name { get; set; }
public string EnableExtractor { get; set; }
public string TemplateURL { get; set; }
}
}

Просмотреть файл

@ -223,8 +223,10 @@ namespace VstsDemoBuilder.Models
public class PrivateTemplate
{
public string privateTemplateName { get; set; }
public string privateTemplateOriginalName { get; set; }
public string privateTemplatePath { get; set; }
public string responseMessage { get; set; }
public bool IsTemplateValid { get; set; }
}
}

Просмотреть файл

@ -21,5 +21,8 @@ namespace VstsDemoBuilder.ServiceInterfaces
bool CheckForInstalledExtensions(string extensionJsonFile, string token, string account);
bool InstallExtensions(Project model, string accountName, string PAT);
bool WhereDoseTemplateBelongTo(string templatName);
}
}

Просмотреть файл

@ -1576,7 +1576,7 @@ namespace VstsDemoBuilder.Services
string repositoryId = string.Empty;
if (model.SelectedTemplate == "MyHealthClinic") { repositoryId = model.Environment.repositoryIdList["MyHealthClinic"]; }
if (model.SelectedTemplate == "SmartHotel360") { repositoryId = model.Environment.repositoryIdList["PublicWeb"]; }
else { repositoryId = model.Environment.repositoryIdList[model.SelectedTemplate]; }
else { repositoryId = model.Environment.repositoryIdList.ContainsKey(model.SelectedTemplate) ? model.Environment.repositoryIdList[model.SelectedTemplate] : ""; }
pullRequestJsonPath = model.ReadJsonFile(pullRequestJsonPath);
pullRequestJsonPath = pullRequestJsonPath.Replace("$reviewer$", model.Environment.UserUniqueId);
@ -2764,5 +2764,24 @@ namespace VstsDemoBuilder.Services
}
}
}
/// <summary>
/// Checkign for template existance - if template is present in private path, return true else return false
/// </summary>
/// <param name="templatName"></param>
/// <returns></returns>
public bool WhereDoseTemplateBelongTo(string templatName)
{
string privatePath = HostingEnvironment.MapPath("~") + @"\PrivateTemplates\";
string privateTemplate = HostingEnvironment.MapPath("~") + @"\PrivateTemplates\" + templatName;
//string publicPath = HostingEnvironment.MapPath("~") + @"\Templates\";
string[] privatedirs = Directory.GetDirectories(privatePath);
//string[] publicdirs = Directory.GetDirectories(privatePath);
if (privatedirs.Contains(privateTemplate))
{
return true;
}
return false;
}
}
}

Просмотреть файл

@ -187,7 +187,6 @@ namespace VstsDemoBuilder.Services
webClient.DownloadFile(TemplateUrl, path);
webClient.Dispose();
}
templatePath = ExtractZipFile(path, templateName);
}

Просмотреть файл

@ -48,6 +48,10 @@
<img src="~/Images/next.png" style="width:10px" />
</a>
</div>
@if (!string.IsNullOrEmpty(ViewBag.resMessage))
{
<p style="text-align:center; color:red;">@ViewBag.resMessage</p>
}
<!--div class="demo-generator-feedback mt-auto text-center text-sm-left">
<p>
<ul>

Просмотреть файл

@ -215,13 +215,15 @@
<input type="hidden" id="PrivateTemplateName" />
<input type="hidden" id="PrivateTemplatePath" />
<div class="alert alert-danger d-none" role="alert" id="ddlTemplates_Error">
</div>
</div>
<div class="template-invoke mb-3 mt-1 col-lg-3">
<button type="button" class="btn btn-primary" id="templateselection" style="padding-left:5px; padding-right:5px; width: 100%">
Choose template
</button>
@if (Session["PrivateTemplateOriginalName"] == null)
{
<button type="button" class="btn btn-primary" id="templateselection" style="padding-left:5px; padding-right:5px; width: 100%">
Choose template
</button>
}
</div>
</div>
</div>

Просмотреть файл

@ -240,30 +240,33 @@ namespace VstsRestAPI.Git
{
try
{
string[] pullRequest = new string[2];
using (var client = GetHttpClient())
if (!string.IsNullOrEmpty(repositoryId))
{
var jsonContent = new StringContent(json, Encoding.UTF8, "application/json");
var method = new HttpMethod("POST");
string[] pullRequest = new string[2];
var request = new HttpRequestMessage(method, Project + "/_apis/git/repositories/" + repositoryId + "/pullRequests?api-version=" + _configuration.VersionNumber) { Content = jsonContent };
var response = client.SendAsync(request).Result;
using (var client = GetHttpClient())
{
var jsonContent = new StringContent(json, Encoding.UTF8, "application/json");
var method = new HttpMethod("POST");
if (response.IsSuccessStatusCode)
{
var responseDetails = response.Content.ReadAsStringAsync().Result;
JObject objResponse = JObject.Parse(responseDetails);
pullRequest[0] = objResponse["pullRequestId"].ToString();
pullRequest[1] = objResponse["title"].ToString();
return pullRequest;
}
else
{
var errorMessage = response.Content.ReadAsStringAsync();
string error = Utility.GeterroMessage(errorMessage.Result.ToString());
this.LastFailureMessage = error;
return pullRequest;
var request = new HttpRequestMessage(method, Project + "/_apis/git/repositories/" + repositoryId + "/pullRequests?api-version=" + _configuration.VersionNumber) { Content = jsonContent };
var response = client.SendAsync(request).Result;
if (response.IsSuccessStatusCode)
{
var responseDetails = response.Content.ReadAsStringAsync().Result;
JObject objResponse = JObject.Parse(responseDetails);
pullRequest[0] = objResponse["pullRequestId"].ToString();
pullRequest[1] = objResponse["title"].ToString();
return pullRequest;
}
else
{
var errorMessage = response.Content.ReadAsStringAsync();
string error = Utility.GeterroMessage(errorMessage.Result.ToString());
this.LastFailureMessage = error;
return pullRequest;
}
}
}
}