Merge "teach the scanner to look at uncommitted files"
This commit is contained in:
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Include the local working copy when scanning the history of the
|
||||||
|
current branch. Notes files must at least be staged to indicate
|
||||||
|
that they will eventually be part of the history, but subsequent
|
||||||
|
changes to the file do not need to also be staged to be seen.
|
||||||
@@ -20,7 +20,9 @@ import re
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
from dulwich import diff_tree
|
from dulwich import diff_tree
|
||||||
|
from dulwich import index as d_index
|
||||||
from dulwich import objects
|
from dulwich import objects
|
||||||
|
from dulwich import porcelain
|
||||||
from dulwich import repo
|
from dulwich import repo
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
@@ -423,7 +425,23 @@ class RenoRepo(repo.Repo):
|
|||||||
return tree
|
return tree
|
||||||
|
|
||||||
def get_file_at_commit(self, filename, sha):
|
def get_file_at_commit(self, filename, sha):
|
||||||
"Return the contents of the file if it exists at the commit, or None."
|
"""Return the contents of the file.
|
||||||
|
|
||||||
|
If sha is None, return the working copy of the file. If the
|
||||||
|
file cannot be read from the working dir, return None.
|
||||||
|
|
||||||
|
If the sha is not None and the file exists at the commit,
|
||||||
|
return the data from the stored blob. If the file does not
|
||||||
|
exist at the commit, return None.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if sha is None:
|
||||||
|
# Get the copy from the working directory.
|
||||||
|
try:
|
||||||
|
with open(os.path.join(self.path, filename), 'r') as f:
|
||||||
|
return f.read()
|
||||||
|
except IOError:
|
||||||
|
return None
|
||||||
# Get the tree associated with the commit identified by the
|
# Get the tree associated with the commit identified by the
|
||||||
# input SHA, then look through the items in the tree to find
|
# input SHA, then look through the items in the tree to find
|
||||||
# the one with the path matching the filename. Take the
|
# the one with the path matching the filename. Take the
|
||||||
@@ -763,10 +781,48 @@ class Scanner(object):
|
|||||||
LOG.debug('current repository version: %s' % current_version)
|
LOG.debug('current repository version: %s' % current_version)
|
||||||
if current_version not in versions_by_date:
|
if current_version not in versions_by_date:
|
||||||
versions_by_date.insert(0, current_version)
|
versions_by_date.insert(0, current_version)
|
||||||
|
versions_by_date.insert(0, '*working-copy*')
|
||||||
|
|
||||||
# Track the versions we have seen and the earliest version for
|
# Track the versions we have seen and the earliest version for
|
||||||
# which we have seen a given note's unique id.
|
# which we have seen a given note's unique id.
|
||||||
tracker = _ChangeTracker()
|
tracker = _ChangeTracker()
|
||||||
|
|
||||||
|
# Process the local index, if we are scanning the current
|
||||||
|
# branch.
|
||||||
|
if not branch:
|
||||||
|
prefix = notesdir.rstrip('/') + '/'
|
||||||
|
index = self._repo.open_index()
|
||||||
|
|
||||||
|
# Pretend anything known to the repo and changed but not
|
||||||
|
# staged is part of the fake version '*working-copy*'.
|
||||||
|
LOG.debug('scanning unstaged changes')
|
||||||
|
for fname in d_index.get_unstaged_changes(index, self.reporoot):
|
||||||
|
fname = fname.decode('utf-8')
|
||||||
|
LOG.debug('found unstaged file %s', fname)
|
||||||
|
if fname.startswith(prefix) and _note_file(fname):
|
||||||
|
fullpath = os.path.join(self.reporoot, fname)
|
||||||
|
if os.path.exists(fullpath):
|
||||||
|
LOG.debug('found file %s', fullpath)
|
||||||
|
tracker.add(fname, None, '*working-copy*')
|
||||||
|
else:
|
||||||
|
LOG.debug('deleted file %s', fullpath)
|
||||||
|
tracker.delete(fname, None, '*working-copy*')
|
||||||
|
|
||||||
|
# Pretend anything in the index is part of the fake
|
||||||
|
# version "*working-copy*".
|
||||||
|
LOG.debug('scanning staged schanges')
|
||||||
|
changes = porcelain.get_tree_changes(self._repo)
|
||||||
|
for fname in changes['add']:
|
||||||
|
fname = fname.decode('utf-8')
|
||||||
|
tracker.add(fname, None, '*working-copy*')
|
||||||
|
for fname in changes['modify']:
|
||||||
|
fname = fname.decode('utf-8')
|
||||||
|
tracker.modify(fname, None, '*working-copy*')
|
||||||
|
for fname in changes['delete']:
|
||||||
|
fname = fname.decode('utf-8')
|
||||||
|
tracker.delete(fname, None, '*working-copy*')
|
||||||
|
|
||||||
|
# Process the git commit history.
|
||||||
for counter, entry in enumerate(self._topo_traversal(branch), 1):
|
for counter, entry in enumerate(self._topo_traversal(branch), 1):
|
||||||
|
|
||||||
sha = entry.commit.id
|
sha = entry.commit.id
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import os.path
|
|||||||
import re
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
import time
|
import time
|
||||||
|
import unittest
|
||||||
|
|
||||||
from dulwich import diff_tree
|
from dulwich import diff_tree
|
||||||
from dulwich import objects
|
from dulwich import objects
|
||||||
@@ -529,6 +530,82 @@ class BasicTest(Base):
|
|||||||
results,
|
results,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_staged_file(self):
|
||||||
|
# Prove that we can get a file we have staged.
|
||||||
|
# Start with a standard commit and tag
|
||||||
|
self._make_python_package()
|
||||||
|
self.repo.git('tag', '-s', '-m', 'first tag', '1.0.0')
|
||||||
|
# Now stage a release note
|
||||||
|
n = self.get_note_num()
|
||||||
|
basename = 'staged-note-%016x.yaml' % n
|
||||||
|
filename = os.path.join(self.reporoot, 'releasenotes', 'notes',
|
||||||
|
basename)
|
||||||
|
create._make_note_file(filename, 'staged note')
|
||||||
|
self.repo.git('add', filename)
|
||||||
|
status_results = self.repo.git('status')
|
||||||
|
self.addDetail('git status', text_content(status_results))
|
||||||
|
# Now run the scanner
|
||||||
|
self.scanner = scanner.Scanner(self.c)
|
||||||
|
raw_results = self.scanner.get_notes_by_version()
|
||||||
|
self.assertEqual(
|
||||||
|
{'*working-copy*': [
|
||||||
|
(os.path.join('releasenotes', 'notes', basename),
|
||||||
|
None)],
|
||||||
|
},
|
||||||
|
raw_results,
|
||||||
|
)
|
||||||
|
|
||||||
|
@unittest.skip('dulwich does not know how to identify new files')
|
||||||
|
def test_added_tagged_not_staged(self):
|
||||||
|
# Prove that we can get a file we have created but not staged.
|
||||||
|
# Start with a standard commit and tag
|
||||||
|
self._make_python_package()
|
||||||
|
self.repo.git('tag', '-s', '-m', 'first tag', '1.0.0')
|
||||||
|
# Now create a note without staging it
|
||||||
|
n = self.get_note_num()
|
||||||
|
basename = 'staged-note-%016x.yaml' % n
|
||||||
|
filename = os.path.join(self.reporoot, 'releasenotes', 'notes',
|
||||||
|
basename)
|
||||||
|
create._make_note_file(filename, 'staged note')
|
||||||
|
status_results = self.repo.git('status')
|
||||||
|
self.addDetail('git status', text_content(status_results))
|
||||||
|
# Now run the scanner
|
||||||
|
self.scanner = scanner.Scanner(self.c)
|
||||||
|
raw_results = self.scanner.get_notes_by_version()
|
||||||
|
# Take the staged version of the file, but associate it with
|
||||||
|
# tagged version 1.0.0 because the file was added before that
|
||||||
|
# version.
|
||||||
|
self.assertEqual(
|
||||||
|
{'1.0.0': [(os.path.join('releasenotes', 'notes', basename),
|
||||||
|
None)],
|
||||||
|
},
|
||||||
|
raw_results,
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_modified_tagged_not_staged(self):
|
||||||
|
# Prove that we can get a file we have changed but not staged.
|
||||||
|
# Start with a standard commit and tag
|
||||||
|
self._make_python_package()
|
||||||
|
f1 = self._add_notes_file('slug1')
|
||||||
|
self.repo.git('tag', '-s', '-m', 'first tag', '1.0.0')
|
||||||
|
# Now modify the note
|
||||||
|
fullpath = os.path.join(self.repo.reporoot, f1)
|
||||||
|
with open(fullpath, 'w') as f:
|
||||||
|
f.write('modified first note')
|
||||||
|
status_results = self.repo.git('status')
|
||||||
|
self.addDetail('git status', text_content(status_results))
|
||||||
|
# Now run the scanner
|
||||||
|
self.scanner = scanner.Scanner(self.c)
|
||||||
|
raw_results = self.scanner.get_notes_by_version()
|
||||||
|
# Take the staged version of the file, but associate it with
|
||||||
|
# tagged version 1.0.0 because the file was added before that
|
||||||
|
# version.
|
||||||
|
self.assertEqual(
|
||||||
|
{'1.0.0': [(f1, None)],
|
||||||
|
},
|
||||||
|
raw_results,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class FileContentsTest(Base):
|
class FileContentsTest(Base):
|
||||||
|
|
||||||
@@ -597,6 +674,19 @@ class FileContentsTest(Base):
|
|||||||
contents,
|
contents,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_staged_file(self):
|
||||||
|
# Prove we are not picking up the contents from the local
|
||||||
|
# filesystem outside of the git history.
|
||||||
|
f1 = self._add_notes_file(contents='initial-contents')
|
||||||
|
with open(os.path.join(self.reporoot, f1), 'w') as f:
|
||||||
|
f.write('new contents for file')
|
||||||
|
r = scanner.RenoRepo(self.reporoot)
|
||||||
|
contents = r.get_file_at_commit(f1, None)
|
||||||
|
self.assertEqual(
|
||||||
|
'new contents for file',
|
||||||
|
contents,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class PreReleaseTest(Base):
|
class PreReleaseTest(Base):
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user