diff --git a/api/src/shipit_api/admin/api.py b/api/src/shipit_api/admin/api.py index 7908b4e9e..fbba72758 100644 --- a/api/src/shipit_api/admin/api.py +++ b/api/src/shipit_api/admin/api.py @@ -28,7 +28,7 @@ rendered_hook_payload, ) from shipit_api.common.config import HG_PREFIX, PROJECT_NAME, PULSE_ROUTE_REBUILD_PRODUCT_DETAILS, SCOPE_PREFIX -from shipit_api.common.models import DisabledProduct, Phase, Release, Signoff, XPIRelease +from shipit_api.common.models import DisabledProduct, Phase, Release, Signoff, Version, XPIRelease from shipit_api.public.api import get_disabled_products, list_releases logger = logging.getLogger(__name__) @@ -375,3 +375,52 @@ def get_signoff_emails(phases): additional_shipit_emails.update({signoff.completed_by for signoff in _phase.signoffs if signoff.completed_by is not None}) return list(additional_shipit_emails) + + +def get_product_channel_version(product, channel): + version = Version.query.filter_by(product_name=product, product_channel=channel).first() + if version: + return version.current_version + else: + return {"error": f"No version found for {product} {channel}."}, 404 + + +def update_product_channel_version(product, channel, body): + required_permission = f"{SCOPE_PREFIX}/update_product_channel_version/{product}" + if not current_user.has_permissions(required_permission): + user_permissions = ", ".join(current_user.get_permissions()) + abort(401, f"required permission: {required_permission}, user permissions: {user_permissions}") + version = Version.query.filter_by(product_name=product, product_channel=channel).first() + if version and version.current_version != body["version"]: + version.current_version = body["version"] + current_app.db.session.commit() + return { + "message": f"The version for {product} {channel} was updated successfully.", + "version": version.current_version, + "product": version.product_name, + "channel": version.product_channel, + }, 200 + elif version and version.current_version == body["version"]: + return {"error": f"The {product} {channel} version is already {body['version']}!"}, 409 + else: + return {"error": f"No version found for {product} {channel}."}, 404 + + +def create_product_channel_version(product, channel, body): + required_permission = f"{SCOPE_PREFIX}/create_product_channel_version/{product}" + if not current_user.has_permissions(required_permission): + user_permissions = ", ".join(current_user.get_permissions()) + abort(401, f"required permission: {required_permission}, user permissions: {user_permissions}") + existing_version = Version.query.filter_by(product_name=product, product_channel=channel).first() + if existing_version: + return {"error": f"A {product} {channel} version already exists."}, 409 + else: + new_version = Version(product_name=product, product_channel=channel, current_version=body["version"]) + current_app.db.session.add(new_version) + current_app.db.session.commit() + return { + "message": f"A {product} {channel} version was created successfully.", + "version": new_version.current_version, + "product": new_version.product_name, + "channel": new_version.product_channel, + }, 201 diff --git a/api/src/shipit_api/admin/api.yml b/api/src/shipit_api/admin/api.yml index 9d309d99a..058f001fc 100644 --- a/api/src/shipit_api/admin/api.yml +++ b/api/src/shipit_api/admin/api.yml @@ -693,6 +693,167 @@ paths: "409": description: Already submitted content: {} + /versions/{product}/{channel}: + get: + summary: Get the current version for the given product channel + operationId: shipit_api.admin.api.get_product_channel_version + parameters: + - name: product + in: path + description: product name + required: true + schema: + type: string + - name: channel + in: path + description: product channel + required: true + schema: + type: string + responses: + "200": + description: The current version for the given product channel + content: + text/plain: + schema: + type: string + example: "127.0a1" + "404": + description: Product channel version not found + content: + application/json: + schema: + type: object + properties: + error: + type: string + example: "No version found for firefox release." + post: + summary: Create a new product channel version + operationId: shipit_api.admin.api.create_product_channel_version + parameters: + - name: product + in: path + description: The product name for which the version is to be updated + required: true + schema: + type: string + - name: channel + in: path + description: product channel + required: true + schema: + type: string + requestBody: + description: Initial version for a new product channel + content: + application/json: + schema: + type: object + properties: + version: + type: string + example: "128.0a1" + required: true + responses: + "201": + description: Product channel version created successfully + content: + application/json: + schema: + type: object + properties: + message: + type: string + example: "A firefox nightly version was created successfully." + version: + type: string + example: "128.0a1" + product: + type: string + example: "firefox" + channel: + type: string + example: "nightly" + "409": + description: Product channel version already exists + content: + application/json: + schema: + type: object + properties: + error: + type: string + example: "A firefox nightly version already exists." + put: + summary: Update an existing product channel's version + operationId: shipit_api.admin.api.update_product_channel_version + parameters: + - name: product + in: path + description: The product name for which the version is to be updated + required: true + schema: + type: string + - name: channel + in: path + description: product channel + required: true + schema: + type: string + requestBody: + description: A valid version for the product channel + content: + application/json: + schema: + type: object + properties: + version: + type: string + example: "129.0a1" + required: true + responses: + "200": + description: Product version updated successfully + content: + application/json: + schema: + type: object + properties: + message: + type: string + example: "The version for firefox nightly was updated successfully." + version: + type: string + example: "128.0a1" + product: + type: string + example: "firefox" + channel: + type: string + example: "nightly" + "409": + description: Product channel is already the given value + content: + application/json: + schema: + type: object + properties: + error: + type: string + example: "The firefox nightly version is already 128.0a1!" + "404": + description: Product channel version not found + content: + application/json: + schema: + type: object + properties: + error: + type: string + example: "No version found for firefox release." + + components: schemas: ReleaseInput: diff --git a/api/src/shipit_api/admin/settings.py b/api/src/shipit_api/admin/settings.py index d4941c9e9..ab399c4ea 100644 --- a/api/src/shipit_api/admin/settings.py +++ b/api/src/shipit_api/admin/settings.py @@ -99,7 +99,8 @@ AUTH0_AUTH_SCOPES = assign_ldap_groups_to_scopes() # other scopes -AUTH0_AUTH_SCOPES.update({"rebuild_product_details": LDAP_GROUPS["firefox-signoff"], "update_release_status": []}) +AUTH0_AUTH_SCOPES.update({"rebuild_product_details": LDAP_GROUPS["firefox-signoff"], "update_release_status": [], "create_product_channel_version/firefox": []}) + # Github scopes # The following scope gives permission to all github queries, inlcuding private repos diff --git a/api/src/shipit_api/common/models.py b/api/src/shipit_api/common/models.py index df336feac..466f28e67 100644 --- a/api/src/shipit_api/common/models.py +++ b/api/src/shipit_api/common/models.py @@ -264,3 +264,12 @@ def json(self): "completed": self.completed or "", "phases": [p.json for p in self.phases], } + + +class Version(db.Model): + __tablename__ = "shipit_api_versions" + id = sa.Column(sa.Integer, primary_key=True) + product_name = sa.Column(sa.String, unique=True, nullable=False) + product_channel = sa.Column(sa.String, nullable=False) + current_version = sa.Column(sa.String, nullable=False) + __table_args__ = (sa.UniqueConstraint("product_name", "product_channel", name="_product_name_channel_uc"),)