name: Update Time Data
on:
workflow_dispatch:
schedule:
- cron: "23 5 * * 1"
permissions:
contents: write
concurrency:
group: update-time-data
cancel-in-progress: true
jobs:
refresh:
name: Refresh IERS/USNO time snapshot
runs-on: ubuntu-latest
outputs:
data_changed: ${{ steps.commit.outputs.data_changed }}
steps:
- uses: actions/checkout@v4
with:
ref: main
fetch-depth: 0
persist-credentials: true
token: ${{ secrets.GITHUB_TOKEN }}
- uses: dtolnay/rust-toolchain@stable
- name: Run updater
working-directory: .
run: |
cargo run --release --features fetch \
--bin siderust-archive-update-time-data -- \
--archive-root "${GITHUB_WORKSPACE}"
- name: Enforce time-data-only refresh scope
run: |
set -euo pipefail
mapfile -t changed < <(git status --porcelain --untracked-files=all | sed -E 's/^...//')
unexpected=()
for path in "${changed[@]}"; do
case "$path" in
src/time/eop/raw/*|src/time/bundled/snapshot.rs|src/time/eop/manifest.toml)
;;
*)
unexpected+=("$path")
;;
esac
done
if [ "${#unexpected[@]}" -ne 0 ]; then
echo "::error::Time-data refresh changed files outside the approved IERS/USNO snapshot paths."
printf 'Unexpected path: %s\n' "${unexpected[@]}"
exit 1
fi
- name: Validate manifests
working-directory: .
run: cargo run -p archive-validate -- MANIFEST.toml
- name: Test the refreshed bundle
working-directory: .
run: cargo test --all-features
- name: Commit and push if changed
id: commit
env:
GIT_AUTHOR_NAME: github-actions[bot]
GIT_AUTHOR_EMAIL: 41898282+github-actions[bot]@users.noreply.github.com
GIT_COMMITTER_NAME: github-actions[bot]
GIT_COMMITTER_EMAIL: 41898282+github-actions[bot]@users.noreply.github.com
run: |
set -euo pipefail
git add src/time/eop/raw/ src/time/bundled/snapshot.rs src/time/eop/manifest.toml
if git diff --cached --quiet; then
echo "No IERS/USNO data changes; skipping commit."
echo "data_changed=false" >> "$GITHUB_OUTPUT"
exit 0
fi
git commit -m "chore: refresh IERS/USNO time-data snapshot"
git push origin HEAD:main
echo "data_changed=true" >> "$GITHUB_OUTPUT"
publish:
name: Publish patch release to crates.io
runs-on: ubuntu-latest
needs: refresh
if: needs.refresh.outputs.data_changed == 'true'
steps:
- uses: actions/checkout@v4
with:
ref: main
fetch-depth: 0
persist-credentials: true
token: ${{ secrets.GITHUB_TOKEN }}
- uses: dtolnay/rust-toolchain@stable
- name: WIP guard
id: wip
run: |
set -euo pipefail
LAST_TAG=$(git describe --tags --abbrev=0 --match "v[0-9]*.[0-9]*.[0-9]*" 2>/dev/null || echo "")
if [ -z "$LAST_TAG" ]; then
echo "::warning::No version tag found. Skipping auto-publish because non-data history cannot be bounded."
echo "skip=true" >> "$GITHUB_OUTPUT"
exit 0
fi
echo "Last version tag: $LAST_TAG"
NON_DATA=$(git log "$LAST_TAG"..HEAD --oneline -- ':!src/time/eop/raw/**' ':!src/time/bundled/snapshot.rs' ':!src/time/eop/manifest.toml' || true)
if [ -n "$NON_DATA" ]; then
echo "::warning::WIP detected — non-data commits exist since $LAST_TAG. Skipping auto-publish."
echo "Commits found:"
echo "$NON_DATA"
echo "skip=true" >> "$GITHUB_OUTPUT"
else
echo "No WIP commits detected since $LAST_TAG. Proceeding."
echo "skip=false" >> "$GITHUB_OUTPUT"
fi
- name: Check crates.io token
id: publish_token
if: steps.wip.outputs.skip != 'true'
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
run: |
set -euo pipefail
if [ -z "${CARGO_REGISTRY_TOKEN:-}" ]; then
echo "::warning::CARGO_REGISTRY_TOKEN is not configured. Skipping auto-publish."
echo "skip=true" >> "$GITHUB_OUTPUT"
else
echo "skip=false" >> "$GITHUB_OUTPUT"
fi
- name: Validate release candidate
if: steps.wip.outputs.skip != 'true' && steps.publish_token.outputs.skip != 'true'
working-directory: .
run: |
cargo run -p archive-validate -- MANIFEST.toml
cargo test --all-features
- name: Bump patch version and changelog
id: versions
if: steps.wip.outputs.skip != 'true' && steps.publish_token.outputs.skip != 'true'
working-directory: .
run: |
set -euo pipefail
CUR=$(grep -m1 '^version' Cargo.toml | sed -E 's/version *= *"([^"]+)"/\1/')
MAJOR=$(echo "$CUR" | cut -d. -f1)
MINOR=$(echo "$CUR" | cut -d. -f2)
PATCH=$(echo "$CUR" | cut -d. -f3)
NEW="${MAJOR}.${MINOR}.$((PATCH + 1))"
sed -i -E "s/^version *= *\"${CUR}\"/version = \"${NEW}\"/" Cargo.toml
RELEASE_DATE=$(date -u +%F)
NEW_VERSION="$NEW" RELEASE_DATE="$RELEASE_DATE" python3 - <<'PY'
import os
import re
from pathlib import Path
path = Path("CHANGELOG.md")
if not path.exists():
raise SystemExit("CHANGELOG.md is missing")
text = path.read_text(encoding="utf-8")
lines = text.splitlines()
version = os.environ["NEW_VERSION"]
release_date = os.environ["RELEASE_DATE"]
unreleased = None
for index, line in enumerate(lines):
if line.strip() == "## [Unreleased]":
unreleased = index
break
if unreleased is None:
raise SystemExit("CHANGELOG.md is missing a '## [Unreleased]' section")
next_heading = None
for index in range(unreleased + 1, len(lines)):
if re.match(r"^## \[[^\]]+\]", lines[index]):
next_heading = index
break
if next_heading is None:
raise SystemExit("CHANGELOG.md is missing a version section after [Unreleased]")
heading = f"## [{version}] - {release_date}"
if any(line.strip() == heading for line in lines):
path.write_text(text if text.endswith("\n") else text + "\n", encoding="utf-8")
raise SystemExit(0)
if any(re.match(rf"^## \[{re.escape(version)}\] - ", line) for line in lines):
raise SystemExit(f"CHANGELOG.md already contains an entry for {version} with a different date")
entry = [
heading,
"",
"### Changed",
"- Refreshed IERS/USNO time-data snapshot:",
" - `UTC-TAI.history`",
" - `deltat.data`",
" - `deltat.preds`",
" - `finals2000A.all`",
"- Regenerated bundled time-data snapshot in `src/time/bundled/snapshot.rs`.",
"",
]
updated = lines[:next_heading] + entry + lines[next_heading:]
path.write_text("\n".join(updated) + "\n", encoding="utf-8")
PY
echo "Bumped siderust-archive ${CUR} -> ${NEW}"
echo "version=${NEW}" >> "$GITHUB_OUTPUT"
- name: Publish dry-run
if: steps.wip.outputs.skip != 'true' && steps.publish_token.outputs.skip != 'true'
working-directory: .
run: cargo publish --dry-run --allow-dirty -p siderust-archive
- name: Commit, tag, push
if: steps.wip.outputs.skip != 'true' && steps.publish_token.outputs.skip != 'true'
env:
GIT_AUTHOR_NAME: github-actions[bot]
GIT_AUTHOR_EMAIL: 41898282+github-actions[bot]@users.noreply.github.com
GIT_COMMITTER_NAME: github-actions[bot]
GIT_COMMITTER_EMAIL: 41898282+github-actions[bot]@users.noreply.github.com
run: |
set -euo pipefail
VERSION="${{ steps.versions.outputs.version }}"
git add Cargo.toml CHANGELOG.md
mapfile -t staged < <(git diff --cached --name-only)
unexpected=()
for path in "${staged[@]}"; do
case "$path" in
Cargo.toml|CHANGELOG.md)
;;
*)
unexpected+=("$path")
;;
esac
done
if [ "${#unexpected[@]}" -ne 0 ]; then
echo "::error::Release commit staged files outside Cargo.toml and CHANGELOG.md."
printf 'Unexpected staged path: %s\n' "${unexpected[@]}"
exit 1
fi
git commit -m "chore(release): siderust-archive v${VERSION}"
git tag -a "v${VERSION}" -m "Release ${VERSION} (automated data-refresh patch)"
git push origin HEAD:main --tags
- name: Publish to crates.io
if: steps.wip.outputs.skip != 'true' && steps.publish_token.outputs.skip != 'true'
working-directory: .
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
run: cargo publish