diff --git a/.github/workflows/backup-to-gitlab.yml b/.github/workflows/backup-to-gitlab.yml new file mode 100644 index 0000000000000..8fa52cf4f5878 --- /dev/null +++ b/.github/workflows/backup-to-gitlab.yml @@ -0,0 +1,12 @@ +name: backup to gitlab +on: [push] + +concurrency: + group: ${{ github.workflow }} + cancel-in-progress: true + +jobs: + backup-to-gitlabwh: + uses: deepin-community/.github/.github/workflows/backup-to-gitlabwh.yml@master + secrets: + BRIDGETOKEN: ${{ secrets.BRIDGETOKEN }} \ No newline at end of file diff --git a/.github/workflows/backup-to-gitlabwh.yml b/.github/workflows/backup-to-gitlabwh.yml new file mode 100644 index 0000000000000..b777156dc91fb --- /dev/null +++ b/.github/workflows/backup-to-gitlabwh.yml @@ -0,0 +1,31 @@ +name: backup to gitlab + workflow_call: + secrets: + BRIDGETOKEN: + required: true + +jobs: + backup-to-gitlab: + if: github.repository_owner == 'deepin-community' + name: backup-to-gitlab + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + repository: "linuxdeepin/jenkins-bridge-client" + path: jenkins-bridge-client + + - name: Install Client + run: | + cd $GITHUB_WORKSPACE/jenkins-bridge-client + go build . + sudo install -Dvm755 jenkins-bridge-client -t /usr/bin/ + + - name: Trigger sync + id: generate-runid + run: | + echo "::set-output name=RUN_ID::$(jenkins-bridge-client triggerSync --token '${{ secrets.BRIDGETOKEN }}')" + + - name: Print log + run: | + jenkins-bridge-client printLog --token "${{ secrets.BRIDGETOKEN }}" --runid "${{ steps.generate-runid.outputs.RUN_ID }}" \ No newline at end of file diff --git a/.github/workflows/chatOps.yml b/.github/workflows/chatOps.yml new file mode 100644 index 0000000000000..04f7a65e39976 --- /dev/null +++ b/.github/workflows/chatOps.yml @@ -0,0 +1,370 @@ +name: chatOps +on: + workflow_call: + +env: + APP_ID: 229710 + APP_PRIVATE_KEY: ${{ secrets.APP_PRIVATE_KEY }} + +jobs: + chatopt: + if: contains(github.event.comment.html_url, '/pull/') + runs-on: [ubuntu-latest] + steps: + # assign to someone + - name: assign + uses: actions/github-script@v5 + if: startsWith(github.event.comment.body, '/assign') + env: + COMMENT_BODY: ${{ github.event.comment.body }} + with: + script: | + const { COMMENT_BODY } = process.env + const groups = COMMENT_BODY.match(/\/assign \@(\S+)/) + groups && await github.rest.issues.addAssignees({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + assignees: groups[1] + }) + # request someone to review + - name: review + uses: actions/github-script@v5 + if: startsWith(github.event.comment.body, '/review') + env: + COMMENT_BODY: ${{ github.event.comment.body }} + with: + script: | + const { COMMENT_BODY } = process.env + const command = COMMENT_BODY.match(/\/review (\@\w+ )+/) + if ( !command || !command[0] ){ + return + } + const users = command[0].match(/\@\w+/g) + if( !users ){ + return + } + await github.rest.pulls.requestReviewers({ + pull_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + reviewers: users.map(a=>a.slice(1)) + }); + # !deprecated add approve label + - name: "approve" + uses: actions/github-script@v5 + if: startsWith(github.event.comment.body, '/+1') + with: + script: | + if(context.payload.sender.id == context.payload.issue.user.id){ + await github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: 'Permission denied' + }) + return + } + await github.rest.issues.addLabels({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + labels: ['approve'] + }) + + # retrigger checks + - name: check + uses: actions/github-script@v5 + if: startsWith(github.event.comment.body, '/check') + env: + COMMENT_BODY: ${{ github.event.comment.body }} + with: + script: | + const { COMMENT_BODY } = process.env + const checkNameGroup = COMMENT_BODY.match(/\/check (\S+)/) + + const pull = await github.rest.pulls.get({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.issue.number, + }) + const listResp = await github.rest.checks.listForRef({ + owner: context.repo.owner, + repo: context.repo.repo, + ref: pull.data.head.sha, + }); + for(const run of listResp.data.check_runs){ + if(checkNameGroup) { + const input = checkNameGroup[1].startsWith("/") ? checkNameGroup[1] : '/' + checkNameGroup[1] + const name ='/' + run.name.replace(/ \/ /g,'/') + if(name.includes(input)){ + console.log(name, "re-check") + await github.request(`POST /repos/${context.repo.owner}/${context.repo.repo}/actions/jobs/${run.id}/rerun`); + } else { + console.log(name, "skip") + } + }else{ + await github.request(`POST /repos/${context.repo.owner}/${context.repo.repo}/actions/jobs/${run.id}/rerun`); + } + } + + - name: install depends for load scripts + if: | + startsWith(github.event.comment.body, '/merge') || startsWith(github.event.comment.body, '/check') + run: | + npm install @octokit/rest@19.0.13 + npm install @octokit/auth-app@6.1.1 + + - name: Get token using github-script + if: | + startsWith(github.event.comment.body, '/merge') || startsWith(github.event.comment.body, '/check') + id: get-token + uses: actions/github-script@v6 + with: + script: | + global["fetch"] = fetch + const { Octokit } = require("@octokit/rest"); + const { createAppAuth } = require("@octokit/auth-app"); + const appOctokit = new Octokit({ + authStrategy: createAppAuth, + auth: { + appId: process.env.APP_ID, + privateKey: process.env.APP_PRIVATE_KEY, + } + }); + const app_installation = await appOctokit.rest.apps.getRepoInstallation({ + owner: context.payload.organization.login, + repo: context.payload.repository.name + }); + const { token } = await appOctokit.auth({ + type: "installation", + installationId: app_installation.data.id + }); + core.setOutput('app_token', token) + + # retrigger obs build webhook + - name: check obs + uses: actions/github-script@v6 + if: startsWith(github.event.comment.body, '/check') + id: check-obs + env: + COMMENT_BODY: ${{ github.event.comment.body }} + HOOK_ID: 396506100 + with: + github-token: ${{ steps.get-token.outputs.app_token }} + script: | + const BOT_NAME = "Deepin Obs Bot" + const COMMENT_HEAD = "**" + BOT_NAME + "**\n" + let BODY = "Starting find obs webhook event and retrigger!" + + if ( context.issue.number != undefined ) { + const response = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number + }) + const reg = new RegExp("\\*+" + BOT_NAME + "\\*+") + BotComment= response.data.find(comment => comment.body.match(reg)) + if (BotComment) { + await github.rest.issues.deleteComment({ + comment_id: BotComment.id, + owner: context.repo.owner, + repo: context.repo.repo, + }) + } + + await github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: COMMENT_HEAD + BODY + }) + } else { + console.log("context.issue.number is not a valid issue number: " + context.issue.number) + } + + const { COMMENT_BODY } = process.env + const checkNameGroup = COMMENT_BODY.match(/\/check (\S+)/) + + // handle obs workflow resend + obs_webhook_need_resend = true + + if (checkNameGroup && !COMMENT_BODY.includes("obs")) { + obs_webhook_need_resend = false + } + + // console.log("HOOK_ID: ", process.env.HOOK_ID) + core.setOutput('retriggered', "true") + if (obs_webhook_need_resend) { + // deliveries obs webhook + let maxWebhooks = 1000 + let retriggered = false + for await (const WebhookDeliveriesResp of github.paginate.iterator( + github.rest.orgs.listWebhookDeliveries, + { + org: context.repo.owner, + hook_id: process.env.HOOK_ID, + per_page: 100, + }, + (response, done) => { + if (retriggered) { + done(); + } + return response.data; + } + )) { + console.log("github repository_id: ", ${{ github.repository_id }}) + core.setOutput('retriggered', "false") + for (var i = 0; i < WebhookDeliveriesResp.data.length; i++) { + let wh = WebhookDeliveriesResp.data[i] + console.log("webhook event: ", wh.event, ", webhook repository_id: ", wh.repository_id) + if (wh.event == 'pull_request' && wh.repository_id == ${{ github.repository_id }} && (wh.action == 'opened' || wh.action == 'synchronize')) { + // Get delivery payload and filter + const resp = await github.rest.orgs.getWebhookDelivery({ + org: context.repo.owner, + hook_id: process.env.HOOK_ID, + delivery_id: wh.id, + }); + //console.log("delivery payload: " + JSON.stringifyesp.data)) + console.log("payload number: " + resp.data.request.payload.number) + console.log("pr number: " + context.issue.number) + if (resp.data.request.payload.number == context.issue.number) { + const resp = await github.rest.orgs.redeliverWebhookDelivery({ + org: context.repo.owner, + hook_id: process.env.HOOK_ID, + delivery_id: wh.id, + }); + console.log("redeliver webhook resp: ", resp) + retriggered = true + core.setOutput('retriggered', "true") + return + } + } + } + } + } + + + - name: check obs comment + uses: actions/github-script@v6 + if: | + startsWith(github.event.comment.body, '/check obs') && steps.check-obs.outputs.retriggered == 'false' + with: + github-token: ${{ steps.get-token.outputs.app_token }} + script: | + console.log("redeliveried failed, context.issue.number: ", context.issue.number) + const BOT_NAME = "Deepin Obs Bot" + const COMMENT_HEAD = "**" + BOT_NAME + "**\n" + let COMMENT_BODY = "Deepin redeliveried failed, need update or recreate pull request!!!" + + if ( context.issue.number != undefined ) { + const response = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number + }) + const reg = new RegExp("\\*+" + BOT_NAME + "\\*+") + BotComment= response.data.find(comment => comment.body.match(reg)) + if (BotComment) { + await github.rest.issues.updateComment({ + comment_id: BotComment.id, + owner: context.repo.owner, + repo: context.repo.repo, + body: COMMENT_HEAD + COMMENT_BODY + }) + } else { + await github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: COMMENT_HEAD + COMMENT_BODY + }) + } + } + + # auto merge pull request + - name: merge + uses: actions/github-script@v5 + if: startsWith(github.event.comment.body, '/merge') + with: + github-token: ${{ steps.get-token.outputs.app_token }} + script: | + await github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: `Merge" command is disabled` + }) + return + + if(context.payload.sender.id != context.payload.issue.user.id){ + const permission = await github.request(`GET /repos/${context.repo.owner}/${context.repo.repo}/collaborators/${context.payload.sender.login}/permission`, { + owner: context.repo.owner, + repo: context.repo.repo, + username: context.payload.sender.login, + }) + if(!["admin","maintain","write"].includes(permission.data.permission)){ + await github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: 'Permission denied' + }) + return + } + } + + const pull = await github.rest.pulls.get({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.issue.number, + }) + + if( pull.data.mergeable_state != "clean" ){ + await github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: `This pr cannot be merged! (status: ${pull.data.mergeable_state})` + }) + return + } + + await github.rest.pulls.merge({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.issue.number, + merge_method: 'rebase' + }); + + pr-info: + runs-on: ubuntu-latest + outputs: + ref: ${{ steps.pr.outputs.ref }} + steps: + - name: Get integration app token + id: pr + uses: actions/github-script@v6 + with: + script: | + const response = await github.rest.pulls.get({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.issue.number + }); + if (response.data.state != "closed") { + core.setOutput('ref', response.data.head.sha) + } else { + core.setOutput('ref', response.data.merge_commit_sha) + } + + integration: + needs: + - pr-info + name: Try pr integration + if: startsWith(github.event.comment.body, '/integrate') + uses: deepin-community/.github/.github/workflows/auto-integration-pr.yml@master + secrets: inherit + with: + integrationrepo: ${{ github.repository }} + tagsha: ${{ needs.pr-info.outputs.ref }} \ No newline at end of file diff --git a/.github/workflows/check-code-cap.yml b/.github/workflows/check-code-cap.yml new file mode 100644 index 0000000000000..391813b820c85 --- /dev/null +++ b/.github/workflows/check-code-cap.yml @@ -0,0 +1,51 @@ +name: code check cap +on: + workflow_call: + inputs: + ref: + required: true + type: string + workflow_dispatch: + inputs: + ref: + required: true + type: string + +env: + GITHUB_TOKEN: ${{ github.token }} + +jobs: + cap: + runs-on: ubuntu-latest + outputs: + reviewer: ${{ steps.cap-output.outputs.reviewer }} + steps: + - uses: actions/checkout@v3 + with: + ref: ${{ inputs.ref }} + + - name: code check cap + id: cap-output + run: | + set -x + echo "code checking cap" + mkdir ../diff + git show > ../diff/diff + cd ../diff/ + cap_num=$(grep -En "\\s*[s|g]etcap\\s*" diff | wc -l || true) + if [ "$cap_num"X != "0X" ];then + echo "found cap changes, need review" + echo "reviewer=CapReviewer" >> $GITHUB_OUTPUT + else + echo "reviewer=AUTO" >> $GITHUB_OUTPUT + fi + + cap-review: + needs: cap + runs-on: ubuntu-latest + environment: ${{ needs.cap-output.outputs.reviewer }} + steps: + - name: Handle cap review status + #TODO: Use the github project to count the review results of the cap? + run: | + echo "cap changes reviewed by ${{ needs.cap-output.outputs.reviewer }}." \ No newline at end of file diff --git a/.github/workflows/check-code.yml b/.github/workflows/check-code.yml new file mode 100644 index 0000000000000..cd0eee1d2efa0 --- /dev/null +++ b/.github/workflows/check-code.yml @@ -0,0 +1,21 @@ +name: code check +on: + workflow_call: + inputs: + ref: + required: true + type: string + workflow_dispatch: + inputs: + ref: + required: true + type: string + +jobs: + check-cap: + name: check cap + strategy: + fail-fast: false + uses: deepin-community/.github/.github/workflows/check-code-cap.yml@master + with: + ref: ${{ inputs.ref }} \ No newline at end of file diff --git a/.github/workflows/cla-check.yml b/.github/workflows/cla-check.yml new file mode 100644 index 0000000000000..88589f2f87c59 --- /dev/null +++ b/.github/workflows/cla-check.yml @@ -0,0 +1,47 @@ +name: "CLA Assistant" +on: + workflow_call: + secrets: + APP_PRIVATE_KEY: + required: true + +jobs: + CLAssistant: + runs-on: ubuntu-latest + steps: + - name: "CLA Assistant" + if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA.') || github.event_name == 'pull_request_target' + # use github app support version + uses: linuxdeepin/contributor-assistant-github-action@master + + env: + APP_ID: 229710 + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + APP_PRIVATE_KEY: ${{ secrets.APP_PRIVATE_KEY }} + + with: + path-to-signatures: 'signatures/version1/cla.json' + path-to-document: 'https://github.com/deepin-community/cla/blob/master/cla.md' # e.g. a CLA or a DCO document + # branch should not be protected + branch: master + allowlist: deepin-community-ci-bot[bot] + + #below are the optional inputs - If the optional inputs are not given, then default values will be taken + remote-organization-name: deepin-community + remote-repository-name: cla + #create-file-commit-message: 'For example: Creating file for storing CLA Signatures' + #signed-commit-message: 'For example: $contributorName has signed the CLA in #$pullRequestNo' + custom-notsigned-prcomment: '
+
+ **如果你是以企业贡献者的身份进行提交,请联系我们签署[企业贡献者许可协议](https://github.com/linuxdeepin/cla/blob/master/%E4%BC%81%E4%B8%9A%E8%B4%A1%E7%8C%AE%E8%80%85%E8%AE%B8%E5%8F%AF%E5%8D%8F%E8%AE%AE%EF%BC%88%E4%B8%AD%E6%96%87%E7%89%88%EF%BC%89-V1.0.md)**
+ **If you submit as corporate contributor, please contact us to sign our [Corporate Contributor License Agreement](https://github.com/linuxdeepin/cla/blob/master/Corporate%20Contributor%20License%20Agreement-EN-V1.0.md)**
+
+ 感谢您的提交,我们非常感谢。 像许多开源项目一样,在接受您的贡献之前,我们要求您签署我们的[个人贡献者许可协议](https://github.com/linuxdeepin/cla/blob/master/%E4%B8%AA%E4%BA%BA%E8%B4%A1%E7%8C%AE%E8%80%85%E8%AE%B8%E5%8F%AF%E5%8D%8F%E8%AE%AE%EF%BC%88%E4%B8%AD%E6%96%87%E7%89%88%EF%BC%89-V1.0.md)。 您只需发布与以下格式相同的评论即可签署[个人贡献者许可协议](https://github.com/linuxdeepin/cla/blob/master/%E4%B8%AA%E4%BA%BA%E8%B4%A1%E7%8C%AE%E8%80%85%E8%AE%B8%E5%8F%AF%E5%8D%8F%E8%AE%AE%EF%BC%88%E4%B8%AD%E6%96%87%E7%89%88%EF%BC%89-V1.0.md)。
+ Thank you for your submission, we really appreciate it. Like many open-source projects, we ask that $you sign our [Individual Contributor License Agreement](https://github.com/linuxdeepin/cla/blob/master/Individual%20Contributor%20License%20Agreement-EN-V1.0.md) before we can accept your contribution. You can sign the [Individual Contributor License Agreement](https://github.com/linuxdeepin/cla/blob/master/Individual%20Contributor%20License%20Agreement-EN-V1.0.md) by just posting a Pull Request Comment same as the below format.
+
' + allow-email-list: '*@uniontech.com,*@deepin.org,*@deepin.com,*@phytium.com.cn,*@zhaoxin.com' + custom-pr-sign-comment: 'I have read the CLA Document and I hereby sign the CLA.' + #custom-allsigned-prcomment: 'pull request comment when all contributors has signed, defaults to **CLA Assistant Lite bot** All Contributors have signed the CLA.' + lock-pullrequest-aftermerge: false + # if you don't want this bot to automatically lock the pull request after merging (default - true) + #use-dco-flag: true - If you are using DCO instead of CLA \ No newline at end of file diff --git a/.gitignore b/.gitignore index 0bbae167bf93e..2ee359e8b0060 100644 --- a/.gitignore +++ b/.gitignore @@ -170,3 +170,6 @@ sphinx_*/ # Rust analyzer configuration /rust-project.json + +# Github actions +!.github/