diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index 7083e3c57..68df91026 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -16,6 +16,7 @@ on: merge_group: branches: - main + workflow_call: {} jobs: build: diff --git a/.github/workflows/packaging-v5.yaml b/.github/workflows/packaging-v5.yaml index b146e5047..ccdd31563 100644 --- a/.github/workflows/packaging-v5.yaml +++ b/.github/workflows/packaging-v5.yaml @@ -11,21 +11,41 @@ on: jobs: package: - uses: pendulum-project/ploutos/.github/workflows/pkg-rust.yml@provide-debug-symbols - with: - workspace_package: ntpd + runs-on: ubuntu-latest + strategy: + matrix: + target: + - aarch64-unknown-linux-gnu + - armv7-unknown-linux-gnueabihf + - x86_64-unknown-linux-gnu + - i686-unknown-linux-gnu + steps: + - name: Setup packaging tools for cross compiled artifacts + uses: awalsh128/cache-apt-pkgs-action@a6c3917cc929dd0345bfb2d3feaf9101823370ad # v1.4.2 + with: + packages: qemu-user-static crossbuild-essential-armhf crossbuild-essential-arm64 crossbuild-essential-i386 + version: 1 - package_build_rules: | - pkg: ntpd-rs - image: - - "rockylinux:9" - - "ubuntu:xenial" - target: x86_64 - extra_build_args: "--features unstable_ntpv5" + - name: Install toolchain + uses: dtolnay/rust-toolchain@be73d7920c329f220ce78e0234b8f96b7ae60248 + with: + toolchain: "stable" + components: "llvm-tools" - package_test_scripts_path: pkg/test-scripts/test-ntpd-rs.sh + - name: Install cross, cargo-deb and cargo-generate-rpm + uses: taiki-e/install-action@4abee32ddd6d3482e57ba21814317997e6268efe + with: + tool: cross, cargo-deb, cargo-generate-rpm - rpm_scriptlets_path: pkg/rpm/scriptlets.toml + - name: Checkout sources + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 - rpm_extra_build_packages: git - deb_extra_build_packages: git + - name: Build the release binaries + run: RELEASE_TARGETS="${{ matrix.target }}" RELEASE_FEATURES="unstable_ntpv5" utils/build-release.sh + + - name: Upload artifacts + uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 + with: + name: release-binaries-${{ matrix.target }} + path: target/pkg/ + if-no-files-found: error diff --git a/.github/workflows/packaging.yaml b/.github/workflows/packaging.yaml index 1ebb0f292..ca8b39732 100644 --- a/.github/workflows/packaging.yaml +++ b/.github/workflows/packaging.yaml @@ -11,20 +11,134 @@ on: jobs: package: - uses: pendulum-project/ploutos/.github/workflows/pkg-rust.yml@provide-debug-symbols - with: - workspace_package: ntpd + runs-on: ubuntu-latest + strategy: + matrix: + target: + - aarch64-unknown-linux-gnu + - armv7-unknown-linux-gnueabihf + - x86_64-unknown-linux-gnu + - i686-unknown-linux-gnu + steps: + - name: Setup packaging tools for cross compiled artifacts + uses: awalsh128/cache-apt-pkgs-action@a6c3917cc929dd0345bfb2d3feaf9101823370ad # v1.4.2 + with: + packages: qemu-user-static crossbuild-essential-armhf crossbuild-essential-arm64 crossbuild-essential-i386 + version: 1 - package_build_rules: | - pkg: ntpd-rs - image: - - "rockylinux:9" - - "ubuntu:xenial" - target: x86_64 + - name: Install toolchain + uses: dtolnay/rust-toolchain@be73d7920c329f220ce78e0234b8f96b7ae60248 + with: + toolchain: "stable" + components: "llvm-tools" - package_test_scripts_path: pkg/test-scripts/test-ntpd-rs.sh + - name: Install cross, cargo-deb and cargo-generate-rpm + uses: taiki-e/install-action@4abee32ddd6d3482e57ba21814317997e6268efe + with: + tool: cross, cargo-deb, cargo-generate-rpm - rpm_scriptlets_path: pkg/rpm/scriptlets.toml + - name: Checkout sources + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 + + - name: Build the release binaries + run: RELEASE_TARGETS="${{ matrix.target }}" utils/build-release.sh + + - name: Upload artifacts + uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 + with: + name: release-binaries-${{ matrix.target }} + path: target/pkg/ + if-no-files-found: error + + gather: + needs: package + runs-on: ubuntu-latest + steps: + - name: Download artifacts + uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 # v4.1.4 + with: + pattern: release-binaries-* + path: target/pkg/ + merge-multiple: true + - name: Create a SHA256SUMS file + run: | + cd target/pkg/ + rm -rf SHA256SUMS + sha256sum -b * > SHA256SUMS + - name: Upload artifacts + uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 + with: + name: release-binaries + path: target/pkg/ + if-no-files-found: error + + checks: + uses: './.github/workflows/checks.yaml' + + release: + needs: [gather, checks] + runs-on: ubuntu-latest + if: ${{ startsWith(github.ref, 'refs/heads/release/') }} + permissions: + # This part of the release pipeline needs to create a tag and a release + contents: write + steps: + - name: Checkout sources + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + + - name: Download artifacts + uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 # v4.1.4 + with: + name: release-binaries + path: target/pkg/ + + - name: Install toolchain + uses: dtolnay/rust-toolchain@be73d7920c329f220ce78e0234b8f96b7ae60248 + with: + toolchain: "stable" + components: "llvm-tools" + + - name: Check that the release commit is verified + run: | + commit_url="${{ github.api_url }}/repos/${{ github.repository }}/commits/${{ github.sha }}" + json_accept_header="Accept: application/vnd.github+json" + auth_bearer_header="Authorization: Bearer ${{ github.token }}" + test "$(curl -sf -H "$json_accept_header" -H "$auth_bearer_header" "$commit_url" | jq .commit.verification.verified)" == "true" + + - name: Read the version from the manifest file + run: echo "release_version=$(cargo read-manifest --manifest-path ntpd/Cargo.toml | jq -r .version)" >> "$GITHUB_ENV" + + - name: Version in Cargo.toml must match the branch name + run: test "release/$release_version" == "${{ github.ref_name }}" + + - name: Ensure there is not already a released tag with a non-draft release + run: test "$(gh release view "v$release_version" --json isDraft --jq .isDraft 2>/dev/null || echo "true")" == "true" + + - name: Verify that the changelog top most entry concerns this release + run: | + release_notes="$(awk '/^## / && !found { found=1; print; next } /^## / && found { exit } found { print }' CHANGELOG.md)" + release_notes_header="$(echo "$release_notes" | head -1)" + echo "Found release notes for '$release_notes_header'" + release_notes_body="$(echo "$release_notes" | tail +2)" + release_notes_body="${release_notes_body#"${release_notes_body%%[![:space:]]*}"}" + release_notes_body="${release_notes_body%"${release_notes_body##*[![:space:]]}"}" + release_notes_version="$(echo "$release_notes_header" | cut -d' ' -f2 | sed 's/[][]//g')" + echo "Found version '$release_notes_version' in release notes" + test "$release_notes_version" == "${{ env.release_version }}" + { + echo "release_notes_body<> "$GITHUB_ENV" + + - name: Create a draft release + uses: softprops/action-gh-release@9d7c94cfd0a1f3ed45544c887983e9fa900f0564 # v2.0.4 + with: + draft: true + fail_on_unmatched_files: true + tag_name: "v${{ env.release_version }}" + target_commitish: "${{ github.sha }}" + name: "Version ${{ env.release_version }}" + files: target/pkg/* + body: "${{ env.release_notes_body }}" - rpm_extra_build_packages: git - deb_extra_build_packages: git diff --git a/Cross.toml b/Cross.toml new file mode 100644 index 000000000..c0bc8754e --- /dev/null +++ b/Cross.toml @@ -0,0 +1,5 @@ +[target.x86_64-unknown-linux-gnu] +image = "ghcr.io/cross-rs/x86_64-unknown-linux-gnu" + +[target.aarch64-unknown-linux-gnu] +image = "ghcr.io/cross-rs/aarch64-unknown-linux-gnu" diff --git a/docs/development-process.md b/docs/development-process.md index 27b4a6bb5..ecfb37c10 100644 --- a/docs/development-process.md +++ b/docs/development-process.md @@ -27,31 +27,26 @@ To determine what version to release we keep to semantic versioning: - [ ] Run `utils/update-version.sh [version]` - [ ] Update `CHANGELOG.md` with the new version, remove any `Unreleased` - section in the changelog. -- [ ] `git switch -c release/[version]` -- [ ] `git commit -a -S -m "Release [version]"` + section in the changelog. Make sure the to release version is the top most + section of the changelog. Also make sure the diff link is updated at the + bottom of the document. +- [ ] `git switch -c release/[version]` (the branch name must match this format) +- [ ] `git commit -a -S -m "Release [version]"` (a signed commit is required) - [ ] `git push -u origin release/[version]` -- [ ] Wait for all actions to finish and succeed, make sure both the checks and - the packaging workflow succeed. -- [ ] Either create a PR and let someone review the release, or directly merge - into the target branch (for most releases this will be `main`). -- [ ] On the merged commit, create a new (signed) tag: - `git tag -a -s -m "Version [version]" v[version]` -- [ ] Push the tag to GitHub: `git push origin v[version]` -- [ ] Release on crates.io by running `utils/release.sh` -- [ ] Download the artifacts by running `utils/prepare-artifacts.sh --api-token [github-api-token] --run-id [run-id] --download-artifacts --delete-zips --reset` - The run id can be extracted from the URL by going to the `Actions` page on - GitHub and clicking through to the specific packaging run. A GitHub API - token can be generated by going to your personal settings (via your - profile picture), clicking on `Developer settings` (at the bottom) and - generating a new 'Fine grained personal access token'. Easiest way here - is to select 'All repositories' and then enabling the Actions 'Read-only' - permission. -- [ ] Create a new release on GitHub: https://github.com/pendulum-project/ntpd-rs/releases/new -- [ ] Pick the tag just pushed. -- [ ] Set the title to `Version [version]`. -- [ ] Add the contents of the changelog specific to this version to the body - of the release. You may add any additional text at the top of the release - text. -- [ ] Upload all the files in the `target/pkg` directory. -- [ ] Publish the release. +- [ ] Wait for the github actions pipelines to complete, take special care of + the packaging pipeline +- [ ] Go to the releases page on Github and find the draft release, check if the + binaries have been properly generated. +- [ ] Let somebody review the branch +- [ ] WARNING: only merge the branch to main if it is fully up to date compared + to main, don't let any other branches on the merge queue in the mean time. + You could also store the release on a non-main branch, but make sure to + sync the main branch at a later time in that case to update the changelog + on main. +- [ ] Go to the releases page on GitHub and find the draft release, edit the + draft release and make it public, this should also create a tag on the + repository. +- [ ] On your local computer, checkout the specific commit that was tagged by + GitHub (i.e. `git fetch && git switch --detach v[version]`) +- [ ] Run `utils/release.sh` to publish the crates.io packages + diff --git a/pkg/rpm/scriptlets.toml b/pkg/rpm/scriptlets.toml index 9d22704aa..0b5aefc6e 100644 --- a/pkg/rpm/scriptlets.toml +++ b/pkg/rpm/scriptlets.toml @@ -63,6 +63,7 @@ if [ $1 -eq 0 ] ; then # Package removal, not upgrade # Run commands equivalent to what the RPM systemd macros would do systemd_preun ntpd-rs.service + systemd_preun ntpd-rs-metrics.service systemd_triggers fi ''' diff --git a/pkg/test-scripts/test-ntpd-rs.sh b/pkg/test-scripts/test-ntpd-rs.sh index 286b4151f..6e482d429 100644 --- a/pkg/test-scripts/test-ntpd-rs.sh +++ b/pkg/test-scripts/test-ntpd-rs.sh @@ -13,6 +13,7 @@ case $1 in # and configuration validates. echo -e "\nNTPD-RS HELP OUTPUT:" /usr/bin/ntp-daemon --help + /usr/bin/ntp-metrics-exporter --help /usr/bin/ntp-ctl validate # # Ensure that the systemd service is running diff --git a/utils/build-release.sh b/utils/build-release.sh new file mode 100755 index 000000000..59c06cbc3 --- /dev/null +++ b/utils/build-release.sh @@ -0,0 +1,67 @@ +#!/usr/bin/env bash + +set -eo pipefail + +: "${RELEASE_TARGETS:=aarch64-unknown-linux-gnu,armv7-unknown-linux-gnueabihf,x86_64-unknown-linux-gnu,i686-unknown-linux-gnu}" +IFS=',' read -r -a targets <<< "$RELEASE_TARGETS" + +target_dir="target/pkg" + +rm -rf "$target_dir" +mkdir -p "$target_dir" + +package_version=$(cargo read-manifest --manifest-path ntpd/Cargo.toml | jq -r .version) +toolchain=$(rustup show active-toolchain | cut -d' ' -f1) +host_target=$(echo "$toolchain" | cut -d'-' -f2-) +sysroot=$(rustc --print sysroot) +llvm_tools_path="$sysroot/lib/rustlib/$host_target/bin" + +echo "--- Running on toolchain '${toolchain}', make sure the llvm-tools component is installed" +echo "--- Host target is '$host_target'" + +for target in "${targets[@]}"; do + dbg_sym_tar="ntpd-rs_dbg_$package_version-$target.tar.gz" + + echo "--- Calling cross for building ntpd package for target '$target'" + cross build --target "$target" --package ntpd --release --features "${RELEASE_FEATURES:-}" + + echo "--- Creating separate debug symbol files for target '$target'" + ( + cd "target/$target/release" + find . -maxdepth 1 -type f -executable -print0 | while IFS= read -r -d '' file; do + echo "--- Writing debug symbols from '$file' to '$file.dbg'" + "$llvm_tools_path/llvm-strip" --only-keep-debug -o "$file.dbg" "$file" + chmod -x "$file.dbg" + echo "--- Removing all symbols from binary '$file'" + "$llvm_tools_path/llvm-strip" -s "$file" + done + ); + + echo "--- Create tar for debug symbols" + ( + cd "target/$target/release" + rm -f "$dbg_sym_tar" + find . -maxdepth 1 -type f -name '*.dbg' -exec tar uvf "$dbg_sym_tar" {} + + ); + + echo "--- Creating deb package" + cargo deb --no-build --no-strip --target "$target" --compress-type xz --package ntpd + + echo "--- Creating rpm package" + cargo generate-rpm --payload-compress xz --package ntpd --target "$target" --target-dir target + + echo "--- Copying output files to target" + cp "target/$target/release/$dbg_sym_tar" "$target_dir/" + find "target/$target/debian" -maxdepth 1 -type f -name '*.deb' -exec cp "{}" "$target_dir/" \; + find "target/$target/generate-rpm" -maxdepth 1 -type f -name '*.rpm' -exec cp "{}" "$target_dir/" \; +done + +echo "--- Generating SHA256SUMS file" +( + cd $target_dir + sha256sum -b * > SHA256SUMS +) + +echo "--- Done, output is in $target_dir" + + diff --git a/utils/prepare-artifacts.sh b/utils/prepare-artifacts.sh deleted file mode 100755 index 070bb1777..000000000 --- a/utils/prepare-artifacts.sh +++ /dev/null @@ -1,132 +0,0 @@ -#!/usr/bin/env bash - -set -eo pipefail - -print_help() { - echo "Usage: utils/prepare-artifacts.sh OPTIONS" - echo "" - echo "Options:" - echo " --[no-]reset Clear the pkg directory or not (default: no)" - echo " --[no-]delete-zips Delete the downloaded zip files or not (default: no)" - echo " --[no-]download-artifacts Download the artifacts or not (default: no)" - echo " --api-token TOKEN The Github API token for downloading artifacts" - echo " --run-id ID The id of the Workflow run for which to download artifacts" -} - -GITHUB_API_TOKEN= -RUN_ID= -TARGET_DIR="target/pkg" -DO_RESET=false -DELETE_ZIPS=false -DOWNLOAD_ARTIFACTS=false -ZIP_DOWNLOADS_FOLDER="$TARGET_DIR/zips" - - -while [[ $# -gt 0 ]]; do - case $1 in - --reset) - DO_RESET=true - ;; - --no-reset) - DO_RESET=false - ;; - --delete-zips) - DELETE_ZIPS=true - ;; - --no-delete-zips) - DELETE_ZIPS=false - ;; - --download-artifacts) - DOWNLOAD_ARTIFACTS=true - ;; - --no-download-artifacts) - DOWNLOAD_ARTIFACTS=false - ;; - --api-token) - GITHUB_API_TOKEN="$2" - shift - ;; - --run-id) - RUN_ID="$2" - shift - ;; - --help) - print_help - exit 0 - ;; - esac - shift -done - -if [ "$DOWNLOAD_ARTIFACTS" = true ] && ([ -z "$GITHUB_API_TOKEN" ] || [ -z "$RUN_ID" ]); then - if [ -z "$GITHUB_API_TOKEN" ]; then - echo "ERROR: Missing Github API token" - fi - - if [ -z "$RUN_ID" ]; then - echo "ERROR: Missing github workflow run id" - fi - print_help - exit 1 -fi - -if [ "$DO_RESET" = true ]; then - echo "Resetting target dir" - rm -rf "$TARGET_DIR" -fi - -mkdir -p "$ZIP_DOWNLOADS_FOLDER" - -if [ "$DOWNLOAD_ARTIFACTS" = true ]; then - echo "Retrieving artifacts from run" - artifacts_json=$(curl -L \ - -H "Accept: application/vnd.github+json" \ - -H "X-GitHub-Api-Version: 2022-11-28" \ - -H "Authorization: Bearer $GITHUB_API_TOKEN" \ - https://api.github.com/repos/pendulum-project/ntpd-rs/actions/runs/$RUN_ID/artifacts) - - echo "Extracting artifact urls" - artifact_urls=$(echo "$artifacts_json" | jq -r '.artifacts[] | (.name + ";" + .archive_download_url)') - - echo "Download artifacts" - while read artifact; do - IFS=';' read -r name url <<< "$artifact" - echo "Downloading artifact '$name' from '$url'" - zipfile="$ZIP_DOWNLOADS_FOLDER/$name.zip" - curl -L \ - -H "Accept: application/vnd.github+json" \ - -H "X-GitHub-Api-Version: 2022-11-28" \ - -H "Authorization: Bearer $GITHUB_API_TOKEN" \ - -o "$zipfile" "$url" - done < <(echo "$artifact_urls") - echo "Downloads complete" -fi - -for f in $(find "$ZIP_DOWNLOADS_FOLDER" -type f); do - echo "Extracting downloaded zip file '$f'" - unzip -d "$TARGET_DIR" "$f" -done - -if [ "$DELETE_ZIPS" = true ]; then - echo "Delete the downloaded zips" - rm -rf "$ZIP_DOWNLOADS_FOLDER" -else - echo "Not deleting any downloaded zips" -fi - -echo "Flatten file structure" -find "$TARGET_DIR" -mindepth 2 -type f -not -path "$ZIP_DOWNLOADS_FOLDER/*" -exec mv -t "$TARGET_DIR" -i '{}' + - -echo "Remove any leftover directories" -find "$TARGET_DIR" -mindepth 1 -type d -not -path "$ZIP_DOWNLOADS_FOLDER" -exec rm -Rf '{}' + - -echo "Replace tildes by dashes for github" -for f in $(find "$TARGET_DIR" -type f); do - newf=$(echo "$f" | sed 's/~/-/g') - if [ "$f" != "$newf" ]; then - mv "$f" "$newf" - fi -done - -echo "Create SHA256SUMS" -(cd "$TARGET_DIR" && rm -rf "SHA256SUMS" && find * -type f -not -name "SHA256SUMS" -exec sha256sum -b {} + | tee "SHA256SUMS")