1. Joel Ross
  2. TrafficLight

Commits

Joel Ross  committed 9146ce7 Merge

merge

  • Participants
  • Parent commits 625bed2, d92fd7f
  • Branches default

Comments (0)

Files changed (11)

File readme.md

View file
     * CruiseControl.NET: use /XmlStatusReport.aspx. 
     * Jenkins: Jenkins provides a CC.NET compatible output at /cc.xml
     * TeamCity: TeamCity also provides a CC.NET compatible output.
-        * For authorized users: /httpAuth//app/rest/cctray/projects.xm
+        * For authorized users: /httpAuth//app/rest/cctray/projects.xml
         * For guest access: /guestAuth/app/rest/cctray/projects.xml
     * Pulse: Pulse uses an XML-RPC endpoint at /xmlrpc
 * Server Type: Select CruiseControl for any server that uses a CruiseControl compatible output. Select Pulse for Pulse servers.
 1. An On-Screen Traffic Light. Just double click on the system tray icon for Traffic Light, and a screen will show the Traffic Light (it takes up to 15 seconds to update with the latest build status for now).
 2. [Delcom Traffic Light](https://www.delcomproducts.com/productdetails.asp?PartNumber=907241): Ensure the Delcom.dll is in the same folder as the Traffic Light executable, and that the device is plugged into a USB port, and it will be used to report build status.
 
+## Issues / Features
+
+Traffic light is using a Trello board to manage new development and track issues. [Details about the board can be found on this card](https://trello.com/c/dZKiOhOV).
 
 <div style="background: #00578e url('http://www.jetbrains.com/img/banners/Codebetter.png') no-repeat 0 50%; margin:0;padding:0;text-decoration:none;text-indent:0;letter-spacing:-0.001em; width:728px; height:90px">
 [keyboard-centric bug tracker][] [continuous integration server][]

File src/Core/Presenters/EditProjectPresenter.cs

View file
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
 using RossCode.TrafficLight.Core.Domain;
 using RossCode.TrafficLight.Core.Domain.Repositories;
 using RossCode.TrafficLight.Core.Factories;
             var result = new ValidationResult();
 
             if (string.IsNullOrWhiteSpace(View.ProjectUrl)) result.AddError("Project URL is required.");
+            Uri validatedUri;
+            if (!Uri.TryCreate(View.ProjectUrl, UriKind.Absolute, out validatedUri)) result.AddError("Project URL is not a valid URL");
             if (View.ServerType == ServerTypes.Unknown) result.AddError("Server type is required.");
             if (!View.MonitorAllProjects && string.IsNullOrWhiteSpace(View.ProjectName)) result.AddError("Name is required.");
 

File src/Core/Presenters/ProjectsPresenter.cs

View file
             View.ProjectSelected += ProjectSelected;
             View.AddProject += AddProject;
             View.ProjectDeleted += DeleteProject;
+            View.CopyProject += CopyProject;
 
             DomainEvents.Register<ProjectAdded>(ProjectAdded);
         }
         {
             DomainEvents.Raise(new EditProjectRequested(projects.ElementAt(projectIndex)));
         }
+
+        private void CopyProject(int projectIndex)
+        {
+            var selectedProject = projects.ElementAt(projectIndex);
+            var newProject = new Project
+                                 {
+                                     Name = selectedProject.Name,
+                                     Username = selectedProject.Username,
+                                     Password = selectedProject.Password,
+                                     ServerType = selectedProject.ServerType,
+                                     Url = selectedProject.Url,
+                                 };
+            DomainEvents.Raise(new EditProjectRequested(newProject));
+        }
     }
 }

File src/Core/Presenters/Views/IProjectsView.cs

View file
 {
     public interface IProjectsView : IView
     {
-        IEnumerable<Project> Projects { set; }
+        ICollection<Project> Projects { set; }
         event SimpleHandler<int> ProjectSelected;
         event SimpleHandler<int> ProjectDeleted;
         event VoidHandler AddProject;
+        event SimpleHandler<int> CopyProject;
     }
 }

File src/Core/Services/ProjectStatusResolvers/PulseProjectStatusResolverService.cs

