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
|
||||
|
||||
from dulwich import diff_tree
|
||||
from dulwich import index as d_index
|
||||
from dulwich import objects
|
||||
from dulwich import porcelain
|
||||
from dulwich import repo
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
@@ -423,7 +425,23 @@ class RenoRepo(repo.Repo):
|
||||
return tree
|
||||
|
||||
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
|
||||
# input SHA, then look through the items in the tree to find
|
||||
# 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)
|
||||
if current_version not in versions_by_date:
|
||||
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
|
||||
# which we have seen a given note's unique id.
|
||||
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):
|
||||
|
||||
sha = entry.commit.id
|
||||
|
@@ -20,6 +20,7 @@ import os.path
|
||||
import re
|
||||
import subprocess
|
||||
import time
|
||||
import unittest
|
||||
|
||||
from dulwich import diff_tree
|
||||
from dulwich import objects
|
||||
@@ -529,6 +530,82 @@ class BasicTest(Base):
|
||||
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):
|
||||
|
||||
@@ -597,6 +674,19 @@ class FileContentsTest(Base):
|
||||
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):
|
||||
|
||||
|
Reference in New Issue
Block a user