private static CorrectApimRevisionNumber GetCorrectApimRevisionNumber()

in tools/code/publisher/Api.cs [358:443]


    private static CorrectApimRevisionNumber GetCorrectApimRevisionNumber(IServiceProvider provider)
    {
        var getPreviousCommitDtos = provider.GetRequiredService<GetApiDtosInPreviousCommit>();
        var putApiInApim = provider.GetRequiredService<PutApiInApim>();
        var makeApiRevisionCurrent = provider.GetRequiredService<MakeApiRevisionCurrent>();
        var isNameInSourceControl = provider.GetRequiredService<IsApiNameInSourceControl>();
        var deleteApiFromApim = provider.GetRequiredService<DeleteApiFromApim>();
        var logger = provider.GetRequiredService<ILogger>();

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

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

        async ValueTask<Option<ApiRevisionNumber>> tryGetPreviousRevisionNumber(ApiName name, CancellationToken cancellationToken) =>
            await getPreviousCommitDtos()
                    .Find(name)
                    .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, CancellationToken cancellationToken)
        {
            if (newRevisionNumber == existingRevisionNumber)
            {
                return;
            }

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

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

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

            await putApiInApim(name, dto, Option<(ApiSpecification.GraphQl, BinaryData)>.None, 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, CancellationToken cancellationToken)
        {
            var revisionedName = ApiName.GetRevisionedName(name, oldRevisionNumber);

            if (isNameInSourceControl(revisionedName))
            {
                return;
            }

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