Giter Club home page Giter Club logo

compare-url's Introduction

Compare URL Orb CircleCI status CircleCI Orb Version CircleCI Community

CircleCI's 2.1 config processing preview disables the $CIRCLE_COMPARE_URL environment variable, useful when working with monorepo projects. This orb manually recreates (and slightly improves!) it.

Functionality

Originally, and as recreated here, $CIRCLE_COMPARE_URL outputs a URL of the following form, slighly different for GitHub vs. Bitbucket projects:

# GitHub
https://github.com/$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME/compare/$COMMIT1...$COMMIT2

# Bitbucket
https://bitbucket.org/$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME/branches/compare/$COMMIT1...$COMMIT2

$COMMIT2 always represents the current job's commit ($CIRCLE_SHA1). In the most common use case, $COMMIT1 will be the most recent previously pushed commit on the same branch as the current job.

If the current branch is new or has only ever had a single commit pushed to it, then $COMMIT1 will be the most recent ancestor commit as defined in the git specifications (whereas the original $CIRCLE_COMPARE_URL environment variable would, in this case, instead output a compare URL containing only $COMMIT2—essentially unusable in the monorepo scenario that this orb addresses).

Usage

Declare the orb in your config.yml file:

orbs:
  circle-compare-url: iynere/[email protected]

Then call the orb's reconstruct command or job:

Command usage

steps:
  - checkout
  - circle-compare-url/reconstruct

Job usage

workflows:
  deploy:
    jobs:
      - circle-compare-url/reconstruct
      - deploy:
          requires:
            - circle-compare-url/reconstruct

use command

Finally, the circle-compare-url/use command saves the CIRCLE_COMPARE_URL value, previously stored in file, to a local environment variable and transforms it into a true commit range value (stored as a COMMIT_RANGE environment variable), ready to be utilized as desired:

- circle-compare-url/use:
    step-name: Desired step name to display on CircleCI
    attach-workspace: # set this to `true` if `reconstruct` was called as a job; default is `false`
    custom-logic: |
      # what would you like to do with the $CIRCLE_COMPARE_URL/$COMMIT_RANGE values?
      # this typically involves some kind of dynamic decision-making about release types,
      # based on what level of changes were made to your source code between the base commit and the current commit
      # for examples, see below

Parameters

reconstruct

The orb's reconstruct command and job both take three optional parameters:

Parameter Type Default Description
circle-token env_var_name CIRCLE_TOKEN Name of environment variable storing your CircleCI API token
project-path string ~/project Absolute path to your project's base directory, for running git commands
debug boolean false Additional debugging output for folks developing the orb
when enum always Specify when this command will run ([always, on_fail, on_success])

Its job also takes an optional fourth paramater, which allows users to run the job in a smaller container to conserve resources:

Parameter Type Default Description
resource-class enum medium Container size for reconstruct job (["small", "medium"])

use

The use command also takes three optional parameters and one that is technically optional but typically required:

Parameter Type Default Description
step-name string Evaluate/use CIRCLE_COMPARE_URL Specify a custom step name for this command, if desired
attach-workspace boolean false Attach a workspace for this command to use? Useful when this orb's reconstruct job is called upstream in a given workflow
workspace-root string "." Workspace root path (either an absolute path or a path relative to the working directory), defaults to "." (the working directory)
custom-logic string echo "What should COMMIT_RANGE ($COMMIT_RANGE) be used for?" What should be done with the commit information created by the reconstruct command/job? See examples in the orb registry (or below)

Refer to CircleCI's Reusing Config documentation for additional information about parameters.

Examples

The below examples are drawn from CircleCI's circleci-orbs monorepo, where the Compare URL Orb is used to automate publishing changes to individual orbs. See that repository's config.yml file for a more recent iteration of what follows.

By default, every new CircleCI step runs in a fresh shell. Thus, any environment variables stored during the circle-compare-url/reconstruct step would not be available to subsequent steps, without additional configuration by the end user (e.g., exporting the environment variable to a .bash_env and then file manually sourcing that file in any subsequent steps).

