diff --git a/.github/actions/build/action.yml b/.github/actions/build/action.yml index bb148c8..eabcb88 100644 --- a/.github/actions/build/action.yml +++ b/.github/actions/build/action.yml @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 + name: Build Project description: Build and install project @@ -51,28 +53,31 @@ runs: sudo apt-get update sudo apt-get install -y python3-venv libffi-dev python3 -m venv .venv + echo "$(pwd)/.venv/bin" >> "$GITHUB_PATH" shell: bash - name: Install dependencies working-directory: ${{ inputs.source-path }} run: | - ./.venv/bin/pip install --upgrade pip - ./.venv/bin/pip install build abi3audit + pip install --upgrade pip + pip install build abi3audit shell: bash - name: Generate distribution artifacts id: dist working-directory: ${{ inputs.source-path }} - if: ${{ inputs.dist == 'true' }} + if: inputs.dist == 'true' + env: + BUILD_PATH: ${{ inputs.build-path }} run: | - ./.venv/bin/python3 -m build -o "${{ inputs.build-path }}" - ./.venv/bin/abi3audit -v \ - $(find "${{ inputs.build-path }}" -name "*.whl") - echo "dist-path=${{ inputs.build-path }}" >> "$GITHUB_OUTPUT" + python3 -m build -o "$BUILD_PATH" + abi3audit -v \ + $(find "$BUILD_PATH" -name "*.whl") + echo "dist-path=${BUILD_PATH}" >> "$GITHUB_OUTPUT" shell: bash - name: Install project working-directory: ${{ inputs.source-path }} - if: ${{ inputs.install == 'true' }} - run: ./.venv/bin/pip install . + if: inputs.install == 'true' + run: pip install . shell: bash diff --git a/.github/actions/generate-latest-artifacts/action.yml b/.github/actions/generate-latest-artifacts/action.yml new file mode 100644 index 0000000..ddfd8d9 --- /dev/null +++ b/.github/actions/generate-latest-artifacts/action.yml @@ -0,0 +1,42 @@ +# SPDX-License-Identifier: Apache-2.0 + +name: 'Generate Latest Artifacts' +description: 'Generate latest artifacts by replacing version with "latest"' + +inputs: + local-path: + description: 'Local path where the artifacts are' + default: 'build' + +runs: + using: 'composite' + steps: + - name: Generate latest artifacts + env: + LOCAL_PATH: ${{ inputs.local-path }} + run: | + # Attempt to match filenames of the form + # pkg-A.B.C[.postD.devE+gF{9}][.dG{8}][moretext].extension + # where capital letters are numbers, F is 9 digits and G is 8 digits long + BASE_RE='\d+\.\d+\.\d+' # base version: A.B.C + POST_RE='\.post\d+\.dev\d+\+g[\da-z].{8}' # post abbr: .postD.devE+gF{9} + DATE_RE='\.d[\d].{7}' # date: .dG{8} + VERSION_REGEX="([^\d]+)${BASE_RE}(${POST_RE})*(${DATE_RE})*([^.]*\..+)" + + if [ -d "$LOCAL_PATH" ]; then + echo "Local path is a directory, skipping" + exit 0 + fi + + dir=$(dirname "$LOCAL_PATH") + files=$(basename "$LOCAL_PATH") + pushd "${dir}" + for f in $(find . -maxdepth 1 -type f -name "${files}"); do + latest_filename=$(echo "$f" | \ + perl -pe "s/${VERSION_REGEX}/\1latest\4/g") + + echo "Copying $f to ${latest_filename}" + cp "$f" "$latest_filename" + done + popd + shell: bash diff --git a/.github/actions/run-examples/action.yml b/.github/actions/run-examples/action.yml index 70855c4..ae5a64b 100644 --- a/.github/actions/run-examples/action.yml +++ b/.github/actions/run-examples/action.yml @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 + name: Run Examples description: Run vaccel examples @@ -18,12 +20,16 @@ runs: - name: Ensure run dir exists run: | uid=$(id -u) - [ -d "/run/user/${uid}" ] && exit 0 - sudo mkdir -p "/run/user/${uid}" - sudo chown -R "${uid}" "/run/user/${uid}" + run_dir="/run/user/${uid}" + + if [[ -d "$run_dir" ]]; then + exit 0 + fi + + sudo mkdir -p "$run_dir" + sudo chown -R "$uid" "$run_dir" shell: bash - name: Run examples - run: | - ./.venv/bin/python3 run-examples.py + run: python3 run-examples.py shell: bash diff --git a/.github/actions/run-tests/action.yml b/.github/actions/run-tests/action.yml index 053f866..75fb2f3 100644 --- a/.github/actions/run-tests/action.yml +++ b/.github/actions/run-tests/action.yml @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 + name: Run Tests description: Run project tests and generate coverage report @@ -21,38 +23,33 @@ runs: - name: Install dependencies working-directory: ${{ inputs.source-path }} run: | - # FIXME: This should be in the vaccel coverage workflow - if ! dpkg -s vaccel &> /dev/null; then - wget "https://s3.nbfc.io/nbfc-assets/github/vaccel/rev/main/x86_64/release/vaccel_latest_amd64.deb" - sudo apt install ./vaccel_latest_amd64.deb - rm vaccel_latest_amd64.deb - fi - # Use pre-meson NumPy so our arm jammy runners will work correctly - ./.venv/bin/pip install "numpy<1.25" + pip install "numpy<1.25" arch=$(python3 -c "import platform; print(platform.architecture()[0])") if [[ "${arch}" == "32bit" ]]; then - ./.venv/bin/pip install .[test] + pip install .[test] else - ./.venv/bin/pip install .[test-full] + pip install .[test-full] fi shell: bash - name: Run tests working-directory: ${{ inputs.source-path }} - run: ./.venv/bin/python3 -m pytest + run: python3 -m pytest shell: bash - name: Calculate coverage working-directory: ${{ inputs.source-path }} - if: ${{ inputs.coverage == 'true' }} + if: inputs.coverage == 'true' + env: + BUILD_PATH: ${{ inputs.build-path }} run: | - ./.venv/bin/pip install tomli - pkg_name=$(./.venv/bin/python3 -c \ + pip install tomli + pkg_name=$(python3 -c \ "import tomli; print(tomli.load(open('pyproject.toml', 'rb'))['project']['name'])") - ./.venv/bin/python3 -m pytest \ + python3 -m pytest \ --cov-report term \ - --cov-report xml:"${{ inputs.build-path }}/coverage.xml" \ - --cov="${pkg_name}" tests/ + --cov-report xml:"${BUILD_PATH}/coverage.xml" \ + --cov="$pkg_name" tests/ shell: bash diff --git a/.github/actions/upload-to-s3/action.yml b/.github/actions/upload-to-s3/action.yml deleted file mode 100644 index 1f576a0..0000000 --- a/.github/actions/upload-to-s3/action.yml +++ /dev/null @@ -1,74 +0,0 @@ -name: Upload to s3 -description: Upload artifacts to s3 - -inputs: - arch: - default: 'x86_64' - build-type: - default: 'release' - local-path: - default: 'build' - remote-basepath: - default: 'nbfc-assets/github/vaccel' - remote-subpath: - default: '' - access-key: - required: true - secret-key: - required: true - -runs: - using: composite - steps: - - name: Determine SHA and branch - id: get-rev-info - uses: ./.github/actions/get-revision-info - - - name: Generate paths - id: get-artifact-vars - run: | - branch=${{ steps.get-rev-info.outputs.branch }} - local_path=$(realpath -s --relative-to="${{ github.workspace }}" \ - "${{ inputs.local-path }}") - echo "local-path=${local_path}" >> "$GITHUB_OUTPUT" - base_path="${{ inputs.remote-basepath }}" - if [ -n "${{ inputs.remote-subpath }}" ]; then - base_path="${base_path}/${{ inputs.remote-subpath }}" - fi - remote_path="${base_path}/rev/${branch}/${{inputs.arch}}/${{inputs.build-type}}/" - echo "remote-path=${remote_path}" >> "$GITHUB_OUTPUT" - shell: bash - - # TODO: Split this into a separate action upstream, so we don't have to - # override whole upload process - - name: Generate \"latest\" artifacts - run: | - # attempt to match filenames of the form - # pkg-A.B.C[.devD][.gE{7}][.dF{8}][moretext].extension - # where capital letters are numbers and E is 8 digits long - VERSION_REGEX="(.+)\d+\.\d+\.\d+(\.dev\d+\+g[\da-z].{6})*(\.d[\d].{7})*([^.]*\..+)" - if [ -d "${{ inputs.local-path }}" ]; then - echo "Local path is a directory, skipping" - exit 0 - fi - dir=$(dirname "${{ inputs.local-path }}") - files=$(basename "${{ inputs.local-path }}") - pushd "${dir}" - for f in $(find . -maxdepth 1 -type f -name "${files}"); do - latest_filename=$(echo "$f" | \ - perl -pe "s/${VERSION_REGEX}/\1latest\4/g") - echo "Copying $f to ${latest_filename}" - cp "$f" "${latest_filename}" - done - popd - shell: bash - - - name: Upload artifact to s3 - uses: cloudkernels/minio-upload@v5 - with: - url: https://s3.nubificus.co.uk - access-key: ${{ inputs.access-key }} - secret-key: ${{ inputs.secret-key }} - local-path: ${{ steps.get-artifact-vars.outputs.local-path }} - remote-path: ${{ steps.get-artifact-vars.outputs.remote-path }} - policy: 1 diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 6c71439..c98b956 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,8 +1,15 @@ version: 2 updates: - package-ecosystem: "github-actions" - directory: "/" + directories: + - "/" + # Workaround for https://github.com/dependabot/dependabot-core/issues/6345 + - "/.github/actions/*" schedule: interval: "monthly" + groups: + github-actions: + patterns: + - "*" commit-message: prefix: "ci(deps)" diff --git a/.github/workflows/dispatch-prepare-release.yml b/.github/workflows/dispatch-prepare-release.yml new file mode 100644 index 0000000..a40bde0 --- /dev/null +++ b/.github/workflows/dispatch-prepare-release.yml @@ -0,0 +1,172 @@ +# SPDX-License-Identifier: Apache-2.0 + +name: Prepare Release + +on: + workflow_dispatch: + inputs: + actions-repo: + description: 'Repository with remote actions' + type: string + default: 'nubificus/vaccel' + actions-ref: + description: 'Revision of remote actions repository' + type: string + default: 'main' + version: + description: 'Version to release (e.g., 0.3.2+core-0.7.0)' + type: string + required: true + component: + description: > + Component to release. Defaults to the current repository name. + type: string + required: false + branch: + description: 'Branch to release' + type: string + required: false + core-component: + description: 'Core component name' + type: string + required: true + core-version: + description: 'Core component version' + type: string + required: true + tracking-issue-url: + description: 'Tracking issue URL' + type: string + required: true + orchestrator-repo: + description: 'Repository orchestrating the release (e.g., owner/repo)' + type: string + required: true + dependencies: + description: > + JSON array of dependencies to update, e.g., + [{"name": "dep1", "version": "0.2.0"}] + type: string + required: true + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + +permissions: read-all + +jobs: + prepare: + name: Prepare Release + runs-on: base-2204-amd64 + steps: + - name: Parse repository names + id: parse-repos + env: + ACTIONS_REPO: ${{ inputs.actions-repo }} + COMPONENT_REPO: >- + ${{ inputs.component && + format('{0}/{1}', github.repository_owner, inputs.component) || + github.repository }} + ORCHESTRATOR_REPO: ${{ inputs.orchestrator-repo }} + run: | + { + echo "repo-name=$(basename "$GITHUB_REPOSITORY")" + echo "actions-repo-name=$(basename "$ACTIONS_REPO")" + echo "component-repo=${COMPONENT_REPO}" + echo "component-repo-name=$(basename "$COMPONENT_REPO")" + echo "orchestrator-repo-name=$(basename "$ORCHESTRATOR_REPO")" + } >> "$GITHUB_OUTPUT" + shell: bash + + - name: Generate initialization vaccel-bot token + id: generate-initial-token + uses: actions/create-github-app-token@v3 + with: + client-id: ${{ vars.VACCEL_BOT_CLIENT_ID }} + private-key: ${{ secrets.VACCEL_BOT_PRIVATE_KEY }} + repositories: | + ${{ steps.parse-repos.outputs.actions-repo-name }} + ${{ steps.parse-repos.outputs.component-repo-name }} + permission-contents: read + + - name: Checkout .github directory + uses: actions/checkout@v6 + with: + sparse-checkout: .github + repository: ${{ inputs.actions-repo }} + ref: ${{ inputs.actions-ref }} + token: ${{ steps.generate-initial-token.outputs.token }} + + - name: Initialize workspace + uses: ./.github/actions/initialize-workspace + with: + repository: ${{ steps.parse-repos.outputs.component-repo }} + remote-actions-repo: ${{ inputs.actions-repo }} + ref: ${{ inputs.branch || '' }} + fetch-depth: 0 + submodules: 'false' + token: ${{ steps.generate-initial-token.outputs.token }} + + - name: Update core build dependency version + env: + CORE_COMPONENT: ${{ inputs.core-component }} + CORE_VERSION: ${{ inputs.core-version }} + run: | + if [[ "$CORE_VERSION" =~ ^[0-9]+\.[0-9]+\.0$ ]]; then + ffi_dep_regex='PKG_MIN_VERSION *= *"[0-9]*\.[0-9]*\.[0-9]*"' + ffi_dep_new="PKG_MIN_VERSION = \"${CORE_VERSION}\"" + sed -i "s/${ffi_dep_regex}/${ffi_dep_new}/" build_ffi.py + + setup_dep_regex="requires_external *= *${CORE_COMPONENT} *(>=[0-9]*\.[0-9]*\.[0-9]*)" + setup_dep_new="requires_external = ${CORE_COMPONENT} (>=${CORE_VERSION})" + sed -i "s/${setup_dep_regex}/${setup_dep_new}/" setup.cfg + + if ! git diff --quiet build_ffi.py setup.cfg; then + echo "Updated ${CORE_COMPONENT} min version to: ${CORE_VERSION}" + else + echo "Nothing to update" + fi + else + printf "%s version '%s' is a patch update - skipping" \ + "$CORE_COMPONENT" "$CORE_VERSION" + fi + shell: bash + + - name: Render pull request + id: render-pr + uses: ./.github/actions/render-template + with: + template: .github/templates/prepare-release-pr.md.j2 + data: | + { + "version": "${{ inputs.version }}", + "tracking_issue_url": "${{ inputs.tracking-issue-url }}", + "subprojects": [] + } + + - name: Generate PR vaccel-bot token + id: generate-pr-token + if: always() + uses: actions/create-github-app-token@v3 + with: + client-id: ${{ vars.VACCEL_BOT_CLIENT_ID }} + private-key: ${{ secrets.VACCEL_BOT_PRIVATE_KEY }} + repositories: | + ${{ steps.parse-repos.outputs.component-repo-name }} + ${{ steps.parse-repos.outputs.orchestrator-repo-name }} + permission-contents: write + permission-pull-requests: write + permission-actions: write + + - name: Create release PR + if: always() + uses: ./.github/actions/create-release-pr + with: + component: ${{ steps.parse-repos.outputs.component-repo-name }} + version: ${{ inputs.version }} + body: ${{ steps.render-pr.outputs.result }} + orchestrator-repo: ${{ inputs.orchestrator-repo }} + core-version: ${{ inputs.core-version }} + committer-slug: ${{ steps.generate-pr-token.outputs.app-slug }} + result: ${{ job.status }} + token: ${{ steps.generate-pr-token.outputs.token }} diff --git a/.github/workflows/generate-api-reference.yml b/.github/workflows/generate-api-reference.yml index 4606924..98c5e6e 100644 --- a/.github/workflows/generate-api-reference.yml +++ b/.github/workflows/generate-api-reference.yml @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 + name: Generate API Reference on: @@ -6,7 +8,7 @@ on: actions-repo: type: string default: 'nubificus/vaccel' - actions-rev: + actions-ref: type: string default: 'main' deploy: @@ -22,124 +24,124 @@ on: type: string default: 'dispatch-update-external-repo.yml' secrets: - GIT_CLONE_PAT: - required: false VACCEL_BOT_PRIVATE_KEY: required: true +permissions: read-all + jobs: generate-reference: name: Generate API Reference - runs-on: [base-dind-2204-amd64] - permissions: - contents: write - + runs-on: base-dind-2204-amd64 steps: + - name: Parse repository names + id: parse-repos + env: + ACTIONS_REPO: ${{ inputs.actions-repo }} + run: | + { + echo "repo-name=$(basename "$GITHUB_REPOSITORY")" + echo "actions-repo-name=$(basename "$ACTIONS_REPO")" + } >> "$GITHUB_OUTPUT" + shell: bash + + - name: Generate initialization vaccel-bot token + id: generate-init-token + uses: actions/create-github-app-token@v3 + with: + client-id: ${{ vars.VACCEL_BOT_CLIENT_ID }} + private-key: ${{ secrets.VACCEL_BOT_PRIVATE_KEY }} + repositories: | + ${{ steps.parse-repos.outputs.repo-name }} + ${{ steps.parse-repos.outputs.actions-repo-name }} + permission-contents: read + - name: Checkout .github directory uses: actions/checkout@v6 with: sparse-checkout: .github repository: ${{ inputs.actions-repo }} - ref: ${{ inputs.actions-rev }} + ref: ${{ inputs.actions-ref }} + token: ${{ steps.generate-init-token.outputs.token }} - name: Initialize workspace + id: initialize-workspace uses: ./.github/actions/initialize-workspace with: - submodules: 'false' remote-actions-repo: ${{ inputs.actions-repo }} - token: ${{ secrets.GIT_CLONE_PAT || github.token }} fetch-depth: 0 + submodules: 'false' + token: ${{ steps.generate-init-token.outputs.token }} - name: Determine SHA and branch - id: get-rev-info + id: get-revision uses: ./.github/actions/get-revision-info - - name: Generate vaccel-bot token - id: generate-token - uses: actions/create-github-app-token@v2 + - name: Generate trigger vaccel-bot token + id: generate-trigger-token + uses: actions/create-github-app-token@v3 with: - app-id: ${{ vars.VACCEL_BOT_APP_ID }} + client-id: ${{ vars.VACCEL_BOT_CLIENT_ID }} private-key: ${{ secrets.VACCEL_BOT_PRIVATE_KEY }} owner: ${{ inputs.target-repo-owner }} repositories: ${{ inputs.target-repo-name }} + permission-contents: read + permission-checks: read permission-actions: write - - name: Trigger docs update - id: trigger-update - uses: the-actions-org/workflow-dispatch@v4 + - name: Create docs PR + timeout-minutes: 30 env: - RUN_NAME: >- - Update External Repo ${{ github.repository }} - [Run ID: ${{ github.run_id }}] - with: - workflow: ${{ inputs.target-workflow }} - ref: main - repo: ${{ inputs.target-repo-owner }}/${{ inputs.target-repo-name }} - token: ${{ steps.generate-token.outputs.token }} - run-name: ${{ env.RUN_NAME }} - inputs: >- - { - "run-name": "${{ env.RUN_NAME }}", - "trigger-id": "${{ github.run_id }}", - "ref": "${{ steps.get-rev-info.outputs.sha }}", - "branch": "${{ steps.get-rev-info.outputs.branch }}", - "repo": "${{ github.repository }}", - "deploy": "${{ inputs.deploy }}" - } - display-workflow-run-url-interval: 10s - display-workflow-run-url-timeout: 2m - wait-for-completion-interval: 30s - wait-for-completion-timeout: 20m - workflow-logs: json-output - - - name: Print remote request info + GH_TOKEN: ${{ steps.generate-trigger-token.outputs.token }} + TARGET_WORKFLOW: ${{ inputs.target-workflow }} + REPO: >- + ${{ format('{0}/{1}', + inputs.target-repo-owner, inputs.target-repo-name) }} + TRIGGER_ID: ${{ github.run_id }} + REF: ${{ steps.get-revision.outputs.sha }} + BRANCH: ${{ steps.get-revision.outputs.branch }} + DEPLOY: ${{ inputs.deploy }} + WATCH_INTERVAL_SEC: 20 run: | - remote_repo="${{ inputs.target-repo-owner }}/${{ inputs.target-repo-name }}" - remote_id="${{ steps.trigger-update.outputs.workflow-id }}" - remote_url="${{ steps.trigger-update.outputs.workflow-url }}" - echo "## Remote request info" >> "$GITHUB_STEP_SUMMARY" - echo "- Triggered **${remote_repo}** run [#${remote_id}](${remote_url})" \ - >> "$GITHUB_STEP_SUMMARY" - [[ "${{ inputs.deploy }}" == 'false' ]] && exit 0 + run_url=$(gh workflow run "$TARGET_WORKFLOW" \ + --repo "$REPO" \ + -f trigger-id="$TRIGGER_ID" \ + -f ref="$REF" \ + -f branch="$BRANCH" \ + -f repository="$GITHUB_REPOSITORY" \ + -f deploy="$DEPLOY") + run_id="${run_url##*/}" + + echo "Triggered workflow run: ${run_url}" + { + echo "## Create docs PR summary" + echo "- Triggered **${REPO}** run [#${run_id}](${run_url})" + } >> "$GITHUB_STEP_SUMMARY" + + echo "Waiting for run to complete..." + gh run watch "$run_id" \ + --repo "$REPO" \ + --interval "$WATCH_INTERVAL_SEC" \ + --compact \ + --exit-status + + echo "Run completed successfully" + [[ "$DEPLOY" == 'true' ]] || exit 0 + + run_log=$(gh run view "$run_id" --repo "$REPO" --log) + read -r pr_number pr_operation pr_url < <(echo "$run_log" | awk ' + /Pull request number:/ { number = $NF } + /Pull request operation:/ { operation = $NF } + /Pull request URL:/ { url = $NF } + END { print number, operation, url } + ') - logs=$(cat <<'EOF' - ${{ steps.trigger-update.outputs.workflow-logs }} - EOF - ) - pr_number=$( - echo "$logs" | jq -r ' - .["Update Repo / Verify Build"] - | map(select( - .message != null - and (.message | test("Pull request number")) - )) - | map(.message | capture("Pull request number: (?[^\\s]+)").val) - | .[1] - ' - ) - pr_operation=$( - echo "$logs" | jq -r ' - .["Update Repo / Verify Build"] - | map(select( - .message != null - and (.message | test("Pull request operation")) - )) - | map(.message | capture("Pull request operation: (?[^\\s]+)").val) - | .[1] - ' - ) - pr_url=$( - echo "$logs" | jq -r ' - .["Update Repo / Verify Build"] - | map(select( - .message != null - and (.message | test("Pull request URL")) - )) - | map(.message | capture("Pull request URL: (?[^\\s]+)").val) - | .[1] - ' - ) - echo "" - echo "${pr_operation^} PR: ${pr_url}" - echo "- ${pr_operation^} PR [${remote_repo}#${pr_number}](${pr_url})" \ - >> "$GITHUB_STEP_SUMMARY" + if [[ -n "$pr_operation" ]]; then + echo "${pr_operation^} PR: ${pr_url}" + echo "- ${pr_operation^} PR [${REPO}#${pr_number}](${pr_url})" \ + >> "$GITHUB_STEP_SUMMARY" + else + echo "No PR was created or updated" + echo "- No PR was created or updated" >> "$GITHUB_STEP_SUMMARY" + fi + shell: bash diff --git a/.github/workflows/main-build-and-upload.yml b/.github/workflows/main-build-and-upload.yml index dc49856..5344968 100644 --- a/.github/workflows/main-build-and-upload.yml +++ b/.github/workflows/main-build-and-upload.yml @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 + name: Build and Upload on: @@ -9,6 +11,8 @@ on: concurrency: group: ${{ github.workflow }}-${{ github.ref }} +permissions: read-all + jobs: build-dist: name: Build and Upload @@ -26,3 +30,16 @@ jobs: with: deploy: true secrets: inherit + + update-release: + needs: [build-dist, generate-api-reference] + name: Update Release + if: always() + uses: nubificus/vaccel/.github/workflows/update-release.yml@main + with: + artifacts-path: 'python' + result: >- + ${{ needs.build-dist.result != 'failure' && + needs.generate-api-reference.result != 'failure' && + 'success' || 'failure' }} + secrets: inherit diff --git a/.github/workflows/pr-build-and-verify.yml b/.github/workflows/pr-build-and-verify.yml index 099c6c8..98c0f6b 100644 --- a/.github/workflows/pr-build-and-verify.yml +++ b/.github/workflows/pr-build-and-verify.yml @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 + name: Build and Verify on: @@ -7,9 +9,12 @@ on: workflow_dispatch: concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + group: >- + ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true +permissions: read-all + jobs: check-pr-status: name: Check PR status @@ -19,7 +24,7 @@ jobs: test-build: needs: check-pr-status name: Test Build - if: ${{ needs.check-pr-status.outputs.expects-checks == 'true' }} + if: needs.check-pr-status.outputs.expects-checks == 'true' uses: nubificus/vaccel/.github/workflows/test-build.yml@main with: options: '' @@ -29,7 +34,7 @@ jobs: verify-build: needs: check-pr-status name: Verify Build - if: ${{ needs.check-pr-status.outputs.expects-checks == 'true' }} + if: needs.check-pr-status.outputs.expects-checks == 'true' uses: nubificus/vaccel/.github/workflows/verify-build.yml@main with: package: 'python' @@ -41,14 +46,14 @@ jobs: validate-files-and-commits: needs: check-pr-status name: Validate Files and Commits - if: ${{ needs.check-pr-status.outputs.expects-checks == 'true' }} + if: needs.check-pr-status.outputs.expects-checks == 'true' uses: nubificus/vaccel/.github/workflows/validate-files-and-commits.yml@main secrets: inherit validate-code: needs: check-pr-status name: Validate Code - if: ${{ needs.check-pr-status.outputs.expects-checks == 'true' }} + if: needs.check-pr-status.outputs.expects-checks == 'true' uses: nubificus/vaccel/.github/workflows/validate-code.yml@main with: skip-cppcheck: true @@ -71,17 +76,18 @@ jobs: uses: nubificus/vaccel/.github/workflows/coverage-report.yml@main with: comment-diff: true + secrets: inherit # Dummy job for setting required checks jobs-completed: needs: [check-pr-status, generate-coverage] name: Jobs Completed if: >- - ${{ always() && - (needs.check-pr-status.outputs.is-approved == 'true' || - (needs.check-pr-status.outputs.expects-checks == 'true' && - !contains(needs.*.result, 'failure') && - !contains(needs.*.result, 'cancelled'))) }} + always() && + (needs.check-pr-status.outputs.is-approved == 'true' || + (needs.check-pr-status.outputs.expects-checks == 'true' && + !contains(needs.*.result, 'failure') && + !contains(needs.*.result, 'cancelled'))) runs-on: base-2204-amd64 steps: - run: exit 0 diff --git a/.github/workflows/pr-trailers.yml b/.github/workflows/pr-trailers.yml index deb4341..a19cba6 100644 --- a/.github/workflows/pr-trailers.yml +++ b/.github/workflows/pr-trailers.yml @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 + name: Add Git Trailers to PR commits on: @@ -7,7 +9,10 @@ on: types: [synchronize, labeled] concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + group: >- + ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + +permissions: read-all jobs: # commit-coverage: @@ -21,7 +26,7 @@ jobs: check-pr-status: # needs: commit-coverage name: Check PR status - if: ${{ always() && github.event.pull_request.base.ref == 'main' }} + if: always() && github.event.pull_request.base.ref == 'main' uses: nubificus/vaccel/.github/workflows/check-pr-status.yml@main with: pr-number: >- @@ -33,7 +38,8 @@ jobs: needs: check-pr-status name: Add Git Trailers to PR commits if: >- - ${{ always() && github.event.pull_request.base.ref == 'main' && - needs.check-pr-status.outputs.is-approved == 'true' }} + always() && + github.event.pull_request.base.ref == 'main' && + needs.check-pr-status.outputs.is-approved == 'true' uses: nubificus/vaccel/.github/workflows/add-git-trailers.yml@main secrets: inherit diff --git a/.github/workflows/schedule-update-notice.yml b/.github/workflows/schedule-update-notice.yml new file mode 100644 index 0000000..ef84fcc --- /dev/null +++ b/.github/workflows/schedule-update-notice.yml @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: Apache-2.0 + +name: Update NOTICE + +on: + schedule: + # 00:05 UTC on January 1st every year + - cron: '5 0 1 1 *' + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + +permissions: read-all + +jobs: + update-notice: + name: Update NOTICE Year + uses: nubificus/vaccel/.github/workflows/update-notice-year.yml@main + secrets: inherit diff --git a/pyproject.toml b/pyproject.toml index b779568..3ad3d85 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,7 +26,7 @@ include = ["vaccel*"] [tool.setuptools_scm] version_file = "vaccel/_version.py" -version_scheme = "release-branch-semver" +version_scheme = "no-guess-dev" fallback_version = "0.0.1" [tool.pytest.ini_options] diff --git a/setup.cfg b/setup.cfg index 0b1eae2..c30f094 100644 --- a/setup.cfg +++ b/setup.cfg @@ -2,3 +2,6 @@ [bdist_wheel] py_limited_api = cp310 + +[metadata] +requires_external = vaccel (>=0.7.0) diff --git a/setup.py b/setup.py index 73bc490..73f902f 100644 --- a/setup.py +++ b/setup.py @@ -5,8 +5,35 @@ This module is only necessary for building the CFFI module library. """ +from typing import Any + +from packaging.version import Version from setuptools import setup +from setuptools_scm.git import parse as git_parse +from setuptools_scm.version import ScmVersion + + +def custom_parse(root: str, config: Any) -> ScmVersion | None: + """Custom parse function that removes tag local segment. + + Removes semver metadata from tags to generate pypi compatible versions. + """ + version: ScmVersion | None = git_parse(root, config) + if version is None: + return None + + # Strip local segment from parsed tag so setuptools-scm does not + # re-append it + base = str(version.tag).split("+")[0] + version.tag = Version(base) + + return version + setup( cffi_modules=["build_ffi.py:compile_ffi"], + use_scm_version={ + "parse": custom_parse, + "version_scheme": "no-guess-dev", + }, )