I fixed up this script so it can be run autonomously from a CI tool. The script will connect to a Pro Project and look for a map that contains the feature layers to be overwritten. All the feature layers contained in this map and their service definitions must have already been published initially and hosted on AGOL.
The script disables sync and unregisters replicas before overwriting the service definition file and existing feature service. The feature layers in the map may be grouped or ungrouped. Grouped layers will be published as a single feature service, same as the ungrouped layers. All service properties (sync, sharing, editing etc.) will remain the same as they originally were. The layer names in the Pro map must match the published feature layer names, so make sure the map is setup correctly in Pro.
Thanks to Jake Skinner for getting this started in the right direction.
import arcpy, os, time
from arcgis.gis import GIS
from arcgis.features import FeatureLayerCollection
# Variables
prjPath = r"C:\PathToProProject\ProProject.aprx" # Path to Pro Project
map_name = 'Test Map Overwrite' # Name of map in Pro Project
portal = "https://www.arcgis.com" # AGOL
user = "username" # AGOL username
password = "password" # AGOL password
unregisterReplicas = True # True/False to unregister existing replicas
group_layer_names = []
ungrouped_layer_names = []
# Set Environment Variables
arcpy.env.overwriteOutput = 1
# Start Timer
startTime = time.time()
print(f"Connecting to AGOL")
gis = GIS(portal, user, password)
project = arcpy.mp.ArcGISProject(prjPath)
# Get the map in the project
map_obj = project.listMaps(map_name)[0]
# Iterate through all layers in the map and list the grouped layer names
for layer in map_obj.listLayers():
if layer.isGroupLayer:
group_layer_names.append(layer.name)
print (f"Grouped layer names: {group_layer_names}")
# Iterate through all layers in the map and list the ungrouped layer names
for layer in map_obj.listLayers():
if not layer.isGroupLayer:
# Check if the layer is part of any group layer
is_in_group = False
for parent_layer in map_obj.listLayers():
if parent_layer.isGroupLayer and layer in parent_layer.listLayers():
is_in_group = True
break
if not is_in_group:
ungrouped_layer_names.append(layer.name)
print (f"Ungrouped layer names: {ungrouped_layer_names}")
layer_list = ungrouped_layer_names + group_layer_names
print (f"Layers to be republished: {layer_list}")
# Loop through all the layers and get the feature layer and service definition ID's
for layer_name in layer_list:
# Filter the feature layers for an exact match and get the feature layer ID
fl_search_results = gis.content.search(query=f"title:{layer_name}", item_type="Feature Layer", sort_field='title', sort_order='asc')
fl_item = None
# Iterate through the search results to find the exact match
for item in fl_search_results:
if item.title == layer_name:
fl_item = item
break
if fl_item:
print(f"Found exact match for feature layer: {fl_item.title} (ID: {fl_item.id})")
else:
print(f"No exact match found for feature layer: {layer_name}")
# Filter the service definitions for an exact match and get the service definition ID
sd_search_results = gis.content.search(query=f"title:{layer_name}", item_type="Service Definition", sort_field='title', sort_order='asc')
sd_item = None
# Iterate through the search results to find the exact match
for item in sd_search_results:
if item.title == layer_name:
sd_item = item
break
if sd_item:
print(f"Found exact match for service definition: {sd_item.title} (ID: {sd_item.id})")
else:
print(f"No exact match found for service definition: {layer_name}")
# Local paths to create temporary content
sddraft = os.path.join(arcpy.env.scratchFolder, "WebUpdate.sddraft")
sd = os.path.join(arcpy.env.scratchFolder, "WebUpdate.sd")
sdItem = gis.content.get(sd_item.id)
#print (sdItem)
# Create a new SDDraft and stage to SD
print("Creating SD file")
arcpy.env.overwriteOutput = True
prj = arcpy.mp.ArcGISProject(prjPath)
mp = prj.listMaps(map_name)[0]
serviceDefName = sdItem.title
arcpy.mp.CreateWebLayerSDDraft(mp, sddraft, serviceDefName, 'MY_HOSTED_SERVICES', 'FEATURE_ACCESS', '', True, True)
arcpy.StageService_server(sddraft, sd)
# Reference existing feature service to get properties
fsItem = gis.content.get(fl_item.id)
#print (fsItem)
flyrCollection = FeatureLayerCollection.fromitem(fsItem)
existingDef = flyrCollection.properties
# Unregister existing replicas
if unregisterReplicas:
if flyrCollection.properties.syncEnabled:
print("Unregister existing replicas")
for replica in flyrCollection.replicas.get_list():
replicaID = replica['replicaID']
flyrCollection.replicas.unregister(replicaID)
# Overwrite feature service
sdItem.update(data=sd)
print("Overwriting existing feature service")
fs = sdItem.publish(overwrite=True)
# Update service with previous properties
print("Updating service properties")
flyrCollection.manager.update_definition(existingDef)
print("Clearing scratch directory")
arcpy.env.workspace = arcpy.env.scratchFolder
for file in arcpy.ListFiles():
if file.split(".")[-1] in ('sd', 'sddraft', 'png', 'xml'):
arcpy.Delete_management(file)
endTime = time.time()
elapsedTime = round((endTime - startTime) / 60, 2)
print(f"Script completed in {elapsedTime} minutes")