برنامه نویسی

بهتر – یک اکشن GitHub Code Reviewer با هوش مصنوعی

Summarize this content to 400 words in Persian Lang
بررسی کد همیشه در حفظ استاندارد و تاکید بر بهترین شیوه های کد در یک پروژه بسیار مهم بوده است. این یک پست در مورد اینکه توسعه دهندگان چگونه باید کد را بررسی کنند نیست، بلکه بیشتر مربوط به واگذاری بخشی از آن به هوش مصنوعی است.

همانطور که مایکل لینچ در پست خود – “چگونه مانند یک انسان بازبینی کدها را انجام دهیم” اشاره می کند – ما باید اجازه دهید کامپیوترها از قطعات خسته کننده مراقبت کنند بررسی کد در حالی که مایکل بر ابزار قالب‌بندی تاکید می‌کند، من می‌خواهم آن را یک قدم جلوتر بردارم و اجازه دهم هوش مصنوعی آن را کشف کند. منظورم این است که چرا از رونق هوش مصنوعی در صنعت استفاده نکنیم؟

حالا من نمی گویم که باید از هوش مصنوعی به جای ابزارهای قالب بندی و لینتر استفاده شود. در عوض، قرار است از آن برای گرفتن چیزهای بی اهمیتی که ممکن است توسط یک انسان نادیده گرفته شود، استفاده شود.

به همین دلیل تصمیم گرفتم یک اکشن github ایجاد کنم که کد تفاوت درخواست کشش را بررسی می کند و با استفاده از هوش مصنوعی پیشنهادهایی ایجاد می کند. اجازه دهید شما را از طریق آن راهنمایی کنم.

🚨 توجه

دریافت تفاوت

برای تعامل با github API، من استفاده کرده ام octokit، که نوعی SDK یا کتابخانه مشتری برای تعامل با Github API به روشی اصطلاحی است.

برای اینکه بتوانید تفاوت درخواست کشش مطرح شده را دریافت کنید، باید از آن عبور کنید Accept هدر با مقدار application/vnd.github.diff همراه با پارامترهای مورد نیاز

async function getPullRequestDetails(octokit, { mode }) {
let AcceptFormat = “application/vnd.github.raw+json”;

if (mode === “diff”) AcceptFormat = “application/vnd.github.diff”;
if (mode === “json”) AcceptFormat = “application/vnd.github.raw+json”;

return await octokit.rest.pulls.get({
owner: github.context.repo.owner,
repo: github.context.repo.repo,
pull_number: github.context.payload.pull_request.number,
headers: {
accept: AcceptFormat,
},
});
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اگر اصلاً با اکشن‌های گیت‌هاب آشنایی ندارید، در اینجا یک سری اکشن‌های گیت‌هاب 101 توسط ویکتوریا لو وجود دارد و شروع خوبی است.

هنگامی که تفاوت را دریافت کردم، آن را تجزیه می کنم و تغییرات ناخواسته را حذف می کنم و سپس آن را در طرحی که در زیر نشان داده شده است برمی گردانم:

/** using zod */
schema = z.object({
path: z.string(),
position: z.number(),
line: z.number(),
change: z.object({
type: z.string(),
add: z.boolean(),
ln: z.number(),
content: z.string(),
relativePosition: z.number(),
}),
previously: z.string().optional(),
suggestions: z.string().optional(),
})

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

نادیده گرفتن فایل ها

نادیده گرفتن فایل ها کاملاً ساده است. لیست ورودی کاربر به یک رشته از الگوهای گلوب جدا شده از نقطه ویرگول نیاز دارد. سپس تجزیه می شود، با لیست پیش فرض فایل های نادیده گرفته شده الحاق می شود و فریب می خورد.

**/*.md; **/*.env; **/*.lock;

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

const filesToIgnoreList = [
…new Set(
filesToIgnore
.split(“;”)
.map(file => file.trim())
.filter(file => file !== “”)
.concat(FILES_IGNORED_BY_DEFAULT)
),
];

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

سپس از لیست فایل های نادیده گرفته شده برای حذف تغییرات تفاوت که به آن فایل های نادیده گرفته شده اشاره دارد استفاده می شود. این به شما یک محموله خام می دهد که فقط شامل تغییراتی است که می خواهید.

ایجاد پیشنهادات

هنگامی که پس از تجزیه تفاوت، payload خام را دریافت کردم، آن را به API پلتفرم منتقل می کنم. در اینجا پیاده سازی OpenAI API است.

async function useOpenAI({ rawComments, openAI, rules, modelName, pullRequestContext }) {
const result = await openAI.beta.chat.completions.parse({
model: getModelName(modelName, “openai”),
messages: [
{
role: “system”,
content: COMMON_SYSTEM_PROMPT,
},
{
role: “user”,
content: getUserPrompt(rules, rawComments, pullRequestContext),
},
],
response_format: zodResponseFormat(diffPayloadSchema, “json_diff_response”),
});

const { message } = result.choices[0];

if (message.refusal) {
throw new Error(`the model refused to generate suggestions – ${message.refusal}`);
}

return message.parsed;
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

ممکن است متوجه استفاده از فرمت پاسخ در اجرای API شوید. این یک ویژگی است که توسط بسیاری از پلتفرم‌های LLM ارائه شده است، که به شما امکان می‌دهد به مدل بگویید پاسخ را در یک طرح/قالب خاص تولید کند. این به ویژه در این مورد مفید است زیرا من نمی‌خواهم مدل توهم ایجاد کند و پیشنهادهایی برای فایل‌ها یا موقعیت‌های نادرست در درخواست کشش ایجاد کند یا ویژگی‌های جدیدی به بار پاسخ اضافه کند.

اعلان سیستم وجود دارد تا به مدل زمینه بیشتری در مورد اینکه چگونه باید بازبینی کد را انجام دهد و مواردی که باید در نظر داشته باشید ارائه می دهد. می توانید درخواست سیستم را در اینجا مشاهده کنید github.com/murtuzaalisurti/better.

درخواست کاربر حاوی تفاوت واقعی، قوانین و زمینه درخواست کشش است. این همان چیزی است که بازبینی کد را آغاز می کند.

این اکشن github از هر دو مدل OpenAI و Anthropic پشتیبانی می کند. در اینجا نحوه پیاده سازی Anthropic API آمده است:

async function useAnthropic({ rawComments, anthropic, rules, modelName, pullRequestContext }) {
const { definitions } = zodToJsonSchema(diffPayloadSchema, “diffPayloadSchema”);
const result = await anthropic.messages.create({
max_tokens: 8192,
model: getModelName(modelName, “anthropic”),
system: COMMON_SYSTEM_PROMPT,
tools: [
{
name: “structuredOutput”,
description: “Structured Output”,
input_schema: definitions[“diffPayloadSchema”],
},
],
tool_choice: {
type: “tool”,
name: “structuredOutput”,
},
messages: [
{
role: “user”,
content: getUserPrompt(rules, rawComments, pullRequestContext),
},
],
});

let parsed = null;
for (const block of result.content) {
if (block.type === “tool_use”) {
parsed = block.input;
break;
}
}

return parsed;
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

افزودن نظرات

در نهایت، پس از بازیابی پیشنهادات، آنها را ضد عفونی می کنم و به Github API ارسال می کنم تا نظرات را به عنوان بخشی از بررسی اضافه کنم.

من راه زیر را برای افزودن نظرات انتخاب کردم زیرا با ایجاد یک بررسی جدید، می توانید به جای افزودن یک نظر در یک زمان، همه نظرات را یکجا اضافه کنید. افزودن نظرات یک به یک نیز ممکن است باعث محدودیت نرخ شود، زیرا افزودن نظرات باعث ایجاد اعلان‌ها می‌شود و نمی‌خواهید کاربران را با اعلان‌ها اسپم کنید.

function filterPositionsNotPresentInRawPayload(rawComments, comments) {
return comments.filter(comment =>
rawComments.some(rawComment => rawComment.path === comment.path && rawComment.line === comment.line)
);
}

async function addReviewComments(suggestions, octokit, rawComments, modelName) {
const { info } = log({ withTimestamp: true }); // eslint-disable-line no-use-before-define
const comments = filterPositionsNotPresentInRawPayload(rawComments, extractComments().comments(suggestions));

try {
await octokit.rest.pulls.createReview({
owner: github.context.repo.owner,
repo: github.context.repo.repo,
pull_number: github.context.payload.pull_request.number,
body: `Code Review by ${modelName}`,
event: “COMMENT”,
comments,
});
} catch (error) {
info(`Failed to add review comments: ${JSON.stringify(comments, null, 2)}`);
throw error;
}
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

نتیجه گیری

من می‌خواستم اکشن github را باز نگه دارم و برای ادغام‌ها باز نگه دارم و به همین دلیل است که می‌توانید از هر مدلی که انتخاب می‌کنید استفاده کنید. (لیست مدل های پشتیبانی شده را ببینید)، یا می توانید مدل سفارشی خود را در بالای مدل های پایه پشتیبانی شده تنظیم کرده و بسازید و با این اکشن github از آن استفاده کنید.

اگر با مشکلات نشانه یا محدودیت نرخ مواجه شدید، ممکن است بخواهید محدودیت های مدل خود را با مراجعه به اسناد پلتفرم مربوطه ارتقا دهید.

بنابراین، منتظر چه چیزی هستید؟ اگر مخزن در github دارید، اکنون این اکشن را امتحان کنید – این در بازار اکشن github است.

یک اکشن github بازبینی کد که توسط هوش مصنوعی طراحی شده و آماده استفاده در گردش کار شما است.

یک اکشن github بازبینی کد که توسط هوش مصنوعی طراحی شده و آماده استفاده در گردش کار شما است.

چرا از آن استفاده کنید؟

فرآیند بررسی کد خود را استاندارد کنید
بازخورد سریعتر دریافت کنید
تشخیص الگوهایی که منجر به کد بد می شود
تشخیص مسائل رایج
آسیب پذیری های امنیتی را شناسایی کنید
نظر دوم
برای اینکه انسان ها روی کارهای پیچیده تر تمرکز کنند

استفاده

1. یک گردش کار ایجاد کنید

یک فایل گردش کار در داخل ایجاد کنید .github/workflows پوشه (اگر وجود ندارد ایجاد کنید) مخزن خود با محتوای زیر:

name: Code Review
on
pull_request:
types: [opened, reopened, synchronize, ready_for_review] branches:
– main # change this to your target branch
workflow_dispatch: # Allows you to run the workflow manually from the Actions tab

permissions: # necessary permissions
pull-requests: write
contents: read

jobs:
your-job-name:
runs-on: ubuntu-latest
name: your-job-name
steps:
– name: step-name
id: step-id
uses: murtuzaalisurti/better@v2 # this is…

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

بررسی کد همیشه در حفظ استاندارد و تاکید بر بهترین شیوه های کد در یک پروژه بسیار مهم بوده است. این یک پست در مورد اینکه توسعه دهندگان چگونه باید کد را بررسی کنند نیست، بلکه بیشتر مربوط به واگذاری بخشی از آن به هوش مصنوعی است.

همانطور که مایکل لینچ در پست خود – “چگونه مانند یک انسان بازبینی کدها را انجام دهیم” اشاره می کند – ما باید اجازه دهید کامپیوترها از قطعات خسته کننده مراقبت کنند بررسی کد در حالی که مایکل بر ابزار قالب‌بندی تاکید می‌کند، من می‌خواهم آن را یک قدم جلوتر بردارم و اجازه دهم هوش مصنوعی آن را کشف کند. منظورم این است که چرا از رونق هوش مصنوعی در صنعت استفاده نکنیم؟

حالا من نمی گویم که باید از هوش مصنوعی به جای ابزارهای قالب بندی و لینتر استفاده شود. در عوض، قرار است از آن برای گرفتن چیزهای بی اهمیتی که ممکن است توسط یک انسان نادیده گرفته شود، استفاده شود.

به همین دلیل تصمیم گرفتم یک اکشن github ایجاد کنم که کد تفاوت درخواست کشش را بررسی می کند و با استفاده از هوش مصنوعی پیشنهادهایی ایجاد می کند. اجازه دهید شما را از طریق آن راهنمایی کنم.

🚨 توجه

دریافت تفاوت

برای تعامل با github API، من استفاده کرده ام octokit، که نوعی SDK یا کتابخانه مشتری برای تعامل با Github API به روشی اصطلاحی است.

برای اینکه بتوانید تفاوت درخواست کشش مطرح شده را دریافت کنید، باید از آن عبور کنید Accept هدر با مقدار application/vnd.github.diff همراه با پارامترهای مورد نیاز

async function getPullRequestDetails(octokit, { mode }) {
    let AcceptFormat = "application/vnd.github.raw+json";

    if (mode === "diff") AcceptFormat = "application/vnd.github.diff";
    if (mode === "json") AcceptFormat = "application/vnd.github.raw+json";

    return await octokit.rest.pulls.get({
        owner: github.context.repo.owner,
        repo: github.context.repo.repo,
        pull_number: github.context.payload.pull_request.number,
        headers: {
            accept: AcceptFormat,
        },
    });
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اگر اصلاً با اکشن‌های گیت‌هاب آشنایی ندارید، در اینجا یک سری اکشن‌های گیت‌هاب 101 توسط ویکتوریا لو وجود دارد و شروع خوبی است.

هنگامی که تفاوت را دریافت کردم، آن را تجزیه می کنم و تغییرات ناخواسته را حذف می کنم و سپس آن را در طرحی که در زیر نشان داده شده است برمی گردانم:

/** using zod */
schema = z.object({
    path: z.string(),
    position: z.number(),
    line: z.number(),
    change: z.object({
        type: z.string(),
        add: z.boolean(),
        ln: z.number(),
        content: z.string(),
        relativePosition: z.number(),
    }),
    previously: z.string().optional(),
    suggestions: z.string().optional(),
})
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

نادیده گرفتن فایل ها

نادیده گرفتن فایل ها کاملاً ساده است. لیست ورودی کاربر به یک رشته از الگوهای گلوب جدا شده از نقطه ویرگول نیاز دارد. سپس تجزیه می شود، با لیست پیش فرض فایل های نادیده گرفته شده الحاق می شود و فریب می خورد.

**/*.md; **/*.env; **/*.lock;
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

const filesToIgnoreList = [
    ...new Set(
        filesToIgnore
            .split(";")
            .map(file => file.trim())
            .filter(file => file !== "")
            .concat(FILES_IGNORED_BY_DEFAULT)
    ),
];
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

سپس از لیست فایل های نادیده گرفته شده برای حذف تغییرات تفاوت که به آن فایل های نادیده گرفته شده اشاره دارد استفاده می شود. این به شما یک محموله خام می دهد که فقط شامل تغییراتی است که می خواهید.

ایجاد پیشنهادات

هنگامی که پس از تجزیه تفاوت، payload خام را دریافت کردم، آن را به API پلتفرم منتقل می کنم. در اینجا پیاده سازی OpenAI API است.

async function useOpenAI({ rawComments, openAI, rules, modelName, pullRequestContext }) {
    const result = await openAI.beta.chat.completions.parse({
        model: getModelName(modelName, "openai"),
        messages: [
            {
                role: "system",
                content: COMMON_SYSTEM_PROMPT,
            },
            {
                role: "user",
                content: getUserPrompt(rules, rawComments, pullRequestContext),
            },
        ],
        response_format: zodResponseFormat(diffPayloadSchema, "json_diff_response"),
    });

    const { message } = result.choices[0];

    if (message.refusal) {
        throw new Error(`the model refused to generate suggestions - ${message.refusal}`);
    }

    return message.parsed;
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

ممکن است متوجه استفاده از فرمت پاسخ در اجرای API شوید. این یک ویژگی است که توسط بسیاری از پلتفرم‌های LLM ارائه شده است، که به شما امکان می‌دهد به مدل بگویید پاسخ را در یک طرح/قالب خاص تولید کند. این به ویژه در این مورد مفید است زیرا من نمی‌خواهم مدل توهم ایجاد کند و پیشنهادهایی برای فایل‌ها یا موقعیت‌های نادرست در درخواست کشش ایجاد کند یا ویژگی‌های جدیدی به بار پاسخ اضافه کند.

اعلان سیستم وجود دارد تا به مدل زمینه بیشتری در مورد اینکه چگونه باید بازبینی کد را انجام دهد و مواردی که باید در نظر داشته باشید ارائه می دهد. می توانید درخواست سیستم را در اینجا مشاهده کنید github.com/murtuzaalisurti/better.

درخواست کاربر حاوی تفاوت واقعی، قوانین و زمینه درخواست کشش است. این همان چیزی است که بازبینی کد را آغاز می کند.

این اکشن github از هر دو مدل OpenAI و Anthropic پشتیبانی می کند. در اینجا نحوه پیاده سازی Anthropic API آمده است:

async function useAnthropic({ rawComments, anthropic, rules, modelName, pullRequestContext }) {
    const { definitions } = zodToJsonSchema(diffPayloadSchema, "diffPayloadSchema");
    const result = await anthropic.messages.create({
        max_tokens: 8192,
        model: getModelName(modelName, "anthropic"),
        system: COMMON_SYSTEM_PROMPT,
        tools: [
            {
                name: "structuredOutput",
                description: "Structured Output",
                input_schema: definitions["diffPayloadSchema"],
            },
        ],
        tool_choice: {
            type: "tool",
            name: "structuredOutput",
        },
        messages: [
            {
                role: "user",
                content: getUserPrompt(rules, rawComments, pullRequestContext),
            },
        ],
    });

    let parsed = null;
    for (const block of result.content) {
        if (block.type === "tool_use") {
            parsed = block.input;
            break;
        }
    }

    return parsed;
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

افزودن نظرات

در نهایت، پس از بازیابی پیشنهادات، آنها را ضد عفونی می کنم و به Github API ارسال می کنم تا نظرات را به عنوان بخشی از بررسی اضافه کنم.

من راه زیر را برای افزودن نظرات انتخاب کردم زیرا با ایجاد یک بررسی جدید، می توانید به جای افزودن یک نظر در یک زمان، همه نظرات را یکجا اضافه کنید. افزودن نظرات یک به یک نیز ممکن است باعث محدودیت نرخ شود، زیرا افزودن نظرات باعث ایجاد اعلان‌ها می‌شود و نمی‌خواهید کاربران را با اعلان‌ها اسپم کنید.

function filterPositionsNotPresentInRawPayload(rawComments, comments) {
    return comments.filter(comment =>
        rawComments.some(rawComment => rawComment.path === comment.path && rawComment.line === comment.line)
    );
}

async function addReviewComments(suggestions, octokit, rawComments, modelName) {
    const { info } = log({ withTimestamp: true }); // eslint-disable-line no-use-before-define
    const comments = filterPositionsNotPresentInRawPayload(rawComments, extractComments().comments(suggestions));

    try {
        await octokit.rest.pulls.createReview({
            owner: github.context.repo.owner,
            repo: github.context.repo.repo,
            pull_number: github.context.payload.pull_request.number,
            body: `Code Review by ${modelName}`,
            event: "COMMENT",
            comments,
        });
    } catch (error) {
        info(`Failed to add review comments: ${JSON.stringify(comments, null, 2)}`);
        throw error;
    }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

نتیجه گیری

من می‌خواستم اکشن github را باز نگه دارم و برای ادغام‌ها باز نگه دارم و به همین دلیل است که می‌توانید از هر مدلی که انتخاب می‌کنید استفاده کنید. (لیست مدل های پشتیبانی شده را ببینید)، یا می توانید مدل سفارشی خود را در بالای مدل های پایه پشتیبانی شده تنظیم کرده و بسازید و با این اکشن github از آن استفاده کنید.

اگر با مشکلات نشانه یا محدودیت نرخ مواجه شدید، ممکن است بخواهید محدودیت های مدل خود را با مراجعه به اسناد پلتفرم مربوطه ارتقا دهید.

بنابراین، منتظر چه چیزی هستید؟ اگر مخزن در github دارید، اکنون این اکشن را امتحان کنید – این در بازار اکشن github است.

یک اکشن github بازبینی کد که توسط هوش مصنوعی طراحی شده و آماده استفاده در گردش کار شما است.

یک اکشن github بازبینی کد که توسط هوش مصنوعی طراحی شده و آماده استفاده در گردش کار شما است.

چرا از آن استفاده کنید؟

  • فرآیند بررسی کد خود را استاندارد کنید
  • بازخورد سریعتر دریافت کنید
  • تشخیص الگوهایی که منجر به کد بد می شود
  • تشخیص مسائل رایج
  • آسیب پذیری های امنیتی را شناسایی کنید
  • نظر دوم
  • برای اینکه انسان ها روی کارهای پیچیده تر تمرکز کنند

استفاده

1. یک گردش کار ایجاد کنید

یک فایل گردش کار در داخل ایجاد کنید .github/workflows پوشه (اگر وجود ندارد ایجاد کنید) مخزن خود با محتوای زیر:

name: Code Review
on
    pull_request:
        types: [opened, reopened, synchronize, ready_for_review]
        branches:
            - main # change this to your target branch
    workflow_dispatch: # Allows you to run the workflow manually from the Actions tab

permissions: # necessary permissions
    pull-requests: write
    contents: read

jobs:
    your-job-name:
        runs-on: ubuntu-latest
        name: your-job-name
        steps:
            - name: step-name
              id: step-id
              uses: murtuzaalisurti/better@v2 # this is

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا