Category Archives: Software Development

Exporting your bugs out of YouTrack

If you need to export your bug reports from your YouTrack instance, this is how to get it done using C#. Its a small example that will print all the issues,comments and attachments for each project in your instance.

Don’t forget to enable the REST API in your YourTrack settings page.

Create a new project called YouTrackExport and use NuGet to install the YouTrackSharp package

PM> Install-Package YouTrackSharp
Attempting to resolve dependency 'EasyHttp (≥ 1.6.29.0)'.
Attempting to resolve dependency 'JsonFX (≥ 2.0.1209.2802)'.
Installing 'JsonFx 2.0.1209.2802'.
...
...

The following code will print out the information:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.Dynamic;
using YouTrackSharp.Infrastructure;
using YouTrackSharp.Projects;
using YouTrackSharp.Issues;
using YouTrackSharp.Admin;
using System.Net;

namespace YouTrackExport
{
    class Program
    {
        static void Main(string[] args)
        {
            String Username = "xxx";
            String Password = "yyy";
            String Site = "zzz.myjetbrains.com";

            YouTrackSharp.Infrastructure.Connection Connection;
            YouTrackSharp.Projects.ProjectManagement ProjectManager;
            IEnumerable<YouTrackSharp.Projects.Project> Projects;
            YouTrackSharp.Issues.IssueManagement IssueManager;
            IEnumerable<YouTrackSharp.Issues.Issue> Issues;
            IEnumerable<YouTrackSharp.Issues.Comment> Comments;


            Connection = new Connection(Site, 80, false, "youtrack");
            Connection.Authenticate(Username, Password);
                    
            ProjectManager = new ProjectManagement(Connection);
            Projects    = ProjectManager.GetProjects();
            foreach (Project project in Projects)
            {
               
                Console.WriteLine(String.Format("Found project {0} - {1} ", project.ShortName, project.Name));
                IssueManager = new IssueManagement(Connection);
                Issues = IssueManager.GetAllIssuesForProject(project.ShortName); 
                
                //An issue in youtrack can have many fields that we dont know at compile time.
                //Therefore its a .Net DynamicObject
                foreach (dynamic Issue in Issues) 
                {
                    Console.WriteLine(String.Format("\tFound issue {0}", Issue.Id));

                    Comments = IssueManager.GetCommentsForIssue(Issue.Id);
                    foreach (Comment Comment in Comments)
                    {
                        Console.WriteLine(String.Format("\t\tComment: {0} - {1} - {2}", Comment.Author, Comment.Created, Comment.Text));
                    }

                    foreach (dynamic Attachment in Issue.Attachments)
                    {
                        String Name = Attachment.name;
                        String Url = Attachment.url;
                        String Author = Attachment.authorLogin;
                        String Id = Attachment.id;
                        String Group = Attachment.group;
                        long Created = Attachment.created;
                        Console.WriteLine(String.Format("\t\tAttachment: {0} - {1} - {2}", Name, Author, Url));
                    }
                }
            }
        }
    }
}

Some gotcha’s that I encountered

The following code wont work if your YouTrack instance is hosted in the cloud:

var connection = new Connection("http://zzz.myjetbrains.com/youtrack"); 
var connection = new Connection("zzz.myjetbrains.com/youtrack"); 
var connection = new Connection("zzz.myjetbrains.com"); 

The following code will raise a HTTPException: NotFound Not Found exception. You need to to use the ShortName member:

Issues = IssueManager.GetAllIssuesForProject(project.Name); 

PowerShell for recursive file and directory listings with MD5 hashes

The other day I needed to know if the files in a specific directory structure on different systems were identical or different. Many tools exist for doing file and directory comparisons but the challenge here was that each system was locked-down, no installation of software was possible. And even worse, we needed to compare at least 3 different machines that couldn’t reach each others drives or shares. Instead of hunting around to find which one of the many tools would work in this environment I thought that Windows Powershell should be able to do this quite easily. In fact, it turned out to be so easy that just finding another tool would have taken much longer.

The script uses the Get-ChildItem cmdlet to recursively get each file/directory in the form of a System.IO.FileInfo or System.IO.DirectoryInfo object. We calculate the MD5 hash using the ComputeHash() method of the System.Security.Cryptography.MD5CryptoServiceProvider class. We simply write the hash and some interesting fields as a CSV string to the output.

Here’s the bits of code glued into a single script.

function Get-MD5
{
  [CmdletBinding(SupportsShouldProcess=$false)]
  param
  (
    [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, HelpMessage="file(s) to create hash for")]
    [Alias("File", "Path", "PSPath", "String")]
    [ValidateNotNull()]
    $InputObject
  )
 
  begin
  {
     $hasher = new-object System.Security.Cryptography.MD5CryptoServiceProvider
  }
 
  process
  {
    $hashBytes = ''

    $item = Get-Item $InputObject -ErrorAction SilentlyContinue
 
    if ($item)
    {
      $InputObject = $item
    }
 
    if ($InputObject -is [System.IO.FileInfo])
    {
      $stream    = $null;
      $hashBytes = $null
 
      try
      {
        $stream     = $InputObject.OpenRead();
        $hashBytes  = $hasher.ComputeHash($stream);
      }
      finally
      {
        if ($stream -ne $null)
        {
          $stream.Close();
        }
      }
    }

 
    Write-Output ([BitConverter]::ToString($hashBytes)).Replace("-",'')
  }
}

