diff --git a/hooks/update.secondary b/hooks/update.secondary index 3710160..ae6ebdd 100755 --- a/hooks/update.secondary +++ b/hooks/update.secondary @@ -1,232 +1,232 @@ #!/usr/bin/env python # Load dependencies import os import re import sys import subprocess from hooklib import Repository, RepositoryMetadataLoader, Commit, CommitAuditor, CommitNotifier, MessageBuilder, CommitChecker, CiaNotifier, RepoType, ChangeType, RefType def usage(): print "Information needed to run could not be gathered successfully." print "Required environment variables: GIT_DIR, GL_USER, HOME" print "Syntax: update.secondary " exit(1) def maintenance(): print "Sorry, but the repository you are trying to access is currently unavailable." print "This is to allow for maintenance, we apologise for any inconvience caused." print "If you believe this not to be the case, please contact sysadmin@kde.org." exit(1) ##### # Initialisation ##### # Read arguments... try: ref_name = sys.argv[1] old_sha1 = sys.argv[2] new_sha1 = sys.argv[3] except IndexError: usage() # Read needed environment variables git_dir = os.getenv('GIT_DIR') push_user = os.getenv('GL_USER') user_home = os.getenv('HOME') # Check for maintenance mode... if os.path.exists(user_home + "/.gitolite.down") or os.path.exists(git_dir + "/.gitolite.down"): maintenance() # Initialise the repository if os.path.exists("/srv/git/repositories"): Repository.BaseDir = "/srv/git/repositories/" elif os.path.exists("/home/git/repositories"): Repository.BaseDir = "/home/git/repositories/" else: print "Base directory could not be found" exit(1) repository = Repository( ref_name, old_sha1, new_sha1, push_user ) ##### # Repository Metadata Loading ##### repositoryMetadata = RepositoryMetadataLoader() repositoryMetadata.loadProjectsFromTree("/home/git/repo-metadata/") # Is the current repository known? if repository.path in repositoryMetadata.KnownRepos: # The grab the metadata metadata = repositoryMetadata.KnownRepos[ repository.path ] # And overwrite the virtual path repository.virtual_path = metadata['projectpath'] ##### # Auditing ##### # Repository change checks... push_size_restricted = [RepoType.Normal, RepoType.Website, RepoType.Sysadmin, RepoType.Others] if repository.ref_type == RefType.Backup: print "Pushing to backup refs is not supported for security reasons" print "Push declined - attempted repository integrity violation" exit(1) elif repository.ref_type == RefType.Upstream: print "Pushing to server maintained upstreams is not permitted" print "Push declined - attempted repository integrity violation" exit(1) elif repository.ref_type == RefType.Unknown: print "Sorry, but the ref you are trying to push to could not be recognised." print "Only pushes to branches, tags and notes are permitted." exit(1) elif repository.ref_name == "HEAD": print "Creating refs which conflict with internally used names is not permitted." print "Push declined - attempted repository integrity violation" exit(1) elif repository.change_type == ChangeType.Create and re.match("^origin/(.+)$", repository.ref_name): print "Creating refs starting with the name origin/ is not permitted." print "This is usually caused by incorrectly pushing a branch or tag." print "Please ensure your remote branch name does not contain 'origin/' at the beginning" print "Push declined - attempted repository integrity violation" exit(1) -if repository.ref_type == RefType.Tag and repository.change_type != ChangeType.Delete and repository.commit_type != "tag": - print "Pushing an unannotated tag is not permitted." - print "Push declined - attempted repository integrity violation" - exit(1) +#if repository.ref_type == RefType.Tag and repository.change_type != ChangeType.Delete and repository.commit_type != "tag": +# print "Pushing an unannotated tag is not permitted." +# print "Push declined - attempted repository integrity violation" +# exit(1) if repository.ref_type == RefType.Changes and push_user != "gerrit": print "Pushes to changes refs is only permitted by the Gerrit instance" print "Push declined - attempted repository integrity violation" exit(1) if repository.ref_type is RefType.Tag and re.match("^phabricator/(.+)/(.+)", repository.ref_name): print "Pushes to phabricator refs is only permitted to staging instance" print "Push declined - attempted repository integrity violation" exit(1) # Access Restrictions for repositories which are part of modules ModuleReleaseManagers = ['aacid', 'cfeck', 'dfaure', 'jriddell', 'davidedmundson', 'bshah'] if repository.ref_type == RefType.Tag and re.match("^v[0-9]\.", repository.ref_name) and re.match("^(kde|frameworks)/.*", repository.virtual_path) and push_user not in ModuleReleaseManagers: print "Pushing tags to repositories which are part of modules is restricted to the release managers of those modules." print "Please contact the release manager for your module for further assistance." print "Push declined - attempted release procedure violation" exit(1) # New commits... notification_base = repository.management_directory + "/repo-configs/notifications/" if len(repository.commits) > 100 and not os.path.exists(notification_base + repository.path + ".git/skip-notifications") and not os.path.exists(git_dir + "/kde-hooks-off") and repository.repo_type in push_size_restricted: print "More than 100 commits are being pushed" print "Push declined - excessive notifications would be sent" print "Please file a KDE Sysadmin bug to continue" exit(1) auditedRef = True # We don't audit commits pushed to the meta ref if repository.ref_type == RefType.Meta: auditedRef = False auditor = CommitAuditor( repository ) audit_base = repository.management_directory + "/repo-configs/audit/" if auditedRef and not os.path.exists(audit_base + repository.path + ".git/skip-eol"): auditor.audit_eol() if auditedRef and not os.path.exists(audit_base + repository.path + ".git/skip-filename"): auditor.audit_filename() if auditedRef and not os.path.exists(audit_base + repository.path + ".git/skip-author-names"): auditor.audit_names_in_metadata() if auditedRef and not os.path.exists(audit_base + repository.path + ".git/skip-author-emails"): auditor.audit_emails_in_metadata() blocked_path = repository.management_directory + "/repo-configs/blocked/" + repository.path if auditedRef and os.path.exists(blocked_path): auditor.audit_hashes(blocked_path) # Did we have any commit audit failures? if auditor.audit_failed: print "Push declined - commits failed audit" exit(1) ##### # Pre-acceptance ##### # Do we need to back it up?? if repository.change_type == ChangeType.Forced or repository.change_type == ChangeType.Delete: repository.backup_ref() # Repository specific special handling.... # KDE PIM: Add a note to all commits which are new to the Enterprise branch... notes_repos = ["kdepim", "kdepim-runtime", "kdepimlibs", "kdelibs"] notes_refs = ["enterprise/e3", "enterprise/e4"] if repository.path in notes_repos and repository.ref_name in notes_refs: for commit in repository.commits: command = "git notes add --message 'PENDING' " + commit subprocess.Popen(command, shell=True).wait() ##### # Post acceptance ##### # Are post commands supposed to be run? if os.path.exists(git_dir + "/kde-hooks-off") or os.path.exists(notification_base + repository.path + ".git/skip-notifications"): print "Hooks are currently disabled!" exit(0) # Does this user need a special post-update skip? post_exceptions = ["scripty"] if push_user in post_exceptions: exit(0) # Output a helpful url.... if repository.repo_type != RepoType.Sysadmin and repository.new_sha1 in repository.commits: if len(repository.commits) == 1: print "This commit is available for viewing at:" else: print "The last commit in this series is available for viewing at:" print repository.commits[ repository.new_sha1 ].url # Are we allowed to send notifications on this repo? notify_allowed = [RepoType.Normal, RepoType.Website, RepoType.Sysadmin, RepoType.Others] if not repository.repo_type in notify_allowed: exit(0) # Also ignore Gerrit's refs/notes/review and refs/changes/* if repository.ref_type == RefType.NotesReview or repository.ref_type == RefType.Changes: exit(0) # Perform notifications cia_allowed = [RepoType.Normal, RepoType.Website, RepoType.Others] notifier = CommitNotifier() cia = CiaNotifier(repository) checker = CommitChecker() for (commit, diff) in notifier.handler(repository): # Check for license, etc problems in the commit checker.check_commit_problems( commit, diff ) # Create the message builder in preperation to send notifications builder = MessageBuilder( repository, commit, checker ) builder.determine_keywords() # Do CIA if repository.repo_type in cia_allowed: cia.notify(builder) if repository.repo_type == RepoType.Sysadmin: notify_address = "sysadmin-svn@kde.org" else: notify_address = "kde-commits@kde.org" notifier.notify_email( builder, notify_address, diff ) # Handle Bugzilla and Reviewboard notifier.notify_bugzilla( builder ) notifier.notify_reviewboard( builder ) # Everything is done.... exit(0)