To mitigate this problem, the orb outputs the $CIRCLE_COMPARE_URL data to a file called CIRCLE_COMPARE_URL.txt, making it available to any subsequent steps (and even subsequent jobs, via Workspaces). It also persists this file, along with a BASE_COMPARE_COMMIT.txt file, to a workspace, for possible usage in downstream jobs.

Thus, as seen in the below examples, it may be necessary to save the contents of the CIRCLE_COMPARE_URL.txt file as a (step-localized) environment variable in any steps that will make use of the compare URL.

Command example

version: 2.1

orbs:
  compare-url: iynere/[email protected]

jobs:
  publish:
    docker:
      - image: circleci/circleci-cli
    steps:
      - checkout

      - compare-url/reconstruct

      - compare-url/use:
          step-name: Publish modified orbs
          custom-logic: |
            for ORB in folder-containing-orb-subdirs/*/; do

              orbname=$(basename $ORB)

              if [[ $(git diff $COMMIT_RANGE --name-status | grep "$orbname") ]]; then

                echo "publishing ${orbname}"

                circleci orb publish ${ORB}/orb.yml namespace/${orbname}@version
              else
                echo "${orbname} not modified; no need to publish"
              fi
            done

workflows:
  publish-orbs:
    jobs:
      - publish

Job example

version: 2.1

orbs:
  compare-url: iynere/[email protected]

jobs:
  publish:
    docker:
      - image: circleci/circleci-cli
    steps:
      - checkout

      - compare-url/use:
          step-name: Publish modified orbs
          attach-workspace: true
          command: |
            for ORB in folder-containing-orb-subdirs/*/; do

              orbname=$(basename $ORB)

              if [[ $(git diff $COMMIT_RANGE --name-status | grep "$orbname") ]]; then

                echo "publishing ${orbname}"

                circleci orb publish ${ORB}/orb.yml namespace/${orbname}@version
              else
                echo "${orbname} not modified; no need to publish"
              fi
            done

workflows:
  publish-orbs:
    jobs:
      - compare-url/reconstruct
      - publish:
          requires:
            - compare-url/reconstruct

Contributing

See CircleCI's Creating Orbs documentation to get started.

This orb has only minimal testing—issues, pull requests, or other suggestions are welcome towards the goal of improving test depth/coverage.

See Creating automated build, test, and deploy workflows for orbs, part 1 and Creating automated build, test, and deploy workflows for orbs, part 2 for more information on automated orb testing/deployment.

compare-url's People

Contributors

iynere avatar jasonkuhrt avatar jrnail23 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

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

compare-url's Issues

First build on a branch with no changes fails

If I create a new branch and push to the repository without adding a new commit, I get the following error:

checking if foo a new branch...
----------------------------------------------------------------------------------------------------
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

100 41822  100 41822    0     0   559k      0 --:--:-- --:--:-- --:--:--  559k
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

100 58216  100 58216    0     0   719k      0 --:--:-- --:--:-- --:--:--  719k
----------------------------------------------------------------------------------------------------
yes,foo is new and 37dc2b3b5fc1f729e7d35ec178cd67873d7519f0 is its only commit
finding most recent ancestor commit from any other branch...
----------------------------------------------------------------------------------------------------
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

100 68958  100 68958    0     0   370k      0 --:--:-- --:--:-- --:--:--  367k
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

100 68958  100 68958    0     0   534k      0 --:--:-- --:--:-- --:--:--  534k
Exited with code 1

Reconstruct command fails on missing commit in old job

Orb version

1.2.0

What happened

----------------------------------------------------------------------------------------------------
commit [DELETED] from job 18253 is not an ancestor of the current commit
----------------------------------------------------------------------------------------------------
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 18334  100 18334    0     0  75684      0 --:--:-- --:--:-- --:--:-- 75760
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 18334  100 18334    0     0   110k      0 --:--:-- --:--:-- --:--:--  109k
----------------------------------------------------------------------------------------------------
commit [DELETED] from job 18252 is not an ancestor of the current commit
----------------------------------------------------------------------------------------------------
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 13570  100 13570    0     0  84419      0 --:--:-- --:--:-- --:--:-- 84812
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 13570  100 13570    0     0  78757      0 --:--:-- --:--:-- --:--:-- 78895
fatal: Not a valid commit name [DELETED]
unknown return code 128 from git merge-base with base commit [DELETED], from job 18251
Exited with code 1
CircleCI received exit code 1

