NotesWhat is notes.io?

Notes brand slogan

Notes - notes.io

package com.example.service;

import com.example.config.GitHubConfig;
import com.example.model.UploadRequest;
import com.example.model.UploadResult;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.json.JSONObject;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestClient;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.Base64;

/**
* Service for interacting with GitHub Enterprise API.
*/
@Service
@RequiredArgsConstructor
@Slf4j
public class GitHubService {

private final GitHubConfig config;
private final RestClient restClient;

/**
* Uploads a file to a GitHub Enterprise repository.
*
* @param request The upload request containing file details
* @return UploadResult containing success status and performance metrics
* @throws IOException if an I/O error occurs
*/
public UploadResult uploadFile(UploadRequest request) throws IOException {
// Create result object to track performance
UploadResult result = new UploadResult();
result.startOperation();

// Validate file exists
File file = new File(request.getLocalFilePath());
if (!file.exists() || !file.isFile()) {
String errorMessage = "File does not exist or is not a file: " + request.getLocalFilePath();
log.error(errorMessage);
result.setSuccess(false);
result.setMessage(errorMessage);
result.endOperation();
return result;
}

// Use branch from request if provided, otherwise use default from config
String branch = request.getBranch() != null && !request.getBranch().isEmpty()
? request.getBranch()
: config.getBranch();

// Use commit message from request if provided, otherwise use default from config
String commitMessage = request.getCommitMessage() != null && !request.getCommitMessage().isEmpty()
? request.getCommitMessage()
: config.getDefaultCommitMessage();

String targetPath = request.getTargetPath();

try {
// If targetPath starts with a slash, remove it
if (targetPath.startsWith("/")) {
targetPath = targetPath.substring(1);
}

// Construct the API URL for GitHub Enterprise file content API
String url = String.format("%s/repos/%s/%s/contents/%s",
config.getApiUrl(), config.getOwner(), config.getRepo(), targetPath);

log.debug("Using URL: {}", url);
log.info("Uploading file {} to {} on branch {} (will replace if exists)", file.getName(), targetPath, branch);

// Read file content and encode as Base64
byte[] fileContent = Files.readAllBytes(file.toPath());
String base64Content = Base64.getEncoder().encodeToString(fileContent);

// Create JSON payload for GitHub API
JSONObject payload = new JSONObject();
payload.put("message", commitMessage);
payload.put("branch", branch);
payload.put("content", base64Content);

// Check if file already exists to get its SHA (needed for updates)
String fileSha = getFileSha(targetPath, branch);
if (fileSha != null) {
payload.put("sha", fileSha);
log.debug("File exists, adding SHA: {}", fileSha);
}

// Start timing the API call
result.startApiCall();

try {
// Execute the PUT request using RestClient
ResponseEntity<String> response = restClient.put()
.uri(url)
.contentType(MediaType.APPLICATION_JSON)
.header(HttpHeaders.AUTHORIZATION, "Bearer " + config.getAccessToken())
.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
.header("X-GitHub-Api-Version", "2022-11-28")
.body(payload.toString())
.retrieve()
.toEntity(String.class);

// End timing the API call
result.endApiCall();

// Process successful response
int statusCode = response.getStatusCode().value();
String responseBody = response.getBody();

log.debug("Upload status: {}", statusCode);
log.debug("Response body: {}", responseBody);

if (statusCode >= 200 && statusCode < 300) {
String successMessage = String.format(
"File uploaded successfully to branch '%s'! (If the file already existed, it has been replaced)",
branch);
log.info(successMessage);
result.setSuccess(true);
result.setMessage(successMessage);
} else {
// Upload failed
String errorMessage = String.format(
"Failed to upload file to branch '%s'. Status code: %d, Response: %s",
branch, statusCode, responseBody);
log.error(errorMessage);
result.setSuccess(false);
result.setMessage(errorMessage);
}
} catch (HttpClientErrorException e) {
// End timing the API call
result.endApiCall();

// Handle error response
int statusCode = e.getStatusCode().value();
String responseBody = e.getResponseBodyAsString();

String errorMessage = String.format("Failed to upload file to branch '%s'. Status code: %d, Response: %s",
branch, statusCode, responseBody);
log.error(errorMessage);

// Check if this is a 404 error because the branch doesn't exist
if (statusCode == 404 && responseBody.contains("branch") && responseBody.contains("not found")) {
String detailedError = String.format(
"Branch '%s' does not exist or is not accessible. Please make sure the branch exists before uploading files.",
branch);
result.setMessage(errorMessage + "n" + detailedError);
} else {
// Provide more specific error messages based on status code
String detailedError = getDetailedErrorMessage(statusCode, responseBody);
result.setMessage(errorMessage + "n" + detailedError);
}

result.setSuccess(false);
}

// End timing the operation
result.endOperation();

// Log performance metrics at debug level only
if (log.isDebugEnabled()) {
log.debug(result.getPerformanceSummary());
}

return result;
} catch (Exception e) {
log.error("Error uploading file: {}", e.getMessage(), e);
result.setSuccess(false);
result.setMessage("Error uploading file: " + e.getMessage());
result.endOperation();
return result;
}
}

/**
* Gets the SHA of a file in the repository, which is needed for updating files.
*
* @param path The path to the file in the repository
* @param branch The branch where the file is located
* @return The SHA of the file, or null if the file doesn't exist
*/
private String getFileSha(String path, String branch) {
try {
// Construct the API URL for GitHub Enterprise file content API
String url = String.format("%s/repos/%s/%s/contents/%s?ref=%s",
config.getApiUrl(), config.getOwner(), config.getRepo(), path, branch);

log.debug("Getting file SHA from URL: {}", url);

// Execute the GET request using RestClient
ResponseEntity<String> response = restClient.get()
.uri(url)
.header(HttpHeaders.AUTHORIZATION, "Bearer " + config.getAccessToken())
.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
.header("X-GitHub-Api-Version", "2022-11-28")
.retrieve()
.toEntity(String.class);

// Process successful response
if (response.getStatusCode().is2xxSuccessful() && response.getBody() != null) {
JSONObject json = new JSONObject(response.getBody());
if (json.has("sha")) {
String sha = json.getString("sha");
log.debug("Found file SHA: {}", sha);
return sha;
}
}

return null;
} catch (Exception e) {
log.debug("File doesn't exist or error getting SHA: {}", e.getMessage());
return null;
}
}

/**
* Provides a detailed error message based on the HTTP status code and response body.
*
* @param statusCode The HTTP status code
* @param responseBody The response body from the server
* @return A detailed error message
*/
private String getDetailedErrorMessage(int statusCode, String responseBody) {
switch (statusCode) {
case 400:
return "Bad request. Please check your request parameters.";
case 401:
return "Authentication failed. Please check your access token.";
case 403:
return "Permission denied. Your user does not have permission to perform this operation.";
case 404:
return "Resource not found. Please check the repository owner, name, and file path.";
case 409:
return "Conflict. The operation could not be completed due to a conflict.";
case 422:
return "Validation error. The request was well-formed but contains semantic errors.";
case 429:
return "Too many requests. You have exceeded the rate limit.";
case 500:
case 502:
case 503:
case 504:
return "Server error. Please try again later or contact the GitHub administrator.";
default:
// Try to extract error message from JSON response if possible
if (responseBody != null && responseBody.contains(""message"")) {
try {
JSONObject json = new JSONObject(responseBody);
if (json.has("message")) {
return "API Error: " + json.getString("message");
}
} catch (Exception e) {
// Ignore JSON parsing errors
}
}
return "Unexpected error. Status code: " + statusCode;
}
}
}
     
 
what is notes.io
 

