refactor: harden inputs and secret usage #2
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| --- | ||
|
Check failure on line 1 in .github/workflows/copr-ci.yml
|
||
| name: CI Copr Call | ||
| permissions: | ||
| contents: read | ||
| on: | ||
| workflow_call: | ||
| inputs: | ||
| copr_pr_webhook_token: | ||
| description: 'Copr PR webhook key. This should not be secret if you want it to work for PRs from forks.' | ||
| required: true | ||
| type: string | ||
| github_org_owner: | ||
| description: 'GitHub organization owner. This will prevent user forks from triggering the workflow.' | ||
| required: true | ||
| type: string | ||
| copr_ownername: | ||
| description: 'User or group name.' | ||
| required: true | ||
| type: string | ||
| auto_update_package: | ||
| description: 'Automatically create/update a package in Copr.' | ||
| required: false | ||
| type: boolean | ||
| default: true | ||
| job_timeout: | ||
| description: 'Job timeout in minutes.' | ||
| required: false | ||
| type: number | ||
| default: 90 | ||
| secrets: | ||
| COPR_BETA_WEBHOOK_TOKEN: | ||
| description: 'Copr beta webhook token. This should be a secret.' | ||
| required: true | ||
| COPR_STABLE_WEBHOOK_TOKEN: | ||
| description: 'Copr stable webhook token. This should be a secret.' | ||
| required: true | ||
| COPR_CLI_CONFIG: | ||
| description: 'Copr CLI configuration file. See https://copr.fedorainfracloud.org/api' | ||
| required: true | ||
| env: | ||
| INPUTS_AUTO_UPDATE_PACKAGE: ${{ inputs.auto_update_package }} | ||
| INPUTS_COPR_PR_WEBHOOK_TOKEN: ${{ inputs.copr_pr_webhook_token }} | ||
| INPUTS_COPR_OWNERNAME: ${{ inputs.copr_ownername }} | ||
| INPUTS_GITHUB_ORG_OWNER: ${{ inputs.github_org_owner }} | ||
| INPUTS_JOB_TIMEOUT: ${{ inputs.job_timeout }} | ||
| SECRETS_COPR_BETA_WEBHOOK_TOKEN: ${{ secrets.COPR_BETA_WEBHOOK_TOKEN }} | ||
| SECRETS_COPR_STABLE_WEBHOOK_TOKEN: ${{ secrets.COPR_STABLE_WEBHOOK_TOKEN }} | ||
| SECRETS_COPR_CLI_CONFIG: ${{ secrets.COPR_CLI_CONFIG }} | ||
| jobs: | ||
| package-init: | ||
| name: Create/update copr package | ||
| runs-on: ubuntu-latest | ||
| container: fedora:latest | ||
| env: | ||
| BASE_URL: https://copr.fedorainfracloud.org/api_3 | ||
| PACKAGE_NAME: ${{ github.event.repository.name }} | ||
| SOURCE_TYPE_TEXT: "custom" | ||
| steps: | ||
| - name: Debug inputs | ||
| run: | | ||
| echo "inputs:" | ||
| echo "copr_pr_webhook_token: ${INPUTS_COPR_PR_WEBHOOK_TOKEN}" | ||
| echo "github_org_owner: ${INPUTS_GITHUB_ORG_OWNER}" | ||
| echo "copr_ownername: ${INPUTS_COPR_OWNERNAME}" | ||
| echo "auto_update_package: ${INPUTS_AUTO_UPDATE_PACKAGE}" | ||
| echo "job_timeout: ${INPUTS_JOB_TIMEOUT}" | ||
| - name: Test secrets | ||
| id: test_secrets | ||
| if: > | ||
| github.repository_owner == env.INPUTS_GITHUB_ORG_OWNER && | ||
| env.INPUTS_AUTO_UPDATE_PACKAGE == 'true' | ||
| run: | | ||
| # return if secrets.COPR_CLI_CONFIG is empty | ||
| if [ -z "${SECRETS_COPR_CLI_CONFIG}" ]; then | ||
| echo "Copr CLI configuration file is empty. Exiting..." | ||
| # if a pull request exit with 0 | ||
| if [ "${{ github.event_name }}" = "pull_request" ]; then | ||
| echo "SKIP_REMAINING_JOBS=true" >> "${GITHUB_OUTPUT}" | ||
| else | ||
| exit 1 | ||
| fi | ||
| else | ||
| mkdir -p ~/.config | ||
| echo "${SECRETS_COPR_CLI_CONFIG}" > ~/.config/copr | ||
| fi | ||
| - name: Install dependencies | ||
| if: steps.test_secrets.outputs.SKIP_REMAINING_JOBS != 'true' | ||
| run: | | ||
| dnf install -y \ | ||
| copr-cli \ | ||
| jq | ||
| - name: create packages | ||
| if: steps.test_secrets.outputs.SKIP_REMAINING_JOBS != 'true' | ||
| run: | | ||
| projects=( | ||
| "pulls" | ||
| "beta" | ||
| "stable" | ||
| ) | ||
| # download the latest copr-ci.sh script | ||
| if [ "${{ github.repository }}" = "LizardByte/copr-ci" ]; then | ||
| # use the version from the same ref | ||
| ref="${{ github.ref }}" | ||
| else | ||
| ref="master" # default to master branch | ||
| fi | ||
| curl \ | ||
| -fsSL \ | ||
| --retry 3 \ | ||
| "https://raw.githubusercontent.com/lizardbyte/copr-ci/${ref}/copr-ci.sh" \ | ||
| -o copr-ci.sh | ||
| # set parameters for package creation | ||
| script="copr-ci.sh" | ||
| builddeps="git jq python3 rpmlint" | ||
| resultdir="" | ||
| chroot="fedora-latest-x86_64" | ||
| for project in "${projects[@]}"; do | ||
| # check if 404 on get package (package does not exist) | ||
| url_query="ownername=${INPUTS_COPR_OWNERNAME}&projectname=${project}&packagename=${PACKAGE_NAME}" | ||
| url="${BASE_URL}/package?${url_query}" | ||
| status_code=$(curl --write-out '%{http_code}' --silent --output /dev/null "${url}") | ||
| if [[ "$status_code" == 404 ]]; then | ||
| echo "Creating package for ${project}..." | ||
| command="add-package-custom" | ||
| else | ||
| echo "Editing package for ${project}..." | ||
| command="edit-package-custom" | ||
| fi | ||
| copr-cli \ | ||
| ${command} \ | ||
| --script "${script}" \ | ||
| --script-builddeps "${builddeps}" \ | ||
| --script-resultdir "${resultdir}" \ | ||
| --script-chroot "${chroot}" \ | ||
| --name "${PACKAGE_NAME}" \ | ||
| --timeout $((60 * ${INPUTS_JOB_TIMEOUT})) \ | ||
| "${project}" | ||
| done | ||
| build: | ||
| name: Copr build | ||
| needs: package-init | ||
| if: github.repository_owner == env.INPUTS_GITHUB_ORG_OWNER | ||
| runs-on: ubuntu-latest | ||
| container: fedora:latest | ||
| timeout-minutes: ${{ env.INPUTS_JOB_TIMEOUT }} | ||
| outputs: | ||
| BUILD_ID: ${{ steps.build.outputs.BUILD_ID }} | ||
| BUILD_CANCEL: ${{ steps.build.outcome == 'cancelled' }} | ||
| BUILD_SUCCESS: ${{ steps.build.outcome == 'success' }} | ||
| steps: | ||
| - name: Install dependencies | ||
| run: | | ||
| dnf install -y \ | ||
| copr-cli \ | ||
| git \ | ||
| jq \ | ||
| nodejs \ | ||
| zip | ||
| - name: Checkout | ||
| uses: actions/checkout@v5 | ||
| - name: Set git safe directory | ||
| run: git config --global --add safe.directory '*' | ||
| - name: Add problem matchers | ||
| run: | | ||
| # add default matchers | ||
| mkdir -p .github/matchers | ||
| # download the latest rpmlint.json matcher | ||
| if [ ! "${{ github.repository }}" = "LizardByte/copr-ci" ]; then | ||
| # not in copr-ci repo, so download the rpmlint.json | ||
| ref="master" # default to master branch | ||
| curl \ | ||
| -fsSL \ | ||
| --retry 3 \ | ||
| "https://raw.githubusercontent.com/lizardbyte/copr-ci/${ref}/.github/matchers/rpmlint.json" \ | ||
| -o ".github/matchers/rpmlint.json" | ||
| fi | ||
| echo "::add-matcher::.github/matchers/rpmlint.json" | ||
| # repo specific matchers | ||
| if [ -f ".github/matchers/copr-ci.json" ]; then | ||
| echo "Found copr-ci.json matcher, adding it..." | ||
| echo "::add-matcher::.github/matchers/copr-ci.json" | ||
| fi | ||
| - name: Get properties | ||
| run: | | ||
| # package name = repository name | ||
| package=${{ github.event.repository.name }} | ||
| copr_base="https://copr.fedorainfracloud.org/webhooks/custom-dir/${INPUTS_COPR_OWNERNAME}" | ||
| # release and released type | ||
| if [ "${{ github.event_name }}" = "release" ]; then | ||
| if [ "${{ github.event.action }}" = "prereleased" ]; then | ||
| BUILD_CHANNEL="beta" | ||
| COPR_PUSH_WEBHOOK="${copr_base}/${BUILD_CHANNEL}/${SECRETS_COPR_BETA_WEBHOOK_TOKEN}/${package}/" | ||
| elif [ "${{ github.event.action }}" = "released" ]; then | ||
| BUILD_CHANNEL="stable" | ||
| COPR_PUSH_WEBHOOK="${copr_base}/${BUILD_CHANNEL}/${SECRETS_COPR_STABLE_WEBHOOK_TOKEN}/${package}/" | ||
| fi | ||
| elif [ "${{ github.event_name }}" = "pull_request" ]; then | ||
| BUILD_CHANNEL="pulls:pr:${{ github.event.number }}" | ||
| COPR_PR_WEBHOOK="${copr_base}/${BUILD_CHANNEL}/${INPUTS_COPR_PR_WEBHOOK_TOKEN}/${package}/" | ||
| fi | ||
| { | ||
| echo "BUILD_CHANNEL=${BUILD_CHANNEL}" | ||
| echo "COPR_PUSH_WEBHOOK=${COPR_PUSH_WEBHOOK}" | ||
| echo "COPR_PR_WEBHOOK=${COPR_PR_WEBHOOK}" | ||
| } >> "${GITHUB_ENV}" | ||
| echo "BUILD_CHANNEL=${BUILD_CHANNEL}" | ||
| echo "COPR_PUSH_WEBHOOK=${COPR_PUSH_WEBHOOK}" | ||
| echo "COPR_PR_WEBHOOK=${COPR_PR_WEBHOOK}" | ||
| - name: Build | ||
| id: build | ||
| run: | | ||
| curl \ | ||
| -fsSL \ | ||
| --retry 3 \ | ||
| "https://raw.githubusercontent.com/reenignearcher/copr-ci-tooling/patch-1/copr-gh-actions-submit" > submit | ||
| # TODO: https://github.com/praiskup/copr-ci-tooling/pull/1 | ||
| # "https://raw.githubusercontent.com/praiskup/copr-ci-tooling/main/copr-gh-actions-submit" | ||
| # if a PR number is added the script will use the PR webhook, otherwise it will use the push webhook | ||
| bash submit ${{ github.event.pull_request.number }} | ||
| - name: Cancel Copr build | ||
| if: >- | ||
| always() && | ||
| steps.build.outcome == 'cancelled' && | ||
| github.secret_source | ||
| run: | | ||
| mkdir -p ~/.config | ||
| echo "${SECRETS_COPR_CLI_CONFIG}" > ~/.config/copr | ||
| copr-cli \ | ||
| cancel \ | ||
| ${{ steps.build.outputs.BUILD_ID }} | ||
| - name: Logs | ||
| if: >- | ||
| always() && | ||
| steps.build.outcome != 'skipped' | ||
| run: | | ||
| package=${{ github.event.repository.name }} | ||
| base_url="https://download.copr.fedorainfracloud.org/results/${INPUTS_COPR_OWNERNAME}/${BUILD_CHANNEL}" | ||
| # get chroots and prefixed build_id | ||
| build_url="https://copr.fedorainfracloud.org/api_3/build/${{ steps.build.outputs.BUILD_ID }}" | ||
| data=$(curl -fsSL --retry 3 "${build_url}") | ||
| # Extract build_id from source_package.url (matches the last path segment after 'srpm-builds/') | ||
| build_id=$(echo "${data}" | jq -r '.source_package.url' | sed -E 's#.*/srpm-builds/([0-9]+)/.*#\1#') | ||
| echo "build_id: ${build_id}" | ||
| # Extract chroots | ||
| chroots=$(echo "${data}" | jq -r '.chroots[]') | ||
| echo "chroots:" | ||
| echo "${chroots}" | ||
| # Array of "name|url" pairs | ||
| logs=( | ||
| "source_builder|${base_url}/srpm-builds/${build_id}/builder-live.log.gz" | ||
| "source_backend|${base_url}/srpm-builds/${build_id}/backend.log.gz" | ||
| "import|https://copr-dist-git.fedorainfracloud.org/per-task-logs/${{ steps.build.outputs.BUILD_ID }}.log" | ||
| ) | ||
| for chroot in $chroots; do | ||
| logs+=("builder_${chroot}|${base_url}/${chroot}/${build_id}-${package}/builder-live.log.gz") | ||
| logs+=("backend_${chroot}|${base_url}/${chroot}/${build_id}-${package}/backend.log.gz") | ||
| done | ||
| error=0 | ||
| for entry in "${logs[@]}"; do | ||
| name="${entry%%|*}" | ||
| url="${entry#*|}" | ||
| set +e | ||
| echo "::group::Logs - ${name}" | ||
| [[ "${url}" == *.gz ]] && \ | ||
| (curl -fsSL --retry 3 "${url}" | gunzip -c) || \ | ||
| curl -fsSL --retry 3 "${url}" || { | ||
| echo "Failed to download logs from ${url}" | ||
| error=1 | ||
| } | ||
| echo "::endgroup::" | ||
| set -e | ||
| done | ||
| exit ${error} | ||
| - name: Download build | ||
| id: download-build | ||
| if: steps.build.outcome == 'success' | ||
| run: | | ||
| mkdir -p artifacts | ||
| copr-cli \ | ||
| download-build \ | ||
| --dest . \ | ||
| --rpms \ | ||
| ${{ steps.build.outputs.BUILD_ID }} | ||
| - name: Setup gh actions artifact client | ||
| id: download-build-client | ||
| if: steps.download-build.outcome == 'success' | ||
| uses: lhotari/gh-actions-artifact-client@v2 | ||
| - name: Upload artifacts | ||
| if: steps.download-build-client.outcome == 'success' | ||
| run: | | ||
| find . -type f -name "*.rpm" ! -name "*.src.rpm" | while read -r file; do | ||
| name=build-$(basename "$file") | ||
| echo "Uploading $name, file: $file" | ||
| zip -j - "$file" | gh-actions-artifact-client.js upload "${name}" --retentionDays=7 | ||
| done | ||