Chad has submitted this change and it was merged.
Change subject: `scap patch` tool for applying patches to a wmf/branch
..
`scap patch` tool for applying patches to a wmf/branch
Reads through patches from `/srv/patches/$branch` and applies them
to `./php-$branch` one by one
Change-Id: Ic2e55e97fd5dff270a1064655255cd7c19c6a544
---
A scap/plugins/patch.py
1 file changed, 101 insertions(+), 0 deletions(-)
Approvals:
Chad: Looks good to me, approved
jenkins-bot: Verified
diff --git a/scap/plugins/patch.py b/scap/plugins/patch.py
new file mode 100644
index 000..ca4c4b8
--- /dev/null
+++ b/scap/plugins/patch.py
@@ -0,0 +1,101 @@
+from __future__ import print_function, unicode_literals
+
+import os.path
+import subprocess
+
+import scap.cli as cli
+import scap.arg as arg
+import scap.utils as utils
+
+from exceptions import ValueError
+
+
+class PatchError(Exception):
+"""Exception raised for errors applying a patch.
+
+Attributes:
+msg -- explanation of the error.
+patch -- the name of the patch that failed.
+"""
+
+def __init__(self, msg, patch):
+self.msg = msg
+self.patch = patch
+
+def __str__(self):
+return self.msg
+
+
+@cli.command('patch')
+class SecurityPatchManager(cli.Application):
+""" Scap sub-command to manage mediawiki security patches """
+
+def _process_arguments(self, args, extra_args):
+return args, extra_args
+
+@cli.argument('--check-only', action='store_true',
+ help='Just check if patches apply cleanly.')
+@cli.argument('branch', help='The name of the branch to operate on.')
+def main(self, *extra_args):
+""" Apply security patches """
+
+logger = self.get_logger()
+
+branch = self.arguments.branch
+
+if branch.startswith('php-'):
+branch = branch[4:]
+
+branch = branch.rstrip('/')
+stage_dir = self.config.get('stage_dir', './')
+
+self.patchdir = os.path.join('/srv/patches/', branch)
+self.checkdir('patch', self.patchdir)
+
+self.branchdir = os.path.join(stage_dir, 'php-%s' % branch)
+self.checkdir('branch', self.branchdir)
+
+with utils.cd(self.branchdir):
+for base, path, filename in self.get_patches():
+repo_dir = './' if path == 'core' else os.path.join('./', path)
+patchfile = os.path.join(base, path, filename)
+try:
+self.apply_patch(patchfile, repo_dir)
+except PatchError as e:
+os.rename(e.patch, e.patch + ".failed")
+logger.exception(e)
+
+def checkdir(self, name, path):
+if not os.path.isdir(path):
+msg = '%s directory "%s" does not exist.' % (name, path)
+self.get_logger().error(msg)
+raise ValueError(msg)
+
+def get_patches(self, path=''):
+patchdir = os.path.join(self.patchdir, path)
+prefix_length = len(self.patchdir) + 1
+for folder, subdirs, files in os.walk(patchdir):
+for filename in files:
+if filename.endswith('.failed'):
+self.get_logger().warning('Skipping failed patch: %s/%s',
+ folder, filename)
+else:
+yield self.patchdir, folder[prefix_length:], filename
+
+def check_patch(self, patch):
+try:
+subprocess.check_call(['git', 'apply', '--check', '-3', patch])
+except subprocess.CalledProcessError as ex:
+msg = 'Patch %s failed to apply: %s' % (patch, ex.output)
+raise PatchError(msg, patch)
+
+def apply_patch(self, patch, repo_dir='./'):
+with utils.cd(repo_dir):
+self.check_patch(patch)
+if not self.arguments.check_only:
+self.get_logger().info('In %s, Applying patch: %s' %
(repo_dir, patch))
+try:
+subprocess.check_call(['git', 'am', '-3', patch])
+except subprocess.CalledProcessError as ex:
+msg = 'Patch %s failed to apply: %s' % (patch, ex.output)
+raise PatchError(msg, patch)
--
To view, visit https://gerrit.wikimedia.org/r/312013
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: Ic2e55e97fd5dff270a1064655255cd7c19c6a544
Gerrit-PatchSet: 8
Gerrit-Project: operations/mediawiki-config
Gerrit-Branch: master
Gerrit-Owner: 20after4
Gerrit-Reviewer: 20after4
Gerrit-Reviewer: Chad
Gerrit-Reviewer: Dduvall
Gerrit-Reviewer: Thcipriani
Gerrit-Reviewer: jenkins-bot <>
___
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits