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/