View file
+using System.Net;
 using CookComputing.XmlRpc;
 using RossCode.TrafficLight.Core.Domain;
 
                     project.CurrentStatus = GetBuildStatusFrom(result[0].status);
                     buildStatus = project.CurrentStatus;
                 }
-            } 
+            }
+            catch (WebException)
+            {
+                // The server was likely unreachable for some reason (or perhaps a 404 or other error was returned.)
+                buildStatus = BuildStatus.Unknown;
+            }
+            catch (XmlRpcIllFormedXmlException)
+            {
+                // The server was reachable, but the URL was likely invalid resulting in nonexistent or incorrect XML.
+                buildStatus = BuildStatus.Unknown;
+            }
+            catch (XmlRpcFaultException)
+            {
+                // This can occur if the supplied credentials are missing or invalid.
+                buildStatus = BuildStatus.Unknown;
+            }
             finally
             {
                 if (!string.IsNullOrEmpty(token))

File src/Tests/Presenters/ProjectsPresenterSpecs.cs

View file
             [Test]
             public void it_should_refresh_the_display()
             {
-                View.VerifySet(v => v.Projects = It.IsAny<IEnumerable<Project>>());    
+                View.VerifySet(v => v.Projects = It.IsAny<ICollection<Project>>());
+            }
+        }
+
+        public class when_copying_a_project : under.context_where_the_view_has_already_been_loaded
+        {
+            private Project project;
+            protected override void EstablishContext()
+            {
+                base.EstablishContext();
+                DomainEvents.Register<EditProjectRequested>(args => project = args.Project);
+            }
+
+            protected override void When()
+            {
+                View.Raise(v => v.CopyProject += null, 0);
+            }
+
+            [Test]
+            public void it_should_raise_an_event_to_copy_the_project()
+            {
+                Assert.IsNotNull(project);
+                Assert.AreEqual("first-project", project.Name);
             }
         }
 
                 protected Mock<IProjectRepository> ProjectRepository;
                 protected Mock<IProjectsView> View;
                 protected ProjectsPresenter SUT;
-                protected IEnumerable<Project> Projects;
+                protected ICollection<Project> Projects;
 
                 protected override void EstablishContext()
                 {
                     Projects = new List<Project>
                         {
-                            new Project(),
-                            new Project()
+                            new Project { Id = 1234, Name = "first-project" },
+                            new Project { Id = 5678, Name = "second-project" }
                         };
                     
                     ProjectRepository = new Mock<IProjectRepository>();

File src/UI/BaseForm.cs

View file
                 setBuildIcon[status]();
             }
         }
+
+        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
+        {
+            if (keyData == Keys.Escape)
+            {
+                Close();
+            }
+
+            return base.ProcessCmdKey(ref msg, keyData);
+        }
     }
 }

File src/UI/EditProjectView.Designer.cs

View file
             this.lblName.Location = new System.Drawing.Point(37, 61);
             this.lblName.Name = "lblName";
             this.lblName.Size = new System.Drawing.Size(38, 13);
-            this.lblName.TabIndex = 0;
+            this.lblName.TabIndex = 4;
             this.lblName.Text = "Name:";
             // 
             // lblPassword
             this.lblPassword.Location = new System.Drawing.Point(19, 163);
             this.lblPassword.Name = "lblPassword";
             this.lblPassword.Size = new System.Drawing.Size(53, 13);
-            this.lblPassword.TabIndex = 0;
+            this.lblPassword.TabIndex = 10;
             this.lblPassword.Text = "Password";
             // 
             // lblUsername
             this.lblUsername.Location = new System.Drawing.Point(19, 136);
             this.lblUsername.Name = "lblUsername";
             this.lblUsername.Size = new System.Drawing.Size(55, 13);
-            this.lblUsername.TabIndex = 0;
+            this.lblUsername.TabIndex = 8;
             this.lblUsername.Text = "Username";
             // 
             // txtProjectName
             this.txtProjectName.Location = new System.Drawing.Point(78, 58);
             this.txtProjectName.Name = "txtProjectName";
             this.txtProjectName.Size = new System.Drawing.Size(269, 20);
-            this.txtProjectName.TabIndex = 1;
+            this.txtProjectName.TabIndex = 5;
             // 
             // txtPassword
             // 
             this.txtPassword.Location = new System.Drawing.Point(78, 159);
             this.txtPassword.Name = "txtPassword";
             this.txtPassword.Size = new System.Drawing.Size(269, 20);
-            this.txtPassword.TabIndex = 4;
+            this.txtPassword.TabIndex = 11;
             this.txtPassword.UseSystemPasswordChar = true;
             // 
             // txtUsername
             this.txtUsername.Location = new System.Drawing.Point(78, 133);
             this.txtUsername.Name = "txtUsername";
             this.txtUsername.Size = new System.Drawing.Size(269, 20);
-            this.txtUsername.TabIndex = 3;
+            this.txtUsername.TabIndex = 9;
             // 
             // btnSave
             // 
             this.btnSave.Location = new System.Drawing.Point(212, 185);
             this.btnSave.Name = "btnSave";
             this.btnSave.Size = new System.Drawing.Size(135, 23);
-            this.btnSave.TabIndex = 5;
+            this.btnSave.TabIndex = 13;
             this.btnSave.Text = "Save Project";
             this.btnSave.UseVisualStyleBackColor = true;
             // 
             this.btnTest.Location = new System.Drawing.Point(78, 185);
             this.btnTest.Name = "btnTest";
             this.btnTest.Size = new System.Drawing.Size(128, 23);
-            this.btnTest.TabIndex = 6;
+            this.btnTest.TabIndex = 12;
             this.btnTest.Text = "Test";
             this.btnTest.UseVisualStyleBackColor = true;
             // 
             this.txtProjectUrl.Location = new System.Drawing.Point(78, 6);
             this.txtProjectUrl.Name = "txtProjectUrl";
             this.txtProjectUrl.Size = new System.Drawing.Size(269, 20);
-            this.txtProjectUrl.TabIndex = 2;
+            this.txtProjectUrl.TabIndex = 1;
             // 
             // chkMonitorAllProjects
             // 
             this.chkMonitorAllProjects.Location = new System.Drawing.Point(78, 84);
             this.chkMonitorAllProjects.Name = "chkMonitorAllProjects";
             this.chkMonitorAllProjects.Size = new System.Drawing.Size(173, 17);
-            this.chkMonitorAllProjects.TabIndex = 7;
+            this.chkMonitorAllProjects.TabIndex = 6;
             this.chkMonitorAllProjects.Text = "Monitor all projects for this URL";
             this.chkMonitorAllProjects.UseVisualStyleBackColor = true;
             // 
             this.label1.Location = new System.Drawing.Point(6, 35);
             this.label1.Name = "label1";
             this.label1.Size = new System.Drawing.Size(68, 13);
-            this.label1.TabIndex = 8;
+            this.label1.TabIndex = 2;
             this.label1.Text = "Server Type:";
             // 
             // cboServerTypes
             this.cboServerTypes.Location = new System.Drawing.Point(78, 32);
             this.cboServerTypes.Name = "cboServerTypes";
             this.cboServerTypes.Size = new System.Drawing.Size(269, 21);
-            this.cboServerTypes.TabIndex = 9;
+            this.cboServerTypes.TabIndex = 3;
             // 
             // label2
             // 
             this.label2.Location = new System.Drawing.Point(78, 114);
             this.label2.Name = "label2";
             this.label2.Size = new System.Drawing.Size(263, 13);
-            this.label2.TabIndex = 10;
+            this.label2.TabIndex = 7;
             this.label2.Text = "Does the server require authentication? Enter it below:";
             // 
             // EditProjectView

File src/UI/ProjectsView.Designer.cs

View file
             this.bsProjects = new System.Windows.Forms.BindingSource(this.components);
             this.pnlMain = new System.Windows.Forms.Panel();
             this.pnlButtons = new System.Windows.Forms.Panel();
+            this.btnDeleteProject = new System.Windows.Forms.Button();
             this.btnAddProject = new System.Windows.Forms.Button();
-            this.btnDeleteProject = new System.Windows.Forms.Button();
+            this.btnCopyProject = new System.Windows.Forms.Button();
             ((System.ComponentModel.ISupportInitialize)(this.dgProjects)).BeginInit();
             ((System.ComponentModel.ISupportInitialize)(this.bsProjects)).BeginInit();
             this.pnlMain.SuspendLayout();
             // 
             // pnlButtons
             // 
+            this.pnlButtons.Controls.Add(this.btnCopyProject);
             this.pnlButtons.Controls.Add(this.btnDeleteProject);
             this.pnlButtons.Controls.Add(this.btnAddProject);
             this.pnlButtons.Dock = System.Windows.Forms.DockStyle.Bottom;
             this.pnlButtons.Size = new System.Drawing.Size(644, 31);
             this.pnlButtons.TabIndex = 1;
             // 
-            // btnAddProject
-            // 
-            this.btnAddProject.Location = new System.Drawing.Point(566, 4);
-            this.btnAddProject.Name = "btnAddProject";
-            this.btnAddProject.Size = new System.Drawing.Size(75, 23);
-            this.btnAddProject.TabIndex = 0;
-            this.btnAddProject.Text = "Add Project";
-            this.btnAddProject.UseVisualStyleBackColor = true;
-            // 
             // btnDeleteProject
             // 
             this.btnDeleteProject.Location = new System.Drawing.Point(3, 4);
             this.btnDeleteProject.Text = "Delete Project";
             this.btnDeleteProject.UseVisualStyleBackColor = true;
             // 
+            // btnAddProject
+            // 
+            this.btnAddProject.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
+            this.btnAddProject.Location = new System.Drawing.Point(489, 4);
+            this.btnAddProject.Name = "btnAddProject";
+            this.btnAddProject.Size = new System.Drawing.Size(75, 23);
+            this.btnAddProject.TabIndex = 0;
+            this.btnAddProject.Text = "Add Project";
+            this.btnAddProject.UseVisualStyleBackColor = true;
+            // 
+            // btnCopyProject
+            // 
+            this.btnCopyProject.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
+            this.btnCopyProject.Location = new System.Drawing.Point(566, 4);
+            this.btnCopyProject.Name = "btnCopyProject";
+            this.btnCopyProject.Size = new System.Drawing.Size(75, 23);
+            this.btnCopyProject.TabIndex = 2;
+            this.btnCopyProject.Text = "Copy Project";
+            this.btnCopyProject.UseVisualStyleBackColor = true;
+            // 
             // ProjectsView
             // 
             this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
         private System.Windows.Forms.Panel pnlButtons;
         private System.Windows.Forms.Button btnAddProject;
         private System.Windows.Forms.Button btnDeleteProject;
+        private System.Windows.Forms.Button btnCopyProject;
     }
 }

File src/UI/ProjectsView.cs

View file
             Closing += (sender, e) => bsProjects.DataSource = null;
             dgProjects.CellDoubleClick += (sender, e) => ProjectSelected(e.RowIndex);
             btnAddProject.Click += (sender, args) => AddProject();
+            btnCopyProject.Click += (sender, args) => CopyProject(dgProjects.SelectedRows[0].Index);
             btnDeleteProject.Click += (sender, args) => ProjectDeleted(dgProjects.SelectedRows[0].Index);
         }
 
-        public IEnumerable<Project> Projects
+        public ICollection<Project> Projects
         {
-            set { bsProjects.DataSource = value; }
+            set
+            {
+                bsProjects.DataSource = value;
+                bool hasProjects = (value != null && value.Count > 0);
+                btnDeleteProject.Enabled = btnCopyProject.Enabled = hasProjects;
+            }
         }
 
         public event SimpleHandler<int> ProjectSelected = delegate { };
         public event SimpleHandler<int> ProjectDeleted = delegate { };
         public event VoidHandler AddProject = delegate { };
+        public event SimpleHandler<int> CopyProject = delegate { };
     }
 }

File src/UI/ProjectsView.resx

View file
   <metadata name="bsProjects.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
     <value>17, 17</value>
   </metadata>
-  <metadata name="colName.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
-    <value>True</value>
-  </metadata>
-  <metadata name="colUrl.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
-    <value>True</value>
-  </metadata>
-  <metadata name="bsProjects.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
-    <value>17, 17</value>
-  </metadata>
 </root>