Coder Social home page Coder Social logo

dotnet-sonar's Introduction

dotnet-sonar

This is a container used to build dotnet projects and provide SonarQube analysis using SonarQube MSBuild Scanner.

It also allows you to run Docker in Docker using a docker.sock mount.


This latest image was built with the following components:

  • dotnetcore-sdk 8.0.201
  • dotnetcore-runtime 8.0.2 (required by Sonar-Scanner)
  • SonarQube MSBuild Scanner 6.2.0.85879
  • Docker binaries 24.0.x (for running Docker in Docker using the docker.sock mount)
  • OpenJDK Java Runtime 17 (required by Sonar-Scanner and some Sonar-Scanner plugins)
  • NodeJS 20 (required by Sonar-Scanner web analysis plugins)

Supported tags and respective Dockerfile links

Tags are written using the following pattern: dotnet-sonar:<year>.<month>.<revision>

โš ๏ธ (THIS VERSION HAS REACHED END OF LIFE)

Compiling dotnet code with SonarQube Analysis

Full documentation: https://docs.sonarqube.org/display/SCAN/Analyzing+with+SonarQube+Scanner+for+MSBuild

Inside container

Using Docker

Inside container:

$ dotnet /sonar-scanner/SonarScanner.MSBuild.dll begin /k:sonarProjectKey
$ dotnet build
$ dotnet /sonar-scanner/SonarScanner.MSBuild.dll end

Configure external SonarQube Server:

$ dotnet /sonar-scanner/SonarScanner.MSBuild.dll begin /k:sonarProjectKey /d:sonar.host.url="<SonarQubeServerUrl:Port>" /d:sonar.login="<SonarQubeServerToken>"
$ dotnet build
$ dotnet /sonar-scanner/SonarScanner.MSBuild.dll end  /d:sonar.login="<SonarQubeServerToken>"

Outside container:

Simple Usage:

$ docker run -it --rm -v <my-project-source-path>:/source ghcr.io/nosinovacao/dotnet-sonar:latest bash -c "cd source \
    && dotnet /sonar-scanner/SonarScanner.MSBuild.dll begin /k:sonarProjectKey /name:sonarProjectName /version:buildVersion \
    && dotnet restore \
    && dotnet build -c Release \
    && dotnet /sonar-scanner/SonarScanner.MSBuild.dll end"

Advance Usage:

$ docker run -it --rm \
    -v <my-project-source-path>:/source \
    -v <my-nugetconfig-source-path>:/nuget \
    dotnet-sonar:latest \
    bash -c \
        "cd source \
        && dotnet /sonar-scanner/SonarScanner.MSBuild.dll begin \
        /k:<ProjectName> /name:<my-project-name> /version:<my-project-version> \
        /d:sonar.host.url="<my-sonar-server-url>" \
        /d:sonar.login="<my-sonar-server-user>" \
        /d:sonar.password="<my-sonar-server-pass>" \
        /d:sonar.cs.opencover.reportsPaths='tests/**/coverage.opencover.xml' \
        && dotnet restore --configfile /nuget/NuGet.Config \
        && dotnet build -c Release \
        && dotnet publish -c Release -r linux-x64 -o deployment \
        && dotnet test --no-build -c Release --filter "Category=Unit" --logger trx --results-directory testResults /p:CollectCoverage=true /    p:CoverletOutputFormat=\"opencover\" \
        && dotnet /sonar-scanner/SonarScanner.MSBuild.dll end \
        /d:sonar.login="<my-sonar-server-user>" \
        /d:sonar.password="<my-sonar-server-pass>""

The script above does the following:

  • Mounts your project folder to the container's /source folder
  • Mounts your nuget config to the container's /nuget folder (optional if no private nuget server is used)
  • Begins the sonarscanner with the sonarqube server credentials
  • Performs a dotnet restore with the nuget config in /nuget folder
  • Executes the build command
  • Publishes the build to the deployment folder
  • Runs the tests and stores the test results in testResults folder. Change this command to your unit tests needs
  • Ends the sonarscanner and publishes the sonarqube analysis results to the sonarqube server

