Skip to content

test: cover mtime-stable watch fingerprints #5

test: cover mtime-stable watch fingerprints

test: cover mtime-stable watch fingerprints #5

Workflow file for this run

name: Autonomous Release
on:
push:
branches: [main]
paths:
- Cargo.toml
- pyproject.toml
workflow_dispatch:
permissions:
contents: write
attestations: write
id-token: write
concurrency:
group: release-auto-${{ github.ref_name }}
cancel-in-progress: false
env:
CARGO_TERM_COLOR: always
RUSTFLAGS: "-D warnings"
jobs:
prepare:
name: Prepare release
runs-on: ubuntu-24.04
outputs:
should_build: ${{ steps.prepare.outputs.should_build }}
should_publish_github: ${{ steps.prepare.outputs.should_publish_github }}
should_publish_pypi: ${{ steps.prepare.outputs.should_publish_pypi }}
version: ${{ steps.prepare.outputs.version }}
project_version: ${{ steps.prepare.outputs.project_version }}
commit_sha: ${{ steps.prepare.outputs.commit_sha }}
release_ref: ${{ steps.prepare.outputs.release_ref }}
steps:
- uses: actions/checkout@v6
- name: Check release eligibility
id: prepare
shell: bash
run: |
set -euo pipefail
cargo_version="$(
python - <<'PY'
import tomllib
with open("Cargo.toml", "rb") as f:
print(tomllib.load(f)["workspace"]["package"]["version"])
PY
)"
pyproject_version="$(
python - <<'PY'
import tomllib
with open("pyproject.toml", "rb") as f:
print(tomllib.load(f)["project"]["version"])
PY
)"
if [ "$cargo_version" != "$pyproject_version" ]; then
echo "Cargo.toml version ($cargo_version) does not match pyproject.toml version ($pyproject_version)" >&2
exit 1
fi
version="v${cargo_version}"
commit_sha="$(git rev-parse HEAD)"
release_ref="${commit_sha}"
tag_exists="false"
tag_sha=""
if tag_sha="$(git ls-remote --exit-code --tags origin "refs/tags/${version}" | awk '{print $1}' | tail -n1)"; then
tag_exists="true"
release_ref="${version}"
fi
pypi_json="$(mktemp)"
if curl -fsSL https://pypi.org/pypi/fbuild/json -o "$pypi_json"; then
latest="$(python -c 'import json,sys; print(json.load(open(sys.argv[1]))["info"]["version"])' "$pypi_json")"
pypi_file_count="$(python -c 'import json,sys; data=json.load(open(sys.argv[1])); print(len(data.get("releases", {}).get(sys.argv[2], [])))' "$pypi_json" "$cargo_version")"
else
latest="0.0.0"
pypi_file_count="0"
fi
should_build="false"
should_publish_github="false"
should_publish_pypi="false"
newest="$(printf '%s\n%s\n' "$latest" "$cargo_version" | sort -V | tail -n1)"
if [ "$tag_exists" != "true" ] && [ "$newest" = "$cargo_version" ] && [ "$pypi_file_count" -lt 4 ]; then
should_build="true"
should_publish_github="true"
should_publish_pypi="true"
elif [ "${GITHUB_EVENT_NAME}" = "workflow_dispatch" ] && [ "$tag_exists" = "true" ] && [ "$pypi_file_count" -lt 4 ]; then
should_build="true"
should_publish_pypi="true"
fi
{
echo "version=${version}"
echo "project_version=${cargo_version}"
echo "commit_sha=${commit_sha}"
echo "release_ref=${release_ref}"
echo "should_build=${should_build}"
echo "should_publish_github=${should_publish_github}"
echo "should_publish_pypi=${should_publish_pypi}"
} >> "$GITHUB_OUTPUT"
echo "Candidate version: ${version}"
echo "Latest PyPI version: ${latest}"
echo "PyPI files for ${cargo_version}: ${pypi_file_count}"
echo "Tag exists: ${tag_exists}"
echo "Tag SHA: ${tag_sha:-<none>}"
echo "Release ref: ${release_ref}"
echo "Should build: ${should_build}"
echo "Should publish GitHub release: ${should_publish_github}"
echo "Should publish PyPI: ${should_publish_pypi}"
build:
name: Native build (${{ matrix.target }})
needs: prepare
if: needs.prepare.outputs.should_build == 'true'
strategy:
fail-fast: false
matrix:
include:
- target: x86_64-unknown-linux-musl
runner: ubuntu-latest
binary_ext: ""
linux_cross: false
macos_cross: false
- target: aarch64-unknown-linux-musl
runner: ubuntu-latest
binary_ext: ""
linux_cross: true
macos_cross: false
- target: aarch64-apple-darwin
runner: macos-latest
binary_ext: ""
linux_cross: false
macos_cross: false
- target: x86_64-pc-windows-msvc
runner: windows-latest
binary_ext: ".exe"
linux_cross: false
macos_cross: false
uses: ./.github/workflows/template_native_build.yml
with:
target: ${{ matrix.target }}
runner: ${{ matrix.runner }}
binary_ext: ${{ matrix.binary_ext }}
linux_cross: ${{ matrix.linux_cross }}
macos_cross: ${{ matrix.macos_cross }}
ref: ${{ needs.prepare.outputs.release_ref }}
publish:
name: Publish GitHub release
needs: [prepare, build]
if: needs.prepare.outputs.should_publish_github == 'true'
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
with:
ref: ${{ needs.prepare.outputs.release_ref }}
- name: Download native artifacts
uses: actions/download-artifact@v7
with:
pattern: binaries-*
path: artifacts
- name: Package release archives
shell: bash
run: |
set -euo pipefail
version="${{ needs.prepare.outputs.version }}"
mkdir -p dist pkg
for artifact_dir in artifacts/binaries-*; do
[ -d "$artifact_dir" ] || continue
target="${artifact_dir#artifacts/binaries-}"
package_name="fbuild-${version}-${target}"
package_dir="pkg/${package_name}"
rm -rf "$package_dir"
mkdir -p "$package_dir"
cp -a "$artifact_dir"/. "$package_dir"/
if [[ "$target" == *windows* ]]; then
(cd pkg && zip -r "../dist/${package_name}.zip" "$package_name")
else
tar -C pkg -czf "dist/${package_name}.tar.gz" "$package_name"
fi
done
cd dist
sha256sum fbuild-* > "fbuild-${version}-SHA256SUMS.txt"
- name: Attest release artifacts
uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3
with:
subject-checksums: dist/fbuild-${{ needs.prepare.outputs.version }}-SHA256SUMS.txt
- name: Create draft release
env:
GH_TOKEN: ${{ github.token }}
shell: bash
run: |
set -euo pipefail
version="${{ needs.prepare.outputs.version }}"
gh release create "$version" dist/* \
--draft \
--generate-notes \
--target "${{ needs.prepare.outputs.release_ref }}" \
--title "$version"
- name: Publish release
env:
GH_TOKEN: ${{ github.token }}
shell: bash
run: gh release edit "${{ needs.prepare.outputs.version }}" --draft=false
build-pypi:
name: Build PyPI wheels
needs: [prepare, build]
if: needs.prepare.outputs.should_publish_pypi == 'true'
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
with:
ref: ${{ needs.prepare.outputs.release_ref }}
- name: Download native artifacts
uses: actions/download-artifact@v7
with:
pattern: binaries-*
path: dist/_tmp
- name: Build wheels
shell: bash
run: |
set -euo pipefail
python - <<'PY'
import shutil
import ci.publish as publish
tmp = publish.DIST_DIR / "_tmp"
missing = []
for artifact_name, subdir in publish.ARTIFACT_MAP.items():
src = tmp / artifact_name
if not src.exists():
missing.append(artifact_name)
continue
dest = publish.DIST_DIR / subdir
if dest.exists():
shutil.rmtree(dest)
dest.mkdir(parents=True)
for path in src.iterdir():
if path.is_file():
target = dest / path.name
shutil.copy2(path, target)
if not path.name.endswith(".exe"):
target.chmod(0o755)
if missing:
raise SystemExit(f"Missing native artifacts: {', '.join(missing)}")
meta = publish.read_project_meta()
wheels = publish.build_all_wheels(*meta)
print(f"Built {len(wheels)} wheel(s)")
PY
- name: Smoke test Linux x86_64 wheel
shell: bash
run: |
set -euo pipefail
python -m venv .venv
. .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install dist/wheels/*manylinux_2_17_x86_64*.whl
fbuild --version
python -c "import fbuild; print(fbuild.__version__)"
- name: Upload PyPI distributions
uses: actions/upload-artifact@v7
with:
name: pypi-fbuild
path: dist/wheels/*.whl
if-no-files-found: error
publish-pypi:
name: Publish PyPI
needs: [prepare, build-pypi]
if: needs.prepare.outputs.should_publish_pypi == 'true'
runs-on: ubuntu-24.04
environment: pypi
permissions:
contents: read
id-token: write
steps:
- name: Download PyPI distributions
uses: actions/download-artifact@v7
with:
name: pypi-fbuild
path: dist
- name: List distributions
shell: bash
run: ls -lh dist
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # release/v1
with:
packages-dir: dist
attestations: true
skip-existing: true