Skip to content

Latest commit

 

History

History
642 lines (495 loc) · 28.9 KB

CONTRIBUTING.md

File metadata and controls

642 lines (495 loc) · 28.9 KB

Contributing

Table of Contents

Background

Retrospectives is an Azure DevOps extension. Visit this link to learn more about developing extensions. The Retrospectives Azure DevOps extension frontend is implemented in React using Typescript, and the backend is implemented in C#. The project follows a single branch source control strategy.

Contributing Guidelines

Branching and Pull Requests

  1. When creating a new branch, follow the {alias}/{issue##} naming convention. - Note: It is recommended to keep the branch name length below 30 characters in order to allow the Github Action which builds and deploys the development extension on Pull Request creation or update to successfully execute.

  2. Once your feature addition or bug fix is ready for review, create a pull request against the main branch of the repository.

  3. Include a link to the GitHub issue you are addressing to the description of your pull request. Reviewers will be added to the pull request automatically.

  4. Ensure all CI/CD checks are successful after the creation of the pull request.

  5. Update any documentation, user and contributor, that is impacted by your changes.

  6. You may merge the pull request in once you have the sign-off from one developer from the Retrospectives team, or if you do not have permission to do that, you may request the reviewer to merge it for you.

Continuous Integration (CI) and Pre-commit Hook

Our CI pipeline can be invoked on Github, or if you want to get ahead of the potential failures, you can use the pre-commit configuration. It will run linting on markdown files and python files, and run a spellcheck. The same rules will be caught locally that will be caught in Github actions.

To use pre-commit, it's recommended to have a python virtual environment (venv). If the venv ends with -env, such as retro-env, then the .gitignore is configured to not watch this environment during development!

Either in the dev container or locally:

  1. Run: pip install -r requirements.txt
  2. Run: pre-commit install
  3. To run the checks ahead of commiting:
    • pre-commit run will run the pre-commit hooks against staged files
    • pre-commit run --all-files will run against everything
    • pre-commit run markdownlint to run the markdown linting
    • pre-commit run spellcheck-cli to run the spellchecking
  4. To run linting for the typescript/javascript (must be done within the RetrospectiveExtension.Frontend directory): npm run lint

Read more about the python pre-commit framework. To disable the pre-commit hook run pre-commit uninstall from the root folder.

Development Environments

The Retrospectives Extension can be built, developed and tested in several development environments. This section highlights three of the primary environments in order of relevance.

All of the development prerequisites, such as Webpack and NodeJS are listed in the Dockerfile. This file can be opened in a text editor and the install commands can be used to configure the prerequisites outside of a dev container.

Dev Containers

  1. Install the latest version of Docker Desktop.

  2. Install the latest version of Visual Studio Code.

  3. Install the Docker extension for Visual Studio Code.

  4. Install the Remote - Containers extension for Visual Studio Code.

  5. Check out this repository and open the parent folder in Visual Studio Code.

  6. Follow the steps outlined in the Build section to build, test, and deploy development versions of the extension.


  • The first time this repository is opened in Visual Studio Code, the .devcontainer folder will be detected. In the bottom right-hand corner of the screen, a prompt will be displayed: “Folder contains a Dev Container configuration file. Reopen folder to develop in a container.”.
  • Selecting the “Reopen in Container” option will automatically start the process of creating the Dev Container; this may take a few minutes the first time the container is created, or any time the settings for the container have changed and the container needs to be recreated.
  • If there are issues running the ci.sh script in a clean checkout, check the Files: Eol setting in Visual Studio Code. Change it to \n, open the ci.sh file, save it, and retry the script.

Windows Subsystem For Linux

  1. To configure the WSL if it is not already available on the development machine, follow this tutorial.

  2. Follow Git on WSL Instructions if Git is not already installed on the development machine.

  3. Follow Node Installation Instructions to enable Node for WSL.

  4. Install the latest version of Visual Studio Code.

  5. Install the Remote – WSL extension for Visual Studio Code.

  6. Check out this repository and open the parent folder in Visual Studio Code.

  7. If VSCode does not recognize the WSL on its own, in the top right hand corner of the terminal window, select the down arrow to "Launch Profile..." and select the name of the distribution in use to create a new WSL terminal.

  8. Perform the commands listed in the Dockerfile to globally install required packages such as dotnet core.

  9. Run the setup_ci.sh script to configure the WSL for the pre-commit hook.

  10. Follow the steps outlined in the Build section to build, test, and deploy development versions of the extension.


  • Some commands, such as dotnet build and npm run build:p may need sudo prefixed to execute successfully.

Github Codespaces

  1. If necessary, read GitHub's codespace creation documentation.

  2. Create a branch for the work you are planning to complete.

  3. Create a codespace through the new branch's dropdown on GitHub.

  4. Codespaces are powered by Visual Studio Code and dev containers - once the codespace has been entered, you can follow the instructions within the dev containers section for continuing to set up the development environment. View the Developing in a codespace documentation for additional details.

Build

Test in Azure DevOps

Test changes in the Azure DevOps environment by publishing a development version of the extension under an Azure DevOps publisher account.


  1. Clone this repository, and open in your preferred development environment.

  2. Using Powershell, navigate to the /RetrospectiveExtension.Frontend folder, run npm install. This will download all the dependent packages listed in package.json.

  3. When developing or publishing the extension locally, you need to create a .env file at the top-level directory of the front end project (where package.json lives). You can copy RetrospectiveExtension.Frontend/.env.template to RetrospectiveExtension.Frontend/.env to get started. The contents of the .env file are

    # Backend Service URL
    REACT_APP_COLLABORATION_STATE_SERVICE_URL="put the deployed backend service url here"
    # App Instrumentation Key
    REACT_APP_APP_INSIGHTS_INSTRUMENTATION_KEY="put Instrumentation key here"
    • In lieu of the .env file you can set actual environment variables.

    • When using the CI/CD github action(s) pipeline to deploy the extension, environment variables are used to set Application Insights instrumentation key and the backend service url.

  4. Run npm run build:d or npm run build:p to build the project. The difference in commands is development versus production, respectively; the production command will generate a smaller bundle.

  5. To test your changes, you will need to publish a new extension under a new Azure DevOps publisher account. Refer to the documentation on publishing extensions. You can publish it to any test Azure DevOps organization that you are an admin of (As a Microsoft employee, you can create a new test organization from your Azure DevOps profile page). Currently this is the only way to test the extension.

  6. Copy the file vss-extension-dev.json.template into a new vss-extension-dev.json file with the new publisher that you setup. Also update the name and id fields.

    {
      "manifestVersion": 1,
      "id": <any new id>,
      "publisher": <the new publisher you created>,
      "version": <your staring version>,
      "name": <your extension's name. Can be any name you can identify by. Eg. Retrospectives-test>,
    }
  7. Run npm run pack:d to package the modules into a Azure DevOps extension package. This generated package has a .vsix extension. This package is generated using information from the manifest file and your built code. Refer to the documentation to know more about extension manifests.

  8. Publish your to the marketplace. Once published, share the extension with the newly created test org. See this link for documentation on sharing.


  • Once the extension has been shared with your test org, you can install it to your org and start using it. This installation process is similar to installing any other DevOps extensions. Refer to this link for instructions. Since the extension is still in preview mode, it needs to be enabled for the Azure DevOps project. Enable the extension from the Preview Features tab.

  • Now start using the extension to test your changes.

  • For updates, rebuild and package your extension and publish an update from the Azure DevOps marketplace. That will automatically update the extension in your project.

  • For the real time live syncing to work, our service needs to know your publisher id and your extension's unique key. To enable real time updates for your test extension, please reach out to us with your publisher id and the unique key of your extension.

Test with Hot Reload and Debug

Test changes by loading changes locally without having to re-package and re-publish the extension in the marketplace.


Hot Reload Prerequisites

  1. Azure DevOps Extension Hot Reload and Debug

  2. Visual Studio Code

  3. Firefox

  4. Debugger for Firefox VS Code extension


  1. In the RetrospectiveExtension.Frontend folder, create the vss-extension-dev.json file using the template file vss-extension-dev.json.template for reference.

  2. Update the webpack.config.js to enable source maps. Set the devtool property to inline-source-map. Also set devServer.https to true and devServer.port to 3000.

    module.exports = {
      devtool: 'inline-source-map',
      devServer: {
        https: true,
        port: 3000,
        static: {
          directory: path.join(__dirname),
        }
      },
    ...
  3. Set output.publicPath to /dist/ in the webpack.config.json file. This will allow webpack to serve files from https://localhost:3000/dist.

    module.exports = {
        output: {
          publicPath: "/dist/"
          // ...
        }
        // ..
    };
  4. In the root of the project, create a folder named .vscode. In there, create a file named launch.json, which will help to set up a debug configuration for VS Code that launches Firefox with the correct path mappings. Inside of this file, you will add a path mapping with url set to webpack:/// and have the path set to ${workspaceFolder}/RetrospectiveExtension.Frontend/. Also set the reAttach property on the configuration to true to avoid restarting Firefox every time you debug.

    {
      "version": "0.2.0",
      "configurations": [
        {
          "name": "Launch Firefox",
          "type": "firefox",
          "request": "launch",
          "url": "https://localhost:3000/",
          "reAttach": true,
          "pathMappings": [
            {
              "url": "webpack://retrospective-vsts-extension/components",
              "path": "${workspaceFolder}/RetrospectiveExtension.Frontend/components"
            },
            {
              "url": "webpack://retrospective-vsts-extension/dal",
              "path": "${workspaceFolder}/RetrospectiveExtension.Frontend/dal"
            },
            {
              "url": "webpack:///",
              "path": "${workspaceFolder}/RetrospectiveExtension.Frontend/"
            }
          ]
        }
      ]
    }
  5. Navigate to the /RetrospectiveExtension.Frontend folder, run npm install to download all the dependent packages listed in package.json.

  6. Run npm run build:d to build the project.

  7. Run npm run start:dev to start the webpack-dev-server

  8. Start debugger (making sure the webpack-dev-server is still running). The default launch configuration should be set to Launch Firefox.

  9. IF YOU ARE ON WINDOWS -> Access Firefox settings from the hamburger menu. Navigate to Privacy & Security and under Logins and Passwords select Allow Windows single sign-on for Microsoft, work and school accounts. This is necessary to login to Azure otherwise you will be blocked by a Microsoft management policy for Firefox. This step needs to be completed each time you launch the debugger as it launches Firefox with a cleared cache and default settings.

  10. Once Firefox starts up, you should get an untrusted certificate error page. Select Advanced and then select Accept the Risk and Continue and log into your Azure DevOps account. From now on, if you leave this Firefox window open, the debugger will reattach instead of starting a clean Firefox instance each time.

  11. Once you are logged in to Azure DevOps, your extension should be running. Set a breakpoint in a method in VS Code and you should see that breakpoint hit when that method executes.

Test with Deployed Backend Service

The Retrospectives extension uses the Azure SignalR service to add real time support. The backend codebase can be found here.

To enable real time updates from your test extension you will need to deploy the backend to Azure specifying your publisher id and the unique key of your extension.


Notes

  • This setup is not required for contributing to this extension, but can be helpful if you want certain debugging options available to you.
  • If you are part of a team working on the Retrospectives extension you can deploy a single backend to support multiple developer test extensions.

Backend Prerequisites

  1. Azure CLI - installation instructions here

  2. dotnet CLI - the CLI comes as a part of the .NET SDK

  3. the zip CLI tool - via brew install zip or apt-get install zip in a unix-flavored environment.

Setup

  1. Copy /deploy/.env.template to /deploy/.env and make the following changes:

    • Add the Service Principal values used by the env_setup.sh script. Instructions on how to create a Service Principal.
    • Add the RESOURCE_NAME_SUFFIX value. This will be used for naming all Azure resources including the App Service name - https://<RESOURCE_NAME_SUFFIX>.azurewebsites.net. Note: The app name must be globally unique so select something accordingly.
    • Add the LOCATION value i.e. "eastus", "westus", etc.
  2. Copy /allowed_origins.json.template to /allowed_origins.json and replace the <publisher id> with your publisher id. This id uniquely identifies your publisher in the Visual Studio Marketplace. If you are part of a team working on the retro tool you can add additional allowed origins. There should be two allowed origins per publisher id. Remember to increment the name index as you add additional origins.

  3. Copy /dev_certs.json.template to /dev_certs.json and replace the <extension secret> with your secret. Instructions on how to download the unique key. If you are part of a team working on the retro tool you can add additional secrets. Remember to increment the name index to add additional secrets.

  4. Run the deploy/env_setup.sh script.

  5. Once the script completes, it will output the url of the backend service. You can navigate to the Azure Portal and validate that the rg-<RESOURCE_NAME_SUFFIX> resource group exists and contains the App Service, App Service Plan and SignalR resources.

  6. Update the RetrospectiveExtension.FrontEnd/config/environment.tsx to reflect changes to:

    • CollaborationStateServiceUrl value to the App Service URL - https://<RESOURCE_NAME_SUFFIX>.azurewebsites.net.
    • AppInsightsInstrumentKey value to Application Insights' Instrumentation Key for the resource ai-<RESOURCE_NAME_SUFFIX>.
  7. After updating the above values redeploy the extension.

Frontend Development

Frontend Style Guide

This extension uses ESLint for consistent formatting and styling within the React components.

Frontend Unit Testing

Framework

React Component tests are written using the following packages:


Test Coverage

To automatically generate the test coverage report, add the --coverage flag to the test script defined in package.json. After the test run is completed, coverage statistics will then be reported in the newly created coverage directory.


Test Execution

  • npm install must be executed before running any tests.
  • npm run test is the default test execution method defined in the package.json file. This will automatically run all of the tests in files suffixed with .test.tsx inside of the tests folder.
  • npm run test:watch will run tests in watch mode, re-running tests every time a component change is saved.
  • jest --env=jsdom --silent -ci --testResultsProcessor=jest-junit {FULL_FILE_PATH} can be used to run tests only in the specified file. Wildcards also work instead of a fully qualified path.

Mocks

  • In this project, mocks have been implemented for simulating API calls and external module functionality. Reusable mocks should be added to the mock folder.
  • Mocks which are shared by the majority of tests should be initialized in the test setup file.

Snapshots

To ensure proper rendering of components, snapshots tests are being used to compare expected component rendering state against its actual state. Snapshot tests will fail when changes are made to components that are not accounted for through updates to these stored snapshots.

To update snapshots, delete the snapshot for the component you are testing, (located in the snapshots folder) and run the test command. On test run completion, new snapshots should be created. Please check the newly created snapshot file, to ensure that the expected changes are present, and include the snapshot in your pull request.

To enable real time updates from your test extension you will need to deploy the backend to Azure specifying your publisher id and the unique key of your extension. Note: If you are part of a team working on the retro tool you can deploy a single backend to support multiple developer test extensions.

  1. Copy /deploy/.env.template to /deploy/.env and make the following changes:
    • Add the Service Principal values used by the env_setup.sh script. Instructions on how to create a Service Principal.
    • Add the RESOURCE_NAME_SUFFIX value. This will be used for naming all Azure resources including the App Service name - https://<RESOURCE_NAME_SUFFIX>.azurewebsites.net. Note: The app name must be globally unique so select something accordingly.
    • Add the LOCATION value i.e. "eastus", "westus", etc.
  2. Copy /allowed_origins.json.template to /allowed_origins.json and replace the <publisher id> with your publisher id. This id uniquely identifies your publisher in the Visual Studio Marketplace. If you are part of a team working on the retro tool you can add additional allowed origins. There should be two allowed origins per publisher id. Remember to increment the name index as you add additional origins.
  3. Copy /dev_certs.json.template to /dev_certs.json and replace the <extension secret> with your secret. Instructions on how to download the unique key. If you are part of a team working on the retro tool you can add additional secrets. Remember to increment the name index to add additional secrets.
  4. Run the deploy/env_setup.sh script.
  5. Once the script completes, it will output the url of the backend service. You can navigate to the Azure Portal and validate that the rg-<RESOURCE_NAME_SUFFIX> resource group exists and contains the App Service, App Service Plan and SignalR resources.
  6. Update the RetrospectiveExtension.FrontEnd/config/environment.tsx to reflect changes to:
    • CollaborationStateServiceUrl value to the App Service URL - https://<RESOURCE_NAME_SUFFIX>.azurewebsites.net.
    • AppInsightsInstrumentKey value to Application Insights' Instrumentation Key for the resource ai-<RESOURCE_NAME_SUFFIX>.
  7. After updating the above values redeploy the extension.

Backend Development

Style Guidelines

Follow the coding guidelines here - C# Coding Conventions (C# Programming Guide).

Storage

The Retrospectives tool uses the Azure DevOps data service for handling all its storage.

Code

  1. The project is developed using the .NET Core development platform. The CollaborationStateService web project contains the code for the backend service. Since .NET Core is platform independent, project can be developed on any operating system.

  2. The ReflectBackend.ReflectHub class contains the implementation of all the functions that the backend service supports. New methods should be added here to support more real time scenarios.

  3. Examples:

    • The code snippet below provides a method that the client can use to join a backend Group. Groups in SignalR provide a method for broadcasting messages to specified subsets of connected clients. Any client using this method gets added to the group that it specifies by the reflectBoardId.

          /// <summary>
          /// Adds the client to the group for this reflect board.
          /// </summary>
          /// <param name="reflectBoardId">The id of the reflect board.</param>
          public Task JoinReflectBoardGroup( string reflectBoardId )
          {
              _insights.TrackEvent("Adding client to board");
              return Groups.AddToGroupAsync( Context.ConnectionId, reflectBoardId );
          }
    • The code snippet below broadcasts that a new Feedback specified by the feedbackItemId is available on the board specified by reflectBoardId. The columnId specifies which column of the board the item was added to. Clients can use this method to signal to other clients that a new Feedback was added to one of its boards.

      /// <summary>
      /// Broadcast receiveNewItem to all other clients viewing the same reflect board.
      /// </summary>
      /// <param name="reflectBoardId">The id of the reflect board.</param>
      /// <param name="columnId">The id of column this item is associated with.</param>
      /// <param name="feedbackItemId">The id of the new feedback item.</param>
      public Task BroadcastNewItem( string reflectBoardId, string columnId, string feedbackItemId )
      {
          _insights.TrackEvent("Broadcasting new item");
          return Clients.OthersInGroup( reflectBoardId ).SendAsync( "receiveNewItem",
                                                                   columnId, feedbackItemId );
      }

Backend Unit Testing

Unit Tests for the Backend are located in the Backend Tests folder. To execute these tests, perform the following steps:

  1. Navigate to the RetrospectiveExtension.Backend folder.

  2. Execute dotnet restore.

  3. Execute dotnet build.

  4. Execute dotnet test ../RetrospectiveExtension.Backend.Tests.

  5. View test results in the terminal.

Application Monitoring and Telemetry

  1. The Retro tool uses Azure Application Insights to capture application logs, telemetry and performance data.

  2. A custom Azure portal is deployed as part of the backend deployment script that enables real time monitoring of the application. The dashboard includes useful telemetry data such as number of active user sessions, histogram of React Components visited, HTTP requests made, page load times, backend and front end exceptions and other metrics.

License Information

Copyright (c) Microsoft Corporation. All rights reserved.