Authenticate() public méthode

Authenticates against Rally with the specified credentials
Rally returned an HTML page. This usually occurs when Rally is off-line. Please check the ErrorMessage property for more information. The JSON returned by Rally was not able to be deserialized. Please check the JsonData property for what was returned by Rally.
public Authenticate ( string username, string password, Uri serverUrl, WebProxy proxy = null, bool allowSSO = true ) : AuthenticationResult
username string The user name to be used for access
password string The password to be used for access
serverUrl System.Uri The Rally server to use (defaults to DEFAULT_SERVER)
proxy System.Net.WebProxy Optional proxy configuration
allowSSO bool Is SSO authentication allowed for this call? It can be useful to disable this during startup processes.
Résultat AuthenticationResult
        static void Main(string[] args)
        {
            RallyRestApi restApi = new RallyRestApi(webServiceVersion: "v2.0");
            String apiKey = "_abc123";
            restApi.Authenticate(apiKey, "https://rally1.rallydev.com", allowSSO: false);

            String[] workspaces = new String[] { "/workspace/12352608129", "/workspace/34900020610" };

            foreach (var s in workspaces)
            {
                Console.WriteLine(" ______________ " + s + " _________________");
                Request typedefRequest = new Request("TypeDefinition");
                typedefRequest.Workspace = s;
                typedefRequest.Fetch = new List<string>() { "ElementName", "Ordinal" };
                typedefRequest.Query = new Query("Parent.Name", Query.Operator.Equals, "Portfolio Item");
                QueryResult typedefResponse = restApi.Query(typedefRequest);

                foreach (var t in typedefResponse.Results)
                {

                    if (t["Ordinal"] > -1)
                    {
                        Console.WriteLine("ElementName: " + t["ElementName"] + " Ordinal: " + t["Ordinal"]);
                    }
                }
            }
        }
        static void Main(string[] args)
        {
            RallyRestApi restApi = new RallyRestApi(webServiceVersion: "v2.0");
            String apiKey = "_abc123";
            restApi.Authenticate(apiKey, "https://rally1.rallydev.com", allowSSO: false);
            String workspaceRef = "/workspace/12352608129";
            //String projectRef = "/project/39468725060";
            Request request = new Request("Attachment");
            request.Workspace = workspaceRef;
            //request.Project = projectRef;
            request.Fetch = new List<string>() { "Artifact", "TestCaseResult", "Size", "CreationDate" };
            request.Limit = 400;
            request.Order = "CreationDate Desc";
            QueryResult results = restApi.Query(request);

            foreach (var a in results.Results)
            {
                if (a["Artifact"] != null)
                {
                    Console.WriteLine("Artifact: " + a["Artifact"]["_ref"]);
                }
                else if (a["TestCaseResult"] != null)
                {
                    Console.WriteLine("TestCaseResult: " + a["TestCaseResult"]["_ref"]);
                }
                Console.WriteLine("Size: " + a["Size"]);
            }
        }
        public RallyApi.RallyRestApi GetApi(string userName, string password)
        {
            int hash = (userName + "|" + password).GetHashCode();
            if (Pools == null)
            {
                Pools = new Dictionary<int, RallyApi.RallyRestApi>();
            }
            if (Pools.ContainsKey(hash) && Pools[hash].ConnectionInfo.UserName == userName && Pools[hash].ConnectionInfo.Password == password)
                {
                    var conn = Pools[hash];
                    if (conn.ConnectionInfo != null &&
                        conn.AuthenticationState == RallyApi.RallyRestApi.AuthenticationResult.Authenticated)
                    {
                        return conn;
                    }
                    RallyApi.RallyRestApi.AuthenticationResult r = conn.Authenticate(userName, password, allowSSO:false);
                    if (r != RallyApi.RallyRestApi.AuthenticationResult.Authenticated)
                    {
                        return null;
                    }
                }

                RallyApi.RallyRestApi api = new RallyApi.RallyRestApi();
                var result = api.Authenticate(userName, password, allowSSO:false);
                if (result != RallyApi.RallyRestApi.AuthenticationResult.Authenticated)
                {
                    return null;
                }
                Pools.Add(hash, api);
                return api;
        }
        public RallyApi.RallyRestApi GetApi(string userName, string password)
        {
            int hash = (userName + "|" + password).GetHashCode();

            if (Pools == null)
            {
                Pools = new Dictionary <int, RallyApi.RallyRestApi>();
            }
            if (Pools.ContainsKey(hash) && Pools[hash].ConnectionInfo.UserName == userName && Pools[hash].ConnectionInfo.Password == password)
            {
                var conn = Pools[hash];
                if (conn.ConnectionInfo != null &&
                    conn.AuthenticationState == RallyApi.RallyRestApi.AuthenticationResult.Authenticated)
                {
                    return(conn);
                }
                RallyApi.RallyRestApi.AuthenticationResult r = conn.Authenticate(userName, password, allowSSO: false);
                if (r != RallyApi.RallyRestApi.AuthenticationResult.Authenticated)
                {
                    return(null);
                }
            }

            RallyApi.RallyRestApi api = new RallyApi.RallyRestApi();
            var result = api.Authenticate(userName, password, allowSSO: false);

            if (result != RallyApi.RallyRestApi.AuthenticationResult.Authenticated)
            {
                return(null);
            }
            Pools.Add(hash, api);
            return(api);
        }
        static void Main(string[] args)
        {
            RallyRestApi restApi = new RallyRestApi(webServiceVersion: "v2.0");
            String apiKey = "_abc123";
            restApi.Authenticate(apiKey, "https://rally1.rallydev.com", allowSSO: false);
            String workspaceRef = "/workspace/123";
            String projectRef = "/project/456";

            Request request = new Request("PortfolioItem/Feature");
            request.Fetch = new List<string>() { "Name", "FormattedID" };
            request.Query = new Query("FormattedID", Query.Operator.Equals, "F2356");
            QueryResult result = restApi.Query(request);

            String featureRef = result.Results.First()._ref;
            Console.WriteLine("found" + featureRef);

            //create stories
            try
            {
                for (int i = 1; i <= 25; i++)
                {
                    DynamicJsonObject story = new DynamicJsonObject();
                    story["Name"] = "story " + i;
                    story["PlanEstimate"] = new Random().Next(2,10);
                    story["PortfolioItem"] = featureRef;
                    story["Project"] = projectRef;
                    CreateResult createResult = restApi.Create(workspaceRef, "HierarchicalRequirement", story);
                    story = restApi.GetByReference(createResult.Reference, "FormattedID");
                    Console.WriteLine("creating..." + story["FormattedID"]);
                }
            //read stories
                DynamicJsonObject feature = restApi.GetByReference(featureRef, "UserStories");
                Request storiesRequest = new Request(feature["UserStories"]);
                storiesRequest.Fetch = new List<string>()
                {
                    "FormattedID",
                    "PlanEstimate"
                };
                storiesRequest.Limit = 1000;
                QueryResult storiesResult = restApi.Query(storiesRequest);
                int storyCount = 0;
                foreach (var userStory in storiesResult.Results)
                {
                    Console.WriteLine(userStory["FormattedID"] + " " + userStory["PlanEstimate"]);
                    storyCount++;
                }
                Console.WriteLine(storyCount);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
        }
        static void Main(string[] args)
        {
            RallyRestApi restApi = new RallyRestApi(webServiceVersion: "v2.0");
            String apiKey = "_abc777";
            restApi.Authenticate(apiKey, "https://rally1.rallydev.com", allowSSO: false);
            String workspaceRef = "/workspace/123";
            String projectRef = "/project/134";

            DynamicJsonObject badDefect = new DynamicJsonObject();
            badDefect["Name"] = "bad defect " + DateTime.Now;
            badDefect["Project"] = projectRef;

            CreateResult createRequest = restApi.Create(workspaceRef, "Defect", badDefect);
            badDefect = restApi.GetByReference(createRequest.Reference, "FormattedID", "Project");
            Console.WriteLine(badDefect["FormattedID"] + " " + badDefect["Project"]._refObjectName);
        }
        static void Main(string[] args)
        {
            RallyRestApi restApi = new RallyRestApi(webServiceVersion: "v2.0");
            String apiKey = "_abc123";
            restApi.Authenticate(apiKey, "https://rally1.rallydev.com", allowSSO: false);
            String workspaceRef = "/workspace/1011574887"; //non-default workspace of the user
            String projectRef = "/project/1791269111"; //a non-default project of the user (inside the workspace above)
            try
            {
                //create testset
                DynamicJsonObject myTestSet = new DynamicJsonObject();
                myTestSet["Name"] = "important set " + DateTime.Now;
                myTestSet["Project"] = projectRef;

                CreateResult createTestSet = restApi.Create(workspaceRef, "TestSet", myTestSet);
                myTestSet = restApi.GetByReference(createTestSet.Reference, "FormattedID", "Project");
                Console.WriteLine(myTestSet["FormattedID"] + " " + myTestSet["Project"]._refObjectName);

                //find current iteration

                Request iterationRequest = new Request("Iteration");
                iterationRequest.Project = projectRef;
                iterationRequest.ProjectScopeDown = false;
                iterationRequest.ProjectScopeUp = false;
                iterationRequest.Fetch = new List<string>() { "ObjectID", "Name" };
                iterationRequest.Query = new Query("(StartDate <= Today)").And(new Query("(EndDate >= Today)"));
                QueryResult queryResults = restApi.Query(iterationRequest);
                if (queryResults.TotalResultCount > 0)
                {
                    Console.WriteLine(queryResults.Results.First()["Name"] + " " + queryResults.Results.First()["ObjectID"]);
                    myTestSet["Iteration"] = queryResults.Results.First()._ref;
                    OperationResult updateResult = restApi.Update(myTestSet["_ref"], myTestSet);
                }
                else
                {
                    Console.WriteLine("No current iterations");
                }

            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
        }
        static void Main(string[] args)
        {
            RallyRestApi restApi = new RallyRestApi(webServiceVersion: "v2.0");
                String apiKey = "_abc123";
                restApi.Authenticate(apiKey, "https://rally1.rallydev.com", allowSSO: false);
                String projectRef = "/project/32904827032";
                try
                {
                    //create story
                    DynamicJsonObject myStory = new DynamicJsonObject();
                    myStory["Name"] = "another story " + DateTime.Now;
                    myStory["Project"] = projectRef;

                    CreateResult createStory = restApi.Create(workspaceRef, "HierarchicalRequirement", myStory);
                    myStory = restApi.GetByReference(createStory.Reference, "FormattedID", "Project");

                    //update story
                    myStory["Description"] = "updated " + DateTime.Now;
                    myStory["c_CustomString"] = "abc123";
                    Console.WriteLine("--------------------");
                    Console.WriteLine(myStory["FormattedID"]);
                    OperationResult updateResult = restApi.Update(myStory["_ref"], myStory);

                    //create tasks
                    for (int i = 1; i <= 3; i++)
                    {
                        DynamicJsonObject myTask = new DynamicJsonObject();
                        myTask["Name"] = "task " + i + DateTime.Now;
                        myTask["State"] = "In-Progress";
                        myTask["WorkProduct"] = myStory["_ref"];
                        CreateResult createTask = restApi.Create(workspaceRef, "Task", myTask);
                        myTask = restApi.GetByReference(createTask.Reference, "FormattedID", "Owner", "State");
                        Console.WriteLine(myTask["FormattedID"]);

                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                }
        }
Exemple #9
0
        static void Main(string[] args)
        {
            #region StartUp Section
            // Initialize all variables
            ConfigRallyUID = "";
            ConfigRallyPWD = "";
            ConfigLogPath = "";
            ConfigStatusEOL = "";
            ConfigReportPath = "";
            ReportFile = "";
            LogFile = "";
            ConfigDBServer = "";
            ConfigDBName = "";
            ConfigDBUID = "";
            ConfigDBPWD = "";
            ReportDayNum = 0;
            ReportWeekNum = 0;
            ReportMonth = 0;
            ReportQuarter = 0;
            ReportYear = 0;

            // Get the configuration information from config file
            if (!GetConfigSettings())
            {
                // If we can't get the configuration settings, we can't even log anything, so just terminate
                Environment.Exit(-1);
            }

            // Check for any commandline arguments.  If there are not any, assume a "Daily" operating mode and set
            // the report date to yesterday (we don't want to report on today)
            if (args.Length != 0)
            {
                GetCommandArgs();
            }
            else
            {
                OperatingMode = OperateMode.Daily;
                ReportingDay = DateTime.Today.AddDays(-1);
                ReportDayNum = ReportingDay.Day;
                ReportMonth = ReportingDay.Month;
                ReportYear = ReportingDay.Year;
            }
            #endregion StartUp Section

            // Log the start of processing
            LogOutput("Started processing at " + DateTime.Now.ToLongTimeString() + " on " + DateTime.Now.ToLongDateString(), "Main", false);
            DateTime dtStartTime = DateTime.Now;

            // Log the operating mode
            switch (OperatingMode)
            {
                case OperateMode.Daily:
                    LogOutput("Operating in Daily Mode...Processing for Day " + ReportingDay.ToString("dd-MMM-yyyy"), "Main", false);
                    break;
                case OperateMode.Monthly:
                    LogOutput("Operating in Monthly Mode...Processing for " + ReportingDay.ToString("MMM"), "Main", false);
                    break;
                case OperateMode.Quarterly:
                    LogOutput("Operating in Quarterly mode...Processing for Quarter Q" + ReportQuarter.ToString() + "Y" + ReportYear.ToString(), "Main", false);
                    break;
                case OperateMode.Annual:
                    LogOutput("Operating in Annual mode...Processing for year " + ReportYear.ToString(), "Main", false);
                    break;
                case OperateMode.Weekly:
                    LogOutput("Operating in Weekly mode...Processing for Day " + ReportingDay.ToString("dd-MMM-yyyy"), "Main", false);
                    break;
                default:
                    LogOutput("Unknown Operating mode...assuming Daily...", "Main", false);
                    break;
            }

            #region Gather from Rally
            // Create the Rally API object
            LogOutput("Creating reference to RallyAPI...", "Main", true);
            RallyAPI = new RallyRestApi();

            // Login to Rally
            LogOutput("Starting connection to Rally...", "Main", true);
            try
            {
                RallyAPI.Authenticate(ConfigRallyUID, ConfigRallyPWD, ConfigRallyURL);
                LogOutput("Response from RallyAPI.Authenticate: " + RallyAPI.AuthenticationState.ToString(), "Main", true);
                if (RallyAPI.AuthenticationState.ToString() != "Authenticated")
                {
                    // We did not actually connect
                    LogOutput("Unable to connect to Rally and establish session.  Application will terminate.", "Main", false);
                    Environment.Exit(-1);
                }
                else
                {
                    if (RallyAPI.ConnectionInfo.UserName == null)
                    {
                        LogOutput("RallyAPI.ConnectionInfo: " + RallyAPI.ConnectionInfo.ToString(), "Main", false);
                        LogOutput("Unable to authenticate with Rally.  Application will terminate.", "Main", false);
                        Environment.Exit(-1);
                    }
                    else
                    {
                        LogOutput("Connected to Rally as user " + RallyAPI.ConnectionInfo.UserName, "Main", true);
                    }
                }
            }
            catch (Exception ex)
            {
                LogOutput("Error Connecting to Rally: " + ex.Message, "Main", false);
                LogOutput("Rally Authentication State: " + RallyAPI.AuthenticationState.ToString() +
                    "Rally Connection Info: " + RallyAPI.ConnectionInfo.ToString(), "Main", false);
            }

            // Grab the active Initiatives we want to report on
            LogOutput("Getting all Initiatives...", "Main", false);
            List<Initiative> InitiativeList = new List<Initiative>();
            LogOutput("Calling 'GetInitiativeList'...", "Main", true);
            InitiativeList = GetInitiativeList();
            LogOutput("Done with 'GetInitiativeList'", "Main", true);
            if (InitiativeList.Count == 0)
            {
                // Could not get the Initiatives...or nothing to report on, so stop
                LogOutput("Unable to open Initiative list or no Initiatives to report on.  Application will terminate.", "Main", false);
                InitiativeList.Clear();
                RallyAPI.Logout();      // Disconnect from Rally
                Environment.Exit(-1);   // End Program
            }
            LogOutput("Retrieved " + InitiativeList.Count + " Initiatives to report on", "Main", false);

            // Now iterate through the initiatives and get all the Features or "Projects"
            LogOutput("Getting all Projects for the Initiatives...", "Main", false);
            BasicProjectList = new List<Project>();
            LogOutput("Looping for each Initiative...", "Main", true);
            foreach (Initiative init in InitiativeList)
            {
                // Get the project list for the current initiative ONLY
                List<Project> ProjectList = new List<Project>();
                LogOutput("Calling 'GetProjectsForInitiative' with " + init.Name.Trim() + "...", "Main", true);
                ProjectList = GetProjectsForInitiative(init.Name.Trim());
                LogOutput("Done with 'GetProjectsForInitiative' for " + init.Name.Trim(), "Main", true);

                // Append this list to the FULL list
                LogOutput("Appending " + ProjectList.Count + " projects to object 'BasicProjectList'", "Main", true);
                BasicProjectList.AddRange(ProjectList);
            }
            LogOutput("Retrieved " + BasicProjectList.Count + " Projects total", "Main", false);

            // We need to loop through the project list now and for each project
            // we need to get all the epics.  Then with each epic, we recursively
            // get all user stories
            LogOutput("Getting all User Stories for all projects...", "Main", false);
            // Initialize a new list of projects.  This will become the full list including stories
            // and defects
            CompleteProjectList = new List<Project>();
            LogOutput("Looping for each Project...", "Main", true);
            foreach (Project proj in BasicProjectList)
            {
                // Get all the epics for this project
                LogOutput("~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+", "Main", true);
                LogOutput("Calling 'GetEpicsForProject' with " + proj.Name.Trim() + "...", "Main", true);
                List<Epic> EpicList = new List<Epic>();
                EpicList = GetEpicsForProject(proj.FormattedID.Trim());
                LogOutput("Done with 'GetEpicsForProject' for " + proj.Name.Trim(), "Main", true);

                // Now go through each of the Epics for the current project
                // and recurse through to get all final-level user stories
                LogOutput("Getting all User Stories for " + proj.Name + "...", "Main", true);
                List<Epic> FullEpicList = new List<Epic>();
                BasicStoryList = new List<UserStory>();
                LogOutput("Looping for each Epic...", "Main", true);
                foreach (Epic epic in EpicList)
                {
                    Epic newepic = new Epic();
                    List<UserStory> StoryList = new List<UserStory>();
                    LogOutput("Calling 'GetUserStoriesPerParent' with " + epic.FormattedID.Trim() + " as Root Parent...", "Main", true);
                    StoryList = GetUserStoriesPerParent(epic.FormattedID.Trim(), epic.Name.Trim(), true);
                    LogOutput("Done with 'GetUserStoriesPerParent' for " + epic.FormattedID.Trim(), "Main", true);
                    // save the info as a new epic
                    newepic.ActualEndDate = epic.ActualEndDate;
                    newepic.DefectActual = epic.DefectActual;
                    newepic.DefectEstimate = epic.DefectEstimate;
                    newepic.DefectToDo = epic.DefectToDo;
                    newepic.Description = epic.Description;
                    newepic.FormattedID = epic.FormattedID;
                    newepic.Name = epic.Name;
                    newepic.Owner = epic.Owner;
                    newepic.ParentProject = epic.ParentProject;
                    newepic.PlannedEndDate = epic.PlannedEndDate;
                    newepic.PlannedStartDate = epic.PlannedStartDate;
                    newepic.Release = epic.Release;
                    newepic.State = epic.State;
                    newepic.StateChangedDate = epic.StateChangedDate;
                    newepic.StoryActual = epic.StoryActual;
                    newepic.StoryEstimate = epic.StoryEstimate;
                    newepic.StoryToDo = epic.StoryToDo;
                    newepic.UserStories = StoryList;
                    // Add the stories to the full list
                    FullEpicList.Add(newepic);
                    BasicStoryList.AddRange(StoryList);
                }
                LogOutput("Retrieved " + BasicStoryList.Count + " User Stories for " + proj.Name, "Main", false);

                // Get any defects there may be for the User Stories
                LogOutput("Getting all Defects for " + proj.Name + "...", "Main", false);
                BasicDefectList = new List<Defect>();
                LogOutput("Looping for each Story...", "Main", true);
                foreach (UserStory story in BasicStoryList)
                {
                    List<Defect> DefectList = new List<Defect>();
                    // Defects will always be attached to a User Story
                    LogOutput("Calling 'GetDefectsForStory' with " + story.Name + "...", "Main", true);
                    DefectList = GetDefectsForStory(story);
                    LogOutput("Done with 'GetDefectsForStory' for " + story.Name, "Main", true);
                    // If there are any defects, add them to the list
                    if (DefectList.Count > 0)
                    {
                        LogOutput("Appending " + DefectList.Count + " defects to object 'BasicDefectList'", "Main", true);
                        BasicDefectList.AddRange(DefectList);
                    }
                }

                // At this point we have the FULL list of User Stories/Defects for the current
                // project.  We now create a "new" project with the same properties, but this time
                // we are able to store the Epics, User Stories, and Defects.
                LogOutput("Creating new project object and populating with full information...", "Main", true);
                Project newproject = new Project();
                newproject.ActualEndDate = proj.ActualEndDate;
                newproject.Description = proj.Description;
                newproject.Expedite = proj.Expedite;
                newproject.FormattedID = proj.FormattedID;
                newproject.Initiative = proj.Initiative;
                newproject.LastUpdateDate = proj.LastUpdateDate;
                newproject.Name = proj.Name;
                newproject.OpportunityAmount = proj.OpportunityAmount;
                newproject.Owner = proj.Owner;
                newproject.UpdateOwner = proj.UpdateOwner;
                newproject.StakeHolder = proj.StakeHolder;
                newproject.PlannedEndDate = proj.PlannedEndDate;
                newproject.PlannedStartDate = proj.PlannedStartDate;
                newproject.RevokedReason = proj.RevokedReason;
                newproject.State = proj.State;
                newproject.StateChangedDate = proj.StateChangedDate;
                newproject.StatusUpdate = proj.StatusUpdate;
                newproject.UserStories = BasicStoryList;
                newproject.Defects = BasicDefectList;
                newproject.Epics = FullEpicList;
                LogOutput("Appending new project object to object 'CompleteProjectList'", "Main", true);
                CompleteProjectList.Add(newproject);
            }
            LogOutput("Done looping through all projects", "Main", false);
            LogOutput("Appending new project object to object 'CompleteProjectList'", "Main", true);
            #endregion Gather from Rally

            #region Calculation Section
            // We now have a full list of all projects with all complete information so
            // at this point we can calculate the Actuals for each project based on the reporting mode we are operating in
            switch (OperatingMode)
            {
                case OperateMode.Daily:
                    // This mode runs every day and simply keeps running total of time with daily inserts for each project
                    AllProjectInfo = new List<Project>();
                    LogOutput("Calling 'CalculateDailyTotals' with " + CompleteProjectList.Count + " complete projects...", "Main", true);
                    AllProjectInfo = CalculateDailyTotals(CompleteProjectList, ReportingDay);
                    LogOutput("Done with 'CalculateDailyTotals'", "Main", true);

                    // Now create the final report
                    LogOutput("Calling 'CreateDailyReport'...", "Main", true);
                    CreateDailyReport(AllProjectInfo, ReportingDay);
                    LogOutput("Done with 'CreateDailyReport'...", "Main", true);
                    break;
                case OperateMode.Monthly:
                    // This mode runs each month and creates very high-level summary info
                    AllProjectInfo = new List<Project>();
                    LogOutput("Calling 'CalculateMonthlyReport' with " + CompleteProjectList.Count + " complete projects...", "Main", true);
                    AllProjectInfo = CalculateMonthlyReport(CompleteProjectList, ReportMonth);
                    LogOutput("Done with 'CalculateMonthlyReport'", "Main", true);

                    // Now create the final report
                    LogOutput("Calling 'CreateMonthlyReport'...", "Main", true);
                    CreateMonthlyReport(AllProjectInfo, ReportMonth);
                    LogOutput("Done with 'CreateMonthlyReport'...", "Main", true);
                    break;
                case OperateMode.Quarterly:
                    AllProjectInfo = new List<Project>();
                    LogOutput("Calling 'CalculateQuarterTotals' with " + CompleteProjectList.Count + " complete projects...", "Main", true);
                    AllProjectInfo = CalculateQuarterTotals(CompleteProjectList, ReportQuarter, ReportYear);
                    LogOutput("Done with 'CalculateQuarterTotals'", "Main", true);

                    // Now create the final report
                    LogOutput("Calling 'CreateQuarterReport'...", "Main", true);
                    CreateQuarterReport(AllProjectInfo, ReportYear.ToString() + 'Q' + ReportQuarter.ToString());
                    LogOutput("Done with 'CreateQuarterReport'...", "Main", true);
                    break;
                case OperateMode.Annual:
                    AllProjectInfo = new List<Project>();
                    LogOutput("Calling 'CalculateAnnualTotals' with " + CompleteProjectList.Count + " complete projects...", "Main", true);
                    AllProjectInfo = CalculateAnnualTotals(CompleteProjectList, ReportYear);
                    LogOutput("Done with 'CalculateAnnualTotals'", "Main", true);

                    // Now create the final report
                    LogOutput("Calling 'CreateAnnualReport'...", "Main", true);
                    CreateAnnualReport(AllProjectInfo, ReportYear);
                    LogOutput("Done with 'CreateAnnualReport'...", "Main", true);
                    break;
                case OperateMode.Weekly:
                    // This mode is intended to run on Sunday in order to run stats for up-to-and-including current week for projects.  The "Project Update"
                    // is also included so the single table can be queried
                    AllProjectInfo = new List<Project>();
                    LogOutput("Calling 'CalculateWeeklyTotals' with " + CompleteProjectList.Count + " complete projects...", "Main", true);
                    AllProjectInfo = CalculateWeeklyTotals(CompleteProjectList, ReportingDay);
                    LogOutput("Done with 'CalculateWeeklyTotals'", "Main", true);

                    // Now create the weekly report
                    LogOutput("Calling 'CreateWeeklyReport'...", "Main", true);
                    CreateWeeklyReport(AllProjectInfo, ReportingDay);
                    LogOutput("Done with 'CreateWeeklyReport'...", "Main", true);
                    break;
            }
            #endregion

            DateTime dtEndTime = DateTime.Now;
            string strTotSeconds = dtEndTime.Subtract(dtStartTime).TotalSeconds.ToString();
            LogOutput("Completed processing at " + DateTime.Now.ToLongTimeString() + " on " + DateTime.Now.ToLongDateString() + " - Total Processing Time: " + strTotSeconds + " seconds", "Main", false);
            Environment.Exit(0);
        }
        static void Main(string[] args)
        {
            RallyRestApi restApi = new RallyRestApi(webServiceVersion: "v2.0");
            String apiKey = "_abc123";
            restApi.Authenticate(apiKey, "https://rally1.rallydev.com", allowSSO: false);
            String workspaceRef = "/workspace/1011574887";
            String projectRef = "/project/1791269111";
            String userName = "******";

            try
            {

                Request storyRequest = new Request("hierarchicalrequirement");
                storyRequest.Workspace = workspaceRef;
                storyRequest.Project = projectRef;

                storyRequest.Fetch = new List<string>()
                {
                    "FormattedID"
                };

                storyRequest.Query = new Query("FormattedID", Query.Operator.Equals, "US2917");
                QueryResult queryResult = restApi.Query(storyRequest);
                var storyObject = queryResult.Results.First();
                String storyReference = storyObject["_ref"];

                Request userRequest = new Request("user");
                userRequest.Fetch = new List<string>()
                {
                    "UserName"
                };

                userRequest.Query = new Query("UserName", Query.Operator.Equals, userName);
                QueryResult queryUserResults = restApi.Query(userRequest);
                DynamicJsonObject user = new DynamicJsonObject();
                user = queryUserResults.Results.First();
                String userRef = user["_ref"];

                String imageFilePath = "C:\\images\\";
                String imageFileName = "rally.png";
                String fullImageFile = imageFilePath + imageFileName;
                Image myImage = Image.FromFile(fullImageFile);

                string imageBase64String = ImageToBase64(myImage, System.Drawing.Imaging.ImageFormat.Png);
                var imageNumberBytes = Convert.FromBase64String(imageBase64String).Length;
                Console.WriteLine("Image size: " + imageNumberBytes);

                DynamicJsonObject myAttachmentContent = new DynamicJsonObject();
                myAttachmentContent["Content"] = imageBase64String;
                CreateResult myAttachmentContentCreateResult = restApi.Create(workspaceRef,"AttachmentContent", myAttachmentContent);
                String myAttachmentContentRef = myAttachmentContentCreateResult.Reference;
                Console.WriteLine(myAttachmentContentRef);

                DynamicJsonObject myAttachment = new DynamicJsonObject();
                myAttachment["Artifact"] = storyReference;
                myAttachment["Content"] = myAttachmentContentRef;
                myAttachment["Name"] = "rally.png";
                myAttachment["Description"] = "Attachment Desc";
                myAttachment["ContentType"] = "image/png";
                myAttachment["Size"] = imageNumberBytes;
                myAttachment["User"] = userRef;

                CreateResult myAttachmentCreateResult = restApi.Create(workspaceRef, "Attachment", myAttachment);

                List<string> createErrors = myAttachmentContentCreateResult.Errors;
                for (int i = 0; i < createErrors.Count; i++)
                {
                    Console.WriteLine(createErrors[i]);
                }

                String myAttachmentRef = myAttachmentCreateResult.Reference;
                Console.WriteLine(myAttachmentRef);

            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
        }