Expected behavior

Since a missing commit may mean that the branch from the old job was deleted, the loop should simply continue.

Cannot use the Orb in Alpine image

Orb version

0.4.9

What happened

When using the reconstruct job in alpine image, whih doesn't have bash, the job cannot complete due to the following error:

sh: missing ]]

Expected behavior

The script inside the job should be re-written for shell. You can use shellcheck to make sure it is compatible with standard versions of sh.

need to account for scheduled workflows

probably no one would use this w/ scheduled workflows, because you typically want to build everything in nightlies / weeklies / etc., but the orb should do something besides fail & output incorrect information

Mysterious exit code 1

Orb version

0.4.10

What happened

Branch off master, push an insignificant change, exits 1

Has happened twice to me.

  • First time I fixed it by updating to latest version of orb.
  • Second time (this time) I fixed it by setting debug: true. Then I removed debug: true and it continued to work.
checking if fix/base-bash-safe-export is a new branch...
----------------------------------------------------------------------------------------------------
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

100  112k  100  112k    0     0  1120k      0 --:--:-- --:--:-- --:--:-- 1122k
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

100 72190  100 72190    0     0   570k      0 --:--:-- --:--:-- --:--:--  573k
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

100 54585  100 54585    0     0   586k      0 --:--:-- --:--:-- --:--:--  592k
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

100 73775  100 73775    0     0   744k      0 --:--:-- --:--:-- --:--:--  750k
----------------------------------------------------------------------------------------------------
yes, fix/base-bash-safe-export is new and 667069510cd23599dde2c590a0f3ce5e5d07a2ed is its only commit
finding most recent ancestor commit from any other branch...
----------------------------------------------------------------------------------------------------
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

100 54585  100 54585    0     0   479k      0 --:--:-- --:--:-- --:--:--  484k
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

100 54585  100 54585    0     0   635k      0 --:--:-- --:--:-- --:--:--  642k
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

100 73775  100 73775    0     0   891k      0 --:--:-- --:--:-- --:--:--  900k
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

100 73775  100 73775    0     0   460k      0 --:--:-- --:--:-- --:--:--  461k
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

100 75923  100 75923    0     0   503k      0 --:--:-- --:--:-- --:--:--  500k
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

100 75923  100 75923    0     0   748k      0 --:--:-- --:--:-- --:--:--  756k
Exited with code 1

Expected behavior

Branch off master, push an insignificant change, exits 0.

Related:

Breaks on building for a branch

Orb version

1.2.0

What happened

unknown return code 129 from git merge-base with base commit , from job


++ sed -E 's/"vcs_revision" ://'
++ sed -E 's/[[:punct:]]//g'
++ sed -E 's/ //g'
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    37  100    37    0     0   1176      0 --:--:-- --:--:-- --:--:--  1193
+ COMMIT_FROM_JOB_NUM=
+ [[ '' == ecf5ecd8e44e26ca1b7f9107f50210aebf0071a2 ]]
+ cd /home/circleci/repo
+ git merge-base --is-ancestor ecf5ecd8e44e26ca1b7f9107f50210aebf0071a2
usage: git merge-base [-a | --all] <commit> <commit>...
   or: git merge-base [-a | --all] --octopus <commit>...
   or: git merge-base --independent <commit>...
   or: git merge-base --is-ancestor <commit> <commit>
   or: git merge-base --fork-point <ref> [<commit>]

    -a, --all             output all common ancestors
    --octopus             find ancestors for a single n-way merge
    --independent         list revs not reachable from others
    --is-ancestor         is the first one ancestor of the other?
    --fork-point          find where <commit> forked from reflog of <ref>

+ RETURN_CODE=129
+ [[ 129 == 1 ]]
+ [[ 129 == '' ]]
+ echo 'unknown return code 129 from git merge-base with base commit , from job 11103'
unknown return code 129 from git merge-base with base commit , from job 11103
+ exit 1

This is my job config:

version: 2.1

executors:
  base-python:
    docker:
      - image: circleci/python:3.7.3

orbs:
  compare-url: iynere/[email protected]

jobs:
  checkout_code:
    working_directory: ~/repo
    executor: base-python
    steps:
      - checkout
      - compare-url/reconstruct:
          debug: true
          project-path: ~/repo

it is hanging

Orb version

compare-url: iynere/[email protected]

What happened

reconstruct circle_compare_url is hanging
image

steps:

  • compare-url/reconstruct

Expected behavior

it should not hang

Exited with code 1

Orb version

0.4.9

What happened

checking if circleci-change-awareness is a new branch...
----------------------------------------------------------------------------------------------------
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

100    37  100    37    0     0    222      0 --:--:-- --:--:-- --:--:--   222
----------------------------------------------------------------------------------------------------
yes, circleci-change-awareness is new and d0ec681bcf2d0a980c3e0f73574edd3d5dbae03d is its only commit
finding most recent ancestor commit from any other branch...
----------------------------------------------------------------------------------------------------
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

100    37  100    37    0     0    215      0 --:--:-- --:--:-- --:--:--   216
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

100    37  100    37    0     0    247      0 --:--:-- --:--:-- --:--:--   248
Exited with code 1

Another user reported the same issue in this thread: https://discuss.circleci.com/t/circle-compare-url-is-empty/24549/14

Could you help check what goes wrong?

Expected behavior

add timeout catcher w/ retries

for branches where the gap between commits is very, very large (ie, 100s or 1000s of circleci jobs), the orb can take 15+ minutes to run & make 1000s of api calls in rapid succession, which, when run in a parallelized job, can lead to timeouts.

a timeout should trigger an automatic retry

also, i wonder if this orb's command could just run as a deploy: (instead of run:) step, so it only ever uses 1 container.... parallelizing it certainly doesn't do anything, functionally, except bog it down

Script exits with code 1

Hi 👋

I've been trying to use this orb but currently it exits with code 1. It seems to happen inside the loop but I'm not sure exactly where. I get the following output

checking if circle-2.1 is a new branch...
----------------------------------------------------------------------------------------------------
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

100    37  100    37    0     0   1311      0 --:--:-- --:--:-- --:--:--  1321
----------------------------------------------------------------------------------------------------
yes, circle-2.1 is new and 4a8d5049b6faaed9a1afd96746023f3995e1d6a4 is its only commit
finding most recent ancestor commit from any other branch...
----------------------------------------------------------------------------------------------------
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

100    37  100    37    0     0    918      0 --:--:-- --:--:-- --:--:--   925
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

100    37  100    37    0     0   1320      0 --:--:-- --:--:-- --:--:--  1370
Exited with code 1

Do you have any idea what could cause this, or is there perhaps a way for me to debug this?

refactor—create option to run as job

running as a job, & persisting the CIRCLE_COMPARE_URL.txt file to a workspace to be attached in downstream jobs would be much more efficient, for most uses of the orb so farf

Update $BASH_ENV by default

Orb version

0.4.9

Recommendation

Referencing from your documentation:

By default, every new CircleCI step runs in a fresh shell. Thus, any environment variables stored during the circle-compare-url/reconstruct step would not be available to subsequent steps, without additional configuration by the end user (e.g., exporting the environment variable to a .bash_env and then file manually sourcing that file in any subsequent steps).

The CircleCI documentation recommends persisting environment variables to $BASH_ENV. I do this often in my projects.

https://circleci.com/docs/2.0/env-vars/#example-configuration-of-environment-variables

Example:

echo 'export CIRCLE_COMPARE_URL="`cat workspace/CIRCLE_COMPARE_URL.txt`"' >> $BASH_ENV