Using Jenkins pipeline

The following pipeline code will:

  • Start a sonar scanning session
  • Build dotnet projects
  • Run tests with coverage analysis (using coverlet) and publish them using the Jenkins XUnit publisher
  • End a sonar scanning session
  • [OPTIONAL] In the end, it waits for sonar's quality gate status and sets the build outcome

Note that in order for coverage analysis to work, you need to add the coverlet NuGet package to the unit test project.

def envVariables = [
    'HOME=/tmp/home',
    'DOTNET_CLI_TELEMETRY_OPTOUT=1'
]

node('somenode-with-docker')
{
    withSonarQubeEnv('my-jenkins-configured-sonar-environment')
    {
        docker.image('ghcr.io/nosinovacao/dotnet-sonar:latest').inside()
        {
            withEnv(envVariables)
            {
                stage('build')
                {
                    checkout scm
                    sh "dotnet /sonar-scanner/SonarScanner.MSBuild.dll begin /k:someKey /name:someName /version:someVersion /d:sonar.cs.opencover.reportsPaths='tests/**/coverage.opencover.xml'"
                    sh "dotnet build -c Release /property:Version=someVersion"
                    sh "rm -drf ${env.WORKSPACE}/testResults"
                    sh (returnStatus: true, script: "find tests/**/* -name \'*.csproj\' -print0 | xargs -L1 -0 -P 8 dotnet test --no-build -c Release --logger trx --results-directory ${env.WORKSPACE}/testResults /p:CollectCoverage=true /p:CoverletOutputFormat=opencover")
                    step([$class: 'XUnitPublisher', testTimeMargin: '3000', thresholdMode: 1, thresholds: [[$class: 'FailedThreshold', unstableThreshold: '0']
                            , [$class: 'SkippedThreshold']], tools: [[$class: 'MSTestJunitHudsonTestType', deleteOutputFiles: true, failIfNotNew: false
                            , pattern: 'testResults/**/*.trx', skipNoTestFiles: true, stopProcessingIfError: true]]])
                    sh "dotnet /sonar-scanner/SonarScanner.MSBuild.dll end"
                }
            }
        }
    }
}

timeout(time: 1, unit: 'HOURS')
{
    def qualityGate = waitForQualityGate()
    if (qualityGate.status == 'ERROR')
    {
        currentBuild.result = 'UNSTABLE'
    }
}

If you want to use Docker in Docker:

Please note that if you want to use Docker inside Docker (DinD) you need to perform additional actions when mounting the docker image in the pipeline.

The following actions will expose your host to several security vulnerabilities and therefore this should only be used when you absolutely must to:

docker.image('ghcr.io/nosinovacao/dotnet-sonar:latest').inside("--group-add docker -v /var/run/docker.sock:/var/run/docker.sock")
{
    // Some stuff
    docker.image.('hello-world:latest').inside()
    {
        sh "echo 'hello from docker inside docker'"
    }
}

The above code will:

  • Add current jenkins user to the Docker group
  • Mount the docker socket into the container so that you can control the Docker instance on the host machine

Code Coverage

The above examples already implement the code-coverage analysis, provided you add the coverlet NuGet package to your unit test project.

If you want to know more, check: https://dev.to/deinsoftware/net-core-unit-test-and-code-coverage-with-visual-studio-code-37bp.

Also, coverlet documentation here: https://github.com/tonerdo/coverlet/.

dotnet-sonar's People

Contributors

aumanjoa avatar calexandre avatar chrisbbe avatar davidrneves avatar diogoserrano avatar gafda avatar jaimesantosferreira avatar joachimaumann avatar jvmdc avatar loekensgard avatar suvl avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

dotnet-sonar's Issues

Support for .net 8

I'm working on a project based on .net 8, can you please add support for .net in the docker image?
if not possible can you guide me how to do it myself?

What License is this under?

Hi,

