Coverage for webapp/publisher/snaps/builds.py: 75%
77 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-07-31 22:23 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-07-31 22:23 +0000
1from enum import Enum
4class StoreFrontBuildState(Enum):
5 NEVER_BUILT = "never_built"
6 BUILDING_SOON = "building_soon"
7 WONT_RELEASE = "wont_release"
8 RELEASED = "released"
9 RELEASE_FAILED = "release_failed"
10 RELEASING_SOON = "releasing_soon"
11 IN_PROGRESS = "in_progress"
12 FAILED_TO_BUILD = "failed_to_build"
13 CANCELLED = "cancelled"
14 UNKNOWN = "unknown"
17class LaunchpadBuildState(Enum):
18 NEEDS_BUILD = "Needs building"
19 FULLY_BUILT = "Successfully built"
20 FAILED_BUILD = "Failed to build"
21 MANUALDEPWAIT = "Dependency wait"
22 CHROOTWAIT = "Chroot problem"
23 SUPERSEDED = "Build for superseded Source"
24 BUILDING = "Currently building"
25 GATHERING_OUTPUT = "Gathering build output"
26 FAILED_UPLOAD = "Failed to upload"
27 UPLOADING = "Uploading build"
28 CANCELLING = "Cancelling build"
29 CANCELLED = "Cancelled build"
32class LaunchpadStoreUploadState(Enum):
33 UNSCHEDULED = "Unscheduled"
34 PENDING = "Pending"
35 FAILED_UPLOAD = "Failed to upload"
36 FAILED_RELEASE = "Failed to release to channels"
37 UPLOADED = "Uploaded"
40def build_link(bsi_url, snap, build):
41 """Builds the link to the build page"""
42 build_id = build["self_link"].split("/")[-1]
44 # Remove GitHub hostname & split owner/repo
45 owner, repo = snap["git_repository_url"][19:].split("/")
47 return f"{bsi_url}/user/{owner}/{repo}/{build_id}"
50def _map_upload_state(upload_state):
51 """Returns a user facing status based on
52 the status of the snap's upload to the store.
53 """
54 upload_state = LaunchpadStoreUploadState(upload_state)
55 if upload_state == LaunchpadStoreUploadState.UNSCHEDULED:
56 return StoreFrontBuildState.WONT_RELEASE.value
58 elif upload_state == LaunchpadStoreUploadState.PENDING:
59 return StoreFrontBuildState.RELEASING_SOON.value
61 elif (
62 upload_state == LaunchpadStoreUploadState.FAILED_UPLOAD
63 or upload_state == LaunchpadStoreUploadState.FAILED_RELEASE
64 ):
65 return StoreFrontBuildState.RELEASE_FAILED.value
67 elif upload_state == LaunchpadStoreUploadState.UPLOADED:
68 return StoreFrontBuildState.RELEASED.value
70 return StoreFrontBuildState.UNKNOWN.value
73def map_build_and_upload_states(build_state, upload_state):
74 """Returns a user facing status based on the LP
75 build state and the status of the snap's
76 upload to the store.
77 """
78 build_state = LaunchpadBuildState(build_state)
80 if build_state == LaunchpadBuildState.NEEDS_BUILD:
81 return StoreFrontBuildState.BUILDING_SOON.value
83 elif build_state == LaunchpadBuildState.FULLY_BUILT:
84 return _map_upload_state(upload_state)
86 elif build_state == LaunchpadBuildState.BUILDING:
87 return StoreFrontBuildState.IN_PROGRESS.value
89 elif build_state == LaunchpadBuildState.GATHERING_OUTPUT:
90 return StoreFrontBuildState.IN_PROGRESS.value
92 elif build_state == LaunchpadBuildState.UPLOADING:
93 return StoreFrontBuildState.IN_PROGRESS.value
95 elif build_state in [
96 LaunchpadBuildState.CANCELLING,
97 LaunchpadBuildState.CANCELLED,
98 ]:
99 return StoreFrontBuildState.CANCELLED.value
101 elif build_state in [
102 LaunchpadBuildState.FAILED_BUILD,
103 LaunchpadBuildState.MANUALDEPWAIT,
104 LaunchpadBuildState.CHROOTWAIT,
105 LaunchpadBuildState.SUPERSEDED,
106 LaunchpadBuildState.FAILED_UPLOAD,
107 ]:
108 return StoreFrontBuildState.FAILED_TO_BUILD.value
110 return StoreFrontBuildState.UNKNOWN.value
113def map_snap_build_status(snap_build_statuses):
114 """Returns a user facing status based on the LP
115 build state and the status of the snap's
116 upload to the store.
117 """
118 mapped_arch_statuses = set()
120 for arch_statuses in snap_build_statuses.values():
121 mapped_status = map_build_and_upload_states(
122 arch_statuses["buildstate"], arch_statuses["store_upload_status"]
123 )
125 # Return instantly a failure status if one arch is failing
126 if mapped_status in [
127 StoreFrontBuildState.NEVER_BUILT.value,
128 StoreFrontBuildState.WONT_RELEASE.value,
129 StoreFrontBuildState.RELEASE_FAILED.value,
130 StoreFrontBuildState.FAILED_TO_BUILD.value,
131 StoreFrontBuildState.CANCELLED.value,
132 ]:
133 return mapped_status
135 mapped_arch_statuses.add(mapped_status)
137 # All the archs have the same status
138 if len(mapped_arch_statuses) == 1:
139 return mapped_arch_statuses.pop()
141 # List of the non-failure status in the preferred order to return
142 positive_statuses = [
143 StoreFrontBuildState.BUILDING_SOON.value,
144 StoreFrontBuildState.IN_PROGRESS.value,
145 StoreFrontBuildState.RELEASING_SOON.value,
146 StoreFrontBuildState.RELEASED.value,
147 ]
149 for status in positive_statuses:
150 if status in mapped_arch_statuses:
151 return status
153 return StoreFrontBuildState.UNKNOWN.value