Notes is a web-based application for online taking notes. You can take your notes and share with others people. If you like taking long notes, notes.io is designed for you. To date, over 8,000,000,000+ notes created and continuing...

With notes.io;

  • * You can take a note from anywhere and any device with internet connection.
  • * You can share the notes in social platforms (YouTube, Facebook, Twitter, instagram etc.).
  • * You can quickly share your contents without website, blog and e-mail.
  • * You don't need to create any Account to share a note. As you wish you can use quick, easy and best shortened notes with sms, websites, e-mail, or messaging services (WhatsApp, iMessage, Telegram, Signal).
  • * Notes.io has fabulous infrastructure design for a short link and allows you to share the note as an easy and understandable link.

Fast: Notes.io is built for speed and performance. You can take a notes quickly and browse your archive.

Easy: Notes.io doesn’t require installation. Just write and share note!

Short: Notes.io’s url just 8 character. You’ll get shorten link of your note when you want to share. (Ex: notes.io/q )

Free: Notes.io works for 14 years and has been free since the day it was started.


You immediately create your first note and start sharing with the ones you wish. If you want to contact us, you can use the following communication channels;


Email: [email protected]

Twitter: http://twitter.com/notesio

Instagram: http://instagram.com/notes.io

Facebook: http://facebook.com/notesio



Regards;
Notes.io Team

     
 
Shortened Note Link
 
 
Looding Image
 
     
 
Long File
 
 

For written notes was greater than 18KB Unable to shorten.

To be smaller than 18KB, please organize your notes, or sign in.