)]}'
{
  "commit": "37282b4b9c5b1d9a1ff07f7f0686a81b65a0a5c6",
  "tree": "aba568b85d38de4cfef90cd771169c9422aef09c",
  "parents": [
    "835cd6888f16ff30a3428adfa3a775efad918880"
  ],
  "author": {
    "name": "Doug Anderson",
    "email": "dianders@google.com",
    "time": "Fri Mar 04 11:54:18 2011 -0800"
  },
  "committer": {
    "name": "Shawn O. Pearce",
    "email": "sop@google.com",
    "time": "Fri Mar 11 11:53:23 2011 -0800"
  },
  "message": "Support repo-level pre-upload hook and prep for future hooks.\n\nAll repo-level hooks are expected to live in a single project at the\ntop level of that project.  The name of the hooks project is provided\nin the manifest.xml.  The manifest also lists which hooks are enabled\nto make it obvious if a file somehow failed to sync down (or got\ndeleted).\n\nBefore running any hook, we will prompt the user to make sure that it\nis OK.  A user can deny running the hook, allow once, or allow\n\"forever\" (until hooks change).  This tries to keep with the git\nspirit of not automatically running anything on the user\u0027s computer\nthat got synced down.  Note that individual repo commands can add\nalways options to avoid these prompts as they see fit (see below for\nthe \u0027upload\u0027 options).\n\nWhen hooks are run, they are loaded into the current interpreter (the\none running repo) and their main() function is run.  This mechanism is\nused (instead of using subprocess) to make it easier to expand to a\nricher hook interface in the future.  During loading, the\ninterpreter\u0027s sys.path is updated to contain the directory containing\nthe hooks so that hooks can be split into multiple files.\n\nThe upload command has two options that control hook behavior:\n  - no-verify\u003dFalse, verify\u003dFalse (DEFAULT):\n    If stdout is a tty, can prompt about running upload hooks if needed.\n    If user denies running hooks, the upload is cancelled.  If stdout is\n    not a tty and we would need to prompt about upload hooks, upload is\n    cancelled.\n  - no-verify\u003dFalse, verify\u003dTrue:\n    Always run upload hooks with no prompt.\n  - no-verify\u003dTrue, verify\u003dFalse:\n    Never run upload hooks, but upload anyway (AKA bypass hooks).\n  - no-verify\u003dTrue, verify\u003dTrue:\n    Invalid\n\nSample bit of manifest.xml code for enabling hooks (assumes you have a\nproject named \u0027hooks\u0027 where hooks are stored):\n  \u003crepo-hooks in-project\u003d\"hooks\" enabled-list\u003d\"pre-upload\" /\u003e\n\nSample main() function in pre-upload.py in hooks directory:\n  def main(project_list, **kwargs):\n    print (\u0027These projects will be uploaded: %s\u0027 %\n           \u0027, \u0027.join(project_list))\n    print (\u0027I am being a good boy and ignoring anything in kwargs\\n\u0027\n           \u0027that I don\\\u0027t understand.\u0027)\n    print \u0027I fail 50% of the time.  How flaky.\u0027\n    if random.random() \u003c\u003d .5:\n      raise Exception(\u0027Pre-upload hook failed.  Have a nice day.\u0027)\n\nChange-Id: I5cefa2cd5865c72589263cf8e2f152a43c122f70\n",
  "tree_diff": [
    {
      "type": "modify",
      "old_id": "2e1c8c353b6c4bbef95a459ae4c938dbbc0873a6",
      "old_mode": 33188,
      "old_path": "docs/manifest-format.txt",
      "new_id": "c76df80177bc247ad6c5351e0287cc7c6d1def83",
      "new_mode": 33188,
      "new_path": "docs/manifest-format.txt"
    },
    {
      "type": "modify",
      "old_id": "cb3b72583a601321c95fbba898eaa0b105140a2d",
      "old_mode": 33188,
      "old_path": "error.py",
      "new_id": "523815818ea6fb56b0f68c8df152fe08cfbc7efc",
      "new_mode": 33188,
      "new_path": "error.py"
    },
    {
      "type": "modify",
      "old_id": "0103cf55842c188cef8a96a29aef5172f6e7f063",
      "old_mode": 33188,
      "old_path": "manifest_xml.py",
      "new_id": "0e6421f102be2a89f8808b65b6f79e7b6dcda561",
      "new_mode": 33188,
      "new_path": "manifest_xml.py"
    },
    {
      "type": "modify",
      "old_id": "37f6d36a9b8229cedb61bc4301cf1a2d8cf3ab69",
      "old_mode": 33188,
      "old_path": "project.py",
      "new_id": "49633f7fd147c91c66edee37aa91d830b4ed1c18",
      "new_mode": 33188,
      "new_path": "project.py"
    },
    {
      "type": "modify",
      "old_id": "20822096b1f0dc866d7b1efefda89033c9d20d27",
      "old_mode": 33188,
      "old_path": "subcmds/upload.py",
      "new_id": "c561b8aa7fa39d8623ceff18d244985a5aa8329b",
      "new_mode": 33188,
      "new_path": "subcmds/upload.py"
    }
  ]
}
