Code Monkey home page Code Monkey logo

ghr's Introduction

ghr

GitHub release Test PkgGoDev MIT License

ghr creates GitHub Release and uploads artifacts in parallel.

Demo

This demo creates GitHub Release page with v1.0.0 tag and uploads cross-compiled golang binaries.

You can see release page here.

Usage

Using ghr is simple. After setting GitHub API token (see more on GitHub API Token section), change into your repository root directory and run the following command:

$ ghr [option] TAG [PATH]

You must provide TAG (git tag) and optionally a PATH to artifacts you want to upload. You can specify a file or a directory. If you provide a directory, all files in that directory will be uploaded.

ghr assumes that you are in a git repository when executed. This is because normally the artifacts you want to upload to a GitHub Release page are in that repository or generated there. With this assumption, ghr implicitly reads repository URL from .git/config file. But you can change this kind of information, see Options section.

GitHub API Token

To use ghr, you need to get a GitHub token with an account which has enough permissions to create releases. To get a token, visit GitHub account settings page, then go to Applications for the user. Here you can create a token in the Personal access tokens section. For a private repository you need repo scope and for a public repository you need public_repo scope.

When using ghr, you can set it via GITHUB_TOKEN env var, -token command line option or github.token property in .gitconfig file.

For instance, to set it via environment variable:

$ export GITHUB_TOKEN="....."

Or set it in github.token in gitconfig:

$ git config --global github.token "....."

Note that environment variable take precedence over gitconfig value.

GitHub Enterprise

You can use ghr for GitHub Enterprise. Change API endpoint via the environment variable.

$ export GITHUB_API=http://github.company.com/api/v3/

Example

To upload all files in pkg/ directory with tag v0.1.0

$ ghr v0.1.0 pkg/
--> Uploading: pkg/0.1.0_SHASUMS
--> Uploading: pkg/ghr_0.1.0_darwin_386.zip
--> Uploading: pkg/ghr_0.1.0_darwin_amd64.zip
--> Uploading: pkg/ghr_0.1.0_linux_386.zip
--> Uploading: pkg/ghr_0.1.0_linux_amd64.zip
--> Uploading: pkg/ghr_0.1.0_windows_386.zip
--> Uploading: pkg/ghr_0.1.0_windows_amd64.zip

Options

You can set some options:

$ ghr \
    -t TOKEN \        # Set Github API Token
    -u USERNAME \     # Set Github username
    -r REPO \         # Set repository name
    -c COMMIT \       # Set target commitish, branch or commit SHA
    -n TITLE \        # Set release title
    -b BODY \         # Set text describing the contents of the release
    -p NUM \          # Set amount of parallelism (Default is number of CPU)
    -delete \         # Delete release and its git tag in advance if it exists (same as -recreate)
    -replace \        # Replace artifacts if it is already uploaded
    -draft \          # Release as draft (Unpublish)
    -soft \           # Stop uploading if the same tag already exists
    -prerelease \     # Create prerelease
    -generatenotes \  # Generate Release Notes automatically (See below)
    TAG PATH

Install

If you are a macOS user, you can use Homebrew:

$ brew install ghr

If you are on another platform, you can download a binary from our release page and place it in $PATH directory.

Or you can use go install.

$ go install github.com/tcnksm/ghr@latest

VS.

  • aktau/github-release - github-release can also create and edit releases and upload artifacts. It has many options. ghr is a simple alternative. And ghr will parallelize upload artifacts.

Generate Release Notes

GitHub added the ability to automatically generate the body of a Release based on a format specified in .github/release.yml in Oct 2021. You can read more about that format here. ghr now has the -generatenotes flag to enable that content to be programmatically added instead of manually supplying the body.

Contribution

  1. Fork (https://github.com/tcnksm/ghr/fork)
  2. Create a feature branch
  3. Commit your changes
  4. Rebase your local changes against the master branch
  5. Run test suite with the make test command and confirm that it passes using correct variables e.g. GITHUB_TOKEN=$GITHUB_TOKEN TEST_REPO_OWNER=tcnksm TEST_REPO_NAME=ghr make test
  6. Run gofmt -s -w .
  7. Create new Pull Request

Author

Taichi Nakashima

ghr's People

Contributors

chfast avatar crackcomm avatar dependabot[bot] avatar djui avatar github-actions[bot] avatar gitter-badger avatar hfm avatar itchyny avatar jehandadk avatar jeppefrandsen avatar karupanerura avatar lestrrat avatar linyows avatar mattn avatar neilgierman avatar realloc avatar robphoenix avatar roschaefer avatar rubenv avatar sanemat avatar scorphus avatar shogo82148 avatar songmu avatar syossan27 avatar tcnksm avatar timfallmk avatar tmtk75 avatar toruuetani avatar virifi avatar wallyqs 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  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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ghr's Issues

pass multiple files

Passing a dir (or a single file) feels a little brittle and inconvenient.
Is there any particular reason the CLI does not use the standard way?

ghr tag file1 file2 file3 ...

Then local*.go would not even be necessary anymore.

Specify the organization

I have fork a organization's repo. and i want to upload file to org's repo. How could upload it to organization.

Release with -b attribute not working with html messages

When using -b flag for passing body of release.

If a complete html body is passed as release body consisting of html attributes we are getting syntax error on circleci

But the release is posted to github without release body.

Combine with existing draft.

I'm using ghr to upload binaries from two separate OS in a CI. The issue that I am seeing is that it seems to create a new draft for each OS build instead of seeing that they are the same and adding the files to the existing draft.

Is there a flag that I am missing that would make the ghr command upload to an existing draft if it already exists?

Errors are cryptic

So first I encountered this:

Cound not retrieve git user name

Which I grepped and looked for, and filed #11

Then I got

Github returned 404 Not Found

Okay, so I know I'm failing to setup something, but this error doesn't tell me anything useful other than the fact that somehow Github responded with failure. This is extremely discouraging for a user who just wants to try out ghr.. Can you please make it so that errors actually tells you in what context it ocurred? For example, something like this would be much much better:

Error while trying to access API $url: Github returned 404 Not Found

Fix linter warnings

I've submitted fixes for the critical linter failures in #69 and #68, but there remains a large number of non-critical warnings. In an effort to clean up the code a little, we should probably take care of these.

I'm using gometalinter to run a number of standard linters at once. My command, along with the output is below.

go get github.com/alecthomas/gometalinter
gometalinter --install


gometalinter --vendor --skip testdata -t --aggregate ./...
cli.go:76::warning: cyclomatic complexity 21 of function (*CLI).Run() is high (> 10) (gocyclo)
github_test.go:180::warning: declaration of "err" shadows declaration at github_test.go:167 (vetshadow)
github_test.go:194::warning: declaration of "err" shadows declaration at github_test.go:167 (vetshadow)
cli.go:34:1:warning: ExitCodeRepoNotFound is unused (deadcode)
cli.go:51:2:warning: exported const DefaultParallel should have comment (or a comment on this block) or be unexported (golint)
cli.go:20:1:warning: EnvStackTrace is unused (deadcode)
ghr_test.go:195::warning: declaration of "err" shadows declaration at ghr_test.go:164 (vetshadow)
github_test.go:173::warning: declaration of "err" shadows declaration at github_test.go:167 (vetshadow)
github_test.go:179::warning: declaration of "filename" shadows declaration at github_test.go:178 (vetshadow)
cli.go:34:1:warning: ExitCodeInvalidURL is unused (deadcode)
cli.go:22::warning: Potential hardcoded credentials,HIGH,LOW (gas)
cli.go:270::warning: declaration of "err" shadows declaration at cli.go:232 (vetshadow)
cli.go:279::warning: declaration of "err" shadows declaration at cli.go:232 (vetshadow)
cli_test.go:37::warning: declaration of "err" shadows declaration at cli_test.go:28 (vetshadow)
ghr_test.go:170::warning: declaration of "err" shadows declaration at ghr_test.go:164 (vetshadow)
ghr_test.go:180::warning: declaration of "err" shadows declaration at ghr_test.go:164 (vetshadow)
cli_test.go:33::warning: declaration of "err" shadows declaration at cli_test.go:28 (vetshadow)
ghr_test.go:37::warning: cyclomatic complexity 12 of function TestGHR_CreateReleaseWithExistingRelease() is high (> 10) (gocyclo)
cli.go:30:2:warning: exported const EnvStackTrace should have comment (or a comment on this block) or be unexported (golint)
cli.go:61:1:warning: comment on exported function PrintRedf should be of the form "PrintRedf ..." (golint)
cli.go:34:1:warning: ExitCodeRleaseError is unused (deadcode)
ghr.go:27:5:warning: error return value not checked (non-boolean condition in if statement) (errcheck)
ghr.go:27:5:warning: non-boolean condition in if statement (gotype, interfacer, maligned, megacheck, unconvert)
ghr.go:27:5:warning: unused struct field non-boolean condition in if statement (structcheck)
github_test.go:98::warning: cyclomatic complexity 11 of function TestGitHubClient_Upload() is high (> 10) (gocyclo)
github_test.go:112::warning: declaration of "err" shadows declaration at github_test.go:106 (vetshadow)
ghr.go:27:5:warning: unused variable or constant non-boolean condition in if statement (varcheck)

Can not use GitHub Enterprise environment

ghr uploads to github.com when I'm using v0.5.0 even if I configured $GITHUB_API.
I read source code of v0.4.0, it seems that it extracts automatically UploadURL from returned value of go-github's CreateRelease method.

I hope fix this issue.

Add env variable support inside option values ...

In TITLE or BODY, if I want to write something which I want to get from environment variables, how to do it?

Like ghr -t TOKEN -u USER -r REPO -n "Release for $DEVICE" -b "Updated at $DATE" -delete v1.0.1 FILE

This returns no env.
How to do so?

tag line for your project

This is such a nit-picking, so please close this issue if you intend it as is.

Easy to ship your project on Github to your user

The grammatically correct way to conprehend this sentence is "It is easy to ship your project on Github to your user", but I assume the intended phrase here would be something like " ghr is a easy way to ship ..." or "You can easily ship ..."

As for tag line, "Easily ship your project to your user using Github Releases" might be more appropriate.

Re-uploading assets fails when more than 30 assets are present

As a user of ghr having a release with more than 30 assets I want to be able to re-upload the assets on a repeated build.

We're using ghr with -replace flag to re-upload assets when the build job is executed more than once for a given tag. While the first 30 assets are deleted as expected and afterwards re-uploaded the assets beginning number 31 are not deleted and cause the upload to fail with 422 Validation Failed [{Resource:ReleaseAsset Field:name Code:already_exists Message:}]

Reason:

GET /repos/:owner/:repo/releases/:id/assets

Is a paginated API call having 30 items per page…

default user should be based on url

Thanks for the awesome library! One suggested update: I think the default user should come from the repo's remote origin url instead of the default git user.

  • Given:
    • my repo remote origin is [email protected]:cucumber/cucumber-pickle-runner.git
    • my git user is Charles Rudolph
  • Expected:
    • the api it hits is POST https://api.github.com/repos/cucumber/cucumber-pickle-runner/releases
  • Actual:
    • the api it hits is POST https://api.github.com/repos/Charles%20Rudolph/cucumber-pickle-runner/releases

Remove deprecated code.google.com imports

Hi,

As code.google.com is shutting down, I get a warning when using ghr:
warning: code.google.com is shutting down; import path code.google.com/p/goauth2/oauth will stop working.
Could you use golang.org/x/oauth2 instead of code.google.com/p/goauth2/oauth here

"code.google.com/p/goauth2/oauth"
?

vendoring is incomplete

Looks like some packages are missing from vendor/ and current versions of these packages can't satisfy dependencies:

+ go install -v all
src/github.com/tcnksm/ghr/vendor/github.com/golang/protobuf/descriptor/descriptor.go:46:2: cannot find package "google.golang.org/genproto/protobuf" in any of:
	/go/src/github.com/tcnksm/ghr/vendor/google.golang.org/genproto/protobuf (vendor tree)
	/usr/local/go/src/google.golang.org/genproto/protobuf (from $GOROOT)
	/go/src/google.golang.org/genproto/protobuf (from $GOPATH)
src/github.com/tcnksm/ghr/vendor/golang.org/x/oauth2/google/default.go:16:2: cannot find package "cloud.google.com/go/compute/metadata" in any of:
	/go/src/github.com/tcnksm/ghr/vendor/cloud.google.com/go/compute/metadata (vendor tree)
	/usr/local/go/src/cloud.google.com/go/compute/metadata (from $GOROOT)
	/go/src/cloud.google.com/go/compute/metadata (from $GOPATH)

Actually -delete release?

Following on from #31… as far as I can tell there is actually no way to completely delete a release…?

You closed that PR as mentioned because of not wanting to confuse users, but the options as they stand are much more confusing…

Surely -delete should actually delete the release instead of apparently being an alias of -recreate (which isn't listed as a separate option) and therefore also not require a PATH argument…
Also -draft (Unpublish) doesn't unpublish anything; it just creates a new draft release (which maybe it should… but why use the term "unpublish"? -unpublish could be an alias for -delete or actually do what it suggests).

IMO the expected API should be something like:

-delete [TAG] # Delete [TAG] release if given, else delete latest release. PATH arg unnecessary.
-unpublish # Alias of -delete
-draft # Release as draft
-title # Set release title
-d|-description # Set text describing the contents of the release

Also, is there any reason the more common -- long style options aren't available?

Otherwise great tool @tcnksm 👍

Does not works with GitHub Actions

I expected this to work with GitHub Actions.

But It seems it is not installing on GitHub Actions platform.

Hope we have an Action Wrapper release on GitHub Actions Marketplace for this.

Missing definition for 'name'

Command run from circleci:

ghr \
  --token ${GITHUB_ACCESS_TOKEN} \
  --username ${CIRCLE_PROJECT_USERNAME} \
  --repository ${CIRCLE_PROJECT_REPONAME}  \
  --commitish ${CIRCLE_SHA1} \
  --name "Facebook SDK ${CIRCLE_TAG}" \
  --body "Consult [Changelog](https://github.com/facebook/facebook-ios-sdk/blob/master/CHANGELOG.md#${STRIPPED_VERSION_NUMBER})" \
  --draft \
  ${CIRCLE_TAG} \
  build/Release

Output

flag provided but not defined: -name
Usage: ghr [options...] TAG PATH

Expected
Should populate the name of the release.

Notes
Without this flag the release works as expected.

404 Not Found

Hello,

I'm trying to setup ghr with Travis but I always receive this error:

ghr --username hacdias --token $GITHUB_TOKEN --replace --prerelease --debug pre-release dist/
POST https://api.github.com/repos/hacdias/journal/releases: 404 Not Found []
The command "ghr --username hacdias --token $GITHUB_TOKEN --replace --prerelease --debug pre-release dist/" exited with 11.

Do you know what it can be?

Is the project abandoned?

Howdy, there's a number of issues and 2 PRs that haven't been looked at in some time. Is there an appetite to add maintainers?

I'd be happy to help :)

Cheers,
iamnande

Unexpected behaviour on artifact upload to existing release

I am seeing strange behavior with both ghr and GitHub when uploading multiple new artifacts to an existing release, with an existing tag. The exact same flow worked fine a couple of weeks ago. The command I am using is

ghr -token **** -u RepoOwner -r Repo -c 98fd86794be759e412842a12a8b0db8f36151eff -n v0.16.0 release/v0.16.0 ./Deploy/v0.16.0

The same command is then run subsequently in different folders for different artifacts. Some artifacts upload without error, however others experience the error

Failed to publish release: failed to edit release: 14293732: PATCH    
https://api.github.com/repos/RepoOwner/Repo/releases/14293732: 422 Validation Failed    
[{Resource:Release Field:tag_name Code:already_exists Message:}]

or

Failed to upload one of assets: one of the goroutines failed: failed to upload asset:   
/path/to/artifact.tar.gz: failed to upload release asset: /path/to/artifact.tar.gz: POST    
https://uploads.github.com/repos/RepoOwner/Repo/releases/14293732/assets?name=artifact.tar.gz:  
422 Validation Failed [{Resource:ReleaseAsset Field:name Code:already_exists Message:}]   

The interesting thing is that on the GitHub release page, the artifacts are there and I have verified they were uploaded correctly. Strangely, there seems to also be a bug with the GitHub interface where if you look at the list of releases, it only shows one artifact under the release, but when you open the release itself, all of the artifacts are present.

failed to find assets (circleci)

Reference: https://circleci.com/blog/publishing-to-github-releases-via-circleci/
From the example given in the above blog post

ghr -t ${GITHUB_TOKEN} -u ${CIRCLE_PROJECT_USERNAME} -r ${CIRCLE_PROJECT_REPONAME} -c ${CIRCLE_SHA1} ${VERSION} ./artifacts/

gives out the error: Failed to find assets from ./artifacts/: no local assets are found when publishing out the release

Do i need the additional step store_artifacts in build: ? and store to the /artifacts dir ?
eg:

       - store_artifacts:
           path: ./artifacts

Downloads docker as dependency

For some reason I end up downloading docker after calling go get -v github.com/tcnksm/ghr:

go get -v github.com/tcnksm/ghr
github.com/dotcloud/docker (download)
...

If you're using docker for testing or something, code should probably be decomposed into two parts - one being the actual app, and the other being what is needed to test/package it.

FreeBSD

Please also provide builds for FreeBSD.

Please let me know if you are interested in setting up a continuous build for it using https://cirrus-ci.org/.

In the meantime, here is one for amd64.

ghr.zip

-body ignored when -replace is used

I have a build system on CircleCI that uses ghr to push weekly builds to GitHub.

My binaries get uploaded, but the message (that includes the date of build) gets ignored.

I believe that -body should still update the release message, even when -replace is used. This is currently not the case.

Tests failing

When make test is run, a few of the tests fail due to the test URL returning a 404 when not expected:

 $ make test
go get  -d
..
go test -v -parallel=4 ./...
=== RUN   TestRun
=== PAUSE TestRun
=== RUN   TestRun_recreate
--- FAIL: TestRun_recreate (0.67s)
    cli_test.go:71: "ghr -username ghtools -repository github-api-test run-recreate ./testdata" exits 11, want 0

        Failed to create GitHub release page: failed to create a release: POST https://api.github.com/repos/ghtools/github-api-test/releases: 404 Not Found []

...
--- FAIL: TestGHR_CreateRelease (0.39s)
    ghr_test.go:31: CreateRelease failed: failed to create a release: POST https://api.github.com/repos/ghtools/github-api-test/releases: 404 Not Found []
--- FAIL: TestRun (0.51s)
    cli_test.go:24: "ghr -username ghtools -repository github-api-test run ./testdata" exits 11, want 0

        Failed to create GitHub release page: failed to create a release: POST https://api.github.com/repos/ghtools/github-api-test/releases: 404 Not Found []

--- FAIL: TestGHR_CreateReleaseWithExistingRelease (1.15s)
    ghr_test.go:104: #0 CreateRelease failed: failed to create a release: POST https://api.github.com/repos/ghtools/github-api-test/releases: 404 Not Found []
--- FAIL: TestGitHubClient (1.17s)
    github_test.go:69: #0 CreateRelease failed: failed to create a release: POST https://api.github.com/repos/ghtools/github-api-test/releases: 404 Not Found []
FAIL
FAIL	github.com/tcnksm/ghr	2.574s
FAIL
make: *** [test] Error 1

https://github.com/ghtools/github-api-test appears to be the repo associated with the test server

Ability to pass a Markdown file as body

I think it would be useful to be able to pass a Markdown file as body.
It would allow more direct changelog generation automation.

It seems easier to manage than to pass long content from the command line.

use of closed file

I am trying to test the re-upload of a release

WARNING: found release (v0.0.5). Use existing one.
--> Uploading:  foo-v0.0.5.tgz
Failed to upload one of assets: one of the goroutines failed: failed to upload asset: /Users/tcurdt/Desktop/base-ci/dist/foo-v0.0.5.tgz: failed to upload release asset: /Users/tcurdt/Desktop/base-ci/dist/foo-v0.0.5.tgz: stat /Users/tcurdt/Desktop/base-ci/dist/foo-v0.0.5.tgz: use of closed file
$ ll /Users/tcurdt/Desktop/base-ci/dist/foo-v0.0.5.tgz
-rw-r--r--  1 tcurdt  staff  209 Jul  4 17:07 /Users/tcurdt/Desktop/base-ci/dist/foo-v0.0.5.tgz

Honestly I have no clue what that error message is trying to tell me. "use of closed file"?

I figured I delete the asset on github and try again - which then worked.

So I see two issues:

  1. A better error message
  2. Support for replacing a release (asset)

Add an option not to release if release already exists

Currently when creating a release that already exists, something like this happens:

WARNING: found release (v0.1.0). Use existing one.
--> Uploading:  artefact.dummy
Failed to upload one of assets: one of the goroutines failed: failed to upload asset: /home/circleci/project/dist/artefact.dummy: failed to upload release asset: /home/circleci/project/dist/artefact.dummy: POST https://uploads.github.com/repos/org/project/releases/14679871/assets?name=artefact.dummy: 422 Validation Failed [{Resource:ReleaseAsset Field:name Code:already_exists Message:}]
Exited with code 11

I propose adding an extra flag, --skip-existing that will detect if the release already exists (this is implemented already) and exit if it happens.

Invalid argument: you must set TAG and PATH name.

Hi,

in my CI, I'm running

ghr -t ${GITHUB_TOKEN} -u ${CIRCLE_PROJECT_USERNAME} -r ${CIRCLE_PROJECT_REPONAME} -c ${CIRCLE_SHA1} v0.1.9 artifacts/

to create my GH release using artifacts from the artifacts directory. Unfortunately, the following error occurs:

Invalid argument: you must set TAG and PATH name.

Any ideas?

Isn't it insecure to use $GITHUB_TOKEN?

Hi,

I'm running an open source project on Github which will automatically build PRs on Circle CI and I need to figure out a way to make artifacts get published to releases (whenever a tag is made). I'm considering using ghr to upload the artifacts, but I'm afraid an author of a malicions PR could edit the .circleci/config.yml to run echo $GITHUB_TOKEN and they'll get my token.

Did I completely misunderstand all of this, or is there some way to avoid getting the token into the wrong hands in my case?

TravisCI gone into infinite loop if ghr --delete used in after_success

I want to upload binaries after each commit to pre-release tag latest. If I used this:

after_success:
  - gox -output "dist/{{.OS}}_{{.Arch}}_{{.Dir}}" -arch="amd64" -os="windows linux darwin"
  - ghr --username popstas --token $GITHUB_TOKEN --replace --delete --prerelease --debug latest dist/

then Travis will begin build latest tag recursively.

Format verbs shows up on output

Format verbs that it's like %s shows up on output.
It looks like bellow.

$ ghr -u myuser v0.1.0 pkg/dist
WARNING: found release (%s). Use existing one.
--> Uploading:   0.1.0_SHASUMS
--> Uploading: myawesometool_0.1.0_linux_amd64.zip
--> Uploading: myawesometool_0.1.0_darwin_amd64.zip

I think you forget to pass *req.TagName as seccond arguments of fmt.Fprintln.

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.