private static CorrectWorkspaceApimRevisionNumber GetCorrectWorkspaceApimRevisionNumber()

in tools/code/publisher/WorkspaceApi.cs [348:433]


    private static CorrectWorkspaceApimRevisionNumber GetCorrectWorkspaceApimRevisionNumber(IServiceProvider provider)
    {
        var getPreviousCommitDtos = provider.GetRequiredService<GetWorkspaceApiDtosInPreviousCommit>();
        var putApiInApim = provider.GetRequiredService<PutWorkspaceApiInApim>();
        var makeApiRevisionCurrent = provider.GetRequiredService<MakeWorkspaceApiRevisionCurrent>();
        var isNameInSourceControl = provider.GetRequiredService<IsWorkspaceApiNameInSourceControl>();
        var deleteApiFromApim = provider.GetRequiredService<DeleteWorkspaceApiFromApim>();
        var logger = provider.GetRequiredService<ILogger>();

        return async (name, dto, workspaceName, cancellationToken) =>
        {
            if (ApiName.IsRevisioned(name))
            {
                return;
            }

            var previousRevisionNumberOption = await tryGetPreviousRevisionNumber(name, workspaceName, cancellationToken);
            await previousRevisionNumberOption.IterTask(async previousRevisionNumber =>
            {
                var currentRevisionNumber = Common.GetRevisionNumber(dto);
                await setApimCurrentRevisionNumber(name, currentRevisionNumber, previousRevisionNumber, workspaceName, cancellationToken);
            });
        };

        async ValueTask<Option<ApiRevisionNumber>> tryGetPreviousRevisionNumber(ApiName name, WorkspaceName workspaceName, CancellationToken cancellationToken) =>
            await getPreviousCommitDtos()
                    .Find((name, workspaceName))
                    .BindTask(async getDto =>
                    {
                        var dtoOption = await getDto(cancellationToken);

                        return from dto in dtoOption
                               select Common.GetRevisionNumber(dto);
                    });

        async ValueTask setApimCurrentRevisionNumber(ApiName name, ApiRevisionNumber newRevisionNumber, ApiRevisionNumber existingRevisionNumber, WorkspaceName workspaceName, CancellationToken cancellationToken)
        {
            if (newRevisionNumber == existingRevisionNumber)
            {
                return;
            }

            logger.LogInformation("Changing current revision on {ApiName} in workspace {WorkspaceName} from {RevisionNumber} to {RevisionNumber}...", name, workspaceName, existingRevisionNumber, newRevisionNumber);

            await putRevision(name, newRevisionNumber, existingRevisionNumber, workspaceName, cancellationToken);
            await makeApiRevisionCurrent(name, newRevisionNumber, workspaceName, cancellationToken);
            await deleteOldRevision(name, existingRevisionNumber, workspaceName, cancellationToken);
        }

        async ValueTask putRevision(ApiName name, ApiRevisionNumber revisionNumber, ApiRevisionNumber existingRevisionNumber, WorkspaceName workspaceName, CancellationToken cancellationToken)
        {
            var dto = new WorkspaceApiDto
            {
                Properties = new WorkspaceApiDto.ApiCreateOrUpdateProperties
                {
                    ApiRevision = revisionNumber.ToString(),
                    SourceApiId = $"/apis/{ApiName.GetRevisionedName(name, existingRevisionNumber)}"
                }
            };

            await putApiInApim(name, dto, Option<(ApiSpecification.GraphQl, BinaryData)>.None, workspaceName, cancellationToken);
        }

        /// <summary>
        /// If the old revision is no longer in source control, delete it from APIM. Handles this scenario:
        /// 1. Dev and prod APIM both have apiA with current revision 1. Artifacts folder has /apis/apiA/apiInformation.json with revision 1.
        /// 2. User changes the current revision in dev APIM from 1 to 2.
        /// 3. User deletes revision 1 from dev APIM, as it's no longer needed.
        /// 4. User runs extractor for dev APIM. Artifacts folder has /apis/apiA/apiInformation.json with revision 2.
        /// 5. User runs publisher to prod APIM. The only changed artifact will be an update in apiInformation.json to revision 2, so we will create revision 2 in prod and make it current.
        /// 
        /// If we do nothing else, dev and prod will be inconsistent as prod will still have the revision 1 API. There was nothing in Git that told the publisher to delete revision 1.
        /// </summary>
        async ValueTask deleteOldRevision(ApiName name, ApiRevisionNumber oldRevisionNumber, WorkspaceName workspaceName, CancellationToken cancellationToken)
        {
            var revisionedName = ApiName.GetRevisionedName(name, oldRevisionNumber);

            if (isNameInSourceControl(revisionedName, workspaceName))
            {
                return;
            }

            logger.LogInformation("Deleting old revision {RevisionNumber} of {ApiName} in workspace {WorkspaceName}...", oldRevisionNumber, name, workspaceName);
            await deleteApiFromApim(revisionedName, workspaceName, cancellationToken);
        }
    }