feat: replace semantic-release with tag-triggered manual release
diff --git a/.github/vcpkg/casbin/portfile.cmake b/.github/vcpkg/casbin/portfile.cmake new file mode 100644 index 0000000..c5bd87b --- /dev/null +++ b/.github/vcpkg/casbin/portfile.cmake
@@ -0,0 +1,33 @@ +# Template for the vcpkg `casbin` port. The Release workflow substitutes +# @VERSION@ and @SHA512@ and opens a pull request against microsoft/vcpkg; +# this file is never consumed by vcpkg directly from here. + +vcpkg_check_linkage(ONLY_STATIC_LIBRARY) + +vcpkg_from_github( + OUT_SOURCE_PATH SOURCE_PATH + REPO casbin/casbin-cpp + REF "v${VERSION}" + SHA512 @SHA512@ + HEAD_REF master +) + +vcpkg_cmake_configure( + SOURCE_PATH "${SOURCE_PATH}" + OPTIONS + # Everything below pulls its dependencies in with FetchContent, which a + # port build has no network for. nlohmann_json is the one real + # dependency and comes from vcpkg instead. + -DCASBIN_BUILD_TEST=OFF + -DCASBIN_BUILD_BENCHMARK=OFF + -DCASBIN_BUILD_PYTHON_BINDINGS=OFF + -DCASBIN_INSTALL=ON +) + +vcpkg_cmake_install() + +vcpkg_cmake_config_fixup(PACKAGE_NAME casbin CONFIG_PATH lib/cmake/casbin) + +file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/include") + +vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/LICENSE")
diff --git a/.github/vcpkg/casbin/vcpkg.json b/.github/vcpkg/casbin/vcpkg.json new file mode 100644 index 0000000..7926319 --- /dev/null +++ b/.github/vcpkg/casbin/vcpkg.json
@@ -0,0 +1,18 @@ +{ + "name": "casbin", + "version": "@VERSION@", + "description": "An authorization library that supports access control models like ACL, RBAC, ABAC in C/C++", + "homepage": "https://github.com/casbin/casbin-cpp", + "license": "Apache-2.0", + "dependencies": [ + "nlohmann-json", + { + "name": "vcpkg-cmake", + "host": true + }, + { + "name": "vcpkg-cmake-config", + "host": true + } + ] +}
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 64b9ef3..d7eee45 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml
@@ -1,25 +1,199 @@ +# Copyright 2026 The casbin Authors. All Rights Reserved. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Releases are cut by hand: the release manager pushes a tag, and this workflow +# turns that tag into a GitHub release. Nothing is published on a plain merge to +# master, because an Apache release has to be voted on before it exists. +# +# v1.4.0-rc1 -> GitHub *pre-release*, for the release manager to sign and +# put up for a vote. +# v1.4.0 -> GitHub release plus a pull request against the vcpkg +# registry, once that vote has passed. +# +# Both cases attach the same source package, named and laid out the way an +# Apache release vote expects. The release manager downloads it, signs it +# locally, and votes with it; the signature never comes back through here. + name: Release on: push: - branches: - - master - pull_request: - branches: - - master + tags: + - 'v*' + +permissions: + contents: write jobs: - semantic-release: + github-release: + name: GitHub release + if: github.repository == 'casbin/casbin-cpp' runs-on: ubuntu-latest + outputs: + version: ${{ steps.meta.outputs.version }} + prerelease: ${{ steps.meta.outputs.prerelease }} steps: - - uses: actions/checkout@v3 + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 - - name: Run semantic-release - if: github.repository == 'casbin/casbin-cpp' && github.event_name == 'push' + - name: Read the version out of the tag + id: meta run: | - export PATH="$(yarn global bin):$PATH" - yarn global add semantic-release@19.0.5 - semantic-release - sleep 10 + set -euo pipefail + tag="${GITHUB_REF_NAME}" + full="${tag#v}" + # The package always carries the final version, even for a release + # candidate, so the exact bits that were voted on can be promoted + # without being repackaged: v1.4.0-rc1 also packages as 1.4.0. + version="${full%%-rc*}" + if [ "$full" = "$version" ]; then + prerelease=false + else + prerelease=true + fi + { + echo "version=${version}" + echo "prerelease=${prerelease}" + } >> "$GITHUB_OUTPUT" + echo "::notice::${tag} -> version ${version}, prerelease=${prerelease}" + + - name: Build the source release package + id: package env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file + VERSION: ${{ steps.meta.outputs.version }} + run: | + set -euo pipefail + name="apache-casbin-cpp-${VERSION}-src" + # git archive ships exactly what is tracked at the tag: no .git, no + # build output, no bundled binaries, everything under a single + # versioned top-level directory. + git archive --format=tar.gz --prefix="${name}/" -o "${name}.tar.gz" "${GITHUB_REF_NAME}" + sha512sum "${name}.tar.gz" > "${name}.tar.gz.sha512" + echo "tarball=${name}.tar.gz" >> "$GITHUB_OUTPUT" + + - name: Check the package carries the required legal files + env: + TARBALL: ${{ steps.package.outputs.tarball }} + run: | + set -euo pipefail + prefix="${TARBALL%.tar.gz}" + # Listed once into a variable: piping tar into `grep -q` would leave + # tar killed by SIGPIPE, which pipefail reports as a failed check. + listing="$(tar -tzf "${TARBALL}")" + for legal in LICENSE NOTICE; do + if ! grep -qx "${prefix}/${legal}" <<< "${listing}"; then + echo "::error::${legal} is missing from ${TARBALL}; the release vote would fail on it" + exit 1 + fi + done + + - name: Publish the release + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + TARBALL: ${{ steps.package.outputs.tarball }} + PRERELEASE: ${{ steps.meta.outputs.prerelease }} + run: | + set -euo pipefail + args=(--title "${GITHUB_REF_NAME}" --generate-notes) + if [ "${PRERELEASE}" = "true" ]; then + args+=(--prerelease) + fi + gh release create "${GITHUB_REF_NAME}" "${args[@]}" "${TARBALL}" "${TARBALL}.sha512" + + vcpkg: + name: Submit to vcpkg + needs: github-release + # Release candidates exist only for the vote; they never reach a registry. + if: needs.github-release.outputs.prerelease == 'false' + runs-on: ubuntu-latest + env: + VERSION: ${{ needs.github-release.outputs.version }} + # A fork of microsoft/vcpkg that the token below can push to. + FORK: ${{ vars.VCPKG_FORK || 'casbin/vcpkg' }} + steps: + - name: Check the vcpkg fork token is configured + id: gate + env: + VCPKG_PR_TOKEN: ${{ secrets.VCPKG_PR_TOKEN }} + run: | + if [ -n "${VCPKG_PR_TOKEN}" ]; then + echo "enabled=true" >> "$GITHUB_OUTPUT" + else + echo "enabled=false" >> "$GITHUB_OUTPUT" + echo "::warning::VCPKG_PR_TOKEN is not set, so no vcpkg pull request was opened for ${VERSION}." + fi + + - name: Checkout casbin-cpp + if: steps.gate.outputs.enabled == 'true' + uses: actions/checkout@v4 + with: + path: casbin-cpp + + - name: Checkout vcpkg + if: steps.gate.outputs.enabled == 'true' + uses: actions/checkout@v4 + with: + repository: microsoft/vcpkg + path: vcpkg + fetch-depth: 0 + + - name: Render the casbin port + if: steps.gate.outputs.enabled == 'true' + run: | + set -euo pipefail + # vcpkg_from_github pins the tarball GitHub generates for the tag, so + # that is the file whose checksum goes into the port. + curl -fsSL -o source.tar.gz \ + "https://github.com/${GITHUB_REPOSITORY}/archive/refs/tags/v${VERSION}.tar.gz" + sha512="$(sha512sum source.tar.gz | cut -d' ' -f1)" + mkdir -p vcpkg/ports/casbin + for file in portfile.cmake vcpkg.json; do + sed -e "s|@VERSION@|${VERSION}|g" -e "s|@SHA512@|${sha512}|g" \ + "casbin-cpp/.github/vcpkg/casbin/${file}" > "vcpkg/ports/casbin/${file}" + done + + - name: Update the vcpkg version database + if: steps.gate.outputs.enabled == 'true' + working-directory: vcpkg + run: | + set -euo pipefail + git config user.name "casbin-bot" + git config user.email "casbin-bot@users.noreply.github.com" + git add ports/casbin + git commit -m "[casbin] Update to ${VERSION}" + ./bootstrap-vcpkg.sh -disableMetrics + # x-add-version reads the port out of the commit above, so it has to + # run after it; the result is folded back into the same commit. + ./vcpkg x-add-version casbin --overwrite-version + git add versions + git commit --amend --no-edit + + - name: Open the pull request against microsoft/vcpkg + if: steps.gate.outputs.enabled == 'true' + working-directory: vcpkg + env: + GH_TOKEN: ${{ secrets.VCPKG_PR_TOKEN }} + run: | + set -euo pipefail + branch="casbin-${VERSION}" + git remote add fork "https://x-access-token:${GH_TOKEN}@github.com/${FORK}.git" + git push --force fork "HEAD:${branch}" + gh pr create \ + --repo microsoft/vcpkg \ + --base master \ + --head "${FORK%%/*}:${branch}" \ + --title "[casbin] Update to ${VERSION}" \ + --body "Updates the \`casbin\` port to ${VERSION}, released at https://github.com/${GITHUB_REPOSITORY}/releases/tag/v${VERSION}."
diff --git a/.releaserc.json b/.releaserc.json deleted file mode 100644 index 10d8b31..0000000 --- a/.releaserc.json +++ /dev/null
@@ -1,13 +0,0 @@ -{ - "debug": true, - "release": { - "branches": [ - "master" - ] - }, - "plugins": [ - "@semantic-release/commit-analyzer", - "@semantic-release/release-notes-generator", - "@semantic-release/github" - ] - } \ No newline at end of file
diff --git a/README.md b/README.md index 4c4eddc..34c78a6 100644 --- a/README.md +++ b/README.md
@@ -3,7 +3,6 @@ [](https://github.com/casbin/casbin-cpp/actions/workflows/ci.yml) [](https://github.com/casbin/casbin-cpp/releases/latest) -[](https://github.com/semantic-release/semantic-release) [](https://discord.gg/S5UjpzGZjN) **News**: Are you still worried about how to write the correct Casbin policy? ``Casbin online editor`` is coming to help! Try it at: http://casbin.org/editor/