Nice Dockerfile.
I'm a member of a team finding it useful in our c# build pipeline.
We've found previous issues with handy Dockerfile's that end up having inappropriate licenses.

Could you please make your License for this explicit?

Getting an error when the sonar scanner runs

I have downloaded the latest version from docker hub and trying to run in my project (building the docker image on a linux machine)

Getting error attached could someone help
A633BBCD-2ED6-48A8-B901-9461069C7C4B

Sonar is ceasing support of Java 11 on October 31 -- Upgrade to Java 17

Sonar will be retiring the Java 11 runtime on October 31st, 2023. (announcement) (docs)

Since it looks like this image uses Java 11, the dockerfile should be updated before then.

Warning log I'm seeing in job execution:
WARN: The version of Java (11.0.18) you have used to run this analysis is deprecated and we will stop accepting it soon. Please update to at least Java 17.

Image version I'm using: 23.06.3

Error running SonarScanner when the project is in DotNetCore 3.x

Error running SonarScanner when the project is in DotNetCore 3.x returns the following error:

It was not possible to find any compatible framework version
The specified framework 'Microsoft.NETCore.App', version '2.0.0' was not found.
  - The following frameworks were found:
      3.0.0 at [/usr/share/dotnet/shared/Microsoft.NETCore.App]

Is it possible to build .net 4 ?

I have a .net 4.6 project and use a VM to build and do SonarQube scan.
But I want to find a docker solution to replace the VM, I can use this image to call SonarQube now,
but it's obvious I cannot build my project because this image only supports .NET 5/6/7.

I'm not sure, is it possible to build .net 4 in this image?

Update dockerhub

Is there any plan to update Dockerhub with the latest version?

Missing metadata file

Error

SonarScanner for MSBuild 4.7.1
Using the .NET Core version of the Scanner for MSBuild
Pre-processing started.
Preparing working directories...
08:05:10.146 Updating build integration targets...
08:05:10.163 Fetching analysis configuration settings...
08:05:12.114 Provisioning analyzer assemblies for cs...
08:05:12.115 Installing required Roslyn analyzers...
08:05:13.929 Provisioning analyzer assemblies for vbnet...
08:05:13.929 Installing required Roslyn analyzers...
08:05:13.993 Pre-processing succeeded.
Microsoft (R) Build Engine version 16.3.0+0f4c62fea for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.

Restore completed in 19.54 ms for /app/Case1.MVC.Test/Case1.MVC.Test.csproj.
Restore completed in 19.31 ms for /app/Case1.MVC/Case1.MVC.csproj.
CSC : error CS0006: Metadata file '/tmp/.sonarqube/resources/2/analyzers/dotnet/YamlDotNet.dll' could not be found [/app/Case1.MVC/Case1.MVC.csproj]
CSC : error CS0006: Metadata file '/tmp/.sonarqube/resources/2/analyzers/dotnet/SecurityCodeScan.dll' could not be found [/app/Case1.MVC/Case1.MVC.csproj]

Build FAILED.

CSC : error CS0006: Metadata file '/tmp/.sonarqube/resources/2/analyzers/dotnet/YamlDotNet.dll' could not be found [/app/Case1.MVC/Case1.MVC.csproj]
CSC : error CS0006: Metadata file '/tmp/.sonarqube/resources/2/analyzers/dotnet/SecurityCodeScan.dll' could not be found [/app/Case1.MVC/Case1.MVC.csproj]
0 Warning(s)
2 Error(s)

My dockerfile to reproduce

`FROM nosinovacao/dotnet-sonar AS build

WORKDIR /app
COPY ./Frontend /app/

RUN dotnet restore
&& dotnet /sonar-scanner/SonarScanner.MSBuild.dll begin
/k:survivorbat-frontend
/d:sonar.login=(login)
/d:sonar.host.url=(host)
&& dotnet build
&& dotnet /sonar-scanner/SonarScanner.MSBuild.dll end
/d:sonar.login=(login)`

My .csproj file

netcoreapp3.0
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
  <DocumentationFile>bin\Debug\Case1.API.xml</DocumentationFile>
