GithubHelp home page GithubHelp logo

jfrog / froggit-go Goto Github PK

View Code? Open in Web Editor NEW
45.0 5.0 16.0 948 KB

Froggit-Go is a universal Go library, allowing to perform actions on VCS providers.

Home Page: https://pkg.go.dev/github.com/jfrog/froggit-go

License: Apache License 2.0

Go 100.00%
github gitlab bitbucket bitbucket-server bitbucket-cloud github-enterprise go golang go-library git

froggit-go's Introduction

Froggit-Go

Frogbot

Froggit-Go is a Go library, allowing to perform actions on VCS providers. Currently supported providers are: GitHub, Bitbucket Server , Bitbucket Cloud, Azure Repos and GitLab.

Project status

Scanned by Frogbot Test Coverage Status Mentioned in Awesome Go Go Report Card

Usage

VCS Clients

Create Clients

GitHub

GitHub api v3 is used

// The VCS provider. Cannot be changed.
vcsProvider := vcsutils.GitHub
// API endpoint to GitHub. Leave empty to use the default - https://api.github.com
apiEndpoint := "https://github.example.com"
// Access token to GitHub
token := "secret-github-token"
// Logger
// [Optional]
// Supported logger is a logger that implements the Log interface.
// More information - https://github.com/jfrog/froggit-go/blob/master/vcsclient/logger.go
logger := log.Default()

client, err := vcsclient.NewClientBuilder(vcsProvider).ApiEndpoint(apiEndpoint).Token(token).Build()
GitLab

GitLab api v4 is used.

// The VCS provider. Cannot be changed.
vcsProvider := vcsutils.GitLab
// API endpoint to GitLab. Leave empty to use the default - https://gitlab.com
apiEndpoint := "https://gitlab.example.com"
// Access token to GitLab
token := "secret-gitlab-token"
// Logger
// [Optional]
// Supported logger is a logger that implements the Log interface.
// More information - https://github.com/jfrog/froggit-go/blob/master/vcsclient/logger.go
logger := logger

client, err := vcsclient.NewClientBuilder(vcsProvider).ApiEndpoint(apiEndpoint).Token(token).Build()
Bitbucket Server

Bitbucket api 1.0 is used.

// The VCS provider. Cannot be changed.
vcsProvider := vcsclient.BitbucketServer
// API endpoint to Bitbucket server. Typically ends with /rest.
apiEndpoint := "https://git.acme.com/rest"
// Access token to Bitbucket
token := "secret-bitbucket-token"
// Logger
// [Optional]
// Supported logger is a logger that implements the Log interface.
// More information - https://github.com/jfrog/froggit-go/blob/master/vcsclient/logger.go
logger := log.Default()

client, err := vcsclient.NewClientBuilder(vcsProvider).ApiEndpoint(apiEndpoint).Token(token).Build()
Bitbucket Cloud

Bitbucket cloud api version 2.0 is used and the version should be added to the apiEndpoint.

// The VCS provider. Cannot be changed.
vcsProvider := vcsutils.BitbucketCloud
// API endpoint to Bitbucket cloud. Leave empty to use the default - https://api.bitbucket.org/2.0
apiEndpoint := "https://bitbucket.example.com"
// Bitbucket username
username := "bitbucket-user"
// Password or Bitbucket "App Password'
token := "secret-bitbucket-token"
// Logger
// [Optional]
// Supported logger is a logger that implements the Log interface.
// More information - https://github.com/jfrog/froggit-go/blob/master/vcsclient/logger.go
logger := log.Default()

client, err := vcsclient.NewClientBuilder(vcsProvider).ApiEndpoint(apiEndpoint).Username(username).Token(token).Build()
Azure Repos

Azure DevOps api version v6 is used.

// The VCS provider. Cannot be changed.
vcsProvider := vcsutils.AzureRepos
// API endpoint to Azure Repos. Set the organization.
apiEndpoint := "https://dev.azure.com/<organization>"
// Personal Access Token to Azure DevOps
token := "secret-azure-devops-token"
// Logger
// [Optional]
// Supported logger is a logger that implements the Log interface.
// More information - https://github.com/jfrog/froggit-go/blob/master/vcsclient/logger.go
logger := log.Default()
// Project name
project := "name-of-the-relevant-project"

client, err := vcsclient.NewClientBuilder(vcsProvider).ApiEndpoint(apiEndpoint).Token(token).Project(project).Build()

Test Connection

// Go context
ctx := context.Background()

err := client.TestConnection(ctx)

List Repositories

// Go context
ctx := context.Background()

repositories, err := client.ListRepositories(ctx)

List Branches

// Go context
ctx := context.Background()
// Organization or username
owner := "jfrog"
// VCS repository
repository := "jfrog-cli"

repositoryBranches, err := client.ListBranches(ctx, owner, repository)

Download Repository

// Go context
ctx := context.Background()
// Organization or username
owner := "jfrog"
// VCS repository
repository := "jfrog-cli"
// Repository branch
branch := "master"
// Local path in the file system
localPath := "/Users/frogger/code/jfrog-cli"

repositoryBranches, err := client.DownloadRepository(ctx, owner, repository, branch, localPath)

Create Webhook

// Go context
ctx := context.Background()
// Organization or username
owner := "jfrog"
// The event to watch
webhookEvent := vcsutils.Push
// VCS repository
repository := "jfrog-cli"
// Optional - Webhooks on branches are supported only on GitLab
branch := ""
// The URL to send the payload upon a webhook event
payloadURL := "https://acme.jfrog.io/integration/api/v1/webhook/event"

// token - A token used to validate identity of the incoming webhook.
// In GitHub and Bitbucket server the token verifies the sha256 signature of the payload.
// In GitLab and Bitbucket cloud the token compared to the token received in the incoming payload.
id, token, err := client.CreateWebhook(ctx, owner, repository, branch, "https://jfrog.com", webhookEvent)

Update Webhook

// Go context
ctx := context.Background()
// Organization or username
owner := "jfrog"
// VCS repository
repository := "jfrog-cli"
// Optional - Webhooks on branches are supported only on GitLab
branch := ""
// The URL to send the payload upon a webhook event
payloadURL := "https://acme.jfrog.io/integration/api/v1/webhook/event"
// A token to validate identity of the webhook, created by CreateWebhook command
token := "abc123"
// The webhook ID returned by the CreateWebhook API, which created this webhook
webhookID := "123"
// The event to watch
webhookEvent := vcsutils.PrCreated

err := client.UpdateWebhook(ctx, owner, repository, branch, "https://jfrog.com", token, webhookID, webhookEvent)

Delete Webhook

// Go context
ctx := context.Background()
// Organization or username
owner := "jfrog"
// VCS repository
repository := "jfrog-cli"
// The webhook ID returned by the CreateWebhook API, which created this webhook
webhookID := "123"

err := client.DeleteWebhook(ctx, owner, repository, webhookID)

Set Commit Status

// Go context
ctx := context.Background()
// One of Pass, Fail, Error, or InProgress
commitStatus := vcsclient.Pass
// Organization or username
owner := "jfrog"
// VCS repository
repository := "jfrog-cli"
// Branch or commit or tag on GitHub and GitLab, commit on Bitbucket
ref := "5c05522fecf8d93a11752ff255c99fcb0f0557cd"
// Title of the commit status
title := "Xray scanning"
// Description of the commit status
description := "Run JFrog Xray scan"
// URL leads to the platform to provide more information, such as Xray scanning results
detailsURL := "https://acme.jfrog.io/ui/xray-scan-results-url"

err := client.SetCommitStatus(ctx, commitStatus, owner, repository, ref, title, description, detailsURL)

Get Commit Status

// Go context
ctx := context.Background()
// Organization or username
owner := "jfrog"
// VCS repository
repository := "jfrog-cli"
// Commit tag on GitHub and GitLab, commit on Bitbucket
ref := "5c05522fecf8d93a11752ff255c99fcb0f0557cd"

commitStatuses, err := client.GetCommitStatus(ctx, owner, repository, ref)
Create Pull Request
// Go context
ctx := context.Background()
// Organization or username
owner := "jfrog"
// VCS repository
repository := "jfrog-cli"
// Source pull request branch
sourceBranch := "dev"
// Target pull request branch
targetBranch := "main"
// Pull request title
title := "Pull request title"
// Pull request description
description := "Pull request description"

err := client.CreatePullRequest(ctx, owner, repository, sourceBranch, targetBranch, title, description)
Update Pull Request
// Go context
ctx := context.Background()
// Organization or username
owner := "jfrog"
// VCS repository
repository := "jfrog-cli"
// Target pull request branch, leave empty for no change.
targetBranch := "main"
// Pull request title
title := "Pull request title"
// Pull request description
body := "Pull request description"
// Pull request ID
id := "1"
// Pull request state
state := vcsutils.Open

err := client.UpdatePullRequest(ctx, owner, repository, title, body, targetBranch, id, state)

List Open Pull Requests With Body

// Go context
ctx := context.Background()
// Organization or username
owner := "jfrog"
// VCS repository
repository := "jfrog-cli"

openPullRequests, err := client.ListOpenPullRequestsWithBody(ctx, owner, repository)

List Open Pull Requests

// Go context
ctx := context.Background()
// Organization or username
owner := "jfrog"
// VCS repository
repository := "jfrog-cli"

openPullRequests, err := client.ListOpenPullRequests(ctx, owner, repository)

Get Pull Request By ID

// Go context
ctx := context.Background()
// Organization or username
owner := "jfrog"
// VCS repository
repository := "jfrog-cli"
// Pull Request ID
pullRequestId := 1

openPullRequests, err := client.GetPullRequestByID(ctx, owner, repository, pullRequestId)
Add Pull Request Comment
// Go context
ctx := context.Background()
// Organization or username
owner := "jfrog"
// VCS repository
repository := "jfrog-cli"
// Comment content
content := "Comment content"
// Pull Request ID
pullRequestID := 5

err := client.AddPullRequestComment(ctx, owner, repository, content, pullRequestID)
Add Pull Request Review Comments
// Go context
ctx := context.Background()
// Organization or username
owner := "jfrog"
// VCS repository
repository := "jfrog-cli"
// Pull Request ID
pullRequestID := 5
// Pull Request Comment
comments := []PullRequestComment{
  {
    CommentInfo: CommentInfo{
      Content: "content",
    },
    PullRequestDiff: PullRequestDiff{
      OriginalFilePath: index.js   
      OriginalStartLine: 1
      OriginalEndLine: 1
      OriginalStartColumn: 1
      OriginalEndColumn: 1  
      NewFilePath: index.js        
      NewStartLine: 1       
      NewEndLine: 1         
      NewStartColumn: 1     
      NewEndColumn: 1       
    },
  }
}


err := client.AddPullRequestReviewComments(ctx, owner, repository, pullRequestID, comments...)
List Pull Request Comments
// Go context
ctx := context.Background()
// Organization or username
owner := "jfrog"
// VCS repository
repository := "jfrog-cli"
// Pull Request ID
pullRequestID := 5

pullRequestComments, err := client.ListPullRequestComment(ctx, owner, repository, pullRequestID)
List Pull Request Review Comments
// Go context
ctx := context.Background()
// Organization or username
owner := "jfrog"
// VCS repository
repository := "jfrog-cli"
// Pull Request ID
pullRequestID := 5

pullRequestComments, err := client.ListPullRequestReviewComments(ctx, owner, repository, pullRequestID)
Delete Pull Request Comment
// Go context
ctx := context.Background()
// Organization or username
owner := "jfrog"
// VCS repository
repository := "jfrog-cli"
// Pull Request ID
pullRequestID := 5
// Comment ID
commentID := 17

err := client.DeletePullRequestComment(ctx, owner, repository, pullRequestID, commentID)
Delete Pull Request Review Comments
// Go context
ctx := context.Background()
// Organization or username
owner := "jfrog"
// VCS repository
repository := "jfrog-cli"
// Pull Request ID
pullRequestID := 5
// Comment ID
comments := []CommentInfo{
  {
    ID: 2
    // For GitLab
    ThreadID: 7
  }
}

err := client.DeletePullRequestComment(ctx, owner, repository, pullRequestID, comments...)

Get Commits

// Go context
ctx := context.Background()
// Organization or username
owner := "jfrog"
// VCS repository
repository := "jfrog-cli"
// VCS branch
branch := "dev"

// Commits information of the latest branch commits 
commitInfo, err := client.GetCommits(ctx, owner, repository, branch)

Get Commits With Options

// Go context
ctx := context.Background()
// Organization or username
owner := "jfrog"
// VCS repository
repository := "jfrog-cli"

// Commits query options 
options := GitCommitsQueryOptions{
  Since: time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC),
  Until: time.Now(),
  ListOptions: ListOptions{
	  Page:    1,
	  PerPage: 30,
    },
  }

result, err := client.GetCommitsWithQueryOptions(ctx, owner, repository, options)

Get Latest Commit

// Go context
ctx := context.Background()
// Organization or username
owner := "jfrog"
// VCS repository
repository := "jfrog-cli"
// VCS branch
branch := "dev"

// Commit information of the latest commit
commitInfo, err := client.GetLatestCommit(ctx, owner, repository, branch)

Get Commit By SHA

// Go context
ctx := context.Background()
// Organization or username
owner := "jfrog"
// VCS repository
repository := "jfrog-cli"
// SHA-1 hash of the commit
sha := "abcdef0123abcdef4567abcdef8987abcdef6543"

// Commit information of requested commit
commitInfo, err := client.GetCommitBySha(ctx, owner, repository, sha)

Get List of Modified Files

The refBefore...refAfter syntax is used. More about it can be found at Commit Ranges Git documentation.

// Go context
ctx := context.Background()
// Organization or username
owner := "jfrog"
// VCS repository
repository := "jfrog-cli"
// SHA-1 hash of the commit or tag or a branch name
refBefore := "abcdef0123abcdef4567abcdef8987abcdef6543"
// SHA-1 hash of the commit or tag or a branch name
refAfter := "main"

filePaths, err := client.GetModifiedFiles(ctx, owner, repository, refBefore, refAfter)

Add Public SSH Key

// Go context
ctx := context.Background()
// Organization or username
owner := "jfrog"
// VCS repository
repository := "jfrog-cli"
// An identifier for the key
keyName := "my ssh key"
// The public SSH key
publicKey := "ssh-rsa AAAA..."
// Access permission of the key: vcsclient.Read or vcsclient.ReadWrite
permission = vcsclient.Read

// Add a public SSH key to a repository
err := client.AddSshKeyToRepository(ctx, owner, repository, keyName, publicKey, permission)

Get Repository Info

// Go context
ctx := context.Background()
// Organization or username
owner := "jfrog"
// VCS repository
repository := "jfrog-cli"

// Get information about repository
repoInfo, err := client.GetRepositoryInfo(ctx, owner, repository)

Get Repository Environment Info

Notice - Get Repository Environment Info is currently supported on GitHub only.

// Go context
ctx := context.Background()
// Organization or username
owner := "jfrog"
// VCS repository
repository := "jfrog-cli"
// Environment name
name := "frogbot"

// Get information about repository environment
repoEnvInfo, err := client.GetRepositoryEnvironmentInfo(ctx, owner, repository, name)

Create a label

Notice - Labels are not supported in Bitbucket

// Go context
ctx := context.Background()
// Organization or username
owner := "jfrog"
// VCS repository
repository := "jfrog-cli"
// Label info
labelInfo := LabelInfo{
  Name:        "label-name",
  Description: "label description",
  Color:       "4AB548",
}
// Create a label
err := client.CreateLabel(ctx, owner, repository, labelInfo)

Get a label

Notice - Labels are not supported in Bitbucket

// Go context
ctx := context.Background()
// Organization or username
owner := "jfrog"
// VCS repository
repository := "jfrog-cli"
// Label name
labelName := "label-name"