Doing this makes CIRCLE_COMPARE_URL available in subsequent shells. It'd be great if your orb did this.

force-pushed branch should be treated as a new branch

Orb version

1.2.0

What happened

Because force push behaviour is changing the commit history, this becomes a bit problematic for compare-url as it will make git diff <commit_range> fail. Of course, it will fail because git can't find a diff between two commits from a different history.

Here is the snippet from CircleCI output:

Commit range: b52f3cbc582f...b41423c44770
fatal: ambiguous argument 'b52f3cbc582f...b41423c44770': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'
project-a not modified; no need to test
fatal: ambiguous argument 'b52f3cbc582f...b41423c44770': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'
project-b not modified; no need to test

When this happens, all tests will be skipped by the CircleCI because it doesn't find any changes from each package/project. And the job will be marked as PASSED because there is no failing test.

Expected behavior

This orb should mark the branch as a new branch so the actual ancestor from the same history can be found instead of using the commit from the previous job from a different history.

I could help to create a fix for this if you want.

[feature request] provide commit range for the whole pull request

Orb version

1.0.2

What happened

It is not showing whole commit range for pull requests

Expected behavior

This is the commits for my pull requests
image

CIRCLE_COMPARE_URL=$(cat CIRCLE_COMPARE_URL.txt)
 COMMIT_RANGE=$(echo $CIRCLE_COMPARE_URL | sed 's:^.*/compare/::g')
 echo "Commit range: $COMMIT_RANGE"

compare url is like this: 068728a95a46...3466429, in the latest commit.
but it should be 29a7e130f034...068728a95a46

We need this because we cancel jobs on pull requests if another commit show up, so we need to run tests based on the whole pull request commit range

Still broken on first build to new branch

Seems the fix to #21 has caused another error:

fatal: Not a valid commit name 29201976786eae7f3a86ed1678b91ef5a62bfc00
unknown return code 128 from git merge-base with base commit 29201976786eae7f3a86ed1678b91ef5a62bfc00, from job 1302

reconstruct fails

Orb version

1.1.0

What happened

attempting to include -compare-url/reconstruct as a step, fails with Exited with code 1

checking if cicd is a new branch...
----------------------------------------------------------------------------------------------------
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

100    37  100    37    0     0   1241      0 --:--:-- --:--:-- --:--:--  1275
----------------------------------------------------------------------------------------------------
yes, cicd is new and f673e3c10bdcf1ebcc6b36aea8515e35f7697df3 is its only commit
finding most recent ancestor commit from any other branch...
----------------------------------------------------------------------------------------------------
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

100    37  100    37    0     0    465      0 --:--:-- --:--:-- --:--:--   468
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

100    37  100    37    0     0   1696      0 --:--:-- --:--:-- --:--:--  1761
Exited with code 1

Expected behavior

Reconstruct command should not fail

Feature request: Commit ranges to last successful job OR last ancestor commit

I'm currently looking into expanding the functionality of this orb to include an opt-in flag to go back to the last successful job.

This is the use case:
A developer files a PR against a branch. The job is executed to return commit A (first commit) and commit B (most recent commit). Tests are executed against the changes between commit A and commit B. The tests fail and abort (leaving some package tests un-executed). The developer makes changes to the affected tests and pushes commit C.

Currently, the orb will return the compare URL for B and C. The proposed functionality will check for the outcome on the job result from the CircleCI API, decrementing and doing another iteration in the failed, canceled, and timedout case.

reconstruct command has `when: always`?

Orb version

v1.1.0

What happened

Hi @iynere, when using this orb, I had a hell of a time figuring out why my job wasn't stopping when a validation step was failing before the reconstruct command started... I didn't realize that reconstruct has when: always.
Is there a way to override that behavior? There's a lot going on in reconstruct, and when it fails, there's a lot of console noise, making it easy to miss any preceding failures (which is what bit me). It just doesn't seem like the kind of command that adds value after a failing step. Your thoughts?

Expected behavior

I'd prefer if the command's when attribute to be parameterized.

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.