</PropertyGroup>

<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
  <DocumentationFile>bin\Release\Case1.API.xml</DocumentationFile>
</PropertyGroup>

<ItemGroup>
  <PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.0.0" />
  <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.0.0" />
  <PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
  <PackageReference Include="Swashbuckle.AspNetCore" Version="5.0.0-rc4" />
</ItemGroup>

Notes

The build works entirely without sonarscanner, I just can't find what is causing this weird manifest error, I've tried it before with my own image and wanted to try out this one, unfortunately this one has the same error.

Getting "Cannot assign requested address" HttpRequestException

When I run the command

docker run -it --rm -v //c/dev/repo:/source nosinovacao/dotnet-sonar:latest bash -c "cd source \
&& dotnet /sonar-scanner/SonarScanner.MSBuild.dll begin -key:MYKEY -d:sonar.host=http://localhost:9000 \
&& dotnet build -c Debug \
&& dotnet /sonar-scanner/SonarScanner.MSBuild.dll end"

I get an exception (first few lines shown)

21:11:47.87  Updating build integration targets...
21:11:48.014  Failed to request and parse 'http://localhost:9000/api/server/version': Cannot assign requested address (localhost:9000)
Unhandled exception. System.Net.Http.HttpRequestException: Cannot assign requested address (localhost:9000)

What causes this and how to fix? I am running SonarQube server locally from it's own docker container, and it exposes the endpoint as http://localhost:9000 on my local machine (host).

Update NodeJS from 16 to 18

NodeJS v16 reached end of life.
Can you please update it to 18 or 20?
I'm mostly interested in .NET 6 images.

4.4.1/4.3.1 Error in dotnet sonarscanner end

I have followed the instructions in here: https://docs.sonarqube.org/display/SCAN/Analyzing+with+SonarQube+Scanner+for+MSBuild

And when I execute: 'dotnet sonarscanner end'