// Get a label named "label-name"
labelInfo, err := client.GetLabel(ctx, owner, repository, labelName)

List Pull Request Labels

Notice - Labels are not supported in Bitbucket

// Go context
ctx := context.Background()
// Organization or username
owner := "jfrog"
// VCS repository
repository := "jfrog-cli"
// Pull Request ID
pullRequestID := 5

// List all labels assigned to pull request 5
pullRequestLabels, err := client.ListPullRequestLabels(ctx, owner, repository, pullRequestID)

Unlabel Pull Request

Notice - Labels are not supported in Bitbucket

// Go context
ctx := context.Background()
// Organization or username
owner := "jfrog"
// VCS repository
repository := "jfrog-cli"
// Label name
name := "label-name"
// Pull Request ID
pullRequestID := 5

// Remove label "label-name" from pull request 5
err := client.UnlabelPullRequest(ctx, owner, repository, name, pullRequestID)

Upload Code Scanning

Notice - Code Scanning is currently supported on GitHub only.

// Go context
ctx := context.Background()
// The account owner of the git repository
owner := "user"
// The name of the repository
repo := "my_repo"
// The branch name for which the code scanning is relevant
branch := "my_branch"
// A string representing the code scanning results
scanResults := "results"

// Uploads the scanning analysis file to the relevant git provider
sarifID, err := client.UploadCodeScanning(ctx, owner, repo, branch, scanResults)

Download a File From a Repository

Note - This API is currently not supported for Bitbucket Cloud.

// Go context
ctx := context.Background()
// The account owner of the git repository
owner := "user"
// The name of the repository
repo := "my_repo"
// The branch name for which the code scanning is relevant
branch := "my_branch"
// A string representing the file path in the repository
path := "path"

// Downloads a file from a repository
content, statusCode, err := client.DownloadFileFromRepo(ctx, owner, repo, branch, path)

Webhook Parser

// Go context
ctx := context.Background()
// Logger
logger := vcsclient.EmptyLogger{}
// Webhook contextual information
origin := webhookparser.WebhookOrigin{
  // The VCS provider (required)
  VcsProvider: vcsutils.GitHub,
  // Optional URL of the VCS provider (used for building some URLs)
  OriginURL: "https://api.github.com",
  // Token to authenticate incoming webhooks. If empty, signature will not be verified. 
  // The token is a random key generated in the CreateWebhook command. 
  Token: []byte("abc123"),
}
// The HTTP request of the incoming webhook
request := http.Request{}

webhookInfo, err := webhookparser.ParseIncomingWebhook(ctx, logger, origin, request)

froggit-go's People

Contributors

attiasas avatar cyrilc-pro avatar dependabot[bot] avatar eyalbe4 avatar eyaldelarea avatar gailazar300 avatar gineshkumar avatar github-actions[bot] avatar omerzi avatar paulkane-gamesys avatar pavelmemory avatar remibou avatar sverdlov93 avatar talarian1 avatar ttetzlaff avatar vitaliil-jfrog avatar yahavi 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

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

froggit-go's Issues

Typed Errors

Froggit is a facade over different git providers and should provide typed error messages. The user of the library should receive clear errors and not have to have knowledge of the internal structure of each git providers errors.

Froggit should return errors such as NotFound, Unauthorized, Forbidden, Bad Request, InternalServerError where possible.

go-bitbucket uses os.Exit

Froggit-go uses github.com/ktrysmt/go-bitbucket but this library may, under some circumstances, kill the process using os.Exit(9).

For instance, in webhooks.go:

	data, err := json.Marshal(body)
	if err != nil {
		pp.Println(err)
		os.Exit(9)
	}

Possible fixes:

  • Drop the library
  • Or fork and open a PR on the library

Provide value for URL field in CommitInfo in Bitbucket server client

Is your feature request related to a problem? Please describe.
BitbucketServerClient returns empty value for URL in CommitInfo returned by GetCommitBySha and GetCommitBySha methods. This happens because Bitbucket API does not provide URL in response.

