def test_write_no_start_line(self): header = """ # HG changeset patch # User byron jones <*****@*****.**> # Date 1523427125 -28800 # Wed Apr 11 14:12:05 2018 +0800 # Node ID 3379ea3cea34ecebdcb2cf7fb9f7845861ea8f07 # Parent 46c36c18528fe2cc780d5206ed80ae8e37d3545d """.strip() commit_desc = """ WIP transplant and diff-start-line """.strip() diff = """ diff --git a/autoland/autoland/transplant.py b/autoland/autoland/transplant.py --- a/autoland/autoland/transplant.py +++ b/autoland/autoland/transplant.py @@ -318,24 +318,58 @@ class PatchTransplant(Transplant): # instead of passing the url to 'hg import' to make ... """.strip() patch = PatchHelper( io.BytesIO('%s\n%s\n\n%s' % (header, commit_desc, diff))) buf = io.BytesIO('') patch.write_commit_description(buf) self.assertEqual(buf.getvalue(), commit_desc) buf = io.BytesIO('') patch.write_diff(buf) self.assertEqual(buf.getvalue(), diff)
def _apply_patch_from_io_buff(self, io_buf): patch = PatchHelper(io_buf) # In production we require each patch to require a `Diff Start Line` header. # In test this is tricky because mercurial doesn't generate this header. if not config.testing() and not patch.diff_start_line: raise Exception("invalid patch: missing `Diff Start Line` header") # Import then commit to ensure correct parsing of the # commit description. desc_temp = tempfile.NamedTemporaryFile() diff_temp = tempfile.NamedTemporaryFile() with desc_temp, diff_temp: patch.write_commit_description(desc_temp) desc_temp.flush() patch.write_diff(diff_temp) diff_temp.flush() # Apply the patch, with file rename detection (similarity). # Using 95 as the similarity to match automv's default. # # XXX Using `hg import` here is less than ideal because it isn't # using a 3-way merge. It would be better to use # `hg import --exact` then `hg rebase`, however we aren't # guaranteed to have the changeset's parent in the local repo. self.run_hg(['import', '-s', '95', '--no-commit', diff_temp.name]) # Commit using the extracted date, user, and commit desc. # --landing_system is provided by the set_landing_system hgext. self.run_hg([ 'commit', '--date', patch.header('Date'), '--user', patch.header('User'), '--landing_system', self.landing_system_id, '--logfile', desc_temp.name ])
def _apply_patch_from_io_buff(self, io_buf): patch = PatchHelper(io_buf) if patch.header('Diff Start Line'): with tempfile.NamedTemporaryFile() as desc_temp, \ tempfile.NamedTemporaryFile() as diff_temp: patch.write_commit_description(desc_temp) desc_temp.flush() patch.write_diff(diff_temp) diff_temp.flush() # Import then commit to ensure correct parsing of the # commit description. # Apply the patch, with file rename detection (similarity). # Using 95 as the similarity to match automv's default. self.run_hg( ['import', '-s', '95', '--no-commit', diff_temp.name]) # Commit using the extracted date, user, and commit desc. self.run_hg([ 'commit', '--date', patch.header('Date'), '--user', patch.header('User'), '--logfile', desc_temp.name ]) else: with tempfile.NamedTemporaryFile() as temp_file: patch.write(temp_file) temp_file.flush() # Apply the patch, with file rename detection (similarity). # Using 95 as the similarity to match automv's default. self.run_hg(['import', '-s', '95', temp_file.name])
def _apply_patch_from_io_buff(self, io_buf): patch = PatchHelper(io_buf) # In production we require each patch to require a `Diff Start Line` header. # In test this is tricky because mercurial doesn't generate this header. if not config.testing() and not patch.diff_start_line: raise Exception("invalid patch: missing `Diff Start Line` header") # Import then commit to ensure correct parsing of the # commit description. desc_temp = tempfile.NamedTemporaryFile() diff_temp = tempfile.NamedTemporaryFile() with desc_temp, diff_temp: patch.write_commit_description(desc_temp) desc_temp.flush() patch.write_diff(diff_temp) diff_temp.flush() # XXX Using `hg import` here is less than ideal because it isn't # using a 3-way merge. It would be better to use # `hg import --exact` then `hg rebase`, however we aren't # guaranteed to have the changeset's parent in the local repo. try: # Fall back to 'patch' if hg's internal code fails (to work around # hg bugs/limitations). # In tests if the patch contains a 'Fail HG Import' header we simulate # a failure from hg's internal code. if config.testing() and patch.header("Fail HG Import"): logger.info("testing: forcing patch fallback") # Create junk to ensure it gets cleaned up. import glob filename = [ f for f in glob.glob("%s/*" % self.path) if os.path.isfile(f) ][0] with open(filename, "w") as f: f.write("junk\n") raise Exception( "1 out of 1 hunk FAILED -- saving rejects to file") # Apply the patch, with file rename detection (similarity). # Using 95 as the similarity to match automv's default. self.run_hg( ["import", "-s", "95", "--no-commit", diff_temp.name]) except Exception as e: msg = str(e) if ("hunk FAILED -- saving rejects to file" in msg or "hunks FAILED -- saving rejects to file" in msg): # Try again using 'patch' instead of hg's internal patch utility. # But first reset to a clean repo as hg's attempt might have # been partially applied. self.clean_repo(strip_non_public_commits=False) logger.info("import failed, trying with 'patch': %s" % e) try: self.run_hg(["import"] + ["-s", "95"] + ["--no-commit"] + ["--config", "ui.patch=patch"] + [diff_temp.name]) # When using an external patch util mercurial won't # automatically handle add/remove/renames. self.run_hg(["addremove", "-s", "95"]) except hglib.error.CommandError as hg_error: raise Exception(hg_error.out) else: raise # Commit using the extracted date, user, and commit desc. # --landing_system is provided by the set_landing_system hgext. self.run_hg(["commit"] + ["--date", patch.header("Date")] + ["--user", patch.header("User")] + ["--landing_system", self.landing_system_id] + ["--logfile", desc_temp.name])