name: Make Release on: workflow_dispatch: inputs: version: description: 'Release version (e.g. v0.1.0). Leave empty to use version from CMakeLists.txt' required: false type: string dry_run: description: 'Dry run - validate without creating the tag' required: true type: boolean default: true env: GH_TOKEN: ${{ github.token }} permissions: contents: write jobs: make-release: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v6 with: fetch-depth: 0 - name: Determine version id: version run: | if [[ -n "${{ github.event.inputs.version }}" ]]; then VERSION="${{ github.event.inputs.version }}" else MAJOR=$(grep "set(LLAMA_VERSION_MAJOR" CMakeLists.txt | grep -oP '\d+') MINOR=$(grep "set(LLAMA_VERSION_MINOR" CMakeLists.txt | grep -oP '\d+') PATCH=$(grep "set(LLAMA_VERSION_PATCH" CMakeLists.txt | grep -oP '\d+') VERSION="v${MAJOR}.${MINOR}.${PATCH}" fi echo "version=${VERSION}" >> $GITHUB_OUTPUT echo "Determined version: ${VERSION}" - name: Check tag does not already exist run: | VERSION="${{ steps.version.outputs.version }}" if git ls-remote --tags origin "${VERSION}" | grep -q "${VERSION}"; then echo "Error: tag ${VERSION} already exists on remote" exit 1 fi - name: Check release.yml completed successfully for HEAD run: | SHA=$(git rev-parse HEAD) echo "Checking release.yml status for commit ${SHA}..." RUNS=$(gh api "repos/${{ github.repository }}/actions/workflows/release.yml/runs" \ --jq "[.workflow_runs[] | select(.head_sha == \"${SHA}\" and .conclusion == \"success\")] | length") if [[ "$RUNS" -eq 0 ]]; then if [[ "${{ github.event.inputs.dry_run }}" == "false" ]]; then echo "Error: no successful release.yml run found for HEAD (${SHA})" echo "The nightly build must complete successfully before making a release." exit 1 else echo "Warning: no successful release.yml run found for HEAD (${SHA}) (dry run, continuing)." fi else echo "Found successful release.yml run for HEAD." fi - name: Check local ggml matches upstream run: | MAJOR=$(grep "set(GGML_VERSION_MAJOR" ggml/CMakeLists.txt | grep -oP '\d+') MINOR=$(grep "set(GGML_VERSION_MINOR" ggml/CMakeLists.txt | grep -oP '\d+') PATCH=$(grep "set(GGML_VERSION_PATCH" ggml/CMakeLists.txt | grep -oP '\d+') GGML_VERSION="v${MAJOR}.${MINOR}.${PATCH}" echo "Local ggml version: ${GGML_VERSION}" if ! git clone --depth 1 --branch "${GGML_VERSION}" https://github.com/ggml-org/ggml.git upstream-ggml 2>/dev/null; then echo "Warning: tag ${GGML_VERSION} not found in upstream ggml - skipping comparison" exit 0 fi echo "Comparing local ggml/ src and include with upstream ${GGML_VERSION}..." DIFF=$(diff -rq \ ggml/src upstream-ggml/src \ 2>&1 || true) DIFF+=$(diff -rq \ ggml/include upstream-ggml/include \ 2>&1 || true) DIFF+=$(diff \ ggml/CMakeLists.txt upstream-ggml/CMakeLists.txt \ 2>&1 || true) if [[ -n "$DIFF" ]]; then echo "local ggml/ differs from upstream ${GGML_VERSION}:" echo "$DIFF" if [[ "${{ github.event.inputs.dry_run }}" == "false" ]]; then echo "Error: ggml must match upstream before making a release." exit 1 else echo "Warning: would abort release due to ggml mismatch (dry run, continuing)." fi else echo "local ggml/ matches upstream ${GGML_VERSION}" fi - name: Create release tag if: ${{ github.event.inputs.dry_run == 'false' }} run: | VERSION="${{ steps.version.outputs.version }}" git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" git tag -a "${VERSION}" -m "Release ${VERSION}" git push origin "${VERSION}" echo "Created and pushed tag ${VERSION}" - name: Dry run summary if: ${{ github.event.inputs.dry_run == 'true' }} run: | echo "Dry run complete - all checks passed." echo "Would have created tag: ${{ steps.version.outputs.version }}"