I get the following output:
`SonarScanner for MSBuild 4.3.1

Using the .NET Core version of the Scanner for MSBuild

Default properties file was found at /opt/programas/jenkins2/.dotnet/tools/.store/dotnet-sonarscanner/4.3.1/dotnet-sonarscanner/4.3.1/tools/netcoreapp2.1/any/SonarQube.Analysis.xml

Loading analysis properties from /opt/programas/jenkins2/.dotnet/tools/.store/dotnet-sonarscanner/4.3.1/dotnet-sonarscanner/4.3.1/tools/netcoreapp2.1/any/SonarQube.Analysis.xml

Post-processing started.

11:15:10.274 Loading the SonarQube analysis config from /opt/programas/jenkins2/workspace/DEBHE/DE605/NetCore/.sonarqube/conf/SonarQubeAnalysisConfig.xml

11:15:10.302 Not running under TeamBuild

11:15:10.303 Analysis base directory: /opt/programas/jenkins2/workspace/DEBHE/DE605/NetCore/.sonarqube

Build directory:

Bin directory: /opt/programas/jenkins2/workspace/DEBHE/DE605/NetCore/.sonarqube/bin

Config directory: /opt/programas/jenkins2/workspace/DEBHE/DE605/NetCore/.sonarqube/conf

Output directory: /opt/programas/jenkins2/workspace/DEBHE/DE605/NetCore/.sonarqube/out

Config file: /opt/programas/jenkins2/workspace/DEBHE/DE605/NetCore/.sonarqube/conf/SonarQubeAnalysisConfig.xml

Generating SonarQube project properties file to /opt/programas/jenkins2/workspace/DEBHE/DE605/NetCore/.sonarqube/out/sonar-project.properties

Setting analysis property: sonar.visualstudio.enable=false

The supplied Code Analysis ErrorLog file is a valid json file and does not need to be fixed: /opt/programas/jenkins2/workspace/DEBHE/DE605/NetCore/src/dist/APISN.Webservices.Opcao.dll.RoslynCA.json

Using longest common projects root path as project base directory: '/opt/programas/jenkins2/workspace/DEBHE/DE605/NetCore/src/APISN.Webservices.Opcao'.

Dumping content of sonar-project.properties


sonar.projectKey=DEBHE.DE605.APISN.Webservices.Opcao

sonar.projectName=DEBHE.DE605.APISN.Webservices.Opcao

sonar.projectVersion=0.0.1

sonar.working.directory=/opt/programas/jenkins2/workspace/DEBHE/DE605/NetCore/.sonarqube/out/.sonar

sonar.projectBaseDir=/opt/programas/jenkins2/workspace/DEBHE/DE605/NetCore/src/APISN.Webservices.Opcao

C78B51AA-1311-4EFE-BDB7-5FE10BEE452E.sonar.projectKey=DEBHE.DE605.APISN.Webservices.Opcao:C78B51AA-1311-4EFE-BDB7-5FE10BEE452E

C78B51AA-1311-4EFE-BDB7-5FE10BEE452E.sonar.projectName=APISN.Webservices.Opcao

C78B51AA-1311-4EFE-BDB7-5FE10BEE452E.sonar.projectBaseDir=/opt/programas/jenkins2/workspace/DEBHE/DE605/NetCore/src/APISN.Webservices.Opcao

C78B51AA-1311-4EFE-BDB7-5FE10BEE452E.sonar.sourceEncoding=utf-8

C78B51AA-1311-4EFE-BDB7-5FE10BEE452E.sonar.sources=\

"/opt/programas/jenkins2/workspace/DEBHE/DE605/NetCore/src/APISN.Webservices.Opcao/Authentication/JwtTokenConfiguration.cs",\

"/opt/programas/jenkins2/workspace/DEBHE/DE605/NetCore/src/APISN.Webservices.Opcao/Controllers/OpcaoController.cs",\

"/opt/programas/jenkins2/workspace/DEBHE/DE605/NetCore/src/APISN.Webservices.Opcao/Helpers/HttpHelper.cs",\

"/opt/programas/jenkins2/workspace/DEBHE/DE605/NetCore/src/APISN.Webservices.Opcao/Models/Erro.cs",\

"/opt/programas/jenkins2/workspace/DEBHE/DE605/NetCore/src/APISN.Webservices.Opcao/Models/OpcaoSn.cs",\

"/opt/programas/jenkins2/workspace/DEBHE/DE605/NetCore/src/APISN.Webservices.Opcao/Models/PeriodoMei.cs",\

"/opt/programas/jenkins2/workspace/DEBHE/DE605/NetCore/src/APISN.Webservices.Opcao/Models/PeriodoSimples.cs",\

"/opt/programas/jenkins2/workspace/DEBHE/DE605/NetCore/src/APISN.Webservices.Opcao/Program.cs",\

"/opt/programas/jenkins2/workspace/DEBHE/DE605/NetCore/src/APISN.Webservices.Opcao/Startup.cs",\

"/opt/programas/jenkins2/workspace/DEBHE/DE605/NetCore/src/APISN.Webservices.Opcao/obj/Release/netcoreapp2.1/APISN.Webservices.Opcao.RazorAssemblyInfo.cs",\

"/opt/programas/jenkins2/workspace/DEBHE/DE605/NetCore/src/APISN.Webservices.Opcao/obj/Release/netcoreapp2.1/APISN.Webservices.Opcao.AssemblyInfo.cs",\

"/opt/programas/jenkins2/workspace/DEBHE/DE605/NetCore/src/APISN.Webservices.Opcao/nuget.config",\

"/opt/programas/jenkins2/workspace/DEBHE/DE605/NetCore/src/APISN.Webservices.Opcao/appsettings.Development.json",\

"/opt/programas/jenkins2/workspace/DEBHE/DE605/NetCore/src/APISN.Webservices.Opcao/appsettings.json",\

"/opt/programas/jenkins2/workspace/DEBHE/DE605/NetCore/src/APISN.Webservices.Opcao/Properties/launchSettings.json"

C78B51AA-1311-4EFE-BDB7-5FE10BEE452E.sonar.cs.roslyn.reportFilePath=/opt/programas/jenkins2/workspace/DEBHE/DE605/NetCore/src/dist/APISN.Webservices.Opcao.dll.RoslynCA.json

C78B51AA-1311-4EFE-BDB7-5FE10BEE452E.sonar.cs.analyzer.projectOutPath=/opt/programas/jenkins2/workspace/DEBHE/DE605/NetCore/.sonarqube/out/0

C78B51AA-1311-4EFE-BDB7-5FE10BEE452E.sonar.cs.analyzer.projectOutPaths=\

"/opt/programas/jenkins2/workspace/DEBHE/DE605/NetCore/.sonarqube/out/0"

C78B51AA-1311-4EFE-BDB7-5FE10BEE452E.sonar.cs.roslyn.reportFilePaths=\

"/opt/programas/jenkins2/workspace/DEBHE/DE605/NetCore/src/dist/APISN.Webservices.Opcao.dll.RoslynCA.json"

sonar.host.url=http://sonar.aic.serpro:8080

sonar.cs.vstest.reportsPaths=%CD%TestResults*.trx

sonar.cs.vscoveragexml.reportsPaths=%CD%VisualStudio.coveragexml

sonar.buildbreaker.queryMaxAttempts=60

sonar.verbose=true

sonar.exclusions=/*.css,/.js,**/.xhtml,**/*.xml

sonar.visualstudio.enable=false

sonar.modules=C78B51AA-1311-4EFE-BDB7-5FE10BEE452E


Writing processing summary to /opt/programas/jenkins2/workspace/DEBHE/DE605/NetCore/.sonarqube/out/ProjectInfo.log

SONAR_SCANNER_OPTS is not configured. Setting it to the default value of -Xmx1024m

Calling the SonarQube Scanner...

Setting environment variable 'SONAR_SCANNER_OPTS'. Value: -Xmx1024m

Executing file /opt/programas/jenkins2/.dotnet/tools/.store/dotnet-sonarscanner/4.3.1/dotnet-sonarscanner/4.3.1/tools/netcoreapp2.1/any/sonar-scanner-3.2.0.1227/bin/sonar-scanner

Args: -Dsonar.scanAllFiles=true -Dproject.settings=/opt/programas/jenkins2/workspace/DEBHE/DE605/NetCore/.sonarqube/out/sonar-project.properties --embedded

Working directory: /opt/programas/jenkins2/workspace/DEBHE/DE605/NetCore

Timeout (ms):-1

Process id: 28083

which: no java in (/usr/local/bin:/usr/bin:/opt/programas/jenkins2/.dotnet/tools:/opt/programas/jenkins2/bin)

/opt/programas/jenkins2/.dotnet/tools/.store/dotnet-sonarscanner/4.3.1/dotnet-sonarscanner/4.3.1/tools/netcoreapp2.1/any/sonar-scanner-3.2.0.1227/bin/sonar-scanner: line 59: exec: : not found

Process returned exit code 127

The SonarQube Scanner did not complete successfully

11:15:10.647 Creating a summary markdown file...

11:15:10.65 Post-processing failed. Exit code: 1

script returned exit code 1`

Current versioning system does not work well with automated dependency upgrade managers

With the current CalVer system for versioning the generated images, a breaking change can be experienced by upgrading from the lowest to highest patch version.

Everyone who uses this image likely knows why this is (different dotnet versions) and can refrain from upgrading this image, but automated tools that upgrade dependencies for projects, such as renovate, do not know about this limitation and therefore mistakenly upgrade. This upgrade is often done as one upgrade among several, which also breaks the other upgrades.

Suggested Solution

Do not control for the dotnet version within the image versioning scheme, but rather append a version suffix when publishing the image (so 23.12.3 -> 23.12.0-dotnet6, 23.12.4 -> 23.12.0-dotnet7, 23.12.5 -> 23.12.0-dotnet8)

Making this change would be greatly appreciated, since every automated dependency update made on my server code repository has been foiled by this versioning issue.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.