Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions src/main/java/io/papermc/fill/controller/Publish3Controller.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright 2024 PaperMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.papermc.fill.controller;

import io.papermc.fill.database.ProjectEntity;
import io.papermc.fill.database.ProjectRepository;
import io.papermc.fill.database.VersionEntity;
import io.papermc.fill.database.VersionRepository;
import io.papermc.fill.exception.ProjectNotFoundException;
import io.papermc.fill.exception.VersionNotFoundException;
import io.papermc.fill.model.request.v3.AllocateRequest;
import io.papermc.fill.model.response.v3.AllocateBuildNumberResponse;
import io.papermc.fill.service.PublishingService;
import io.papermc.fill.util.http.Responses;
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Parameter;
import java.util.OptionalInt;
import org.jspecify.annotations.NullMarked;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.CacheControl;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@Hidden
@NullMarked
@RestController
public class Publish3Controller {
private final ProjectRepository projects;
private final VersionRepository versions;
private final PublishingService publishing;

@Autowired
public Publish3Controller(
final ProjectRepository projects,
final VersionRepository versions,
final PublishingService publishing
) {
this.projects = projects;
this.versions = versions;
this.publishing = publishing;
}

@CrossOrigin(methods = RequestMethod.GET)
@PostMapping("/v3/projects/{project}/versions/{version}/publishing")
public ResponseEntity<?> allocateBuild(
@Parameter(description = "The key of the project")
@PathVariable("project")
final String projectKey,
@Parameter(description = "The key of the version")
@PathVariable("version")
final String versionKey,
@RequestBody
final AllocateRequest request
) {
final ProjectEntity project = this.projects.findByKey(projectKey).orElseThrow(ProjectNotFoundException::new);
final VersionEntity version = this.versions.findByProjectAndKey(project, versionKey).orElseThrow(VersionNotFoundException::new);
final int number = this.publishing.allocateBuildNumber(request.session(), version, OptionalInt.empty());
final AllocateBuildNumberResponse response = new AllocateBuildNumberResponse(number);
return Responses.ok(response, CacheControl.noStore());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ public ResponseEntity<?> publish(
}
}

final int number = this.publishing.getNextBuildNumber(version, OptionalInt.of(request.build()));
final int number = this.publishing.allocateBuildNumber(request.id().toString(), version, OptionalInt.of(request.build()));

if (this.builds.findByVersionAndNumber(version, number).isPresent()) {
throw createPublishFailedException(request, "Build already exists", new DuplicateBuildException());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import io.papermc.fill.exception.FamilyNotFoundException;
import io.papermc.fill.exception.ProjectNotFoundException;
import io.papermc.fill.exception.PublishFailedException;
import io.papermc.fill.exception.SessionConflictException;
import io.papermc.fill.exception.SunsetException;
import io.papermc.fill.exception.VersionNotFoundException;
import io.papermc.fill.model.response.ErrorResponse;
Expand Down Expand Up @@ -112,14 +113,16 @@ public ResponseEntity<?> on405MethodNotAllowed(final HttpRequestMethodNotSupport
@ExceptionHandler({
DuplicateBuildException.class,
DuplicateFamilyException.class,
DuplicateVersionException.class
DuplicateVersionException.class,
SessionConflictException.class
})
public ResponseEntity<?> on409Conflict(final Throwable throwable) {
return Responses.conflict(new ErrorResponse(
switch (throwable) {
case final DuplicateBuildException _ -> "build_already_exists";
case final DuplicateFamilyException _ -> "family_already_exists";
case final DuplicateVersionException _ -> "version_already_exists";
case final SessionConflictException _ -> "session_conflict";
default -> throw new IllegalStateException("Unexpected value: " + throwable);
},
throwable.getMessage()
Expand Down
27 changes: 27 additions & 0 deletions src/main/java/io/papermc/fill/database/VersionEntity.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
import io.papermc.fill.model.Version;
import io.papermc.fill.util.git.GitRepository;
import java.time.Instant;
import java.util.HashSet;
import java.util.Set;
import org.bson.types.ObjectId;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
Expand All @@ -42,6 +44,9 @@ public class VersionEntity extends AbstractEntity implements Version {
private @Nullable GitRepository gitRepository;
private Support support;
private @Nullable Java java;
private @Nullable Set<String> publishingSessions;
private @Nullable String publishingSession;
private int nextBuildNumber;
@Deprecated
private @Nullable ObjectId mostRecentPromotedBuild;

Expand Down Expand Up @@ -110,6 +115,28 @@ public void setJava(final @Nullable Java java) {
this.java = java;
}

public boolean isPastPublishingSession(final String publishingSession) {
final boolean isCurrentPublishingSession = publishingSession.equals(this.publishingSession);
final boolean isPastPublishingSession = this.publishingSessions != null && this.publishingSessions.contains(publishingSession);
return !isCurrentPublishingSession && isPastPublishingSession;
}

public void setPublishingSession(final String publishingSession) {
this.publishingSession = publishingSession;
if (this.publishingSessions == null) {
this.publishingSessions = new HashSet<>();
}
this.publishingSessions.add(publishingSession);
}

public int nextBuildNumber() {
return this.nextBuildNumber;
}

public void setNextBuildNumber(final int nextBuildNumber) {
this.nextBuildNumber = nextBuildNumber;
}

@Deprecated
public @Nullable ObjectId mostRecentPromotedBuild() {
return this.mostRecentPromotedBuild;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright 2024 PaperMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.papermc.fill.exception;

import org.jspecify.annotations.NullMarked;

@NullMarked
public class SessionConflictException extends AppException {
public SessionConflictException(final String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright 2024 PaperMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.papermc.fill.model.request.v3;

import org.jspecify.annotations.NullMarked;

@NullMarked
public record AllocateRequest(
String session
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright 2024 PaperMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.papermc.fill.model.response.v3;

import org.jspecify.annotations.NullMarked;

@NullMarked
public record AllocateBuildNumberResponse(
int number
) {
}
3 changes: 2 additions & 1 deletion src/main/java/io/papermc/fill/service/PublishingService.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@

@NullMarked
public interface PublishingService {
int getNextBuildNumber(
int allocateBuildNumber(
final String session,
final VersionEntity version,
@Deprecated(forRemoval = true)
final OptionalInt requested
Expand Down
48 changes: 24 additions & 24 deletions src/main/java/io/papermc/fill/service/PublishingServiceImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,12 @@
*/
package io.papermc.fill.service;

import com.google.common.annotations.VisibleForTesting;
import io.papermc.fill.database.BuildRepository;
import io.papermc.fill.database.VersionEntity;
import io.papermc.fill.database.VersionRepository;
import io.papermc.fill.exception.SessionConflictException;
import io.papermc.fill.model.Numbered;
import java.util.List;
import java.util.OptionalInt;
import java.util.function.Supplier;
import org.jspecify.annotations.NullMarked;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -33,44 +32,45 @@
public class PublishingServiceImpl implements PublishingService {
private static final Logger LOGGER = LoggerFactory.getLogger(PublishingServiceImpl.class);

private final VersionRepository versions;
private final BuildRepository builds;

@Autowired
public PublishingServiceImpl(
final VersionRepository versions,
final BuildRepository builds
) {
this.versions = versions;
this.builds = builds;
}

@Override
public int getNextBuildNumber(
public int allocateBuildNumber(
final String session,
final VersionEntity version,
@Deprecated(forRemoval = true)
final OptionalInt requested
) {
if (requested.isPresent()) {
LOGGER.warn("Manually requested build number {} for version {}", requested, version._id());
if (version.isPastPublishingSession(session)) {
throw new SessionConflictException(String.format("Session %s expired.", session));
}
return getNextBuildNumber(() -> this.builds.findAllByVersion(version).toList(), requested);
}

@VisibleForTesting
static int getNextBuildNumber(
final Supplier<List<? extends Numbered>> builds,
@Deprecated(forRemoval = true)
final OptionalInt requested
) {
final int allocatedBuildNumber;
if (requested.isPresent()) {
return requested.getAsInt();
}
final OptionalInt maxBuildNumber = builds
.get()
.stream()
.mapToInt(Numbered::number)
.max();
if (maxBuildNumber.isPresent()) {
return maxBuildNumber.getAsInt() + 1;
LOGGER.warn("Manually requested build number {} for version {}", requested, version._id());
allocatedBuildNumber = requested.getAsInt();
} else if (version.nextBuildNumber() == 0) {
final OptionalInt maxBuildNumber = this.builds
.findAllByVersion(version)
.mapToInt(Numbered::number)
.max();
allocatedBuildNumber = maxBuildNumber.orElse(0) + 1;
} else {
allocatedBuildNumber = version.nextBuildNumber();
}
return 1;
version.setPublishingSession(session);
version.setNextBuildNumber(allocatedBuildNumber + 1);
this.versions.save(version);
return allocatedBuildNumber;
}
}

This file was deleted.