Module pypowerautomate.package.package
Expand source code
from typing import List, Dict
import uuid
import json
from os import makedirs, path, walk
import shutil
import zipfile
import tempfile
from random import randint
from datetime import datetime, timezone
from ..flow import Flow
def get_timestamp() -> str:
"""
Generates a timestamp in ISO 8601 format appended with a random single digit, suitable for use in file naming or logging.
Returns:
str: The generated timestamp string in UTC.
"""
now = datetime.now(timezone.utc)
return now.strftime("%Y-%m-%dT%H:%M:%S.%f") + str(randint(0, 9)) + "Z"
class Resource:
"""
Manages a single resource defined in a manifest for PowerAutomate, encapsulating various properties including type,
creation attributes, and dependencies among other resources.
"""
def __init__(self, type: str, suggested_creation_type: str,
creation_type: str, configurable_by: str, hierarchy: str, display_name: str, icon_uri: str = None):
"""
Initializes a new resource with specified attributes.
Args:
type (str): The type of the resource.
suggested_creation_type (str): Suggested method for resource creation.
creation_type (str): Specifies how the resource can be created.
configurable_by (str): Indicates who can configure the resource.
hierarchy (str): Hierarchical position of the resource relative to others.
display_name (str): Display name of the resource.
icon_uri (str, optional): URI to the resource's icon image.
"""
self.uuid = uuid.uuid4().__str__()
self.dependencies = []
self.id = None
self.name = None
self.type = type
self.suggested_creation_type = suggested_creation_type
self.creation_type = creation_type
self.configurable_by = configurable_by
self.hierarchy = hierarchy
self.display_name = display_name
self.icon_uri = icon_uri
def set_api_info(self, id: str, name: str):
"""
Sets the API information for the resource.
Args:
id (str): The unique identifier of the API.
name (str): The name of the API.
"""
self.id = id
self.name = name
def set_dependencies(self, resources: List):
"""
Sets dependencies of this resource to other resources.
Args:
resources (List[Resource]): A list of Resource instances that this resource depends on.
"""
for resource in resources:
self.dependencies.append(resource.uuid)
self.dependencies = list(set(self.dependencies))
def export(self) -> dict:
"""
Exports the resource details as a dictionary suitable for serialization.
Returns:
dict: A dictionary containing all relevant details of the resource.
"""
d = {}
if self.id:
d["id"] = self.id
if self.name:
d["name"] = self.name
d["type"] = self.type
d["suggestedCreationType"] = self.suggested_creation_type
if self.creation_type:
d["creationType"] = self.creation_type
details = {}
details["displayName"] = self.display_name
if self.icon_uri:
details["iconUri"] = self.icon_uri
d["details"] = details
d["configurableBy"] = self.configurable_by
d["hierarchy"] = self.hierarchy
d["dependsOn"] = self.dependencies
return d
def __eq__(self, __o: object) -> bool:
"""
Compares this resource with another for equality based on UUID.
Args:
__o (object): The object to compare.
Returns:
bool: True if the objects are the same resource, False otherwise.
"""
if isinstance(__o, Resource):
return self.uuid == __o.uuid
else:
return False
def __hash__(self):
"""
Returns a hash based on the resource's UUID.
Returns:
int: The hash of the resource.
"""
return hash(self.uuid)
class Package:
"""
Manages the packaging of PowerAutomate flows into a deployable ZIP file format,
encapsulating all necessary components like APIs, connections, and definitions.
[Zip directory structure]
.
├── Microsoft.Flow
│ └── flows
│ ├── {uuid}
│ │ ├── apisMap.json
│ │ ├── connectionsMap.json
│ │ └── definition.json
│ └── manifest.json
└── manifest.json
"""
def __init__(self, display_name: str, flow: Flow):
"""
Initializes the package with a specific flow and a display name.
Args:
display_name (str): The name to display for the packaged flow.
flow (Flow): The Flow object containing the workflow logic and configurations.
"""
self.display_name = display_name
self.__apis: List[Resource] = []
self.__connections: List[Resource] = []
self.__api_connection_map: Dict[Resource, Resource] = {}
self.__exist_connections: dict = {}
self.flow = flow
self.__set_flow_resource()
def __set_flow_resource(self):
"""
Initializes the primary resource for the flow within the package.
"""
self.__flow_resource = Resource(
"Microsoft.Flow/flows", "New", "Existing, New, Update", "User", "Root", self.display_name)
def set_flow_management_connector(self, connection_name: str = None):
"""
Sets up a connector for the PowerAutomate Management API with optional connection naming.
Args:
connection_name (str, optional): The name to assign to the connection if it already exists.
"""
# PowerAutomate Management APIの設定
api = Resource("Microsoft.PowerApps/apis", "Existing", None, "System", "Child", "Flow Management",
"https://connectoricons-prod.azureedge.net/releases/v1.0.1650/1.0.1650.3374/flowmanagement/icon.png")
api.set_api_info(
"/providers/Microsoft.PowerApps/apis/shared_flowmanagement", "shared_flowmanagement")
# PowerAutomate Management Connectionの設定
connection = Resource("Microsoft.PowerApps/apis/connections", "Existing", "Existing", "User", "Child", "User",
"https://connectoricons-prod.azureedge.net/releases/v1.0.1644/1.0.1644.3342/flowmanagement/icon.png")
# Connectionの依存APIの設定
connection.set_dependencies([api])
# 既存のconenction情報の設定
if connection_name:
self.__exist_connections["shared_flowmanagement"] = {
"connectionName": connection_name,
"source": "Invoker",
"id": "/providers/Microsoft.PowerApps/apis/shared_flowmanagement",
"tier": "NotSpecified"
}
self.__apis.append(api)
self.__connections.append(connection)
self.__api_connection_map[connection] = api
def set_dropbox_connector(self, connection_name: str = None):
"""
Sets up a connector for the Dropbox API with optional connection naming.
Args:
connection_name (str, optional): The name to assign to the connection if it already exists.
"""
# Dropbox APIの設定
api = Resource("Microsoft.PowerApps/apis", "Existing", None, "System", "Child", "Dropbox",
"https://connectoricons-prod.azureedge.net/releases/v1.0.1651/1.0.1651.3382/dropbox/icon.png")
api.set_api_info(
"/providers/Microsoft.PowerApps/apis/shared_dropbox", "shared_dropbox")
# Dropbox Connectionの設定
connection = Resource("Microsoft.PowerApps/apis/connections", "Existing", "Existing", "User", "Child",
"Dropbox", "https://connectoricons-prod.azureedge.net/releases/v1.0.1651/1.0.1651.3382/dropbox/icon.png")
# Connectionの依存APIの設定
connection.set_dependencies([api])
# 既存のconenction情報の設定
if connection_name:
self.__exist_connections["shared_dropbox"] = {
"connectionName": connection_name,
"source": "Invoker",
"id": "/providers/Microsoft.PowerApps/apis/shared_dropbox",
"tier": "NotSpecified"
}
self.__apis.append(api)
self.__connections.append(connection)
self.__api_connection_map[connection] = api
def set_teams_connector(self, connection_name: str = None):
"""
Sets up a connector for the Teams API with optional connection naming.
Args:
connection_name (str, optional): The name to assign to the connection if it already exists.
"""
# Teams APIの設定
api = Resource("Microsoft.PowerApps/apis", "Existing", None, "System", "Child", "Microsoft Teams",
"https://connectoricons-prod.azureedge.net/releases/v1.0.1657/1.0.1657.3443/teams/icon.png")
api.set_api_info(
"/providers/Microsoft.PowerApps/apis/shared_teams", "shared_teams")
# Teams Connectionの設定
connection = Resource("Microsoft.PowerApps/apis/connections", "Existing", "Existing", "User", "Child",
"Microsoft Teams", "https://connectoricons-prod.azureedge.net/releases/v1.0.1657/1.0.1657.3443/teams/icon.png")
# Connectionの依存APIの設定
connection.set_dependencies([api])
# 既存のconenction情報の設定
if connection_name:
self.__exist_connections["shared_teams"] = {
"connectionName": connection_name,
"source": "Invoker",
"id": "/providers/Microsoft.PowerApps/apis/shared_teams",
"tier": "NotSpecified"
}
self.__apis.append(api)
self.__connections.append(connection)
self.__api_connection_map[connection] = api
def set_sharepoint_connector(self, connection_name: str = None):
"""
Sets up a connector for the Sharepoint API with optional connection naming.
Args:
connection_name (str, optional): The name to assign to the connection if it already exists.
"""
# SharePoint APIの設定
api = Resource("Microsoft.PowerApps/apis", "Existing", None, "System", "Child", "SharePoint",
"https://connectoricons-prod.azureedge.net/u/shgogna/globalperconnector-train1/1.0.1639.3312/sharepointonline/icon.png")
api.set_api_info(
"/providers/Microsoft.PowerApps/apis/shared_sharepointonline", "shared_sharepointonline")
# SharePoint Connectionの設定
connection = Resource("Microsoft.PowerApps/apis/connections", "Existing", "Existing", "User", "Child", "SharePoint",
"https://connectoricons-prod.azureedge.net/u/shgogna/globalperconnector-train1/1.0.1639.3312/sharepointonline/icon.png")
# Connectionの依存APIの設定
connection.set_dependencies([api])
# 既存のconenction情報の設定
if connection_name:
self.__exist_connections["shared_sharepointonline"] = {
"connectionName": connection_name,
"source": "Invoker",
"id": "/providers/Microsoft.PowerApps/apis/shared_sharepointonline",
"tier": "NotSpecified"
}
self.__apis.append(api)
self.__connections.append(connection)
self.__api_connection_map[connection] = api
def set_outlook365_connector(self, connection_name: str = None):
"""
Sets up a connector for the Outlook365 API with optional connection naming.
Args:
connection_name (str, optional): The name to assign to the connection if it already exists.
"""
# Outlook 365 APIの設定
api = Resource("Microsoft.PowerApps/apis", "Existing", None, "System", "Child", "Office 365 Outlook",
"https://connectoricons-prod.azureedge.net/u/laborbol/partial-builds/ase-v3/1.0.1653.3402/office365/icon.png")
api.set_api_info(
"/providers/Microsoft.PowerApps/apis/shared_office365", "shared_office365")
# Outlook 365 Connectionの設定
connection = Resource("Microsoft.PowerApps/apis/connections", "Existing", "Existing", "User", "Child", "Office 365 Outlook",
"https://connectoricons-prod.azureedge.net/u/laborbol/partial-builds/ase-v3/1.0.1653.3402/office365/icon.png")
# Connectionの依存APIの設定
connection.set_dependencies([api])
# 既存のconenction情報の設定
if connection_name:
self.__exist_connections["shared_office365"] = {
"connectionName": connection_name,
"source": "Invoker",
"id": "/providers/Microsoft.PowerApps/apis/shared_office365",
"tier": "NotSpecified"
}
self.__apis.append(api)
self.__connections.append(connection)
self.__api_connection_map[connection] = api
def export_solution_manifest(self) -> dict:
"""
Generates the solution manifest file content for the package, detailing all included resources and metadata.
Returns:
dict: The manifest file content as a dictionary.
"""
# update flow dependencies
self.__flow_resource.set_dependencies(self.__apis)
self.__flow_resource.set_dependencies(self.__connections)
d = {}
d["schema"] = "1.0"
details = {}
details["displayName"] = self.display_name
details["description"] = ""
details["createdTime"] = get_timestamp()
details["packageTelemetryId"] = uuid.uuid4().__str__()
details["creator"] = "N/A"
details["sourceEnvironment"] = ""
d["details"] = details
resources = {}
# Define flow resource
resources[self.__flow_resource.uuid] = self.__flow_resource.export()
# Define api resources
for api in self.__apis:
resources[api.uuid] = api.export()
# Define connection resources
for con in self.__connections:
resources[con.uuid] = con.export()
d["resources"] = resources
return d
def export_apis_map(self):
d = {}
for api in self.__apis:
d[api.name] = api.uuid
return d
def export_connections_map(self):
d = {}
for connection in self.__connections:
d[self.__api_connection_map[connection].name] = connection.uuid
return d
def export_package_manifest(self) -> dict:
d = {}
d["packageSchemaVersion"] = "1.0"
d["flowAssets"] = {
"assetPaths": [self.__flow_resource.uuid]
}
return d
def export_definition(self):
d = {}
d["name"] = uuid.uuid4().__str__()
d["id"] = "/providers/Microsoft.Flow/flows/" + d["name"]
d["type"] = "Microsoft.Flow/flows"
properties = {}
properties["apiId"] = "/providers/Microsoft.PowerApps/apis/shared_logicflows"
properties["displayName"] = self.display_name
properties["definition"] = self.flow.export()
properties["connectionReferences"] = self.__exist_connections
properties["flowFailureAlertSubscribed"] = False
properties["isManaged"] = False
d["properties"] = properties
return d
def __write_json_file(self, path: str, content: dict):
with open(path, 'w') as f:
f.write(json.dumps(content))
def export_zipfile(self, output_dir: str = ".") -> str:
work_dir = tempfile.TemporaryDirectory().name
definition_dir = path.join(
work_dir, "Microsoft.Flow", "flows", self.__flow_resource.uuid)
# ディレクトリ階層作成
makedirs(definition_dir, exist_ok=True)
# ./manifest.json
self.__write_json_file(
path.join(work_dir, "manifest.json"), self.export_solution_manifest())
# ./Microsoft.Flow/flows/manifest.json
self.__write_json_file(path.join(
work_dir, "Microsoft.Flow", "flows", "manifest.json"), self.export_package_manifest())
# ./Microsoft.Flow/flows/{uuid}/definition.json
self.__write_json_file(
path.join(definition_dir, "definition.json"), self.export_definition())
# ./Microsoft.Flow/flows/{uuid}/apisMap.json
self.__write_json_file(
path.join(definition_dir, "apisMap.json"), self.export_apis_map())
# ./Microsoft.Flow/flows/{uuid}/connectionsMap.json
self.__write_json_file(path.join(
definition_dir, "connectionsMap.json"), self.export_connections_map())
# zipファイル作成
filepath = path.join(output_dir, f"{self.display_name}.zip")
zip_file = zipfile.ZipFile(filepath, "w", zipfile.ZIP_DEFLATED)
for root, _, files in walk(work_dir):
for file in files:
zip_file.write(path.join(root, file), path.relpath(
path.join(root, file), work_dir))
zip_file.comment = b'\xe2\xa0\x89\xe2\xa0\x97\xe2\xa0\x91\xe2\xa0\x81\xe2\xa0\x9e\xe2\xa0\x91\xe2\xa0\x99\xe2\xa0\x80\xe2\xa0\x83\xe2\xa0\xbd\xe2\xa0\x80\xe2\xa0\x9e\xe2\xa0\x91\xe2\xa0\x81\xe2\xa0\x8d\xe2\xa0\xa7'
zip_file.close()
# clean-up
shutil.rmtree(work_dir)
return path.abspath(filepath)
Functions
def get_timestamp() ‑> str
-
Generates a timestamp in ISO 8601 format appended with a random single digit, suitable for use in file naming or logging.
Returns
str
- The generated timestamp string in UTC.
Expand source code
def get_timestamp() -> str: """ Generates a timestamp in ISO 8601 format appended with a random single digit, suitable for use in file naming or logging. Returns: str: The generated timestamp string in UTC. """ now = datetime.now(timezone.utc) return now.strftime("%Y-%m-%dT%H:%M:%S.%f") + str(randint(0, 9)) + "Z"
Classes
class Package (display_name: str, flow: Flow)
-
Manages the packaging of PowerAutomate flows into a deployable ZIP file format, encapsulating all necessary components like APIs, connections, and definitions. [Zip directory structure] . ├── Microsoft.Flow │ └── flows │ ├── {uuid} │ │ ├── apisMap.json │ │ ├── connectionsMap.json │ │ └── definition.json │ └── manifest.json └── manifest.json
Initializes the package with a specific flow and a display name.
Args
display_name
:str
- The name to display for the packaged flow.
flow
:Flow
- The Flow object containing the workflow logic and configurations.
Expand source code
class Package: """ Manages the packaging of PowerAutomate flows into a deployable ZIP file format, encapsulating all necessary components like APIs, connections, and definitions. [Zip directory structure] . ├── Microsoft.Flow │ └── flows │ ├── {uuid} │ │ ├── apisMap.json │ │ ├── connectionsMap.json │ │ └── definition.json │ └── manifest.json └── manifest.json """ def __init__(self, display_name: str, flow: Flow): """ Initializes the package with a specific flow and a display name. Args: display_name (str): The name to display for the packaged flow. flow (Flow): The Flow object containing the workflow logic and configurations. """ self.display_name = display_name self.__apis: List[Resource] = [] self.__connections: List[Resource] = [] self.__api_connection_map: Dict[Resource, Resource] = {} self.__exist_connections: dict = {} self.flow = flow self.__set_flow_resource() def __set_flow_resource(self): """ Initializes the primary resource for the flow within the package. """ self.__flow_resource = Resource( "Microsoft.Flow/flows", "New", "Existing, New, Update", "User", "Root", self.display_name) def set_flow_management_connector(self, connection_name: str = None): """ Sets up a connector for the PowerAutomate Management API with optional connection naming. Args: connection_name (str, optional): The name to assign to the connection if it already exists. """ # PowerAutomate Management APIの設定 api = Resource("Microsoft.PowerApps/apis", "Existing", None, "System", "Child", "Flow Management", "https://connectoricons-prod.azureedge.net/releases/v1.0.1650/1.0.1650.3374/flowmanagement/icon.png") api.set_api_info( "/providers/Microsoft.PowerApps/apis/shared_flowmanagement", "shared_flowmanagement") # PowerAutomate Management Connectionの設定 connection = Resource("Microsoft.PowerApps/apis/connections", "Existing", "Existing", "User", "Child", "User", "https://connectoricons-prod.azureedge.net/releases/v1.0.1644/1.0.1644.3342/flowmanagement/icon.png") # Connectionの依存APIの設定 connection.set_dependencies([api]) # 既存のconenction情報の設定 if connection_name: self.__exist_connections["shared_flowmanagement"] = { "connectionName": connection_name, "source": "Invoker", "id": "/providers/Microsoft.PowerApps/apis/shared_flowmanagement", "tier": "NotSpecified" } self.__apis.append(api) self.__connections.append(connection) self.__api_connection_map[connection] = api def set_dropbox_connector(self, connection_name: str = None): """ Sets up a connector for the Dropbox API with optional connection naming. Args: connection_name (str, optional): The name to assign to the connection if it already exists. """ # Dropbox APIの設定 api = Resource("Microsoft.PowerApps/apis", "Existing", None, "System", "Child", "Dropbox", "https://connectoricons-prod.azureedge.net/releases/v1.0.1651/1.0.1651.3382/dropbox/icon.png") api.set_api_info( "/providers/Microsoft.PowerApps/apis/shared_dropbox", "shared_dropbox") # Dropbox Connectionの設定 connection = Resource("Microsoft.PowerApps/apis/connections", "Existing", "Existing", "User", "Child", "Dropbox", "https://connectoricons-prod.azureedge.net/releases/v1.0.1651/1.0.1651.3382/dropbox/icon.png") # Connectionの依存APIの設定 connection.set_dependencies([api]) # 既存のconenction情報の設定 if connection_name: self.__exist_connections["shared_dropbox"] = { "connectionName": connection_name, "source": "Invoker", "id": "/providers/Microsoft.PowerApps/apis/shared_dropbox", "tier": "NotSpecified" } self.__apis.append(api) self.__connections.append(connection) self.__api_connection_map[connection] = api def set_teams_connector(self, connection_name: str = None): """ Sets up a connector for the Teams API with optional connection naming. Args: connection_name (str, optional): The name to assign to the connection if it already exists. """ # Teams APIの設定 api = Resource("Microsoft.PowerApps/apis", "Existing", None, "System", "Child", "Microsoft Teams", "https://connectoricons-prod.azureedge.net/releases/v1.0.1657/1.0.1657.3443/teams/icon.png") api.set_api_info( "/providers/Microsoft.PowerApps/apis/shared_teams", "shared_teams") # Teams Connectionの設定 connection = Resource("Microsoft.PowerApps/apis/connections", "Existing", "Existing", "User", "Child", "Microsoft Teams", "https://connectoricons-prod.azureedge.net/releases/v1.0.1657/1.0.1657.3443/teams/icon.png") # Connectionの依存APIの設定 connection.set_dependencies([api]) # 既存のconenction情報の設定 if connection_name: self.__exist_connections["shared_teams"] = { "connectionName": connection_name, "source": "Invoker", "id": "/providers/Microsoft.PowerApps/apis/shared_teams", "tier": "NotSpecified" } self.__apis.append(api) self.__connections.append(connection) self.__api_connection_map[connection] = api def set_sharepoint_connector(self, connection_name: str = None): """ Sets up a connector for the Sharepoint API with optional connection naming. Args: connection_name (str, optional): The name to assign to the connection if it already exists. """ # SharePoint APIの設定 api = Resource("Microsoft.PowerApps/apis", "Existing", None, "System", "Child", "SharePoint", "https://connectoricons-prod.azureedge.net/u/shgogna/globalperconnector-train1/1.0.1639.3312/sharepointonline/icon.png") api.set_api_info( "/providers/Microsoft.PowerApps/apis/shared_sharepointonline", "shared_sharepointonline") # SharePoint Connectionの設定 connection = Resource("Microsoft.PowerApps/apis/connections", "Existing", "Existing", "User", "Child", "SharePoint", "https://connectoricons-prod.azureedge.net/u/shgogna/globalperconnector-train1/1.0.1639.3312/sharepointonline/icon.png") # Connectionの依存APIの設定 connection.set_dependencies([api]) # 既存のconenction情報の設定 if connection_name: self.__exist_connections["shared_sharepointonline"] = { "connectionName": connection_name, "source": "Invoker", "id": "/providers/Microsoft.PowerApps/apis/shared_sharepointonline", "tier": "NotSpecified" } self.__apis.append(api) self.__connections.append(connection) self.__api_connection_map[connection] = api def set_outlook365_connector(self, connection_name: str = None): """ Sets up a connector for the Outlook365 API with optional connection naming. Args: connection_name (str, optional): The name to assign to the connection if it already exists. """ # Outlook 365 APIの設定 api = Resource("Microsoft.PowerApps/apis", "Existing", None, "System", "Child", "Office 365 Outlook", "https://connectoricons-prod.azureedge.net/u/laborbol/partial-builds/ase-v3/1.0.1653.3402/office365/icon.png") api.set_api_info( "/providers/Microsoft.PowerApps/apis/shared_office365", "shared_office365") # Outlook 365 Connectionの設定 connection = Resource("Microsoft.PowerApps/apis/connections", "Existing", "Existing", "User", "Child", "Office 365 Outlook", "https://connectoricons-prod.azureedge.net/u/laborbol/partial-builds/ase-v3/1.0.1653.3402/office365/icon.png") # Connectionの依存APIの設定 connection.set_dependencies([api]) # 既存のconenction情報の設定 if connection_name: self.__exist_connections["shared_office365"] = { "connectionName": connection_name, "source": "Invoker", "id": "/providers/Microsoft.PowerApps/apis/shared_office365", "tier": "NotSpecified" } self.__apis.append(api) self.__connections.append(connection) self.__api_connection_map[connection] = api def export_solution_manifest(self) -> dict: """ Generates the solution manifest file content for the package, detailing all included resources and metadata. Returns: dict: The manifest file content as a dictionary. """ # update flow dependencies self.__flow_resource.set_dependencies(self.__apis) self.__flow_resource.set_dependencies(self.__connections) d = {} d["schema"] = "1.0" details = {} details["displayName"] = self.display_name details["description"] = "" details["createdTime"] = get_timestamp() details["packageTelemetryId"] = uuid.uuid4().__str__() details["creator"] = "N/A" details["sourceEnvironment"] = "" d["details"] = details resources = {} # Define flow resource resources[self.__flow_resource.uuid] = self.__flow_resource.export() # Define api resources for api in self.__apis: resources[api.uuid] = api.export() # Define connection resources for con in self.__connections: resources[con.uuid] = con.export() d["resources"] = resources return d def export_apis_map(self): d = {} for api in self.__apis: d[api.name] = api.uuid return d def export_connections_map(self): d = {} for connection in self.__connections: d[self.__api_connection_map[connection].name] = connection.uuid return d def export_package_manifest(self) -> dict: d = {} d["packageSchemaVersion"] = "1.0" d["flowAssets"] = { "assetPaths": [self.__flow_resource.uuid] } return d def export_definition(self): d = {} d["name"] = uuid.uuid4().__str__() d["id"] = "/providers/Microsoft.Flow/flows/" + d["name"] d["type"] = "Microsoft.Flow/flows" properties = {} properties["apiId"] = "/providers/Microsoft.PowerApps/apis/shared_logicflows" properties["displayName"] = self.display_name properties["definition"] = self.flow.export() properties["connectionReferences"] = self.__exist_connections properties["flowFailureAlertSubscribed"] = False properties["isManaged"] = False d["properties"] = properties return d def __write_json_file(self, path: str, content: dict): with open(path, 'w') as f: f.write(json.dumps(content)) def export_zipfile(self, output_dir: str = ".") -> str: work_dir = tempfile.TemporaryDirectory().name definition_dir = path.join( work_dir, "Microsoft.Flow", "flows", self.__flow_resource.uuid) # ディレクトリ階層作成 makedirs(definition_dir, exist_ok=True) # ./manifest.json self.__write_json_file( path.join(work_dir, "manifest.json"), self.export_solution_manifest()) # ./Microsoft.Flow/flows/manifest.json self.__write_json_file(path.join( work_dir, "Microsoft.Flow", "flows", "manifest.json"), self.export_package_manifest()) # ./Microsoft.Flow/flows/{uuid}/definition.json self.__write_json_file( path.join(definition_dir, "definition.json"), self.export_definition()) # ./Microsoft.Flow/flows/{uuid}/apisMap.json self.__write_json_file( path.join(definition_dir, "apisMap.json"), self.export_apis_map()) # ./Microsoft.Flow/flows/{uuid}/connectionsMap.json self.__write_json_file(path.join( definition_dir, "connectionsMap.json"), self.export_connections_map()) # zipファイル作成 filepath = path.join(output_dir, f"{self.display_name}.zip") zip_file = zipfile.ZipFile(filepath, "w", zipfile.ZIP_DEFLATED) for root, _, files in walk(work_dir): for file in files: zip_file.write(path.join(root, file), path.relpath( path.join(root, file), work_dir)) zip_file.comment = b'\xe2\xa0\x89\xe2\xa0\x97\xe2\xa0\x91\xe2\xa0\x81\xe2\xa0\x9e\xe2\xa0\x91\xe2\xa0\x99\xe2\xa0\x80\xe2\xa0\x83\xe2\xa0\xbd\xe2\xa0\x80\xe2\xa0\x9e\xe2\xa0\x91\xe2\xa0\x81\xe2\xa0\x8d\xe2\xa0\xa7' zip_file.close() # clean-up shutil.rmtree(work_dir) return path.abspath(filepath)
Methods
def export_apis_map(self)
-
Expand source code
def export_apis_map(self): d = {} for api in self.__apis: d[api.name] = api.uuid return d
def export_connections_map(self)
-
Expand source code
def export_connections_map(self): d = {} for connection in self.__connections: d[self.__api_connection_map[connection].name] = connection.uuid return d
def export_definition(self)
-
Expand source code
def export_definition(self): d = {} d["name"] = uuid.uuid4().__str__() d["id"] = "/providers/Microsoft.Flow/flows/" + d["name"] d["type"] = "Microsoft.Flow/flows" properties = {} properties["apiId"] = "/providers/Microsoft.PowerApps/apis/shared_logicflows" properties["displayName"] = self.display_name properties["definition"] = self.flow.export() properties["connectionReferences"] = self.__exist_connections properties["flowFailureAlertSubscribed"] = False properties["isManaged"] = False d["properties"] = properties return d
def export_package_manifest(self) ‑> dict
-
Expand source code
def export_package_manifest(self) -> dict: d = {} d["packageSchemaVersion"] = "1.0" d["flowAssets"] = { "assetPaths": [self.__flow_resource.uuid] } return d
def export_solution_manifest(self) ‑> dict
-
Generates the solution manifest file content for the package, detailing all included resources and metadata.
Returns
dict
- The manifest file content as a dictionary.
Expand source code
def export_solution_manifest(self) -> dict: """ Generates the solution manifest file content for the package, detailing all included resources and metadata. Returns: dict: The manifest file content as a dictionary. """ # update flow dependencies self.__flow_resource.set_dependencies(self.__apis) self.__flow_resource.set_dependencies(self.__connections) d = {} d["schema"] = "1.0" details = {} details["displayName"] = self.display_name details["description"] = "" details["createdTime"] = get_timestamp() details["packageTelemetryId"] = uuid.uuid4().__str__() details["creator"] = "N/A" details["sourceEnvironment"] = "" d["details"] = details resources = {} # Define flow resource resources[self.__flow_resource.uuid] = self.__flow_resource.export() # Define api resources for api in self.__apis: resources[api.uuid] = api.export() # Define connection resources for con in self.__connections: resources[con.uuid] = con.export() d["resources"] = resources return d
def export_zipfile(self, output_dir: str = '.') ‑> str
-
Expand source code
def export_zipfile(self, output_dir: str = ".") -> str: work_dir = tempfile.TemporaryDirectory().name definition_dir = path.join( work_dir, "Microsoft.Flow", "flows", self.__flow_resource.uuid) # ディレクトリ階層作成 makedirs(definition_dir, exist_ok=True) # ./manifest.json self.__write_json_file( path.join(work_dir, "manifest.json"), self.export_solution_manifest()) # ./Microsoft.Flow/flows/manifest.json self.__write_json_file(path.join( work_dir, "Microsoft.Flow", "flows", "manifest.json"), self.export_package_manifest()) # ./Microsoft.Flow/flows/{uuid}/definition.json self.__write_json_file( path.join(definition_dir, "definition.json"), self.export_definition()) # ./Microsoft.Flow/flows/{uuid}/apisMap.json self.__write_json_file( path.join(definition_dir, "apisMap.json"), self.export_apis_map()) # ./Microsoft.Flow/flows/{uuid}/connectionsMap.json self.__write_json_file(path.join( definition_dir, "connectionsMap.json"), self.export_connections_map()) # zipファイル作成 filepath = path.join(output_dir, f"{self.display_name}.zip") zip_file = zipfile.ZipFile(filepath, "w", zipfile.ZIP_DEFLATED) for root, _, files in walk(work_dir): for file in files: zip_file.write(path.join(root, file), path.relpath( path.join(root, file), work_dir)) zip_file.comment = b'\xe2\xa0\x89\xe2\xa0\x97\xe2\xa0\x91\xe2\xa0\x81\xe2\xa0\x9e\xe2\xa0\x91\xe2\xa0\x99\xe2\xa0\x80\xe2\xa0\x83\xe2\xa0\xbd\xe2\xa0\x80\xe2\xa0\x9e\xe2\xa0\x91\xe2\xa0\x81\xe2\xa0\x8d\xe2\xa0\xa7' zip_file.close() # clean-up shutil.rmtree(work_dir) return path.abspath(filepath)
def set_dropbox_connector(self, connection_name: str = None)
-
Sets up a connector for the Dropbox API with optional connection naming.
Args
connection_name
:str
, optional- The name to assign to the connection if it already exists.
Expand source code
def set_dropbox_connector(self, connection_name: str = None): """ Sets up a connector for the Dropbox API with optional connection naming. Args: connection_name (str, optional): The name to assign to the connection if it already exists. """ # Dropbox APIの設定 api = Resource("Microsoft.PowerApps/apis", "Existing", None, "System", "Child", "Dropbox", "https://connectoricons-prod.azureedge.net/releases/v1.0.1651/1.0.1651.3382/dropbox/icon.png") api.set_api_info( "/providers/Microsoft.PowerApps/apis/shared_dropbox", "shared_dropbox") # Dropbox Connectionの設定 connection = Resource("Microsoft.PowerApps/apis/connections", "Existing", "Existing", "User", "Child", "Dropbox", "https://connectoricons-prod.azureedge.net/releases/v1.0.1651/1.0.1651.3382/dropbox/icon.png") # Connectionの依存APIの設定 connection.set_dependencies([api]) # 既存のconenction情報の設定 if connection_name: self.__exist_connections["shared_dropbox"] = { "connectionName": connection_name, "source": "Invoker", "id": "/providers/Microsoft.PowerApps/apis/shared_dropbox", "tier": "NotSpecified" } self.__apis.append(api) self.__connections.append(connection) self.__api_connection_map[connection] = api
def set_flow_management_connector(self, connection_name: str = None)
-
Sets up a connector for the PowerAutomate Management API with optional connection naming.
Args
connection_name
:str
, optional- The name to assign to the connection if it already exists.
Expand source code
def set_flow_management_connector(self, connection_name: str = None): """ Sets up a connector for the PowerAutomate Management API with optional connection naming. Args: connection_name (str, optional): The name to assign to the connection if it already exists. """ # PowerAutomate Management APIの設定 api = Resource("Microsoft.PowerApps/apis", "Existing", None, "System", "Child", "Flow Management", "https://connectoricons-prod.azureedge.net/releases/v1.0.1650/1.0.1650.3374/flowmanagement/icon.png") api.set_api_info( "/providers/Microsoft.PowerApps/apis/shared_flowmanagement", "shared_flowmanagement") # PowerAutomate Management Connectionの設定 connection = Resource("Microsoft.PowerApps/apis/connections", "Existing", "Existing", "User", "Child", "User", "https://connectoricons-prod.azureedge.net/releases/v1.0.1644/1.0.1644.3342/flowmanagement/icon.png") # Connectionの依存APIの設定 connection.set_dependencies([api]) # 既存のconenction情報の設定 if connection_name: self.__exist_connections["shared_flowmanagement"] = { "connectionName": connection_name, "source": "Invoker", "id": "/providers/Microsoft.PowerApps/apis/shared_flowmanagement", "tier": "NotSpecified" } self.__apis.append(api) self.__connections.append(connection) self.__api_connection_map[connection] = api
def set_outlook365_connector(self, connection_name: str = None)
-
Sets up a connector for the Outlook365 API with optional connection naming.
Args
connection_name
:str
, optional- The name to assign to the connection if it already exists.
Expand source code
def set_outlook365_connector(self, connection_name: str = None): """ Sets up a connector for the Outlook365 API with optional connection naming. Args: connection_name (str, optional): The name to assign to the connection if it already exists. """ # Outlook 365 APIの設定 api = Resource("Microsoft.PowerApps/apis", "Existing", None, "System", "Child", "Office 365 Outlook", "https://connectoricons-prod.azureedge.net/u/laborbol/partial-builds/ase-v3/1.0.1653.3402/office365/icon.png") api.set_api_info( "/providers/Microsoft.PowerApps/apis/shared_office365", "shared_office365") # Outlook 365 Connectionの設定 connection = Resource("Microsoft.PowerApps/apis/connections", "Existing", "Existing", "User", "Child", "Office 365 Outlook", "https://connectoricons-prod.azureedge.net/u/laborbol/partial-builds/ase-v3/1.0.1653.3402/office365/icon.png") # Connectionの依存APIの設定 connection.set_dependencies([api]) # 既存のconenction情報の設定 if connection_name: self.__exist_connections["shared_office365"] = { "connectionName": connection_name, "source": "Invoker", "id": "/providers/Microsoft.PowerApps/apis/shared_office365", "tier": "NotSpecified" } self.__apis.append(api) self.__connections.append(connection) self.__api_connection_map[connection] = api
-
Sets up a connector for the Sharepoint API with optional connection naming.
Args
connection_name
:str
, optional- The name to assign to the connection if it already exists.
Expand source code
def set_sharepoint_connector(self, connection_name: str = None): """ Sets up a connector for the Sharepoint API with optional connection naming. Args: connection_name (str, optional): The name to assign to the connection if it already exists. """ # SharePoint APIの設定 api = Resource("Microsoft.PowerApps/apis", "Existing", None, "System", "Child", "SharePoint", "https://connectoricons-prod.azureedge.net/u/shgogna/globalperconnector-train1/1.0.1639.3312/sharepointonline/icon.png") api.set_api_info( "/providers/Microsoft.PowerApps/apis/shared_sharepointonline", "shared_sharepointonline") # SharePoint Connectionの設定 connection = Resource("Microsoft.PowerApps/apis/connections", "Existing", "Existing", "User", "Child", "SharePoint", "https://connectoricons-prod.azureedge.net/u/shgogna/globalperconnector-train1/1.0.1639.3312/sharepointonline/icon.png") # Connectionの依存APIの設定 connection.set_dependencies([api]) # 既存のconenction情報の設定 if connection_name: self.__exist_connections["shared_sharepointonline"] = { "connectionName": connection_name, "source": "Invoker", "id": "/providers/Microsoft.PowerApps/apis/shared_sharepointonline", "tier": "NotSpecified" } self.__apis.append(api) self.__connections.append(connection) self.__api_connection_map[connection] = api
def set_teams_connector(self, connection_name: str = None)
-
Sets up a connector for the Teams API with optional connection naming.
Args
connection_name
:str
, optional- The name to assign to the connection if it already exists.
Expand source code
def set_teams_connector(self, connection_name: str = None): """ Sets up a connector for the Teams API with optional connection naming. Args: connection_name (str, optional): The name to assign to the connection if it already exists. """ # Teams APIの設定 api = Resource("Microsoft.PowerApps/apis", "Existing", None, "System", "Child", "Microsoft Teams", "https://connectoricons-prod.azureedge.net/releases/v1.0.1657/1.0.1657.3443/teams/icon.png") api.set_api_info( "/providers/Microsoft.PowerApps/apis/shared_teams", "shared_teams") # Teams Connectionの設定 connection = Resource("Microsoft.PowerApps/apis/connections", "Existing", "Existing", "User", "Child", "Microsoft Teams", "https://connectoricons-prod.azureedge.net/releases/v1.0.1657/1.0.1657.3443/teams/icon.png") # Connectionの依存APIの設定 connection.set_dependencies([api]) # 既存のconenction情報の設定 if connection_name: self.__exist_connections["shared_teams"] = { "connectionName": connection_name, "source": "Invoker", "id": "/providers/Microsoft.PowerApps/apis/shared_teams", "tier": "NotSpecified" } self.__apis.append(api) self.__connections.append(connection) self.__api_connection_map[connection] = api
class Resource (type: str, suggested_creation_type: str, creation_type: str, configurable_by: str, hierarchy: str, display_name: str, icon_uri: str = None)
-
Manages a single resource defined in a manifest for PowerAutomate, encapsulating various properties including type, creation attributes, and dependencies among other resources.
Initializes a new resource with specified attributes.
Args
type
:str
- The type of the resource.
suggested_creation_type
:str
- Suggested method for resource creation.
creation_type
:str
- Specifies how the resource can be created.
configurable_by
:str
- Indicates who can configure the resource.
hierarchy
:str
- Hierarchical position of the resource relative to others.
display_name
:str
- Display name of the resource.
icon_uri
:str
, optional- URI to the resource's icon image.
Expand source code
class Resource: """ Manages a single resource defined in a manifest for PowerAutomate, encapsulating various properties including type, creation attributes, and dependencies among other resources. """ def __init__(self, type: str, suggested_creation_type: str, creation_type: str, configurable_by: str, hierarchy: str, display_name: str, icon_uri: str = None): """ Initializes a new resource with specified attributes. Args: type (str): The type of the resource. suggested_creation_type (str): Suggested method for resource creation. creation_type (str): Specifies how the resource can be created. configurable_by (str): Indicates who can configure the resource. hierarchy (str): Hierarchical position of the resource relative to others. display_name (str): Display name of the resource. icon_uri (str, optional): URI to the resource's icon image. """ self.uuid = uuid.uuid4().__str__() self.dependencies = [] self.id = None self.name = None self.type = type self.suggested_creation_type = suggested_creation_type self.creation_type = creation_type self.configurable_by = configurable_by self.hierarchy = hierarchy self.display_name = display_name self.icon_uri = icon_uri def set_api_info(self, id: str, name: str): """ Sets the API information for the resource. Args: id (str): The unique identifier of the API. name (str): The name of the API. """ self.id = id self.name = name def set_dependencies(self, resources: List): """ Sets dependencies of this resource to other resources. Args: resources (List[Resource]): A list of Resource instances that this resource depends on. """ for resource in resources: self.dependencies.append(resource.uuid) self.dependencies = list(set(self.dependencies)) def export(self) -> dict: """ Exports the resource details as a dictionary suitable for serialization. Returns: dict: A dictionary containing all relevant details of the resource. """ d = {} if self.id: d["id"] = self.id if self.name: d["name"] = self.name d["type"] = self.type d["suggestedCreationType"] = self.suggested_creation_type if self.creation_type: d["creationType"] = self.creation_type details = {} details["displayName"] = self.display_name if self.icon_uri: details["iconUri"] = self.icon_uri d["details"] = details d["configurableBy"] = self.configurable_by d["hierarchy"] = self.hierarchy d["dependsOn"] = self.dependencies return d def __eq__(self, __o: object) -> bool: """ Compares this resource with another for equality based on UUID. Args: __o (object): The object to compare. Returns: bool: True if the objects are the same resource, False otherwise. """ if isinstance(__o, Resource): return self.uuid == __o.uuid else: return False def __hash__(self): """ Returns a hash based on the resource's UUID. Returns: int: The hash of the resource. """ return hash(self.uuid)
Methods
def export(self) ‑> dict
-
Exports the resource details as a dictionary suitable for serialization.
Returns
dict
- A dictionary containing all relevant details of the resource.
Expand source code
def export(self) -> dict: """ Exports the resource details as a dictionary suitable for serialization. Returns: dict: A dictionary containing all relevant details of the resource. """ d = {} if self.id: d["id"] = self.id if self.name: d["name"] = self.name d["type"] = self.type d["suggestedCreationType"] = self.suggested_creation_type if self.creation_type: d["creationType"] = self.creation_type details = {} details["displayName"] = self.display_name if self.icon_uri: details["iconUri"] = self.icon_uri d["details"] = details d["configurableBy"] = self.configurable_by d["hierarchy"] = self.hierarchy d["dependsOn"] = self.dependencies return d
def set_api_info(self, id: str, name: str)
-
Sets the API information for the resource.
Args
id
:str
- The unique identifier of the API.
name
:str
- The name of the API.
Expand source code
def set_api_info(self, id: str, name: str): """ Sets the API information for the resource. Args: id (str): The unique identifier of the API. name (str): The name of the API. """ self.id = id self.name = name
def set_dependencies(self, resources: List)
-
Sets dependencies of this resource to other resources.
Args
resources
:List[Resource]
- A list of Resource instances that this resource depends on.
Expand source code
def set_dependencies(self, resources: List): """ Sets dependencies of this resource to other resources. Args: resources (List[Resource]): A list of Resource instances that this resource depends on. """ for resource in resources: self.dependencies.append(resource.uuid) self.dependencies = list(set(self.dependencies))