Describe the solution you'd like to see
BitbucketServerClient can compose URL using client.vcsInfo.ApiEndpoint, owner, repository (available in both GetCommitBySha and GetCommitBySha methods) and commit.ID received in response.
E.g {client.vcsInfo.ApiEndpoint}/rest/api/1.0/projects/{owner}/repos/{repository}/commits/{commit.ID}

How to interact with and manage the remote repo or vcs provider via ssh key instead of user/pass?

Cool library!
Got a question not addressed in the docs or the source…

Setup:
I use Bitbucket cloud.
Seeing that the example requires a username and password for interacting with the “remote”.
Seeing there is a way to add ash keys to repos, which seems to be configuring some access on the “remote”.

Question:
Curious if there is a way to interact with the “remote” via a specific ssh key that is present on my computer instead of username and password.
Not seeing that reflected in the documentation.

Also, there is a comment typo in the file defining how bitbucket cloud will fulfill the interface. List open pull requests seems to have the same comment as create pull request.

Thanks!

Support Github API versioning

Describe the bug
Github introduced API versioning through the use of X-GitHub-Api-Version HTTP header.

Expected behavior
According to Github's documentation, Froggit-Go must set this header when interacting with Github.

Pull Request events parsing for Gitlab

For Gitlab, the PR-related are parsed as follows:

  • If object_attributes.created_at = object_attributes.updated_at, then PrOpened
  • Else PrEdited

From Gitlab's documentation, it seems like PrEdited is therefore mapped from the following object_attributes.action values:

  • close
  • reopen
  • update
  • approved
  • unapproved
  • merge

We may consider mapping:

  • open and repopen to PrOpened
  • update to PrEdited

Note: update does not necessarily mean that commits were pushed to the source branch, but also that some changes were made on the PR (e.g. description or assignees change).

Input validation

Required parameters are not checked before sending request to different providers. It might be nice to check the parameters and return appropriate errors.

Fail to parse date when testing a webhook with Gitlab

When hitting the "test" button of a webhook in Gitlab, 14.4 the date format is slightly different and Froggit-Go is failing with the following error message:
parsing time "2021-11-30T08:52:57.746Z" as "2006-01-02 15:04:05 MST": cannot parse "T08:52:57.746Z" as " "

nil pointer dereference panic: BitbucketServerClient.DownloadFileFromRepo

Describe the bug
Full error:

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x10 pc=0xd9a398]

goroutine 1 [running]:
github.com/jfrog/froggit-go/vcsclient.(*BitbucketServerClient).DownloadFileFromRepo(0xc00030f468?, {0x127dc38?, 0xc0000c0140?}, {0xc00003a03d, 0x4}, {0xc00003a054, 0xb}, {0xc000038043, 0xf}, {0xc0000c57e0, ...})
        /home/frogger/go/pkg/mod/github.com/jfrog/[email protected]/vcsclient/bitbucketserver.go:624 +0x178
github.com/jfrog/frogbot/commands/utils.readConfigFromTarget({0x1286a70, 0xc0000cbef0}, 0xc00027b450)
        /var/opt/jfrog/pipelines/data/release_frogbot/runs/1859134/steps/Release/15770954/dependencyState/resources/frogbotGit/commands/utils/params.go:553 +0x424

The cause of the issue on our end was a missing CA cert for our private BitBucket Server. However, instead of a proper error we are seeing a panic. I believe it's because of the following: https://github.com/jfrog/froggit-go/blob/master/vcsclient/bitbucketserver.go#L646-L647 -> in this case, the resp object is not nil, but the resp.StatusCode seems to be. I guess this makes sense, as underwater a TLS error will be thrown, as opposed to a HTTP error.

To Reproduce
Run frogbot, connecting to a non-public BitBucket Server, for which the proper CA cert (or self-signed cert) is not imported into the system truststore.

Expected behavior
When TLS is not configured properly, I'd expect a TLS error as opposed to a panic.

Versions

  • Froggit-Go version: v1.9.0
  • Frogbot version: v2.11.0
  • Operating system: Ubuntu

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.