guibranco / gstraccini-bot-service

🤖 :octocat: GStraccini-bot automates repository management, ensuring organization and health by handling pull requests, issues, comments, and commits.
https://gstraccini.bot
MIT License
2 stars 0 forks source link

[FEATURE] Add a new command to add content `.infisicalignore` to file from pull request comment #548

Open guibranco opened 1 month ago

guibranco commented 1 month ago

Description

We need to create a new command for the GitHub PHP bot that will automate the process of adding secret information from specific comments in pull requests into the .infisicalignore file. The content to be copied will be parsed from pull request comments and pushed back to the same branch of the pull request.

Functionality:

Acceptance Criteria:

guibranco commented 4 weeks ago

To modify the code to commit and push changes using the GitHub REST API instead of standard Git commands, you need to use the GitHub API to:

  1. Get the latest commit on the branch.
  2. Create a blob (which stores the new file content).
  3. Create a new tree based on the previous commit tree with the updated file.
  4. Create a new commit.
  5. Update the branch to point to the new commit.

Here’s how you can do it step by step:

Sample code logic

[!CAUTION] This code is just an example, not a functional code!

<?php

// Required: GitHub API token and repository details
$githubToken = 'your-github-token';
$repositoryOwner = 'repo-owner';
$repositoryName = 'repo-name';
$pullRequestNumber = 123; // Replace with the actual pull request number
$branchName = 'pull-request-branch'; // Replace with the actual branch name

// GitHub API endpoints
$baseApiUrl = "https://api.github.com/repos/$repositoryOwner/$repositoryName";
$pullRequestCommentsUrl = "$baseApiUrl/issues/$pullRequestNumber/comments";
$refUrl = "$baseApiUrl/git/refs/heads/$branchName";
$commitUrl = "$baseApiUrl/git/commits";
$treeUrl = "$baseApiUrl/git/trees";
$blobUrl = "$baseApiUrl/git/blobs";

// Step 1: Fetch pull request comments
function fetchPullRequestComments($url) {
    $response = doRequestGitHub($url);
    $data = json_decode($response->body, true);
    return $data;
}

// Step 2: Extract secrets content from a specific comment
function extractSecretsFromComment($comments) {
    foreach ($comments as $comment) {
        if (strpos($comment['body'], '<!-- add-pr-comment:secrets-result -->') !== false) {
            preg_match('/```txt(.*?)```/s', $comment['body'], $matches);
            if (isset($matches[1])) {
                return trim($matches[1]);
            }
        }
    }
    return null;
}

// Step 3: Get the last commit SHA on the branch
function getLastCommitSha($refUrl) {
    $response = doRequestGitHub($refUrl);
    $data = json_decode($response->body, true);
    return $data['object']['sha'];
}

// Step 4: Get the tree SHA of the last commit
function getCommitTreeSha($commitSha, $commitUrl) {
    $response = doRequestGitHub("$commitUrl/$commitSha");
    $data = json_decode($response->body, true);
    return $data['tree']['sha'];
}

// Step 5: Create a new blob for the .infisicalignore file
function createBlob($content, $blobUrl) {
    $data = json_encode([
        'content' => $content,
        'encoding' => 'utf-8'
    ]);
    $response = doRequestGitHub($blobUrl, $data);
    return json_decode($response, true)['sha'];
}

// Step 6: Create a new tree with the updated .infisicalignore file
function createTree($treeSha, $blobSha, $filePath, $treeUrl) {
    $data = json_encode([
        'base_tree' => $treeSha,
        'tree' => [
            [
                'path' => $filePath,
                'mode' => '100644',
                'type' => 'blob',
                'sha' => $blobSha
            ]
        ]
    ]);
    $response = doRequestGitHub($treeUrl, $data);
    return json_decode($response, true)['sha'];
}

// Step 7: Create a new commit
function createCommit($commitMessage, $treeSha, $parentCommitSha, $commitUrl) {
    $data = json_encode([
        'message' => $commitMessage,
        'tree' => $treeSha,
        'parents' => [$parentCommitSha]
    ]);

    $response = doRequestGitHub($commitUrl, $data);
    return json_decode($response, true)['sha'];
}

// Step 8: Update the branch reference to point to the new commit
function updateBranchReference($newCommitSha, $refUrl) {
    $data = json_encode([
        'sha' => $newCommitSha,
        'force' => true
    ]);

    $response = doRequestGitHub($treeUrl, $data, "PATCH");
}

// Step 9: Merge content into .infisicalignore and remove duplicates
function mergeInfisicalIgnore($newContent) {
    $ignoreFilePath = '.infisicalignore';
    $existingContent = '';

    if (file_exists($ignoreFilePath)) {
        $existingContent = file_get_contents($ignoreFilePath);
    }

    $mergedContent = $existingContent . "\n" . $newContent;
    $mergedLines = array_unique(array_filter(explode("\n", $mergedContent)));

    return implode("\n", $mergedLines);
}

// Main execution
$comments = fetchPullRequestComments($pullRequestCommentsUrl);
$secrets = extractSecretsFromComment($comments);

if ($secrets) {
    // Step 3: Get last commit SHA and tree SHA
    $lastCommitSha = getLastCommitSha($refUrl);
    $treeSha = getCommitTreeSha($lastCommitSha, $commitUrl);

    // Step 4: Merge content into .infisicalignore
    $updatedContent = mergeInfisicalIgnore($secrets);

    // Step 5: Create a blob for the updated .infisicalignore file
    $blobSha = createBlob($updatedContent, $blobUrl);

    // Step 6: Create a new tree with the updated .infisicalignore
    $newTreeSha = createTree($treeSha, $blobSha, '.infisicalignore', $treeUrl);

    // Step 7: Create a new commit
    $newCommitSha = createCommit('Update .infisicalignore with secrets from PR comment', $newTreeSha, $lastCommitSha, $commitUrl);

    // Step 8: Update the branch reference to the new commit
    updateBranchReference($newCommitSha, $refUrl);

    echo "Updated .infisicalignore and pushed changes to branch: $branchName\n";
} else {
    echo "No secrets found in the pull request comments.\n";
}

?>

Steps

  1. Get the last commit SHA: getLastCommitSha() retrieves the current commit SHA from the branch.
  2. Get the tree SHA from the last commit: getCommitTreeSha() fetches the tree associated with the commit.
  3. Create a new blob: createBlob() uploads the updated content for .infisicalignore as a blob and returns the blob SHA.
  4. Create a new tree: createTree() creates a new tree that includes the updated .infisicalignore using the blob SHA.
  5. Create a new commit: createCommit() creates a new commit with the new tree and points it to the parent commit.
  6. Update the branch: updateBranchReference() updates the branch to point to the new commit SHA.