Skip to content

Commit e5341cb

Browse files
committed
NIFI-15696 - Add Rebase operation for versioned process groups
Signed-off-by: Pierre Villard <pierre.villard.fr@gmail.com>
1 parent 19cd31b commit e5341cb

25 files changed

Lines changed: 3108 additions & 1 deletion

File tree

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.apache.nifi.web.api.dto;
19+
20+
import io.swagger.v3.oas.annotations.media.Schema;
21+
import jakarta.xml.bind.annotation.XmlType;
22+
23+
@XmlType(name = "rebaseChange")
24+
public class RebaseChangeDTO {
25+
private String componentId;
26+
private String componentName;
27+
private String componentType;
28+
private String differenceType;
29+
private String fieldName;
30+
private String localValue;
31+
private String registryValue;
32+
private String classification;
33+
private String conflictCode;
34+
private String conflictDetail;
35+
36+
@Schema(description = "The ID of the component that was changed")
37+
public String getComponentId() {
38+
return componentId;
39+
}
40+
41+
public void setComponentId(final String componentId) {
42+
this.componentId = componentId;
43+
}
44+
45+
@Schema(description = "The name of the component that was changed")
46+
public String getComponentName() {
47+
return componentName;
48+
}
49+
50+
public void setComponentName(final String componentName) {
51+
this.componentName = componentName;
52+
}
53+
54+
@Schema(description = "The type of the component that was changed")
55+
public String getComponentType() {
56+
return componentType;
57+
}
58+
59+
public void setComponentType(final String componentType) {
60+
this.componentType = componentType;
61+
}
62+
63+
@Schema(description = "The type of difference detected for this change")
64+
public String getDifferenceType() {
65+
return differenceType;
66+
}
67+
68+
public void setDifferenceType(final String differenceType) {
69+
this.differenceType = differenceType;
70+
}
71+
72+
@Schema(description = "The name of the field that was changed, or null if not applicable")
73+
public String getFieldName() {
74+
return fieldName;
75+
}
76+
77+
public void setFieldName(final String fieldName) {
78+
this.fieldName = fieldName;
79+
}
80+
81+
@Schema(description = "The local value of the field, or null if not applicable")
82+
public String getLocalValue() {
83+
return localValue;
84+
}
85+
86+
public void setLocalValue(final String localValue) {
87+
this.localValue = localValue;
88+
}
89+
90+
@Schema(description = "The registry value of the field, or null if not applicable")
91+
public String getRegistryValue() {
92+
return registryValue;
93+
}
94+
95+
public void setRegistryValue(final String registryValue) {
96+
this.registryValue = registryValue;
97+
}
98+
99+
@Schema(description = "The classification of this change: COMPATIBLE, CONFLICTING, or UNSUPPORTED")
100+
public String getClassification() {
101+
return classification;
102+
}
103+
104+
public void setClassification(final String classification) {
105+
this.classification = classification;
106+
}
107+
108+
@Schema(description = "A code identifying the type of conflict, or null if the change is not conflicting")
109+
public String getConflictCode() {
110+
return conflictCode;
111+
}
112+
113+
public void setConflictCode(final String conflictCode) {
114+
this.conflictCode = conflictCode;
115+
}
116+
117+
@Schema(description = "A detailed description of the conflict, or null if the change is not conflicting")
118+
public String getConflictDetail() {
119+
return conflictDetail;
120+
}
121+
122+
public void setConflictDetail(final String conflictDetail) {
123+
this.conflictDetail = conflictDetail;
124+
}
125+
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.apache.nifi.web.api.entity;
19+
20+
import io.swagger.v3.oas.annotations.media.Schema;
21+
import jakarta.xml.bind.annotation.XmlRootElement;
22+
import org.apache.nifi.web.api.dto.ComponentDifferenceDTO;
23+
import org.apache.nifi.web.api.dto.RebaseChangeDTO;
24+
25+
import java.util.List;
26+
import java.util.Set;
27+
28+
@XmlRootElement(name = "rebaseAnalysisEntity")
29+
public class RebaseAnalysisEntity extends Entity {
30+
private String processGroupId;
31+
private String currentVersion;
32+
private String targetVersion;
33+
private String analysisFingerprint;
34+
private Boolean rebaseAllowed;
35+
private List<RebaseChangeDTO> localChanges;
36+
private Set<ComponentDifferenceDTO> upstreamChanges;
37+
private String failureReason;
38+
39+
@Schema(description = "The ID of the Process Group being rebased")
40+
public String getProcessGroupId() {
41+
return processGroupId;
42+
}
43+
44+
public void setProcessGroupId(final String processGroupId) {
45+
this.processGroupId = processGroupId;
46+
}
47+
48+
@Schema(description = "The current version of the flow in the Process Group")
49+
public String getCurrentVersion() {
50+
return currentVersion;
51+
}
52+
53+
public void setCurrentVersion(final String currentVersion) {
54+
this.currentVersion = currentVersion;
55+
}
56+
57+
@Schema(description = "The target version to rebase to")
58+
public String getTargetVersion() {
59+
return targetVersion;
60+
}
61+
62+
public void setTargetVersion(final String targetVersion) {
63+
this.targetVersion = targetVersion;
64+
}
65+
66+
@Schema(description = "A fingerprint representing the state of this analysis, used to verify the analysis is still valid when executing the rebase")
67+
public String getAnalysisFingerprint() {
68+
return analysisFingerprint;
69+
}
70+
71+
public void setAnalysisFingerprint(final String analysisFingerprint) {
72+
this.analysisFingerprint = analysisFingerprint;
73+
}
74+
75+
@Schema(description = "Whether the rebase is allowed based on the analysis of local and upstream changes")
76+
public Boolean getRebaseAllowed() {
77+
return rebaseAllowed;
78+
}
79+
80+
public void setRebaseAllowed(final Boolean rebaseAllowed) {
81+
this.rebaseAllowed = rebaseAllowed;
82+
}
83+
84+
@Schema(description = "The list of local changes that were made to the flow since the last version control operation")
85+
public List<RebaseChangeDTO> getLocalChanges() {
86+
return localChanges;
87+
}
88+
89+
public void setLocalChanges(final List<RebaseChangeDTO> localChanges) {
90+
this.localChanges = localChanges;
91+
}
92+
93+
@Schema(description = "The set of upstream changes between the current version and the target version in the flow registry")
94+
public Set<ComponentDifferenceDTO> getUpstreamChanges() {
95+
return upstreamChanges;
96+
}
97+
98+
public void setUpstreamChanges(final Set<ComponentDifferenceDTO> upstreamChanges) {
99+
this.upstreamChanges = upstreamChanges;
100+
}
101+
102+
@Schema(description = "The reason the rebase is not allowed, or null if the rebase is allowed")
103+
public String getFailureReason() {
104+
return failureReason;
105+
}
106+
107+
public void setFailureReason(final String failureReason) {
108+
this.failureReason = failureReason;
109+
}
110+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.apache.nifi.web.api.entity;
19+
20+
import io.swagger.v3.oas.annotations.media.Schema;
21+
import jakarta.xml.bind.annotation.XmlRootElement;
22+
23+
@XmlRootElement(name = "rebaseRequestEntity")
24+
public class RebaseRequestEntity extends Entity {
25+
private VersionControlInformationEntity versionControlInformationEntity;
26+
private String analysisFingerprint;
27+
28+
@Schema(description = "The Version Control information for the Process Group being rebased")
29+
public VersionControlInformationEntity getVersionControlInformationEntity() {
30+
return versionControlInformationEntity;
31+
}
32+
33+
public void setVersionControlInformationEntity(final VersionControlInformationEntity versionControlInformationEntity) {
34+
this.versionControlInformationEntity = versionControlInformationEntity;
35+
}
36+
37+
@Schema(description = "The fingerprint of the rebase analysis, used to verify the analysis is still valid when executing the rebase")
38+
public String getAnalysisFingerprint() {
39+
return analysisFingerprint;
40+
}
41+
42+
public void setAnalysisFingerprint(final String analysisFingerprint) {
43+
this.analysisFingerprint = analysisFingerprint;
44+
}
45+
}

nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@
144144
import org.apache.nifi.web.api.entity.ProcessorEntity;
145145
import org.apache.nifi.web.api.entity.ProcessorStatusEntity;
146146
import org.apache.nifi.web.api.entity.ProcessorsRunStatusDetailsEntity;
147+
import org.apache.nifi.web.api.entity.RebaseAnalysisEntity;
147148
import org.apache.nifi.web.api.entity.RemoteProcessGroupEntity;
148149
import org.apache.nifi.web.api.entity.RemoteProcessGroupPortEntity;
149150
import org.apache.nifi.web.api.entity.RemoteProcessGroupStatusEntity;
@@ -1569,6 +1570,47 @@ Set<DocumentedTypeDTO> getControllerServiceTypes(final String serviceType, final
15691570
*/
15701571
FlowComparisonEntity getLocalModifications(String processGroupId);
15711572

1573+
/**
1574+
* Performs a rebase analysis for the given Process Group, comparing local modifications against
1575+
* upstream changes between the current version and the specified target version.
1576+
*
1577+
* @param processGroupId the ID of the Process Group
1578+
* @param targetVersion the target version to rebase to
1579+
* @return a RebaseAnalysisEntity that contains the analysis of local and upstream changes
1580+
* @throws IllegalStateException if the Process Group with the given ID is not under version control
1581+
*/
1582+
RebaseAnalysisEntity getRebaseAnalysis(String processGroupId, String targetVersion);
1583+
1584+
/**
1585+
* Verifies that the Process Group with the given identifier can be rebased to a new version.
1586+
*
1587+
* @param processGroupId the ID of the Process Group
1588+
* @param targetVersion the target version to rebase to
1589+
* @throws IllegalStateException if the Process Group cannot be rebased
1590+
*/
1591+
void verifyCanRebase(String processGroupId, String targetVersion);
1592+
1593+
/**
1594+
* Returns a FlowSnapshotContainer for the target version of the flow with the merged rebase contents applied.
1595+
* This re-runs the rebase analysis and verifies the fingerprint before producing the merged snapshot.
1596+
*
1597+
* @param processGroupId the ID of the Process Group
1598+
* @param targetVersion the target version to rebase to
1599+
* @param expectedAnalysisFingerprint the expected analysis fingerprint to validate that the analysis has not changed
1600+
* @return a FlowSnapshotContainer containing the target version snapshot with merged local changes applied
1601+
* @throws IllegalStateException if the rebase is not allowed or the fingerprint does not match
1602+
*/
1603+
FlowSnapshotContainer getRebasedFlowSnapshot(String processGroupId, String targetVersion, String expectedAnalysisFingerprint);
1604+
1605+
/**
1606+
* Resets the Version Control Information snapshot for a process group after a rebase operation.
1607+
* After rebase, the VCI snapshot must reference the clean target version (not the merged snapshot)
1608+
* so that subsequent local modification checks correctly detect the preserved local changes.
1609+
*
1610+
* @param processGroupId the process group ID
1611+
*/
1612+
void resetVersionControlSnapshotAfterRebase(String processGroupId);
1613+
15721614
/**
15731615
* Determines whether the process group with the given id or any of its descendants are under version control.
15741616
*

0 commit comments

Comments
 (0)