function Get-FilesWithHash
{
    [CmdletBinding(SupportsShouldProcess=$false)]
    param
    (
        [string]$Directory,
        [switch]$Recurse
    )
 

    Get-ChildItem -Path $Directory -Recurse:$Recurse | foreach {
        $item = $_
        $hash = ''
        if (!$_.PSIsContainer) 
        {
            $hash = Get-MD5 $_    
        }
        else
        {
            $hash = ''
        }
        Write-Output "$($item.FullName),$hash,$($item.Length),$($item.CreationTime),$($item.LastWriteTime)" 
        
    }
}

Combining SpecFlow and Selenium

One of the cool things I like to do when testing webapps, is to define the testcases using SpecFlow (also known as Cucumber) and then use Selenium to actually execute the testcases against the web-application.

Here is an example testcase:

Feature: SpecFlowAndSelenium
	For demonstration purposes, I want to show how the human-readable
	SpecFlow testcases can be executed using Selenium to operate
	a real webbrowser

Scenario: SeleniumAndSpecFlow
	Given I navigate to 'http://www.google.com'
	Then there must be a control with 'id' 'gbqfq' 
	When I type 'Hello World!' into it
	Then there must be a control with 'id' 'gbqfb'
	When I click on it
	Then there must be a link with 'partialtext' 'Wikipedia' 
	When I click on it
	Then there must be a control with 'id' 'searchInput'
	When I type 'Selenium' into it
	Then there must be a control with 'id' 'searchButton' 
	When I click on it
	Then there must be a link with 'text' 'chemical element'
	And there must be a link with 'text' 'Selenium (software)'
	When I click on it
	Then there must be a link with 'text' 'web browsers'

And here you can see Selenium using Firefox to perform all the actions and checks:

Getting MS Access to remember the password for linked tables

If you’re using linked tables from MS Access to a database server (Oracle or SQL Server) using the MS Access GUI you can simply put a check mark in the ‘Remember password’ box. If you’re dynamically creating linked tables from VBA and supplying the username and password in the Connection member of the TableDef object then Access will still prompt for credentials when its restarted.

You can avoid this by using the dbAttachSavePWD attribute. Example:

Dim tDef As TableDef
Set tDef = CurrentDb.CreateTableDef("MyNewTable", dbAttachSavePWD)
tDef.Connect = ...
tDef.SourceTableName = ...

Creating linked tables in MS Access using VBA

Recently I ran into a system that used Oracle as back-end database and an MS Access database/app containing the forms as front-end for the users. The Access database connected to Oracle tables and views using ODBC linked tables. We had about 5 different Oracle servers for development, test, acceptance and production. Due to a lot of legacy code the table names in Access and Oracle weren’t always the same.

Frequently we needed to change to which Oracle server a specific instance of the Access app would talk to. Instead of manually removing and relinking the tables, I created a simple local table to define which tables should exist in the Access database and what the tables name on the Oracle server should be. A simple VBA subroutine actually establishes the links.

Here’s a short version of it:

Option Compare Database
Option Explicit
Private Const gDSNTemplate = "ODBC;DRIVER={Oracle in OraHome817};SERVER=${server};UID=${user};PWD=${password};DBQ=${server};DBA=W;APA=T;EXC=F;XSM=Default;FEN=T;QTO=T;FRC=10;FDL=10;L...(cant remember the rest)..."
 
Public Sub LinkTables(Server As String, username As String, password As String)
    Dim dsn As String
    Dim strAccessName As String
    Dim strOracleName As String
    Dim tDef As TableDef
    Dim rs As Recordset

    'Create the DSN for the requested environment
    dsn = gDSNTemplate
    dsn = Replace(dsn, "${server}", Server)
    dsn = Replace(dsn, "${user}", username)
    dsn = Replace(dsn, "${password}", password)

    Set rs = CurrentDb.OpenRecordset("SELECT * FROM tblLinkedTables")
    Do While Not rs.EOF
        strAccessName = rs!AccessName
        strOracleName = rs!OracleName
 
        'Remove the outdated linked table 
        '(ignore the error if doesn't exist)
        On Error Resume Next
        DoCmd.DeleteObject acTable, strAccessName
        On Error GoTo 0
 
        'Create the linked table
        Set tDef = CurrentDb.CreateTableDef(strAccessName, dbAttachSavePWD)
        tDef.Connect = dsn
        tDef.SourceTableName = strOracleName
        CurrentDb.TableDefs.Append tDef
        tDef.RefreshLink
 
        rs.MoveNext
    Loop
End Sub

Balsamiq a great tool for sketching your user interface

Often I’ll find myself wanting to show someone an idea for a user interface. A few years ago a colleague introduced to me to Balsamiq and I’ve loved it ever since. Its simple to quickly visualize my ideas and its easy enough that I can sit next to someone and we start moving stuff around until we’re happy with the look. It exports to .pdf, .png and the windows clipboard so its trivial to send the idea through mail or *gasp* print-it-out.

An image showing a basic design for a blog page in Balsamiq

Its easy to customize the contents of the various UI controls in the mock-up:
A image showing how a control in Balsamiq can be customized for each specific need

It has plenty of UI elements included by default and you’ll be well set for anything related to web, application, tablet or phone. There’s also lots of plugins available. Some eye-catchers are integration with Confluence and JIRA. The pricing for stand-alone and for the OnCloud versions can be found on Balsamiq’s pricing page

Here’s a video showing how to integrate Balsamiq with JIRA: