diff --git a/azure-pipelines-wrapper/conflict_detect.js b/azure-pipelines-wrapper/conflict_detect.js index 683e0f8..9b36bab 100644 --- a/azure-pipelines-wrapper/conflict_detect.js +++ b/azure-pipelines-wrapper/conflict_detect.js @@ -1,93 +1,153 @@ -const akv = require('./keyvault'); const spawnSync = require('child_process').spawnSync; -const owner = 'sonic-net' -const repo = 'sonic-buildimage' +const { Octokit } = require('@octokit/rest'); +const akv = require('./keyvault'); +const fs = require('fs'); +const { stderr } = require('process'); +const InProgress = 'in_progress' +const MsConflict = 'ms_conflict' +var commentid = '' function init(app) { app.log.info("Init conflict detect"); - app.on(["pull_request.opened", "pull_request.synchronize", "pull_request.reopened", "issue_comment.created"], async (context) => { + app.on( ["pull_request.opened", "pull_request.synchronize", "pull_request.reopened", "issue_comment.created"] , async (context) => { var payload = context.payload; - var gh_token = await akv.getSecretFromCache("GH_TOKEN") - var mssonic_token = await akv.getSecretFromCache("MSSONIC_TOKEN") - var msazure_token = await akv.getSecretFromCache("MSAZURE_TOKEN") - var conflict_script_url = await akv.getSecretFromCache("CONFLICT_SCRIPT_URL") - var url, commit - console.log("conflict_detect.js ", payload.name, payload.action) - if (payload.repository.name != repo){ - console.log("repo not match") + let full_name = payload.repository.full_name + let owner = full_name.split('/')[0] + let repo = full_name.split('/')[1] + // TODO: change to full_name != "sonic-net/sonic-buildimage" + if ("sonic-buildimage" != repo) { + app.log.info("repo not match!") return } - if (payload.issue && payload.action == "created"){ - let issue_user_login = payload.issue.user.login; - let comment_user_login = payload.comment.user.login; - let comment_body = payload.comment.body.trim(); - if (comment_body.toLowerCase() != '/azpw ms_conflict'){ + if (payload.issue) { + if ( commentid == payload.comment.id.toString() ) { return } else { commentid = payload.comment.id.toString() } + app.log.info("conflict_detect " + "issue_comment.created " + payload.comment.user.login + " " + payload.comment.id.toString() + ' "' + payload.comment.body + '"') + } else { + if ( commentid == payload.number.toString() + payload.pull_request.updated_at.toString() ) { return } else { commentid == payload.number.toString() + payload.pull_request.updated_at.toString() } + app.log.info("conflict_detect " + "pull_request." + payload.action + " " + payload.pull_request.user.login + " " + payload.pull_request.html_url) + } + + var url, number, commit, base_branch, pr_owner + let gh_token = await akv.getSecretFromCache("GH_TOKEN") + let script_url = await akv.getSecretFromCache("CONFLICT_SCRIPT_URL") + let msazure_token = await akv.getSecretFromCache("MSAZURE_TOKEN") + + if (payload.issue && payload.action == "created") { + // issue_comment.created + let comment_body = payload.comment.body.trim() + if (comment_body.toLowerCase() != '/azpw ' + MsConflict) { return } - if (! payload.issue.pull_request){ + if (!payload.issue.pull_request) { return } - url = payload.issue.html_url.toString(); - let number = url.split('/').slice(-1)[0] + url = payload.issue.html_url + number = payload.issue.number.toString() let pr = await context.octokit.rest.pulls.get({ owner: owner, repo: repo, pull_number: number, }); commit = pr.data.head.sha + base_branch = pr.data.base.ref + pr_owner = pr.data.head.user.login } else { + // pull_request.opened/synchronize/reopend url = payload.pull_request.html_url + number = payload.number.toString() commit = payload.pull_request.head.sha + base_branch = payload.pull_request.base.ref + pr_owner = payload.pull_request.user.login } - console.log(url) + app.log.info([url, number, commit, base_branch, pr_owner].join(" ")) - await context.octokit.rest.checks.create({ + context.octokit.rest.checks.create({ owner: owner, repo: repo, head_sha: commit, - name: 'ms_conflict', - status: 'in_progress', + name: MsConflict, + status: InProgress, + }); + // If it belongs to ms, comment on PR. + var result = 'failure' + let run = spawnSync('bash', ['-c', ['./conflict_detect.sh', repo, url, gh_token, msazure_token, script_url, pr_owner, number, base_branch].join(" ") ], { encoding: 'utf-8' }) + if (run.status == 254) { + app.log.info("Conflict detected! PR is not completed.") + } else if (run.status != 0){ + app.log.error("=============================") + app.log.error(run.stderr) + app.log.error(run.stdout) + app.log.error("-----------------------------") + } else { + app.log.info("No Conflict.") + result = 'success' } - ); - console.log(url, gh_token, mssonic_token, msazure_token, conflict_script_url) - var result = 'success' - try { - run = spawnSync('bash', ['./conflict_detect.sh', url, gh_token, mssonic_token, msazure_token, conflict_script_url], { encoding: 'utf-8' }) - console.log(run) - if ( run.status != 0 ) { - result = 'failure' - if ( run.status != 254) { console.log(run.status,run) }; + + let description = '', comment_at = '', mspr = '' + if (run.status == 254 || run.status == 253 || run.status == 252){ + for (const line of run.stdout.split(/\r?\n/)){ + if (line.startsWith("pr_owner: ")){ + comment_at = line.replace("pr_owner: ", "") + } + if (line.startsWith("ms_pr: ")){ + mspr = line.replace("ms_pr: ", "") + } + if (line.startsWith("ms_pr_new: ")){ + mspr = line.replace("ms_pr_new: ", "") + } } - } catch (error) { - console.log(error) - return - } - - url = '' - for ( const element of run.output[1].split(/\r?\n|\r|\n/g) ) { - if ( element.startsWith('https://dev.azure') ) { - url = element - break + if (comment_at == '' || mspr == ''){ + app.log.error("Error output by conflict_detect.sh") + } + description = `@${comment_at} PR: ${url} is conflict with MS internal repo
Please complete the following PR by pushing fix commit to sonicbld/conflict_prefix/${number}-fix
${mspr}
Then comment "/azpw ms_conflict" to rerun PR checker.` + let mssonicbld_ghclient = new Octokit({ + auth: gh_token, + }); + let now = new Date() + now.setDate(now.getDate() -1) + let comments = await mssonicbld_ghclient.rest.issues.listComments({ + owner: owner, + repo: repo, + issue_number: number, + since : now.toISOString(), + per_page: 100, + }); + let need_comment = true + if ( Object.values(comments.data).length > 0){ + for (const comment of Object.values(comments.data)) { + if ( comment.body == description ) { + need_comment = false + break + } + } + } + + if (need_comment) { + mssonicbld_ghclient.rest.issues.createComment({ + owner: owner, + repo: repo, + issue_number: number, + body: description, + }); } } var check = await context.octokit.rest.checks.create({ - owner: owner, - repo: repo, - head_sha: commit, - name: 'ms_conflict', - conclusion: result, - status: 'completed', - output: { - title: "ms code conflict", - summary: "conflict details:\n" + url + "\nPlease resolve conflict in the PR by pushing to PRID-fix branch.\nThen comment on PR: /azpw ms_conflict" - } - } - ); - if ( check.status != 201 && check.status != 202 ) { console.log(check) } - }); + owner: owner, + repo: repo, + head_sha: commit, + name: MsConflict, + conclusion: result, + status: 'completed', + output: { + title: "ms code conflict", + summary: description, + }, + }); + if (check.status != 201 && check.status != 202 && check.status != 200) { app.log.error(check) } + }); }; module.exports = Object.freeze({ diff --git a/azure-pipelines-wrapper/conflict_detect.sh b/azure-pipelines-wrapper/conflict_detect.sh index 6fe784e..d0bf355 100644 --- a/azure-pipelines-wrapper/conflict_detect.sh +++ b/azure-pipelines-wrapper/conflict_detect.sh @@ -1,21 +1,34 @@ -set -ex - -URL=$1 -GH_TOKEN=$2 -MSSONIC_TOKEN=$3 -MSAZURE_TOKEN=$4 -SCRIPT_URL=$5 +#!/bin/bash +REPO=$1 mkdir -p workspace cd workspace +rm -rf $(find . -name "tmp.*" -type d -cmin +10) -rm -rf $(find . -name "tmp.*" -type d -cmin +30) +mkdir $REPO -p +cd $REPO tmp=$(mktemp -p ./ -d) cd $tmp -curl "https://mssonicbld:$GH_TOKEN@$SCRIPT_URL" -o ms_conflict_detect.sh -wc -l ms_conflict_detect.sh +echo "tmp dir: $tmp" -bash ms_conflict_detect.sh $MSAZURE_TOKEN $MSSONIC_TOKEN $GH_TOKEN $URL -cd .. +cat > .bashenv << EOF +URL=$2 +GH_TOKEN=$3 +MSAZURE_TOKEN=$4 +SCRIPT_URL=$5 +PR_OWNER=$6 +PR_ID=$7 +BASE_BRANCH=$8 +EOF + +. .bashenv + +curl "https://mssonicbld:$GH_TOKEN@$SCRIPT_URL/ms_conflict_detect.sh" -o ms_conflict_detect.sh -L +curl "https://mssonicbld:$GH_TOKEN@$SCRIPT_URL/azdevops_git_api.sh" -o azdevops_git_api.sh -L +bash ms_conflict_detect.sh +rc=$? + +cd ../ rm -rf $tmp +exit $rc diff --git a/azure-pipelines-wrapper/index.js b/azure-pipelines-wrapper/index.js index c25c9a7..c1b2679 100644 --- a/azure-pipelines-wrapper/index.js +++ b/azure-pipelines-wrapper/index.js @@ -12,9 +12,9 @@ module.exports = (app) => { // Your code here app.log.info("Yay, the app was loaded!"); - issue_comment.init(app); + // issue_comment.init(app); check_run.init(app); - eventhub.init(app); +// eventhub.init(app); conflict_detect.init(app); // For more information on building apps: diff --git a/azure-pipelines-wrapper/issue_comment.js b/azure-pipelines-wrapper/issue_comment.js index f0b156d..d003213 100644 --- a/azure-pipelines-wrapper/issue_comment.js +++ b/azure-pipelines-wrapper/issue_comment.js @@ -19,8 +19,8 @@ function init(app) { comment_body = payload.comment.body.trim(); command = null; - console.log(`issue_comment.created, ${payload.comment.id}`); if (comment_body.toLowerCase().startsWith('/azpw ms_conflict') ){ return }; + console.log(`issue_comment.created, ${payload.comment.id}`); if (isDevEnv){ if (comment_body.toLowerCase().startsWith('/azpwd comment')){ await context.octokit.rest.issues.createComment({ diff --git a/azure-pipelines-wrapper/keyvault.js b/azure-pipelines-wrapper/keyvault.js index 9619365..8c0a10e 100644 --- a/azure-pipelines-wrapper/keyvault.js +++ b/azure-pipelines-wrapper/keyvault.js @@ -31,7 +31,8 @@ async function getSecretFromCache(secretName){ async function getAppPrivateKey() { - return await getSecretFromCache("PRIVATE_KEY"); + // TODO + return await getSecretFromCache("PRIVATE_KEY1"); } async function getAppWebhookSecret() diff --git a/azure-pipelines-wrapper/main.js b/azure-pipelines-wrapper/main.js index d750677..b1bad41 100644 --- a/azure-pipelines-wrapper/main.js +++ b/azure-pipelines-wrapper/main.js @@ -5,6 +5,7 @@ const akv = require('./keyvault.js'); async function startServer() { var privateKey = await akv.getAppPrivateKey(); var secret = await akv.getAppWebhookSecret(); + secret = "default"; const server = new Server({ Probot: Probot.defaults({