Rename hpgit to git-upstream, also changing its license

* rename hpgit to git-upstream
* rename import-upstream commadn to import
* change all occurrences of hpgit and import-upstream in code,
  comments and tests
* code cleanup (remove some typos, improve PEP8 compliance)
* change license from "HP propietary" to "Apache License v2.0"

Change-Id: Ia4f00d662d79ac9725316027a65f4d23ebbd0f02
JIRA:CICD-1319
JIRA:CICD-1318
This commit is contained in:
Davide Guerri 2014-03-03 14:09:21 +00:00
parent 59a131eda5
commit f2e38df455
45 changed files with 728 additions and 402 deletions

2
.gitignore vendored
View File

@ -24,7 +24,7 @@ var/
*.egg-info/ *.egg-info/
.installed.cfg .installed.cfg
*.egg *.egg
hpgit.1 git-upstream.1
# Installer logs # Installer logs
pip-log.txt pip-log.txt

175
LICENSE Normal file
View File

@ -0,0 +1,175 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.

12
README
View File

@ -1,8 +1,12 @@
hpgit is a Python application providing commands to support usage of git for git-upstream is a Python application providing commands to support rebasing of
HP Cloud projects (i.e. feature branch creation/finishing, release local-carried patches on top of upstream repositories.
starting/finishing). The operations are performed using Git commands.
hpgit is intended to make use of multiple configuration files to specify git-upstream provides commands to support usage of git for subjects who need
to integrate big upstream projects in their environment (i.e. feature branch
creation/finishing, release starting/finishing). The operations are performed
using Git commands.
git-upstream is intended to make use of multiple configuration files to specify
project, team and individual preferences. This allows for variations in similar project, team and individual preferences. This allows for variations in similar
workflows to be supported, without needing developers from different projects workflows to be supported, without needing developers from different projects
to be aware of the specific operations need for other projects. to be aware of the specific operations need for other projects.

View File

@ -1 +1 @@
eval "$(register-python-argcomplete git-hp)" eval "$(register-python-argcomplete git-upstream)"

View File

@ -1,11 +1,18 @@
# #
# Copyright (c) 2012, 2013 Hewlett-Packard Development Company, L.P. # Copyright (c) 2012, 2013, 2014 Hewlett-Packard Development Company, L.P.
# #
# Confidential computer software. Valid license from HP required for # Licensed under the Apache License, Version 2.0 (the "License");
# possession, use or copying. Consistent with FAR 12.211 and 12.212, # you may not use this file except in compliance with the License.
# Commercial Computer Software, Computer Software Documentation, and # You may obtain a copy of the License at
# Technical Data for Commercial Items are licensed to the U.S. Government #
# under vendor's standard commercial license. # http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# #
""" Automatically generate the man page from argparse""" """ Automatically generate the man page from argparse"""
@ -14,17 +21,17 @@ import datetime
import argparse import argparse
from distutils.command.build import build from distutils.command.build import build
from distutils.core import Command from distutils.core import Command
from distutils.errors import DistutilsOptionError
class create_manpage(Command):
class CreateManpage(Command):
user_options = [] user_options = []
def initialize_options(self): def initialize_options(self):
from ghp import main from git_upstream import main
self._output = self.distribution.get_name() + '.1' self._output = self.distribution.get_name() + '.1'
self._seealso = ["git:1"] self._see_also = ["git:1"]
self._today = datetime.date.today() self._today = datetime.date.today()
self._commands, self._parser = main.get_parser() self._commands, self._parser = main.get_parser()
self._parser.formatter = ManPageFormatter() self._parser.formatter = ManPageFormatter()
@ -37,22 +44,23 @@ class create_manpage(Command):
def _write_header(self): def _write_header(self):
version = self.distribution.get_version() version = self.distribution.get_version()
appname = self.distribution.get_name() app_name = self.distribution.get_name()
ret = [] ret = list()
ret.append('.TH %s 1 %s "%s v.%s"\n' % (self._markup(appname), ret.append('.TH %s 1 %s "%s v.%s"\n' % (self._markup(app_name),
self._today.strftime('%Y\\-%m\\-%d'), self._today.strftime(
appname, version)) '%Y\\-%m\\-%d'),
app_name, version))
description = self.distribution.get_description() description = self.distribution.get_description()
if description: if description:
name = self._markup('%s - %s' % (self._markup(appname), name = self._markup('%s - %s' % (app_name,
description.splitlines()[0])) description.splitlines()[0]))
else: else:
name = self._markup(appname) name = app_name
ret.append('.SH NAME\n%s\n' % name) ret.append('.SH NAME\n%s\n' % name)
synopsis = self._parser.format_help() synopsis = self._parser.format_help()
if synopsis: if synopsis:
synopsis = synopsis.replace('%s ' % appname, '') synopsis = synopsis.replace('%s ' % app_name, '')
ret.append('.SH SYNOPSIS\n.B %s\n%s\n' % (self._markup(appname), ret.append('.SH SYNOPSIS\n.B %s\n%s\n' % (app_name,
synopsis)) synopsis))
long_desc = self.distribution.get_long_description() long_desc = self.distribution.get_long_description()
if long_desc: if long_desc:
@ -69,12 +77,12 @@ class create_manpage(Command):
return ''.join(ret) return ''.join(ret)
def _write_seealso (self): def _write_see_also(self):
ret = [] ret = []
if self._seealso is not None: if self._see_also is not None:
ret.append('.SH "SEE ALSO"\n') ret.append('.SH "SEE ALSO"\n')
for i in self._seealso: for i in self._see_also:
name, sect = i.split(":") name, sect = i.split(":")
if len(ret) > 1: if len(ret) > 1:
@ -86,20 +94,20 @@ class create_manpage(Command):
def _write_footer(self): def _write_footer(self):
ret = [] ret = []
appname = self.distribution.get_name() app_name = self.distribution.get_name()
author = '%s <%s>' % (self.distribution.get_author(), author = '%s <%s>' % (self.distribution.get_author(),
self.distribution.get_author_email()) self.distribution.get_author_email())
ret.append(('.SH AUTHORS\n.B %s\nwas written by %s.\n' ret.append(('.SH AUTHORS\n.B %s\nwas written by %s.\n'
% (self._markup(appname), self._markup(author)))) % (self._markup(app_name), self._markup(author))))
return ''.join(ret) return ''.join(ret)
def run(self): def run(self):
manpage = [] manpage = list()
manpage.append(self._write_header()) manpage.append(self._write_header())
manpage.append(self._write_options()) manpage.append(self._write_options())
manpage.append(self._write_footer()) manpage.append(self._write_footer())
manpage.append(self._write_seealso()) manpage.append(self._write_see_also())
stream = open(self._output, 'w') stream = open(self._output, 'w')
stream.write(''.join(manpage)) stream.write(''.join(manpage))
stream.close() stream.close()
@ -115,26 +123,12 @@ class ManPageFormatter(argparse.ArgumentDefaultsHelpFormatter):
argparse.HelpFormatter.__init__(self, indent_increment, argparse.HelpFormatter.__init__(self, indent_increment,
max_help_position, width, short_first) max_help_position, width, short_first)
def _markup(self, txt): @staticmethod
def _markup(txt):
return txt.replace('-', '\\-') return txt.replace('-', '\\-')
def format_usage(self, usage): def format_usage(self, usage):
return self._markup(usage) return ManPageFormatter._markup(usage)
def format_heading(self, heading):
if self.level == 0:
return ''
return '.TP\n%s\n' % self._markup(heading.upper())
def format_option(self, option):
result = []
opts = self.option_strings[option]
result.append('.TP\n.B %s\n' % self._markup(opts))
if option.help:
help_text = '%s\n' % self._markup(self.expand_default(option))
result.append(help_text)
return ''.join(result)
build.sub_commands.append(('create_manpage', None)) build.sub_commands.append(('create_manpage', None))

6
debian/changelog vendored
View File

@ -1,5 +1,5 @@
hpgit (0.0.1) UNRELEASED; urgency=low git-upstream (1.0.0) First public release; urgency=low
* UNRELEASED * First public hp-upstream release
-- Darragh Bailey <dbailey@hp.com> Fri, 20 Jan 2012 10:02:30 +0000 -- Davide Guerri <davide.guerri@hp.com> Fri, 3 Mar 2014 13:21:30 +0000

12
debian/control vendored
View File

@ -1,7 +1,7 @@
Source: hpgit Source: git-upstream
Section: vcs Section: vcs
Priority: optional Priority: optional
Maintainer: Darragh Bailey <dbailey@hp.com> Maintainer: Davide Guerri <davide.guerri@hp.com>
Build-Depends: debhelper (>= 7.0.50~), Build-Depends: debhelper (>= 7.0.50~),
python-all-dev (>= 2.6.6-3~) python-all-dev (>= 2.6.6-3~)
Build-Depends-Indep: python-git, Build-Depends-Indep: python-git,
@ -9,7 +9,7 @@ Build-Depends-Indep: python-git,
XS-Python-Version: >=2.6 XS-Python-Version: >=2.6
Standards-Version: 3.9.3 Standards-Version: 3.9.3
Package: hpgit Package: git-upstream
Architecture: all Architecture: all
Section: python Section: python
XB-Python-Version: ${python:Versions} XB-Python-Version: ${python:Versions}
@ -18,6 +18,8 @@ Depends: python-git
${misc:Depends}, ${misc:Depends},
${python:Depends} ${python:Depends}
Provides: ${python:Provides} Provides: ${python:Provides}
Description: Git extensions for the HPCS workflow Description: Git extensions which ease the rebasing of local-carried patches
on top of upstream repositories.
Git extensions to provide high-level abstraction for complex operations Git extensions to provide high-level abstraction for complex operations
that support the HPCS workflow. that support the rebasing of local-carried patches on top of upstream
repositories.

31
debian/copyright vendored
View File

@ -1,17 +1,26 @@
Format: http://dep.debian.net/deps/dep5 Format: http://dep.debian.net/deps/dep5
Source: https://gerrit.hpcloud.net/p/automation/hpgit.git Source: https://xxx
Files: * Files: *
Copyright: 2012 Hewlett-Packard Development Company, L.P. Copyright (c) 2012, 2013, 2014 Hewlett-Packard Development Company, L.P.
License: Other/Proprietary License: Apache-2
Confidential computer software. Valid license from HP required for Licensed under the Apache License, Version 2.0 (the "License");
possession, use or copying. Consistent with FAR 12.211 and 12.212, you may not use this file except in compliance with the License.
Commercial Computer Software, Computer Software Documentation, and You may obtain a copy of the License at
Technical Data for Commercial Items are licensed to the U.S. Government .
under vendor's standard commercial license. http://www.apache.org/licenses/LICENSE-2.0
.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied.
See the License for the specific language governing permissions and
limitations under the License.
.
On Debian-based systems the full text of the Apache version 2.0 license
can be found in `/usr/share/common-licenses/Apache-2.0'.
Files: git_upstream/subcommand.py git_upstream/version.py git_upstream/commands/__init__.py
Files: ghp/subcommand.py ghp/version.py ghp/commands/__init__.py
Copyright: 2011, 2012 OpenStack LLC. Copyright: 2011, 2012 OpenStack LLC.
License: Apache-2 License: Apache-2
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
@ -29,6 +38,6 @@ License: Apache-2
On Debian-based systems the full text of the Apache version 2.0 license On Debian-based systems the full text of the Apache version 2.0 license
can be found in `/usr/share/common-licenses/Apache-2.0'. can be found in `/usr/share/common-licenses/Apache-2.0'.
Comment: Comment:
In the case of ghp/version.py and ghp/commands/__init__.py only part of In the case of git_upstream/version.py and git_upstream/commands/__init__.py only part of
the files are copyright, and as such are marked inline as being taken the files are copyright, and as such are marked inline as being taken
from another project. from another project.

View File

@ -10,7 +10,7 @@ source $BASE_DIR/libs/utils.lib
function test_version_output() { function test_version_output() {
log DEBUG "Starting $TEST_NAME::$FUNCNAME" log DEBUG "Starting $TEST_NAME::$FUNCNAME"
git-hp --version >/dev/null 2>&1 git-upstream --version >/dev/null 2>&1
return $? return $?
} }

View File

@ -11,15 +11,15 @@ function test_help_output() {
local com="$1" local com="$1"
log DEBUG "Starting $TEST_NAME::$FUNCNAME command $com" log DEBUG "Starting $TEST_NAME::$FUNCNAME command $com"
help1=$(git-hp${com:+ }${com} --help) help1=$(git-upstream${com:+ }${com} --help)
help2=$(git-hp${com:+ }${com} -h) help2=$(git-upstream${com:+ }${com} -h)
help3=$(git-hp help${com:+ }${com}) help3=$(git-upstream help${com:+ }${com})
[ -z "$help1" -o -z "$help2" -o -z "$help3" -o \ [ -z "$help1" -o -z "$help2" -o -z "$help3" -o \
"$help1" != "$help2" -o "$help2" != "$help3" ] && return 1 || return 0 "$help1" != "$help2" -o "$help2" != "$help3" ] && return 1 || return 0
} }
for com in "" "import-upstream" "drop" "supersede" ; do for com in "" "import" "drop" "supersede" ; do
test_help_output $com && log INFO "test_help_output::${com:-null} passed." || \ test_help_output $com && log INFO "test_help_output::${com:-null} passed." || \
log ERROR "test_help_output::${com:-null} failed!" log ERROR "test_help_output::${com:-null} failed!"
done done

View File

@ -17,7 +17,7 @@ TEST_REBASE_REF="fd3524e1b7353cda228b6fb73c3a2d34a4fee4de"
function test_no_local_changes() { function test_no_local_changes() {
log DEBUG "Starting $TEST_NAME::$FUNCNAME" log DEBUG "Starting $TEST_NAME::$FUNCNAME"
prepare_for_hpgit $TEST_DIR $REPO_NAME $UPSTREAM_REPO $TEST_BASE_REF \ prepare_for_git_upstream $TEST_DIR $REPO_NAME $UPSTREAM_REPO $TEST_BASE_REF \
$TEST_NAME $TEST_NAME
pushd $TEST_DIR/$REPO_NAME >/dev/null pushd $TEST_DIR/$REPO_NAME >/dev/null
@ -35,7 +35,7 @@ function test_no_local_changes() {
log DEBUG "Rebasing local patches onto upstream version $TEST_REBASE_REF" log DEBUG "Rebasing local patches onto upstream version $TEST_REBASE_REF"
git branch import/$TEST_NAME-new $TEST_REBASE_REF --quiet || return 1 git branch import/$TEST_NAME-new $TEST_REBASE_REF --quiet || return 1
local result="$(git-hp import-upstream import/$TEST_NAME-new)" local result="$(git-upstream import import/$TEST_NAME-new)"
echo "$result" | grep "There are no local changes to be applied!" >/dev/null echo "$result" | grep "There are no local changes to be applied!" >/dev/null

View File

@ -18,7 +18,7 @@ SUCCESS_SHA1="e1dfee279aa5b6b05296a97b4eba8dde0b6eea4b ?-"
function test_simple_rebase() { function test_simple_rebase() {
log DEBUG "Starting $TEST_NAME::$FUNCNAME" log DEBUG "Starting $TEST_NAME::$FUNCNAME"
prepare_for_hpgit $TEST_DIR $REPO_NAME $UPSTREAM_REPO $TEST_BASE_REF \ prepare_for_git_upstream $TEST_DIR $REPO_NAME $UPSTREAM_REPO $TEST_BASE_REF \
$TEST_NAME $TEST_NAME
pushd $TEST_DIR/$REPO_NAME >/dev/null pushd $TEST_DIR/$REPO_NAME >/dev/null
@ -56,7 +56,7 @@ EOP
log DEBUG "Rebasing local patches onto upstream version $TEST_REBASE_REF" log DEBUG "Rebasing local patches onto upstream version $TEST_REBASE_REF"
git branch import/$TEST_NAME-new $TEST_REBASE_REF --quiet || return 1 git branch import/$TEST_NAME-new $TEST_REBASE_REF --quiet || return 1
git-hp import-upstream import/$TEST_NAME-new >/dev/null || return 1 git-upstream import import/$TEST_NAME-new >/dev/null || return 1
local test_sha1="$(git show --numstat | tail -9 | shasum -p -)" local test_sha1="$(git show --numstat | tail -9 | shasum -p -)"
if [ "$test_sha1" != "$SUCCESS_SHA1" ] if [ "$test_sha1" != "$SUCCESS_SHA1" ]

View File

@ -17,7 +17,7 @@ INVALID_CHID="I0123456789abcdef0123456789abcdef01234567"
SUCCESS_SHA1="b8c16b3dd8883d02b4b65882ad5467c9f5e7beb9 ?-" SUCCESS_SHA1="b8c16b3dd8883d02b4b65882ad5467c9f5e7beb9 ?-"
function _common() { function _common() {
prepare_for_hpgit $TEST_DIR $REPO_NAME $UPSTREAM_REPO $TEST_BASE_REF \ prepare_for_git_upstream $TEST_DIR $REPO_NAME $UPSTREAM_REPO $TEST_BASE_REF \
$TEST_NAME $TEST_NAME
pushd $TEST_DIR/$REPO_NAME >/dev/null pushd $TEST_DIR/$REPO_NAME >/dev/null
@ -66,10 +66,10 @@ function test_existing_changeid() {
local commit_sha1=$(git log -1 --format='%H') local commit_sha1=$(git log -1 --format='%H')
git-hp supersede $commit_sha1 $VALID_CHID -u import/$TEST_NAME-new \ git-upstream supersede $commit_sha1 $VALID_CHID -u import/$TEST_NAME-new \
>/dev/null || return 1 >/dev/null || return 1
git-hp import-upstream import/$TEST_NAME-new >/dev/null || return 1 git-upstream import import/$TEST_NAME-new >/dev/null || return 1
git show --numstat | grep '0\s\s*1\s\s*nothing' >/dev/null git show --numstat | grep '0\s\s*1\s\s*nothing' >/dev/null
if [ "$?" -ne 0 ]; then if [ "$?" -ne 0 ]; then
@ -87,7 +87,7 @@ function test_non_existing_changeid() {
local commit_sha1=$(git log -1 --format='%H') local commit_sha1=$(git log -1 --format='%H')
git-hp supersede $commit_sha1 $INVALID_CHID -u import/$TEST_NAME-new 2>&1 | \ git-upstream supersede $commit_sha1 $INVALID_CHID -u import/$TEST_NAME-new 2>&1 | \
grep "CRITICAL: Change-Id '$INVALID_CHID' not found in branch \ grep "CRITICAL: Change-Id '$INVALID_CHID' not found in branch \
'import/$TEST_NAME-new'" >/dev/null 'import/$TEST_NAME-new'" >/dev/null
if [ "$?" -ne 0 ]; then if [ "$?" -ne 0 ]; then
@ -105,10 +105,10 @@ function test_non_existing_changeid_force() {
local commit_sha1=$(git log -1 --format='%H') local commit_sha1=$(git log -1 --format='%H')
git-hp supersede $commit_sha1 $INVALID_CHID -u import/$TEST_NAME-new -f \ git-upstream supersede $commit_sha1 $INVALID_CHID -u import/$TEST_NAME-new -f \
>/dev/null || return 1 >/dev/null || return 1
git-hp -vv import-upstream import/$TEST_NAME-new | \ git-upstream -vv import import/$TEST_NAME-new | \
grep -e "Including commit '[0-9a-f][0-9a-f]* Add nothing'" \ grep -e "Including commit '[0-9a-f][0-9a-f]* Add nothing'" \
>/dev/null >/dev/null
if [ "$?" -ne 0 ]; then if [ "$?" -ne 0 ]; then
@ -126,10 +126,10 @@ function test_multiple_changeids() {
local commit_sha1=$(git log -1 --format='%H') local commit_sha1=$(git log -1 --format='%H')
git-hp supersede $commit_sha1 $VALID_CHID $VALID_CHID2 \ git-upstream supersede $commit_sha1 $VALID_CHID $VALID_CHID2 \
-u import/$TEST_NAME-new >/dev/null || return 1 -u import/$TEST_NAME-new >/dev/null || return 1
git-hp -vv import-upstream import/$TEST_NAME-new >/dev/null || return 1 git-upstream -vv import import/$TEST_NAME-new >/dev/null || return 1
git show --numstat | grep '0\s\s*1\s\s*nothing' >/dev/null git show --numstat | grep '0\s\s*1\s\s*nothing' >/dev/null
if [ "$?" -ne 0 ]; then if [ "$?" -ne 0 ]; then
@ -147,7 +147,7 @@ function test_one_non_exsisting_changeid() {
local commit_sha1=$(git log -1 --format='%H') local commit_sha1=$(git log -1 --format='%H')
git-hp supersede $commit_sha1 $VALID_CHID $INVALID_CHID \ git-upstream supersede $commit_sha1 $VALID_CHID $INVALID_CHID \
-u import/$TEST_NAME-new 2>&1 | \ -u import/$TEST_NAME-new 2>&1 | \
grep "CRITICAL: Change-Id '$INVALID_CHID' not found in branch \ grep "CRITICAL: Change-Id '$INVALID_CHID' not found in branch \
'import/$TEST_NAME-new'" >/dev/null 'import/$TEST_NAME-new'" >/dev/null

View File

@ -14,7 +14,7 @@ TEST_REBASE_REF="fd3524e1b7353cda228b6fb73c3a2d34a4fee4de"
SUCCESS_SHA1="b8c16b3dd8883d02b4b65882ad5467c9f5e7beb9 ?-" SUCCESS_SHA1="b8c16b3dd8883d02b4b65882ad5467c9f5e7beb9 ?-"
function _common() { function _common() {
prepare_for_hpgit $TEST_DIR $REPO_NAME $UPSTREAM_REPO $TEST_BASE_REF \ prepare_for_git_upstream $TEST_DIR $REPO_NAME $UPSTREAM_REPO $TEST_BASE_REF \
$TEST_NAME $TEST_NAME
pushd $TEST_DIR/$REPO_NAME >/dev/null pushd $TEST_DIR/$REPO_NAME >/dev/null
@ -63,9 +63,9 @@ function test_new() {
local commit_sha1=$(git log -1 --format='%H') local commit_sha1=$(git log -1 --format='%H')
git-hp drop $commit_sha1 git-upstream drop $commit_sha1
git-hp import-upstream import/$TEST_NAME-new >/dev/null || return 1 git-upstream import import/$TEST_NAME-new >/dev/null || return 1
git show --numstat | grep '0\s\s*1\s\s*nothing' >/dev/null git show --numstat | grep '0\s\s*1\s\s*nothing' >/dev/null
if [ "$?" -ne 0 ]; then if [ "$?" -ne 0 ]; then
@ -83,9 +83,9 @@ function test_already_present() {
local commit_sha1=$(git log -1 --format='%H') local commit_sha1=$(git log -1 --format='%H')
git-hp drop $commit_sha1 git-upstream drop $commit_sha1
git-hp drop $commit_sha1 2>&1 | \ git-upstream drop $commit_sha1 2>&1 | \
grep "Drop note has not been added as '$commit_sha1' already has one" \ grep "Drop note has not been added as '$commit_sha1' already has one" \
>/dev/null >/dev/null
if [ "$?" -ne 0 ]; then if [ "$?" -ne 0 ]; then

View File

@ -4,8 +4,8 @@ Just run
run_tests.sh run_tests.sh
That script will install a virtual env with hpgit (from the current repo clone) That script will install a virtual env with git-upstream (from the current repo
and will run every script which name match the following regex: clone) and will run every script which name match the following regex:
([0-9]{3})-test_(.+).sh ([0-9]{3})-test_(.+).sh
@ -15,7 +15,7 @@ It's also possible to run single tests creating a test directory and running
BASE_TEST_DIR=<your base test dir> 0xx-test_<your test name>.sh BASE_TEST_DIR=<your base test dir> 0xx-test_<your test name>.sh
But that will need a git-hp executable in yout path. But that will need a git-upstream executable in your path.
# Creating more tests # Creating more tests
@ -57,9 +57,9 @@ TEST_DIR Testing directory. Objects pertaining a test should be
TEST_NAME The name of current test. Extracted from the test filename. TEST_NAME The name of current test. Extracted from the test filename.
prepare_for_hpgit() Using the current hpgit repo, create an initial prepare_for_git_upstream() Using the current git-upstream repo, create an
configuration useful for testing hp-git. After invoking it initial onfiguration useful for testing hp-git.
a "$TEST_DIR/$REPO_NAME" After invoking it a "$TEST_DIR/$REPO_NAME"
## Environment variable used by the test framework ## Environment variable used by the test framework

View File

@ -22,7 +22,7 @@ mkdir -p "$TEST_DIR"
# Define an handler for clean_up # Define an handler for clean_up
trap "_clean_up; exit 0" EXIT trap "_clean_up; exit 0" EXIT
function prepare_for_hpgit() { function prepare_for_git_upstream() {
local TEST_DIR="$1" local TEST_DIR="$1"
local REPO_NAME="$2" local REPO_NAME="$2"
local UPSTREAM_REPO="$3" local UPSTREAM_REPO="$3"

View File

@ -59,7 +59,7 @@ log DEBUG "Initializing testbed"
check_app virtualenv check_app virtualenv
log DEBUG "Creating virtualenv for hpgit" log DEBUG "Creating virtualenv for git-upstream"
rm -rf $BASE_TEST_DIR/virtualenv >/dev/null 2>&1 rm -rf $BASE_TEST_DIR/virtualenv >/dev/null 2>&1
virtualenv $BASE_TEST_DIR/virtualenv >/dev/null 2>&1 virtualenv $BASE_TEST_DIR/virtualenv >/dev/null 2>&1
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
@ -67,7 +67,7 @@ if [ $? -ne 0 ]; then
exit 1 exit 1
fi fi
log DEBUG "Activating virtualenv for hpgit" log DEBUG "Activating virtualenv for git-upstream"
source $BASE_TEST_DIR/virtualenv/bin/activate source $BASE_TEST_DIR/virtualenv/bin/activate
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
@ -75,7 +75,7 @@ if [ $? -ne 0 ]; then
exit 1 exit 1
fi fi
log DEBUG "Installing hpgit" log DEBUG "Installing git-upstream"
easy_install -q $INSTALL_DIR >/dev/null 2>&1 easy_install -q $INSTALL_DIR >/dev/null 2>&1
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
log ERROR "hp git installation failed!" log ERROR "hp git installation failed!"

View File

@ -1,9 +0,0 @@
#
# Copyright (c) 2012, 2013 Hewlett-Packard Development Company, L.P.
#
# Confidential computer software. Valid license from HP required for
# possession, use or copying. Consistent with FAR 12.211 and 12.212,
# Commercial Computer Software, Computer Software Documentation, and
# Technical Data for Commercial Items are licensed to the U.S. Government
# under vendor's standard commercial license.
#

View File

@ -1,16 +0,0 @@
#
# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
#
# Confidential computer software. Valid license from HP required for
# possession, use or copying. Consistent with FAR 12.211 and 12.212,
# Commercial Computer Software, Computer Software Documentation, and
# Technical Data for Commercial Items are licensed to the U.S. Government
# under vendor's standard commercial license.
#
"""Hpgit base error exception"""
class HpgitError(Exception):
"""Exception thrown by Hpgit classes"""
pass

View File

@ -1,11 +0,0 @@
#
# Copyright (c) 2012, 2013 Hewlett-Packard Development Company, L.P.
#
# Confidential computer software. Valid license from HP required for
# possession, use or copying. Consistent with FAR 12.211 and 12.212,
# Commercial Computer Software, Computer Software Documentation, and
# Technical Data for Commercial Items are licensed to the U.S. Government
# under vendor's standard commercial license.
#
from ghp.lib import note

View File

@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
#PYTHON_ARGCOMPLETE_OK #PYTHON_ARGCOMPLETE_OK
# #
# Copyright (c) 2012 Hewlett-Packard # Copyright (c) 2012, 2013, 2014 Hewlett-Packard Development Company, L.P.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -15,8 +15,9 @@
# implied. # implied.
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
#
from ghp.main import main from git_upstream.main import main
from sys import argv from sys import argv
if __name__ == '__main__': if __name__ == '__main__':

16
git_upstream/__init__.py Normal file
View File

@ -0,0 +1,16 @@
#
# Copyright (c) 2012, 2013, 2014 Hewlett-Packard Development Company, L.P.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

View File

@ -1,6 +1,6 @@
# #
# Copyright (c) 2011 OpenStack LLC. # Copyright (c) 2011 OpenStack LLC.
# Copyright (c) 2013 Hewlett-Packard # Copyright (c) 2012, 2013, 2014 Hewlett-Packard Development Company, L.P.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -14,6 +14,7 @@
# implied. # implied.
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
#
import os import os
import sys import sys
@ -29,7 +30,8 @@ def get_subcommands(subparsers):
# partially taken from python-keystoneclient # partially taken from python-keystoneclient
def _find_actions(subparsers, module_path): def _find_actions(subparsers, module_path):
subcommands = {} subcommands = {}
for mod in (p[:-len('.py')] for p in os.listdir(module_path) if p.endswith('.py')): for mod in (p[:-len('.py')] for p in os.listdir(module_path) if
p.endswith('.py')):
__import__(__name__ + '.' + mod) __import__(__name__ + '.' + mod)
module = sys.modules[__name__ + '.' + mod] module = sys.modules[__name__ + '.' + mod]
for attr in (a for a in dir(module) if a.startswith('do_')): for attr in (a for a in dir(module) if a.startswith('do_')):

View File

@ -1,25 +1,32 @@
# #
# Copyright (c) 2013, 2014 Hewlett-Packard Development Company, L.P. # Copyright (c) 2012, 2013, 2014 Hewlett-Packard Development Company, L.P.
# #
# Confidential computer software. Valid license from HP required for # Licensed under the Apache License, Version 2.0 (the "License");
# possession, use or copying. Consistent with FAR 12.211 and 12.212, # you may not use this file except in compliance with the License.
# Commercial Computer Software, Computer Software Documentation, and # You may obtain a copy of the License at
# Technical Data for Commercial Items are licensed to the U.S. Government #
# under vendor's standard commercial license. # http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# #
from ghp.errors import HpgitError from git_upstream.errors import GitUpstreamError
from ghp.log import LogDedentMixin from git_upstream.log import LogDedentMixin
from ghp.lib.utils import GitMixin from git_upstream.lib.utils import GitMixin
from ghp import subcommand, log from git_upstream import subcommand, log
from git import BadObject, util from git import BadObject
import inspect import inspect
import re import re
class DropError(HpgitError): class DropError(GitUpstreamError):
"""Exception thrown by L{Drop}""" """Exception thrown by L{Drop}"""
pass pass
@ -120,11 +127,11 @@ def do_drop(args):
""" """
Mark a commit as dropped. Mark a commit as dropped.
Marked commits will be skipped during the upstream rebasing process. Marked commits will be skipped during the upstream rebasing process.
See also the "git hp import-upstream" command. See also the "git upstream import" command.
""" """
logger = log.getLogger('%s.%s' % (__name__, logger = log.get_logger('%s.%s' % (__name__,
inspect.stack()[0][0].f_code.co_name)) inspect.stack()[0][0].f_code.co_name))
drop = Drop(git_object=args.commit, author=args.author) drop = Drop(git_object=args.commit, author=args.author)

View File

@ -1,19 +1,26 @@
# #
# Copyright (c) 2012, 2013 Hewlett-Packard Development Company, L.P. # Copyright (c) 2012, 2013, 2014 Hewlett-Packard Development Company, L.P.
# #
# Confidential computer software. Valid license from HP required for # Licensed under the Apache License, Version 2.0 (the "License");
# possession, use or copying. Consistent with FAR 12.211 and 12.212, # you may not use this file except in compliance with the License.
# Commercial Computer Software, Computer Software Documentation, and # You may obtain a copy of the License at
# Technical Data for Commercial Items are licensed to the U.S. Government #
# under vendor's standard commercial license. # http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# #
from ghp.errors import HpgitError from git_upstream.errors import GitUpstreamError
from ghp.log import LogDedentMixin from git_upstream.log import LogDedentMixin
from ghp.lib.utils import GitMixin from git_upstream.lib.utils import GitMixin
from ghp.lib.rebaseeditor import RebaseEditor from git_upstream.lib.rebaseeditor import RebaseEditor
from ghp import subcommand, log from git_upstream import subcommand, log
from ghp.lib.searchers import UpstreamMergeBaseSearcher from git_upstream.lib.searchers import UpstreamMergeBaseSearcher
from abc import ABCMeta, abstractmethod from abc import ABCMeta, abstractmethod
from collections import Sequence from collections import Sequence
@ -22,7 +29,7 @@ from git import GitCommandError
import inspect import inspect
class ImportUpstreamError(HpgitError): class ImportUpstreamError(GitUpstreamError):
"""Exception thrown by L{ImportUpstream}""" """Exception thrown by L{ImportUpstream}"""
pass pass
@ -35,7 +42,8 @@ class ImportUpstream(LogDedentMixin, GitMixin):
""" """
def __init__(self, branch=None, upstream=None, import_branch=None, def __init__(self, branch=None, upstream=None, import_branch=None,
extra_branches=[], *args, **kwargs): extra_branches=None, *args, **kwargs):
if not extra_branches: extra_branches = []
self._branch = branch self._branch = branch
self._upstream = upstream self._upstream = upstream
self._import_branch = import_branch self._import_branch = import_branch
@ -285,7 +293,8 @@ class ImportUpstream(LogDedentMixin, GitMixin):
# abort result for if the user needs to abort the rebase of this branch # abort result for if the user needs to abort the rebase of this branch
# onto the new point upstream that was requested to import from. # onto the new point upstream that was requested to import from.
try: try:
self._linearise(self.import_branch, strategy, strategy.searcher.commit) self._linearise(self.import_branch, strategy,
strategy.searcher.commit)
except: except:
# Could ask user if they want to try and use the non clean route # Could ask user if they want to try and use the non clean route
# provided they don't mind that 'git rebase --abort' will result # provided they don't mind that 'git rebase --abort' will result
@ -412,24 +421,27 @@ class ImportStrategiesFactory(object):
__strategies = None __strategies = None
@classmethod @classmethod
def createStrategy(cls, type, *args, **kwargs): def create_strategy(cls, type, *args, **kwargs):
if type in cls.listStrategies(): if type in cls.list_strategies():
return cls.__strategies[type](*args, **kwargs) return cls.__strategies[type](*args, **kwargs)
else: else:
raise RuntimeError("No class implements the requested strategy: " raise RuntimeError("No class implements the requested strategy: "
"{0}".format(type)) "{0}".format(type))
@classmethod @classmethod
def listStrategies(cls): def list_strategies(cls):
cls.__strategies = {subclass._strategy: subclass cls.__strategies = {
for subclass in LocateChangesStrategy.__subclasses__() subclass._strategy: subclass
if subclass._strategy} for subclass in LocateChangesStrategy.__subclasses__()
if subclass._strategy}
return cls.__strategies.keys() return cls.__strategies.keys()
from ghp.lib.searchers import (NoMergeCommitFilter, ReverseCommitFilter, from git_upstream.lib.searchers import (NoMergeCommitFilter,
DiscardDuplicateGerritChangeId, ReverseCommitFilter,
SupersededCommitFilter, DroppedCommitFilter) DiscardDuplicateGerritChangeId,
SupersededCommitFilter,
DroppedCommitFilter)
class LocateChangesStrategy(GitMixin, Sequence): class LocateChangesStrategy(GitMixin, Sequence):
@ -459,7 +471,7 @@ class LocateChangesStrategy(GitMixin, Sequence):
return len(self.data) return len(self.data)
@classmethod @classmethod
def getName(cls): def get_strategy_name(cls):
return cls._strategy return cls._strategy
def filtered_iter(self): def filtered_iter(self):
@ -496,7 +508,7 @@ class LocateChangesWalk(LocateChangesStrategy):
def filtered_iter(self): def filtered_iter(self):
# may wish to make class used to remove duplicate objects configurable # may wish to make class used to remove duplicate objects configurable
# through hpgit specific 'git config' settings # through git-upstream specific 'git config' settings
if self.search_ref: if self.search_ref:
self.filters.append( self.filters.append(
DiscardDuplicateGerritChangeId(self.search_ref, DiscardDuplicateGerritChangeId(self.search_ref,
@ -512,27 +524,31 @@ class LocateChangesWalk(LocateChangesStrategy):
@subcommand.arg('-d', '--dry-run', dest='dry_run', action='store_true', @subcommand.arg('-d', '--dry-run', dest='dry_run', action='store_true',
default=False, default=False,
help='Only print out the list of commits that would be applied.') help='Only print out the list of commits that would be '
'applied.')
@subcommand.arg('-i', '--interactive', action='store_true', default=False, @subcommand.arg('-i', '--interactive', action='store_true', default=False,
help='Let the user edit the list of commits before applying.') help='Let the user edit the list of commits before applying.')
@subcommand.arg('-f', '--force', dest='force', required=False, action='store_true', @subcommand.arg('-f', '--force', dest='force', required=False,
default=False, action='store_true', default=False,
help='Force overwrite of existing import branch if it exists.') help='Force overwrite of existing import branch if it exists.')
@subcommand.arg('--merge', dest='merge', required=False, action='store_true', @subcommand.arg('--merge', dest='merge', required=False, action='store_true',
default=True, default=True,
help='Merge the resulting import branch into the target branch ' help='Merge the resulting import branch into the target branch '
'once complete') 'once complete')
@subcommand.arg('--no-merge', dest='merge', required=False, action='store_false', @subcommand.arg('--no-merge', dest='merge', required=False,
action='store_false',
help="Disable merge of the resulting import branch") help="Disable merge of the resulting import branch")
@subcommand.arg('-s', '--strategy', metavar='<strategy>', @subcommand.arg('-s', '--strategy', metavar='<strategy>',
choices=ImportStrategiesFactory.listStrategies(), choices=ImportStrategiesFactory.list_strategies(),
default=LocateChangesWalk.getName(), default=LocateChangesWalk.get_strategy_name(),
help='Use the given strategy to re-apply locally carried changes ' help='Use the given strategy to re-apply locally carried '
'to the import branch. (default: %(default)s)') 'changes to the import branch. (default: %(default)s)')
@subcommand.arg('--into', dest='branch', metavar='<branch>', default='HEAD', @subcommand.arg('--into', dest='branch', metavar='<branch>', default='HEAD',
help='Branch to take changes from, and replace with imported branch.') help='Branch to take changes from, and replace with imported '
'branch.')
@subcommand.arg('--import-branch', metavar='<import-branch>', @subcommand.arg('--import-branch', metavar='<import-branch>',
help='Name of import branch to use', default='import/{describe}') help='Name of import branch to use',
default='import/{describe}')
@subcommand.arg('upstream_branch', metavar='<upstream-branch>', nargs='?', @subcommand.arg('upstream_branch', metavar='<upstream-branch>', nargs='?',
default='upstream/master', default='upstream/master',
help='Upstream branch to import. Must be specified if ' help='Upstream branch to import. Must be specified if '
@ -540,7 +556,7 @@ class LocateChangesWalk(LocateChangesStrategy):
@subcommand.arg('branches', metavar='<branches>', nargs='*', @subcommand.arg('branches', metavar='<branches>', nargs='*',
help='Branches to additionally merge into the import branch ' help='Branches to additionally merge into the import branch '
'using default git merging behaviour') 'using default git merging behaviour')
def do_import_upstream(args): def do_import(args):
""" """
Import code from specified upstream branch. Import code from specified upstream branch.
@ -548,29 +564,30 @@ def do_import_upstream(args):
merges additional branches given as arguments. Current branch, unless merges additional branches given as arguments. Current branch, unless
overridden by the --into option, is used as the target branch from which a overridden by the --into option, is used as the target branch from which a
list of changes to apply onto the new import is constructed based on the list of changes to apply onto the new import is constructed based on the
the specificed strategy. the specified strategy.
Once complete it will merge and replace the contents of the target branch Once complete it will merge and replace the contents of the target branch
with those from the import branch, unless --no-merge is specified. with those from the import branch, unless --no-merge is specified.
""" """
logger = log.getLogger('%s.%s' % (__name__, logger = log.get_logger('%s.%s' % (__name__,
inspect.stack()[0][0].f_code.co_name)) inspect.stack()[0][0].f_code.co_name))
importupstream = ImportUpstream(branch=args.branch, import_upstream = ImportUpstream(branch=args.branch,
upstream=args.upstream_branch, upstream=args.upstream_branch,
import_branch=args.import_branch, import_branch=args.import_branch,
extra_branches=args.branches) extra_branches=args.branches)
logger.notice("Searching for previous import") logger.notice("Searching for previous import")
strategy = ImportStrategiesFactory.createStrategy( strategy = ImportStrategiesFactory.create_strategy(
args.strategy, branch=args.branch, search_ref=args.upstream_branch) args.strategy, branch=args.branch, search_ref=args.upstream_branch)
if len(strategy) == 0: if len(strategy) == 0:
raise ImportUpstreamError("Cannot find previous import") raise ImportUpstreamError("Cannot find previous import")
# if last commit in the strategy was a merge, then the additional branches that # if last commit in the strategy was a merge, then the additional branches
# were merged in previously can be extracted based on the commits merged. # that were merged in previously can be extracted based on the commits
# merged.
prev_import_merge = strategy[-1] prev_import_merge = strategy[-1]
if len(prev_import_merge.parents) > 1: if len(prev_import_merge.parents) > 1:
idx = next((idx for idx, commit in enumerate(prev_import_merge.parents) idx = next((idx for idx, commit in enumerate(prev_import_merge.parents)
@ -589,17 +606,18 @@ def do_import_upstream(args):
(c.summary[60:] and "...") (c.summary[60:] and "...")
for c in list(strategy.filtered_iter())] for c in list(strategy.filtered_iter())]
logger.notice("""\ logger.notice("""\
Requested a dry-run: printing the list of commit that should be rebased Requested a dry-run: printing the list of commit that should be
rebased
%s %s
""", "\n ".join(commit_list)) """, "\n ".join(commit_list))
return True return True
logger.notice("Starting import of upstream") logger.notice("Starting import of upstream")
importupstream.create_import(force=args.force) import_upstream.create_import(force=args.force)
logger.notice("Successfully created import branch") logger.notice("Successfully created import branch")
if not importupstream.apply(strategy, args.interactive): if not import_upstream.apply(strategy, args.interactive):
logger.notice("Import cancelled") logger.notice("Import cancelled")
return False return False
@ -611,14 +629,14 @@ def do_import_upstream(args):
return True return True
logger.notice("Merging import to requested branch '%s'", args.branch) logger.notice("Merging import to requested branch '%s'", args.branch)
if importupstream.finish(): if import_upstream.finish():
logger.notice( logger.notice(
"""\ """\
Successfully finished import: Successfully finished import:
target branch: '%s' target branch: '%s'
upstream branch: '%s' upstream branch: '%s'
import branch: '%s'""", args.branch, args.upstream_branch, import branch: '%s'""", args.branch, args.upstream_branch,
importupstream.import_branch) import_upstream.import_branch)
if args.branches: if args.branches:
for branch in args.branches: for branch in args.branches:
logger.notice(" extra branch: '%s'", branch, dedent=False) logger.notice(" extra branch: '%s'", branch, dedent=False)

View File

@ -1,18 +1,25 @@
# #
# Copyright (c) 2013, 2014 Hewlett-Packard Development Company, L.P. # Copyright (c) 2012, 2013, 2014 Hewlett-Packard Development Company, L.P.
# #
# Confidential computer software. Valid license from HP required for # Licensed under the Apache License, Version 2.0 (the "License");
# possession, use or copying. Consistent with FAR 12.211 and 12.212, # you may not use this file except in compliance with the License.
# Commercial Computer Software, Computer Software Documentation, and # You may obtain a copy of the License at
# Technical Data for Commercial Items are licensed to the U.S. Government #
# under vendor's standard commercial license. # http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# #
from ghp.errors import HpgitError from git_upstream.errors import GitUpstreamError
from ghp.log import LogDedentMixin from git_upstream.log import LogDedentMixin
from ghp.lib.utils import GitMixin from git_upstream.lib.utils import GitMixin
from ghp.lib.searchers import CommitMessageSearcher from git_upstream.lib.searchers import CommitMessageSearcher
from ghp import subcommand, log from git_upstream import subcommand, log
from git import BadObject, Head from git import BadObject, Head
@ -20,7 +27,7 @@ import inspect
import re import re
class SupersedeError(HpgitError): class SupersedeError(GitUpstreamError):
"""Exception thrown by L{Supersede}""" """Exception thrown by L{Supersede}"""
pass pass
@ -98,10 +105,10 @@ class Supersede(LogDedentMixin, GitMixin):
self.log.debug("Change-id '%s' found in commit '%s'" % self.log.debug("Change-id '%s' found in commit '%s'" %
(change_id, change_commit)) (change_id, change_commit))
except RuntimeError as e: except RuntimeError:
if force: if force:
self.log.warn("Warning: change-id '%s' not found in '%s'" % self.log.warn("Warning: change-id '%s' not found in '%s'" %
(change_id, upstream_branch)) (change_id, upstream_branch))
else: else:
raise SupersedeError( raise SupersedeError(
"Change-Id '%s' not found in branch '%s'" % "Change-Id '%s' not found in branch '%s'" %
@ -165,9 +172,9 @@ class Supersede(LogDedentMixin, GitMixin):
action='store_true', default=False, action='store_true', default=False,
help='Apply the commit mark even if one or more change ids ' help='Apply the commit mark even if one or more change ids '
'could not be found. Use this flag carefully as commits ' 'could not be found. Use this flag carefully as commits '
'will not be dropped during import-upstream command ' 'will not be dropped during import command execution as '
'execution as long as all associated change ids are ' 'long as all associated change ids are present in the '
'present in the local copy of the upstream branch') 'local copy of the upstream branch')
@subcommand.arg('-u', '--upstream-branch', metavar='<upstream-branch>', @subcommand.arg('-u', '--upstream-branch', metavar='<upstream-branch>',
dest='upstream_branch', required=False, dest='upstream_branch', required=False,
default='upstream/master', default='upstream/master',
@ -177,11 +184,11 @@ def do_supersede(args):
""" """
Mark a commit as superseded by a set of change-ids. Mark a commit as superseded by a set of change-ids.
Marked commits will be skipped during the upstream rebasing process. Marked commits will be skipped during the upstream rebasing process.
See also the "git hp import-upstream" command. See also the "git upstream import" command.
""" """
logger = log.getLogger('%s.%s' % (__name__, logger = log.get_logger('%s.%s' % (__name__,
inspect.stack()[0][0].f_code.co_name)) inspect.stack()[0][0].f_code.co_name))
supersede = Supersede(git_object=args.commit, change_ids=args.change_ids, supersede = Supersede(git_object=args.commit, change_ids=args.change_ids,
upstream_branch=args.upstream_branch, upstream_branch=args.upstream_branch,

23
git_upstream/errors.py Normal file
View File

@ -0,0 +1,23 @@
#
# Copyright (c) 2012, 2013, 2014 Hewlett-Packard Development Company, L.P.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
"""GitUpstream base error exception"""
class GitUpstreamError(Exception):
"""Exception thrown by GitUpstream classes"""
pass

View File

@ -0,0 +1,18 @@
#
# Copyright (c) 2012, 2013, 2014 Hewlett-Packard Development Company, L.P.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
from git_upstream.lib import note

View File

@ -1,7 +1,24 @@
from ghp.errors import HpgitError #
# Copyright (c) 2012, 2013, 2014 Hewlett-Packard Development Company, L.P.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
from git_upstream.errors import GitUpstreamError
from git import base, GitCommandError from git import base, GitCommandError
class NoteAlreadyExistsError(HpgitError): class NoteAlreadyExistsError(GitUpstreamError):
"""Exception thrown by note related commands""" """Exception thrown by note related commands"""
pass pass

View File

@ -1,30 +1,38 @@
# #
# Copyright (c) 2012, 2013 Hewlett-Packard Development Company, L.P. # Copyright (c) 2012, 2013, 2014 Hewlett-Packard Development Company, L.P.
# #
# Confidential computer software. Valid license from HP required for # Licensed under the Apache License, Version 2.0 (the "License");
# possession, use or copying. Consistent with FAR 12.211 and 12.212, # you may not use this file except in compliance with the License.
# Commercial Computer Software, Computer Software Documentation, and # You may obtain a copy of the License at
# Technical Data for Commercial Items are licensed to the U.S. Government #
# under vendor's standard commercial license. # http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# #
import git import git
from git import Commit, Repo from git import Commit, Repo
class HpgitCompatRepo(Repo): class GitUpstreamCompatRepo(Repo):
@property @property
def git_dir(self): def git_dir(self):
return self.path return self.path
if not hasattr(Repo, 'git_dir'): if not hasattr(Repo, 'git_dir'):
Repo = HpgitCompatRepo Repo = GitUpstreamCompatRepo
# Monkey patch old python-git library to use HpgitCompatRepo instead of Repo # Monkey patch old python-git library to use GitUpstreamCompatRepo instead
git.Repo = HpgitCompatRepo # of Repo
git.Repo = GitUpstreamCompatRepo
class HpgitCompatCommit(Commit): class GitUpstreamCompatCommit(Commit):
@classmethod @classmethod
def list_from_string(cls, repo, text): def list_from_string(cls, repo, text):
@ -61,7 +69,7 @@ class HpgitCompatCommit(Commit):
message = '\n'.join(messages) message = '\n'.join(messages)
commits.append(HpgitCompatCommit(repo, id=id, parents=parents, commits.append(GitUpstreamCompatCommit(repo, id=id, parents=parents,
tree=tree, author=author, tree=tree, author=author,
authored_date=authored_date, authored_date=authored_date,
committer=committer, committer=committer,
@ -95,6 +103,6 @@ class HpgitCompatCommit(Commit):
raise RuntimeError("Unexpected type returned from 'find_all'") raise RuntimeError("Unexpected type returned from 'find_all'")
if not hasattr(Commit, 'iter_items'): if not hasattr(Commit, 'iter_items'):
Commit = HpgitCompatCommit Commit = GitUpstreamCompatCommit
# monkey patch class so that Repo will use the patched class # monkey patch class so that Repo will use the patched class
git.commit.Commit = HpgitCompatCommit git.commit.Commit = GitUpstreamCompatCommit

View File

@ -1,16 +1,22 @@
# #
# Copyright (c) 2012, 2013 Hewlett-Packard Development Company, L.P. # Copyright (c) 2012, 2013, 2014 Hewlett-Packard Development Company, L.P.
# #
# Confidential computer software. Valid license from HP required for # Licensed under the Apache License, Version 2.0 (the "License");
# possession, use or copying. Consistent with FAR 12.211 and 12.212, # you may not use this file except in compliance with the License.
# Commercial Computer Software, Computer Software Documentation, and # You may obtain a copy of the License at
# Technical Data for Commercial Items are licensed to the U.S. Government #
# under vendor's standard commercial license. # http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# #
from ghp.lib.utils import GitMixin from git_upstream.lib.utils import GitMixin
from ghp.log import LogDedentMixin from git_upstream.log import LogDedentMixin
import ghp
from subprocess import call from subprocess import call
import os import os
@ -19,7 +25,7 @@ REBASE_EDITOR_SCRIPT = "rebase-editor.py"
# insure name of file will match any naming filters used by editors to # insure name of file will match any naming filters used by editors to
# enable syntax highlighting # enable syntax highlighting
REBASE_EDITOR_TODO = "hpgit/git-rebase-todo" REBASE_EDITOR_TODO = "git-upstream/git-rebase-todo"
TODO_EPILOGUE = """\ TODO_EPILOGUE = """\
@ -109,21 +115,22 @@ class RebaseEditor(GitMixin, LogDedentMixin):
if self.git_sequence_editor: if self.git_sequence_editor:
self._saveeditor = self.git_sequence_editor self._saveeditor = self.git_sequence_editor
if self._interactive == 'debug': if self._interactive == 'debug':
os.environ['HPGIT_GIT_SEQUENCE_EDITOR'] = self._saveeditor os.environ['GIT_UPSTREAM_GIT_SEQUENCE_EDITOR'] = \
self._saveeditor
os.environ['GIT_SEQUENCE_EDITOR'] = editor os.environ['GIT_SEQUENCE_EDITOR'] = editor
else: else:
self._saveeditor = self.git_editor self._saveeditor = self.git_editor
if self._interactive == 'debug': if self._interactive == 'debug':
os.environ['HPGIT_GIT_EDITOR'] = self._saveeditor os.environ['GIT_UPSTREAM_GIT_EDITOR'] = self._saveeditor
os.environ['GIT_EDITOR'] = editor os.environ['GIT_EDITOR'] = editor
def _unset_editor(self): def _unset_editor(self):
for var in ['GIT_SEQUENCE_EDITOR', 'GIT_EDITOR']: for var in ['GIT_SEQUENCE_EDITOR', 'GIT_EDITOR']:
# HPGIT_* variations should only be set if script was in a debug # GIT_UPSTREAM_* variations should only be set if script was in a
# mode. # debug mode.
if os.environ.get('HPGIT_' + var, None): if os.environ.get('GIT_UPSTREAM_' + var, None):
del os.environ['HPGIT_' + var] del os.environ['GIT_UPSTREAM_' + var]
# Restore previous editor only if the environment var is set. This # Restore previous editor only if the environment var is set. This
# isn't perfect since we should probably unset the env var if it # isn't perfect since we should probably unset the env var if it
# wasn't previously set, but this shouldn't cause any problems. # wasn't previously set, but this shouldn't cause any problems.
@ -133,7 +140,7 @@ class RebaseEditor(GitMixin, LogDedentMixin):
def run(self, commits, *args, **kwargs): def run(self, commits, *args, **kwargs):
""" """
Reads the list of commits given, and constructions the instuctions Reads the list of commits given, and constructions the instructions
file to be used by rebase. file to be used by rebase.
Will spawn an editor if the constructor was told to be interactive. Will spawn an editor if the constructor was told to be interactive.
Additional arguments *args and **kwargs are to be passed to 'git Additional arguments *args and **kwargs are to be passed to 'git
@ -146,7 +153,7 @@ class RebaseEditor(GitMixin, LogDedentMixin):
user_editor = self.git_sequence_editor or self.git_editor user_editor = self.git_sequence_editor or self.git_editor
status = call("%s %s" % (user_editor, todo_file), shell=True) status = call("%s %s" % (user_editor, todo_file), shell=True)
if status: if status:
return (status, None, "Editor returned non-zero exit code") return status, None, "Editor returned non-zero exit code"
editor = "%s %s" % (self.editor, todo_file) editor = "%s %s" % (self.editor, todo_file)
self._set_editor(editor) self._set_editor(editor)
@ -163,10 +170,11 @@ class RebaseEditor(GitMixin, LogDedentMixin):
cmd = ['git', 'rebase', '--interactive'] cmd = ['git', 'rebase', '--interactive']
cmd.extend(self.git.transform_kwargs(**kwargs)) cmd.extend(self.git.transform_kwargs(**kwargs))
cmd.extend(args) cmd.extend(args)
return (call(cmd), None, None) return call(cmd), None, None
else: else:
return self.git.rebase(interactive=True, with_exceptions=False, return self.git.rebase(interactive=True, with_exceptions=False,
with_extended_output=True, *args, **kwargs) with_extended_output=True, *args,
**kwargs)
finally: finally:
os.remove(todo_file) os.remove(todo_file)
# make sure to remove the environment tweaks added so as not to # make sure to remove the environment tweaks added so as not to

View File

@ -1,22 +1,27 @@
# #
# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. # Copyright (c) 2012, 2013, 2014 Hewlett-Packard Development Company, L.P.
# #
# Confidential computer software. Valid license from HP required for # Licensed under the Apache License, Version 2.0 (the "License");
# possession, use or copying. Consistent with FAR 12.211 and 12.212, # you may not use this file except in compliance with the License.
# Commercial Computer Software, Computer Software Documentation, and # You may obtain a copy of the License at
# Technical Data for Commercial Items are licensed to the U.S. Government #
# under vendor's standard commercial license. # http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# #
from ghp.lib.utils import GitMixin from git_upstream.lib.utils import GitMixin
from ghp.log import LogDedentMixin from git_upstream.log import LogDedentMixin
try: try:
from git.objects.commit import Commit from git.objects.commit import Commit
except ImportError: except ImportError:
from ghp.lib.pygitcompat import HpgitCompatCommit as Commit from git_upstream.lib.pygitcompat import GitUpstreamCompatCommit as Commit
from git import Head
from abc import ABCMeta, abstractmethod from abc import ABCMeta, abstractmethod
import re import re
@ -45,7 +50,7 @@ class Searcher(GitMixin):
""" """
return self._branch return self._branch
def addFilter(self, filter): def add_filter(self, filter):
if filter not in self.filters: if filter not in self.filters:
self.filters.append(filter) self.filters.append(filter)
@ -123,9 +128,10 @@ class UpstreamMergeBaseSearcher(LogDedentMixin, Searcher):
base available. base available.
""" """
def __init__(self, pattern="upstream/*", search_tags=False, def __init__(self, pattern="upstream/*", search_tags=False, remotes=None,
remotes=[], *args, **kwargs): *args, **kwargs):
if not remotes: remotes = []
self._pattern = pattern self._pattern = pattern
self._references = ["refs/heads/{0}".format(self.pattern)] self._references = ["refs/heads/{0}".format(self.pattern)]
@ -174,14 +180,13 @@ class UpstreamMergeBaseSearcher(LogDedentMixin, Searcher):
reachable from another so that the calls to merge-base are minimized. reachable from another so that the calls to merge-base are minimized.
""" """
self.log.info("Searching for most recent merge base with upstream branches") self.log.info(
"Searching for most recent merge base with upstream branches")
rev_list_args = []
# process pattern given to get a list of refs to check # process pattern given to get a list of refs to check
rev_list_args = self.git.for_each_ref(*self._references, rev_list_args = self.git.for_each_ref(*self._references,
format="%(refname:short)" format="%(refname:short)"
).splitlines() ).splitlines()
self.log.info( self.log.info(
"""\ """\
Upstream refs: Upstream refs:
@ -189,7 +194,8 @@ class UpstreamMergeBaseSearcher(LogDedentMixin, Searcher):
""", "\n ".join(rev_list_args) """, "\n ".join(rev_list_args)
) )
# get the sha1 for the tip of each of the upstream refs we are going to search # get the sha1 for the tip of each of the upstream refs we are going to
# search
self.log.info( self.log.info(
"""\ """\
Construct list of upstream revs to search: Construct list of upstream revs to search:
@ -248,7 +254,7 @@ class UpstreamMergeBaseSearcher(LogDedentMixin, Searcher):
merge_bases.add(base) merge_bases.add(base)
if len(merge_bases) == 0: if len(merge_bases) == 0:
self.log.notice("Merge-base couldn't be found: it seems there "+ self.log.notice("Merge-base couldn't be found: it seems there " +
"is no common ancestor for the involved branches") "is no common ancestor for the involved branches")
else: else:
self.log.info( self.log.info(
@ -262,7 +268,8 @@ class UpstreamMergeBaseSearcher(LogDedentMixin, Searcher):
no_walk=True) no_walk=True)
# now that we have the sha1, make sure to save the commit object # now that we have the sha1, make sure to save the commit object
self.commit = self.repo.commit(sha1) self.commit = self.repo.commit(sha1)
self.log.debug("Most recent merge-base commit is: '%s'", self.commit.hexsha) self.log.debug("Most recent merge-base commit is: '%s'",
self.commit.hexsha)
if not self.commit: if not self.commit:
raise RuntimeError("Failed to locate suitable merge-base") raise RuntimeError("Failed to locate suitable merge-base")
@ -350,7 +357,8 @@ class CommitMessageSearcher(LogDedentMixin, Searcher):
if not self.commit: if not self.commit:
raise RuntimeError("Failed to locate a pattern match") raise RuntimeError("Failed to locate a pattern match")
self.log.debug("Commit matching search pattern is: '%s'", self.commit.hexsha) self.log.debug("Commit matching search pattern is: '%s'",
self.commit.hexsha)
return self.commit.hexsha return self.commit.hexsha
@ -488,13 +496,13 @@ class SupersededCommitFilter(LogDedentMixin, GitMixin, CommitFilter):
# present in upstream # present in upstream
if superseding_change_ids: if superseding_change_ids:
self.log.debug( self.log.debug(
"""\ """\
Including commit '%s %s' Including commit '%s %s'
because the following superseding change-ids have not been because the following superseding change-ids have not been
found: found:
%s %s
""", commit.hexsha[:7], commit.message.splitlines()[0], """, commit.hexsha[:7], commit.message.splitlines()[0],
'\n '.join(superseding_change_ids)) '\n '.join(superseding_change_ids))
yield commit yield commit
continue continue
@ -505,7 +513,8 @@ class SupersededCommitFilter(LogDedentMixin, GitMixin, CommitFilter):
note: note:
%s %s
""", commit.hexsha[:7], commit.message.splitlines()[0], """, commit.hexsha[:7], commit.message.splitlines()[0],
commit_note) commit_note)
class DroppedCommitFilter(LogDedentMixin, CommitFilter): class DroppedCommitFilter(LogDedentMixin, CommitFilter):
""" """
@ -532,6 +541,7 @@ class MergeCommitFilter(CommitFilter):
""" """
Includes only those commits that have more than one parent listed (merges) Includes only those commits that have more than one parent listed (merges)
""" """
def filter(self, commit_iter): def filter(self, commit_iter):
for commit in commit_iter: for commit in commit_iter:
if len(commit.parents) >= 2: if len(commit.parents) >= 2:
@ -542,6 +552,7 @@ class NoMergeCommitFilter(CommitFilter):
""" """
Prunes all that have more than one parent listed (merges) Prunes all that have more than one parent listed (merges)
""" """
def filter(self, commit_iter): def filter(self, commit_iter):
for commit in commit_iter: for commit in commit_iter:
if len(commit.parents) < 2: if len(commit.parents) < 2:
@ -595,7 +606,8 @@ class DiscardDuplicateGerritChangeId(LogDedentMixin, GitMixin, CommitFilter):
if limit: if limit:
if not hasattr(limit, 'hexsha'): if not hasattr(limit, 'hexsha'):
raise ValueError("Invalid object: no hexsha attribute for 'limit'") raise ValueError(
"Invalid object: no hexsha attribute for 'limit'")
if not self.is_valid_commit(limit.hexsha): if not self.is_valid_commit(limit.hexsha):
raise ValueError("'limit' object does not contain a valid SHA1") raise ValueError("'limit' object does not contain a valid SHA1")
self.limit = limit self.limit = limit
@ -686,7 +698,8 @@ class DiscardDuplicateGerritChangeId(LogDedentMixin, GitMixin, CommitFilter):
Including unmatched change Including unmatched change
%s %s
Commit: %s %s Commit: %s %s
""", change_id, commit.hexsha[:7], commit.message.splitlines()[0]) """, change_id, commit.hexsha[:7],
commit.message.splitlines()[0])
yield commit yield commit

View File

@ -1,15 +1,22 @@
# #
# Copyright (c) 2012, 2013 Hewlett-Packard Development Company, L.P. # Copyright (c) 2012, 2013, 2014 Hewlett-Packard Development Company, L.P.
# #
# Confidential computer software. Valid license from HP required for # Licensed under the Apache License, Version 2.0 (the "License");
# possession, use or copying. Consistent with FAR 12.211 and 12.212, # you may not use this file except in compliance with the License.
# Commercial Computer Software, Computer Software Documentation, and # You may obtain a copy of the License at
# Technical Data for Commercial Items are licensed to the U.S. Government #
# under vendor's standard commercial license. # http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# #
from ghp.errors import HpgitError from git_upstream.errors import GitUpstreamError
from ghp.lib.pygitcompat import Repo from git_upstream.lib.pygitcompat import Repo
from git import Git from git import Git
import re import re
@ -34,7 +41,7 @@ class GitMixin(object):
os.path.curdir)) os.path.curdir))
except InvalidGitRepositoryError: except InvalidGitRepositoryError:
exc_class, exc, tb = sys.exc_info() exc_class, exc, tb = sys.exc_info()
raise HpgitError("Not a git repository", tb) raise GitUpstreamError("Not a git repository", tb)
self.__git = self.repo.git self.__git = self.repo.git
super(GitMixin, self).__init__(*args, **kwargs) super(GitMixin, self).__init__(*args, **kwargs)
@ -80,8 +87,8 @@ class GitMixin(object):
def check_git_version(major, minor, revision): def check_git_version(major, minor, revision):
""" """
Check git version PythonGit (and hpgit) will be using is greater of equal Check git version PythonGit (and git-upstream) will be using is greater of
than major.minor.revision) equal than major.minor.revision)
""" """
regex = re.compile("^git version ([0-9]+)\.([0-9]+)\.([0-9]+)(\.(.+))*$") regex = re.compile("^git version ([0-9]+)\.([0-9]+)\.([0-9]+)(\.(.+))*$")

View File

@ -1,12 +1,20 @@
# #
# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. # Copyright (c) 2012, 2013, 2014 Hewlett-Packard Development Company, L.P.
# #
# Confidential computer software. Valid license from HP required for # Licensed under the Apache License, Version 2.0 (the "License");
# possession, use or copying. Consistent with FAR 12.211 and 12.212, # you may not use this file except in compliance with the License.
# Commercial Computer Software, Computer Software Documentation, and # You may obtain a copy of the License at
# Technical Data for Commercial Items are licensed to the U.S. Government
# under vendor's standard commercial license.
# #
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
""" """
Custom logging for HP git tool Custom logging for HP git tool
@ -38,12 +46,12 @@ def notice(self, msg, *args, **kwargs):
logging.Logger.notice = notice logging.Logger.notice = notice
def getLogger(name=None): def get_logger(name=None):
""" """
Wrapper for standard logging.getLogger that ensures all loggers in this Wrapper for standard logging.getLogger that ensures all loggers in this
application will have their name prefixed with 'hpgit'. application will have their name prefixed with 'git-upstream'.
""" """
name = ".".join([x for x in "hpgit", name if x]) name = ".".join([x for x in "git-upstream", name if x])
logger = logging.getLogger(name) logger = logging.getLogger(name)
return logger return logger
@ -60,12 +68,13 @@ _levels = [
] ]
def getIncrementLevel(count, default='warning'): def get_increment_level(count, default='warning'):
""" """
Given a default level to start from, and a count to increment the logging Given a default level to start from, and a count to increment the logging
level by, return the associated level that is 'count' levels more verbose. level by, return the associated level that is 'count' levels more verbose.
""" """
idx = next((idx for idx, sublist in enumerate(_levels) if default in sublist), None) idx = next((idx for idx, sublist in enumerate(_levels) if
default in sublist), None)
return _levels[min(idx + count, len(_levels) - 1)][0].upper() return _levels[min(idx + count, len(_levels) - 1)][0].upper()
@ -140,7 +149,7 @@ logging.setLoggerClass(DedentLogger)
class LogDedentMixin(object): class LogDedentMixin(object):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.__log = getLogger('%s.%s' % (__name__, self.__class__.__name__)) self.__log = get_logger('%s.%s' % (__name__, self.__class__.__name__))
super(LogDedentMixin, self).__init__(*args, **kwargs) super(LogDedentMixin, self).__init__(*args, **kwargs)

View File

@ -1,13 +1,20 @@
#!/usr/bin/env python
# #
# Copyright (c) 2012, 2013 Hewlett-Packard Development Company, L.P. # Copyright (c) 2012, 2013, 2014 Hewlett-Packard Development Company, L.P.
# #
# Confidential computer software. Valid license from HP required for # Licensed under the Apache License, Version 2.0 (the "License");
# possession, use or copying. Consistent with FAR 12.211 and 12.212, # you may not use this file except in compliance with the License.
# Commercial Computer Software, Computer Software Documentation, and # You may obtain a copy of the License at
# Technical Data for Commercial Items are licensed to the U.S. Government
# under vendor's standard commercial license.
# #
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
""" """
Command-line tool for the HP Cloud workflow Command-line tool for the HP Cloud workflow
@ -16,20 +23,20 @@ Main parser module, which after parsing the top level options will hand
off to the collected subcommands parsers. off to the collected subcommands parsers.
""" """
import ghp.commands as commands import git_upstream.commands as commands
from ghp.errors import HpgitError from git_upstream.errors import GitUpstreamError
import ghp.log as log import git_upstream.log as log
import ghp.version import git_upstream.version
from ghp.lib import utils from git_upstream.lib import utils
import subcommand import subcommand
import argparse import argparse
from argparse import ArgumentParser from argparse import ArgumentParser
try: try:
import argcomplete import argcomplete
argparse_loaded=True argparse_loaded = True
except ImportError: except ImportError:
argparse_loaded=False argparse_loaded = False
import logging import logging
import sys import sys
@ -38,10 +45,9 @@ def get_parser():
parser = ArgumentParser( parser = ArgumentParser(
description=__doc__.strip(), description=__doc__.strip(),
epilog='See "%(prog)s help COMMAND" for help on a specific command.', epilog='See "%(prog)s help COMMAND" for help on a specific command.',
add_help=False, add_help=False)
)
parser.add_argument('--version', action='version', parser.add_argument('--version', action='version',
version='%(prog)s ' + ghp.version.version) version='%(prog)s ' + git_upstream.version.version)
parser.add_argument('-h', '--help', action='help', parser.add_argument('-h', '--help', action='help',
help='show this help message and exit') help='show this help message and exit')
group = parser.add_mutually_exclusive_group() group = parser.add_mutually_exclusive_group()
@ -74,7 +80,7 @@ def get_parser():
subcommand_parsers = commands.get_subcommands(subparsers) subcommand_parsers = commands.get_subcommands(subparsers)
return (subcommand_parsers, parser) return subcommand_parsers, parser
@subcommand.arg('command', metavar='<command>', nargs='?', @subcommand.arg('command', metavar='<command>', nargs='?',
@ -106,7 +112,7 @@ def main(argv):
return 0 return 0
args.log_level = getattr(logging, args.log_level.upper(), logging.NOTSET) args.log_level = getattr(logging, args.log_level.upper(), logging.NOTSET)
console_log_level = getattr(logging, log.getIncrementLevel(args.verbose), console_log_level = getattr(logging, log.get_increment_level(args.verbose),
logging.NOTSET) logging.NOTSET)
if args.quiet: if args.quiet:
console_log_level = logging.NOTSET console_log_level = logging.NOTSET
@ -117,7 +123,7 @@ def main(argv):
for value in args.log_level, console_log_level for value in args.log_level, console_log_level
if value != logging.NOTSET if value != logging.NOTSET
] + [logging.ERROR]) ] + [logging.ERROR])
logger = log.getLogger() logger = log.get_logger()
logger.setLevel(main_log_level) logger.setLevel(main_log_level)
if not args.quiet: if not args.quiet:
@ -129,28 +135,28 @@ def main(argv):
logger.addHandler(console) logger.addHandler(console)
# make sure error and critical messages go to stderr and aren't suppressed # make sure error and critical messages go to stderr and aren't suppressed
errcon = logging.StreamHandler(sys.stderr) err_con = logging.StreamHandler(sys.stderr)
errcon.setLevel(logging.ERROR) err_con.setLevel(logging.ERROR)
errcon.addFilter(log.LevelFilterIgnoreBelow(logging.ERROR)) err_con.addFilter(log.LevelFilterIgnoreBelow(logging.ERROR))
errcon.setFormatter(logging.Formatter("%(levelname)-8s: %(message)s")) err_con.setFormatter(logging.Formatter("%(levelname)-8s: %(message)s"))
logger.addHandler(errcon) logger.addHandler(err_con)
if args.log_file: if args.log_file:
filehandler = logging.FileHandler(args.log_file) filehandler = logging.FileHandler(args.log_file)
filehandler.setLevel(args.log_level) filehandler.setLevel(args.log_level)
format = "%(asctime)s - %(name)s - %(levelname)s: %(message)s" _format = "%(asctime)s - %(name)s - %(levelname)s: %(message)s"
filehandler.setFormatter(logging.Formatter(format)) filehandler.setFormatter(logging.Formatter(_format))
logger.addHandler(filehandler) logger.addHandler(filehandler)
if not utils.check_git_version(1,7,5): if not utils.check_git_version(1, 7, 5):
logger.fatal("Hpgit requires git version 1.7.5 or later") logger.fatal("Git-Upstream requires git version 1.7.5 or later")
sys.exit(1) sys.exit(1)
try: try:
args.func(args) args.func(args)
except HpgitError, e: except GitUpstreamError, e:
logger.fatal("%s", e[0]) logger.fatal("%s", e[0])
logger.debug("HpgitError: %s", e[0], exc_info=e) logger.debug("Git-Upstream: %s", e[0], exc_info=e)
sys.exit(1) sys.exit(1)
# vim:sw=4:sts=4:ts=4:et: # vim:sw=4:sts=4:ts=4:et:

View File

@ -1,12 +1,19 @@
#!/usr/bin/env python #!/usr/bin/env python
# #
# Copyright (c) 2012, 2013 Hewlett-Packard Development Company, L.P. # Copyright (c) 2012, 2013, 2014 Hewlett-Packard Development Company, L.P.
# #
# Confidential computer software. Valid license from HP required for # Licensed under the Apache License, Version 2.0 (the "License");
# possession, use or copying. Consistent with FAR 12.211 and 12.212, # you may not use this file except in compliance with the License.
# Commercial Computer Software, Computer Software Documentation, and # You may obtain a copy of the License at
# Technical Data for Commercial Items are licensed to the U.S. Government #
# under vendor's standard commercial license. # http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# #
""" """
@ -89,11 +96,12 @@ if __name__ == '__main__':
# calling code should only override one of the two editor variables, # calling code should only override one of the two editor variables,
# starting with the one with the highest precedence # starting with the one with the highest precedence
editor=None
env = os.environ env = os.environ
for var in ['GIT_SEQUENCE_EDITOR', 'GIT_EDITOR']: for var in ['GIT_SEQUENCE_EDITOR', 'GIT_EDITOR']:
editor = env.get('HPGIT_' + var, None) editor = env.get('GIT_UPSTREAM_' + var, None)
if editor: if editor:
del env['HPGIT_' + var] del env['GIT_UPSTREAM_' + var]
env[var] = editor env[var] = editor
break break

View File

@ -1,6 +1,6 @@
# #
# Copyright (c) 2011, 2012 OpenStack LLC. # Copyright (c) 2011, 2012 OpenStack LLC.
# Copyright (c) 2012, 2013 Hewlett-Packard Development Company, L.P. # Copyright (c) 2012, 2013, 2014 Hewlett-Packard Development Company, L.P.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -27,13 +27,14 @@ class CommandException(Exception):
# following function is taken from git-review # following function is taken from git-review
def run_command(cmd, status=False, env={}): def run_command(cmd, status=False, env=None):
if not env: env = {}
if VERBOSE: if VERBOSE:
print(datetime.datetime.now(), "Running:", cmd) print(datetime.datetime.now(), "Running:", cmd)
newenv = os.environ new_env = os.environ
newenv.update(env) new_env.update(env)
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, env=newenv) stderr=subprocess.STDOUT, env=new_env)
(out, nothing) = p.communicate() (out, nothing) = p.communicate()
if p.returncode: if p.returncode:
raise CommandException raise CommandException
@ -52,12 +53,12 @@ def git_describe_version():
return v return v
def hpgit_version(): def git_upstream_version():
try: try:
from ghp import hpgit_version from git_upstream import git_upstream_version
except ImportError: except ImportError:
raise raise
return hpgit_version.version return git_upstream_version.version
def write_version_file(): def write_version_file():
@ -67,13 +68,13 @@ def write_version_file():
return return
print __name__ print __name__
with open(os.path.join(os.path.dirname(__file__), with open(os.path.join(os.path.dirname(__file__),
"hpgit_version.py"), 'w') as f: "git_upstream_version.py"), 'w') as f:
f.write("# Autogenerated file, do not edit by hand") f.write("# Auto-generated file, do not edit by hand")
f.write("version = %s" % v) f.write("version = %s" % v)
def get_version(): def get_version():
for vfunc in hpgit_version, git_describe_version: for vfunc in git_upstream_version, git_describe_version:
try: try:
return vfunc() return vfunc()
except: except:

View File

@ -1,19 +1,25 @@
#!/usr/bin/env python #!/usr/bin/env python
# #
# Copyright (c) 2012, 2013 Hewlett-Packard Development Company, L.P. # Copyright (c) 2012, 2013, 2014 Hewlett-Packard Development Company, L.P.
# #
# Confidential computer software. Valid license from HP required for # Licensed under the Apache License, Version 2.0 (the "License");
# possession, use or copying. Consistent with FAR 12.211 and 12.212, # you may not use this file except in compliance with the License.
# Commercial Computer Software, Computer Software Documentation, and # You may obtain a copy of the License at
# Technical Data for Commercial Items are licensed to the U.S. Government #
# under vendor's standard commercial license. # http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# #
import os import os
from setuptools import setup, find_packages from setuptools import setup, find_packages
from create_manpage import create_manpage from create_manpage import CreateManpage
from ghp import version from git_upstream import version
# following function is taken from setuptools example. # following function is taken from setuptools example.
@ -24,31 +30,34 @@ def read(fname):
version.write_version_file() version.write_version_file()
setup( setup(
name="hpgit", name="git-upstream",
version=version.version, version=version.version,
author="Darragh Bailey", author="Darragh Bailey",
author_email="dbailey@hp.com", author_email="dbailey@hp.com",
description=("Tool supporting HPCloud git workflows."), maintainer="Davide Guerri",
license="Proprietary", maintainer_email="davide.guerri@hp.com",
keywords="git hpcloud workflow", description="Tool supporting import from upstream.",
url="https://wiki.hpcloud.net/display/auto/hpgit", license="Apache Software License",
scripts=['git-hp', os.path.join(os.path.dirname(__file__), keywords="git upstream workflow",
'ghp', 'scripts', 'rebase-editor.py')], url="",
scripts=['git-upstream', os.path.join(os.path.dirname(__file__),
'git_upstream', 'scripts',
'rebase-editor.py')],
packages=find_packages(exclude=['test']), packages=find_packages(exclude=['test']),
install_requires=['GitPython'], install_requires=['GitPython'],
long_description=read('README'), long_description=read('README'),
cmdclass={'create_manpage': create_manpage}, cmdclass={'create_manpage': CreateManpage},
classifiers=[ classifiers=[
"Development Status :: 2 - Pre-Alpha", "Development Status :: 4 - Beta",
"Topic :: Utilities", "Topic :: Utilities",
"License :: Other/Proprietary License", "License :: OSI Approved :: Apache Software License"
], ]
) )
try: try:
import argcomplete import argcomplete
print('Make sure to copy bash_completion/hpgit in appropriate location ' + print('Make sure to copy bash_completion/git-upstream in appropriate ' +
'(e.g. ~/.bash_completion)') 'location (e.g. ~/.bash_completion)')
except ImportError: except ImportError:
print('Warning: argcomplete package is not installed, autocomplete will' + print('Warning: argcomplete package is not installed, autocomplete will' +
' not work.') ' not work.')

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2012, 2013 Hewlett-Packard Development Company, L.P. # Copyright (c) 2012, 2013, 2014 Hewlett-Packard Development Company, L.P.
# #
# Confidential computer software. Valid license from HP required for # Confidential computer software. Valid license from HP required for
# possession, use or copying. Consistent with FAR 12.211 and 12.212, # possession, use or copying. Consistent with FAR 12.211 and 12.212,

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2012, 2013 Hewlett-Packard Development Company, L.P. # Copyright (c) 2012, 2013, 2014 Hewlett-Packard Development Company, L.P.
# #
# Confidential computer software. Valid license from HP required for # Confidential computer software. Valid license from HP required for
# possession, use or copying. Consistent with FAR 12.211 and 12.212, # possession, use or copying. Consistent with FAR 12.211 and 12.212,
@ -13,12 +13,12 @@
import testtools import testtools
from argparse import ArgumentParser from argparse import ArgumentParser
from ghp import commands as c from git_upstream import commands as c
class TestGetSubcommands(testtools.TestCase): class TestGetSubcommands(testtools.TestCase):
"""Test case for get_subcommands function""" """Test case for get_subcommands function"""
_available_subcommands = ('import-upstream', 'supersede' ,'drop') _available_subcommands = ('import', 'supersede' ,'drop')
def test_available_subcommands(self): def test_available_subcommands(self):
"""Test available subcommands""" """Test available subcommands"""

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2012, 2013 Hewlett-Packard Development Company, L.P. # Copyright (c) 2012, 2013, 2014 Hewlett-Packard Development Company, L.P.
# #
# Confidential computer software. Valid license from HP required for # Confidential computer software. Valid license from HP required for
# possession, use or copying. Consistent with FAR 12.211 and 12.212, # possession, use or copying. Consistent with FAR 12.211 and 12.212,
@ -10,7 +10,7 @@
"""Tests the drop module""" """Tests the drop module"""
import testtools import testtools
from ghp.commands import drop as d from git_upstream.commands import drop as d
from git import repo as r from git import repo as r
from git import GitCommandError from git import GitCommandError

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2012, 2013 Hewlett-Packard Development Company, L.P. # Copyright (c) 2012, 2013, 2014 Hewlett-Packard Development Company, L.P.
# #
# Confidential computer software. Valid license from HP required for # Confidential computer software. Valid license from HP required for
# possession, use or copying. Consistent with FAR 12.211 and 12.212, # possession, use or copying. Consistent with FAR 12.211 and 12.212,
@ -11,7 +11,7 @@
"""Tests for then 'log' module""" """Tests for then 'log' module"""
import testtools import testtools
from ghp import log as l from git_upstream import log as l
class TestGetLogger(testtools.TestCase): class TestGetLogger(testtools.TestCase):
@ -20,16 +20,16 @@ class TestGetLogger(testtools.TestCase):
def test_logger_name(self): def test_logger_name(self):
"""Test the default logger name""" """Test the default logger name"""
logger = l.getLogger() logger = l.get_logger()
self.assertIsNotNone(logger) self.assertIsNotNone(logger)
self.assertEquals('hpgit', logger.name) self.assertEquals('git-upstream', logger.name)
def test_logger_name_param(self): def test_logger_name_param(self):
"""Test custom logger name""" """Test custom logger name"""
logger = l.getLogger('test') logger = l.get_logger('test')
self.assertIsNotNone(logger) self.assertIsNotNone(logger)
self.assertEquals('hpgit.test', logger.name) self.assertEquals('git-upstream.test', logger.name)
class TestGetIncrementLevel(testtools.TestCase): class TestGetIncrementLevel(testtools.TestCase):
@ -49,7 +49,7 @@ class TestGetIncrementLevel(testtools.TestCase):
levels = len(self._levels) levels = len(self._levels)
for level_no in range(levels-increment): for level_no in range(levels-increment):
for level in self._levels[level_no]: for level in self._levels[level_no]:
result = l.getIncrementLevel(1, level) result = l.get_increment_level(1, level)
self.assertEquals(self._levels[min(level_no+1, levels-1)][0].upper(), self.assertEquals(self._levels[min(level_no+1, levels-1)][0].upper(),
result) result)

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2012, 2013 Hewlett-Packard Development Company, L.P. # Copyright (c) 2012, 2013, 2014 Hewlett-Packard Development Company, L.P.
# #
# Confidential computer software. Valid license from HP required for # Confidential computer software. Valid license from HP required for
# possession, use or copying. Consistent with FAR 12.211 and 12.212, # possession, use or copying. Consistent with FAR 12.211 and 12.212,
@ -11,7 +11,7 @@
"""Tests the supersede module""" """Tests the supersede module"""
import testtools import testtools
from ghp.commands import supersede as s from git_upstream.commands import supersede as s
from git import repo as r from git import repo as r
from git import GitCommandError from git import GitCommandError

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2012, 2013 Hewlett-Packard Development Company, L.P. # Copyright (c) 2012, 2013, 2014 Hewlett-Packard Development Company, L.P.
# #
# Confidential computer software. Valid license from HP required for # Confidential computer software. Valid license from HP required for
# possession, use or copying. Consistent with FAR 12.211 and 12.212, # possession, use or copying. Consistent with FAR 12.211 and 12.212,
@ -10,7 +10,7 @@
"""Tests for then 'utils' module""" """Tests for then 'utils' module"""
from ghp.lib import utils as u from git_upstream.lib import utils as u
import testtools import testtools