diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000000000000000000000000000000000000..8e5691b5d377968470df65fbc31bbc42b4bb4943 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,170 @@ +pipeline { + agent any + + options { + disableConcurrentBuilds(abortPrevious: true) + parallelsAlwaysFailFast() + } + + triggers { + cron('H H(0-6) * * *') + } + + parameters { + string(name: 'BTFHUB_ARCHIVE_REPO_URL', + description: 'URL of the archive repository', + defaultValue: 'https://gitee.com/openeuler/btfhub-archive.git') + string(name: 'BTFHUB_ARCHIVE_BUILD_BRANCH', + description: 'Branch of the archive repository to build upon', + defaultValue: 'next') + string(name: 'BTFHUB_GIT_AUTHOR_NAME_CREDENTIAL_ID', + description: 'Credential ID for author name in commits', + defaultValue: 'openeuler-btfhub-git-author-name') + string(name: 'BTFHUB_GIT_AUTHOR_EMAIL_CREDENTIAL_ID', + description: 'Credential ID for author email in commits', + defaultValue: 'openeuler-btfhub-git-author-email') + string(name: 'BTFHUB_GITEE_CREDENTIAL_ID', + description: 'Credentail ID for authentication with Gitee', + defaultValue: 'gitee-hanlinyang-username-password') + } + + stages { + stage('Check out repositories') { + parallel { + stage('Check out BTFHub') { + steps { + dir('btfhub') { + checkout scm + } + } + } + + stage('Check out BTFHub Archive') { + steps { + dir('btfhub-archive') { + checkout scmGit( + branches: [[name: "*/${params.BTFHUB_ARCHIVE_BUILD_BRANCH}"]], + userRemoteConfigs: [[ + name: 'origin', + url: params.BTFHUB_ARCHIVE_REPO_URL]], + extensions: [ localBranch() ]) + + withCredentials([ + string( + credentialsId: params.BTFHUB_GIT_AUTHOR_NAME_CREDENTIAL_ID, + variable: 'BTFHUB_GIT_AUTHOR_NAME'), + string( + credentialsId: params.BTFHUB_GIT_AUTHOR_EMAIL_CREDENTIAL_ID, + variable: 'BTFHUB_GIT_AUTHOR_EMAIL') ]) { + sh 'git config --local user.name "$BTFHUB_GIT_AUTHOR_NAME"' + sh 'git config --local user.email "$BTFHUB_GIT_AUTHOR_EMAIL"' + } + + sh 'git rebase origin/master' + sh "git branch --set-upstream-to origin/${params.BTFHUB_ARCHIVE_BUILD_BRANCH}" + } + } + } + } + } + + stage('Build builder image') { + steps { + dir('btfhub') { + sh 'docker build -t openeuler-btfhub-ci-builder - < tools/ci/Dockerfile' + } + + script { + uid = sh(script: 'id -u', returnStdout: true).trim() + gid = sh(script: 'id -g', returnStdout: true).trim() + env.RUN_IN_BUILDER = """ + docker run \ + --rm \ + -u ${uid}:${gid} \ + -v ${env.WORKSPACE}:/workspace \ + -w /workspace \ + openeuler-btfhub-ci-builder \ + """ + } + } + } + + stage('Inspect build environment') { + steps { + sh 'uname -a' + sh 'docker version' + sh 'git --version' + sh ''' + $RUN_IN_BUILDER bash -x -c " \ + uname -a && \ + clang --version && \ + find --version && \ + git --version && \ + go version && \ + jq --version && \ + make --version && \ + pahole --version && \ + rsync --version && \ + xargs --version && \ + xz --version" + ''' + } + } + + stage('Generate BTF files') { + steps { + sh ''' + $RUN_IN_BUILDER bash -x -c " \ + cd btfhub && \ + make bring && \ + make && \ + ./btfhub -distro openEuler && \ + make take" + ''' + } + } + + stage('Commit, push & create PR') { + steps { + dir('btfhub-archive') { + sh 'git add -A' + sh 'git status' + sh ''' + git diff-index --quiet HEAD || \ + ( printf '%s\\n' \ + "Update BTFHub Archive" \ + "" \ + "This commit is created by an automated build process; see also <$BUILD_URL>." \ + | git commit -F - ) && \ + git log -1 + ''' + + withCredentials([ + gitUsernamePassword(credentialsId: params.BTFHUB_GITEE_CREDENTIAL_ID) ]) { + sh 'git push --force-with-lease' + } + } + + withCredentials([ usernamePassword( + credentialsId: params.BTFHUB_GITEE_CREDENTIAL_ID, + usernameVariable: '_UNUSED', + passwordVariable: 'BTFHUB_GITEE_API_TOKEN') ]) { + sh ''' + $RUN_IN_BUILDER bash -x -c " \ + cd btfhub-archive && \ + BTFHUB_GITEE_API_TOKEN="$BTFHUB_GITEE_API_TOKEN" \ + JOB_NAME="$JOB_NAME" \ + JOB_URL="$JOB_URL" \ + ../btfhub/tools/ci/create-pr.sh" + ''' + } + } + } + } + + post { + cleanup { + cleanWs() + } + } +} diff --git a/tools/ci/Dockerfile b/tools/ci/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..af531f3445a37332da5629db23d282af9eb4a925 --- /dev/null +++ b/tools/ci/Dockerfile @@ -0,0 +1,24 @@ +# syntax=docker/dockerfile:1 +# This Dockerfile is used to build a "builder" image providing required tools +# in CI pipelines without polluting the global environment. + +FROM openeuler/openeuler:22.03-lts-sp2 + +ARG GO_INSTALL_VERSION=1.19.11 + +RUN yum -y install \ + clang \ + dwarves \ + findutils \ + git \ + jq \ + make \ + rsync \ + xz \ + && \ + yum clean all + +RUN curl -fL -o - https://mirrors.ustc.edu.cn/golang/go${GO_INSTALL_VERSION}.linux-amd64.tar.gz \ + | tar -C /usr/local -xvzf - +ENV GOPROXY=https://repo.huaweicloud.com/repository/goproxy/,direct +ENV PATH="/usr/local/go/bin:$PATH" diff --git a/tools/ci/create-pr.sh b/tools/ci/create-pr.sh new file mode 100755 index 0000000000000000000000000000000000000000..9ac4fb9398548908fd3291229e82c91d3becc96e --- /dev/null +++ b/tools/ci/create-pr.sh @@ -0,0 +1,131 @@ +#!/usr/bin/env bash + +set -e + +SCRIPT_NAME="$(basename "$0")" +GITEE_API_BASE_URL="https://gitee.com/api/v5" + +info() { + echo "$SCRIPT_NAME: info:" "$@" +} + +error() { + echo "$SCRIPT_NAME: error:" "$@" +} + +prepare_api_token() { + if [[ -z "$BTFHUB_GITEE_API_TOKEN" ]]; then + error "missing required BTFHUB_GITEE_API_TOKEN" + exit 1 + fi + info "using BTFHUB_GITEE_API_TOKEN: $BTFHUB_GITEE_API_TOKEN" +} + +prepare_archive_repo() { + if [[ -z "$BTFHUB_ARCHIVE_REPO" ]]; then + BTFHUB_ARCHIVE_REPO="$(git remote get-url origin \ + | sed 's/^https:\/\/gitee.com\///' \ + | sed 's/^git@gitee.com://' \ + | sed 's/.git$//')" + fi + info "using BTFHUB_ARCHIVE_REPO: $BTFHUB_ARCHIVE_REPO" +} + +prepare_pr_head() { + if [[ -z "$BTFHUB_ARCHIVE_PR_HEAD" ]]; then + BTFHUB_ARCHIVE_PR_HEAD="$(git branch --show-current)" + fi + info "using BTFHUB_ARCHIVE_PR_HEAD: $BTFHUB_ARCHIVE_PR_HEAD" +} + +prepare_pr_base() { + if [[ -z "$BTFHUB_ARCHIVE_PR_BASE" ]]; then + BTFHUB_ARCHIVE_PR_BASE=master + fi + info "using BTFHUB_ARCHIVE_PR_BASE: $BTFHUB_ARCHIVE_PR_BASE" +} + +prepare_pr_title() { + if [[ -z "$BTFHUB_ARCHIVE_PR_TITLE" ]]; then + BTFHUB_ARCHIVE_PR_TITLE="Update BTF files" + fi + info "using BTFHUB_ARCHIVE_PR_TITLE: $BTFHUB_ARCHIVE_PR_TITLE" +} + +prepare_pr_body() { + if [[ -z "$BTFHUB_ARCHIVE_PR_BODY" ]]; then + BTFHUB_ARCHIVE_PR_BODY="$(printf '%s\n' \ + 'This PR updates BTF files in this repository.' \ + '' \ + "Commits and changes included in this PR are created by an automated CI pipeline; visit [**$JOB_NAME**]($JOB_URL) for details.")" + fi + info "$(printf 'using BTFHUB_ARCHIVE_PR_BODY: %q' "$BTFHUB_ARCHIVE_PR_BODY")" +} + +check_branches() { + if git rev-parse --is-inside-work-tree > /dev/null 2>&1 && \ + [[ "$(git rev-list --count "origin/$BTFHUB_ARCHIVE_PR_BASE..origin/$BTFHUB_ARCHIVE_PR_HEAD")" == "0" ]]; then + info "no need to create PR: the base branch $BTFHUB_ARCHIVE_PR_BASE is already up-to-date with the head branch $BTFHUB_ARCHIVE_PR_HEAD" + exit 0 + fi +} + +check_existing_pr() { + local existing_pr_url + existing_pr_url="$(printf '%s/repos/%s/pulls?state=open&head=%s&base=%s' \ + "$GITEE_API_BASE_URL" \ + "$BTFHUB_ARCHIVE_REPO" \ + "$BTFHUB_ARCHIVE_PR_HEAD" \ + "$BTFHUB_ARCHIVE_PR_BASE" \ + | xargs curl -sS --fail-with-body \ + | jq -r '.[].html_url')" + if [[ -n "$existing_pr_url" ]]; then + info "no need to create PR: PR already exists and is still open: $existing_pr_url" + exit 0 + fi +} + +do_create_pr() { + local create_pr_request create_pr_response + create_pr_request="$(echo '{}' \ + | jq -c ".access_token = \"$BTFHUB_GITEE_API_TOKEN\"" \ + | jq -c ".head = \"$BTFHUB_ARCHIVE_PR_HEAD\"" \ + | jq -c ".base = \"$BTFHUB_ARCHIVE_PR_BASE\"" \ + | jq -c ".title = \"$BTFHUB_ARCHIVE_PR_TITLE\"" \ + | jq -c ".body = \"$BTFHUB_ARCHIVE_PR_BODY\"")" + if ! create_pr_response="$(curl -sS --fail-with-body -X POST -d "$create_pr_request" \ + -H 'Content-Type: application/json;charset=UTF-8' \ + -H 'Accept: application/json;charset=UTF-8' \ + "$GITEE_API_BASE_URL/repos/$BTFHUB_ARCHIVE_REPO/pulls")"; then + error "failed to create PR: $(echo "$create_pr_response" | jq -r .message)" + exit 1 + fi + info "successfully created PR: $(echo "$create_pr_response" | jq -r '.html_url')" +} + +prepare_variables() { + info "preparing variables" + + prepare_api_token + prepare_archive_repo + prepare_pr_head + prepare_pr_base + prepare_pr_title + prepare_pr_body +} + +create_pr() { + info "creating PR" + + check_branches + check_existing_pr + + do_create_pr +} + +main() { + prepare_variables + create_pr +} + +main "$@"