All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.gerrit.server.update.context.RefUpdateContext Maven / Gradle / Ivy

The newest version!
// Copyright (C) 2023 The Android Open Source Project
//
// 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.

package com.google.gerrit.server.update.context;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;

import com.google.common.collect.ImmutableList;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Optional;

/**
 * Passes additional information about an operation to the {@code BatchRefUpdate#execute} method.
 *
 * 

To pass the additional information {@link RefUpdateContext}, wraps a code into an open * RefUpdateContext, e.g.: * *

{@code
 * try(RefUpdateContext ctx = RefUpdateContext.open(RefUpdateType.CHANGE_MODIFICATION)) {
 *   ...
 *   // some code which modifies a ref using BatchRefUpdate.execute method
 * }
 * }
* * When the {@code BatchRefUpdate#execute} method is executed, it can get all opened contexts and * use it for an additional actions, e.g. it can put it in the reflog. * *

The information provided by this class is used internally in google. * *

The InMemoryRepositoryManager file makes some validation to ensure that RefUpdateContext is * used correctly within the code (see thee validateRefUpdateContext method). * *

The class includes only operations from open-source gerrit and can be extended (see {@code * TestActionRefUpdateContext} for example how to extend it). */ public class RefUpdateContext implements AutoCloseable { private static final ThreadLocal> current = new ThreadLocal<>(); /** * List of possible ref-update types. * *

Items in this enum are not fine-grained; different actions are shared the same type (e.g. * {@link #CHANGE_MODIFICATION} includes posting comments, change edits and attention set update). * *

It is expected, that each type of operation should include only specific ref(s); check the * validateRefUpdateContext in InMemoryRepositoryManager for relation between RefUpdateType and * ref name. */ public enum RefUpdateType { /** * Indicates that the context is implemented as a descendant of the {@link RefUpdateContext} . * *

The {@link #getUpdateType()} returns this type for all descendant of {@link * RefUpdateContext}. This type is never returned if the context is exactly {@link * RefUpdateContext}. */ OTHER, /** * A ref is updated as a part of change-related operation. * *

This covers multiple different cases - creating and uploading changes and patchsets, * comments operations, change edits, etc... */ CHANGE_MODIFICATION, /** A ref is updated during merge-change operation. */ MERGE_CHANGE, /** A ref is updated as a part of a repo sequence operation. */ REPO_SEQ, /** A ref is updated as a part of a repo initialization. */ INIT_REPO, /** A ref is udpated as a part of gpg keys modification. */ GPG_KEYS_MODIFICATION, /** A ref is updated as a part of group(s) update */ GROUPS_UPDATE, /** A ref is updated as a part of account(s) update. */ ACCOUNTS_UPDATE, /** A ref is updated as a part of direct push. */ DIRECT_PUSH, /** A ref is updated as a part of explicit branch or ref update operation. */ BRANCH_MODIFICATION, /** A ref is updated as a part of explicit tag update operation. */ TAG_MODIFICATION, /** * A tag is updated as a part of an offline operation. * *

Offline operation - an operation which is executed separately from the gerrit server and * can't be triggered by any gerrit API. E.g. schema update. */ OFFLINE_OPERATION, /** A tag is updated as a part of an update-superproject flow. */ UPDATE_SUPERPROJECT, /** A ref is updated as a part of explicit HEAD update operation. */ HEAD_MODIFICATION, /** A ref is updated as a part of versioned meta data change. */ VERSIONED_META_DATA_CHANGE, /** A ref is updated as a part of commit-ban operation. */ BAN_COMMIT, /** * A ref is updated inside a plugin. * *

If a plugin updates one of a special refs - it must also open a nested context. */ PLUGIN, /** A ref is updated as a part of auto-close-changes. */ AUTO_CLOSE_CHANGES } /** Opens a provided context. */ protected static T open(T ctx) { getCurrent().addLast(ctx); return ctx; } /** Opens a context of a give type. */ public static RefUpdateContext open(RefUpdateType updateType) { checkArgument(updateType != RefUpdateType.OTHER, "The OTHER type is for internal use only."); checkArgument( updateType != RefUpdateType.DIRECT_PUSH, "openDirectPush method with justification must be used to open DIRECT_PUSH context."); return open(new RefUpdateContext(updateType, Optional.empty())); } /** Opens a direct push context with an optional justification. */ public static RefUpdateContext openDirectPush(Optional justification) { return open(new RefUpdateContext(RefUpdateType.DIRECT_PUSH, justification)); } /** Returns the list of opened contexts; the first element is the outermost context. */ public static ImmutableList getOpenedContexts() { return ImmutableList.copyOf(getCurrent()); } /** Checks if there is an open context of the given type. */ public static boolean hasOpen(RefUpdateType type) { return getCurrent().stream().anyMatch(ctx -> ctx.getUpdateType() == type); } private final RefUpdateType updateType; private final Optional justification; private RefUpdateContext(RefUpdateType updateType, Optional justification) { this.updateType = updateType; this.justification = justification; } protected RefUpdateContext(Optional justification) { this(RefUpdateType.OTHER, justification); } protected static final Deque getCurrent() { Deque result = current.get(); if (result == null) { result = new ArrayDeque<>(); current.set(result); } return result; } /** * Returns the type of {@link RefUpdateContext}. * *

For descendants, always return {@link RefUpdateType#OTHER} (except known descendants defined * as nested classes). */ public final RefUpdateType getUpdateType() { return updateType; } /** Returns the justification for the operation. */ public final Optional getJustification() { return justification; } /** Closes the current context. */ @Override public void close() { Deque openedContexts = getCurrent(); checkState( openedContexts.peekLast() == this, "The current context is different from this context."); openedContexts.removeLast(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy