diff --git a/.github/workflows/release_schedule.yaml b/.github/workflows/release_schedule.yaml new file mode 100644 index 0000000..751bd25 --- /dev/null +++ b/.github/workflows/release_schedule.yaml @@ -0,0 +1,61 @@ +name: Generate release schedule artifacts +on: + schedule: + # At 00:00 on day-of-month 1 in every 3rd month. (i.e. every quarter) + - cron: "0 0 1 */3 *" + # on demand + workflow_dispatch: + +jobs: + create-artifacts: + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + # We're going to make a tag that we can we release so we'll need the full history for that + fetch-depth: 0 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.13" + - name: Install dependencies + run: | + pip install -r requirements.txt + - name: Run spec_zero_versions.py + run: | + python spec_zero_versions.py + - name: setup git + run: | + # git will complain if we don't do this first + git config user.name "GitHub Actions Bot" + git config user.email "<>" + + - name: determine tag name + id: tag_name + run: | + echo "TAG_NAME=$(date '+%Y-Q%q')" >> "$GITHUB_OUTPUT" + + - name: create tag + env: + TAG_NAME: ${{ steps.tag_name.outputs.TAG_NAME }} + run: | + git add schedule.md chart.md schedule.json + git commit -m "Update SPEC 0 schedule artifacts" + git tag "$TAG_NAME" + git push origin "$TAG_NAME" + + - name: Publish github release + uses: softprops/action-gh-release@v2 + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + generate_release_notes: true + tag_name: ${{ steps.tag_name.outputs.TAG_NAME }} + make_latest: true + files: | + schedule.md + chart.md + schedule.json diff --git a/.gitignore b/.gitignore index d7a22f5..8f5fd87 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1 @@ .history -chart.md -schedule.md -schedule.json diff --git a/action.yaml b/action.yaml index ab54c11..de974b4 100644 --- a/action.yaml +++ b/action.yaml @@ -1,26 +1,64 @@ name: "Generate SPEC-0000 Data" description: "Based on the current SPEC 0 schedule, generate a tarball with the latest versions of all packages." +author: Sam Vente +inputs: + target_branch: + description: "Target branch for the pull request" + required: true + default: "main" + tool: # for now only pixi, but good to make others possible from the start + description: "Which tool you use for managing your environment." + required: true + default: "pixi" + token: + description: "GitHub token with repo permissions to create pull requests" + required: true runs: using: "composite" steps: - - name: Set up Python - uses: actions/setup-python@v5 + - name: Validate tool input + shell: bash + run: | + if [[ "${{ inputs.tool }}" != "pixi" ]]; then + echo "❌ Invalid tool: '${{ inputs.tool }}'" + echo "Accepted values are: 'pixi'" + exit 1 + fi + - name: Checkout code + uses: actions/checkout@v4 with: - python-version: "3.13" - - name: Install dependencies + fetch-depth: 0 + + - name: Set up Git shell: bash run: | - pip install -r requirements.txt - - name: Run spec_zero_versions.py + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + - name: Download schedule artifact + shell: bash + run: gh release download -R "savente93/spec-zero-tools" --pattern schedule.json --clobber + + # make user pixi is available + - uses: prefix-dev/setup-pixi@v0.8.14 + if: ${{ inputs.tool == 'pixi' }} + name: Setup pixi + with: + pixi-version: v0.49.0 + + - name: Update Pixi dependencies + if: ${{ inputs.tool == 'pixi' }} shell: bash run: | - python spec_zero_versions.py - - name: Upload files as an artifact - uses: actions/upload-artifact@v4 + "${{ github.action_path }}/update_pixi.sh" + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v6 with: - name: spec-zero-versions - path: | - schedule.json - schedule.md - chart.md + token: ${{ inputs.token }} + commit-message: "chore: Drop support for unsupported packages conform SPEC 0" + title: "Drop support for unsupported packages conform SPEC 0" + body: "This PR was created automatically" + base: ${{ inputs.target_branch }} + branch: update-spec-0-dependencies-${{ github.run_id }} diff --git a/readme.md b/readme.md index c05545c..27c4955 100644 --- a/readme.md +++ b/readme.md @@ -1,63 +1,53 @@ # SPEC-0 Versions Action -This repository contains a GitHub Action to generate the files required for the SPEC-0 documentation. +This repository contains a Github Action to update python dependencies conform the SPEC 0 support schedule. +It also contains released versions of the schedule in various formats that that action can use to open PRs in your repository. ## Using the action ```yaml -name: Generate spec-zero data +name: Update SPEC 0 dependencies on: - push: - branches: - - main + workflow_dispatch: + schedule: + # At 00:00 on day-of-month 2 in every 3rd month. (i.e. every quarter) + # Releases should happen on the first day of the month in scientific-python/spec-zero-tools + # so allow one day as a buffer to avoid timing issues + - cron: "0 0 2 */3 *" + +permissions: + contents: write + pull-requests: write jobs: - devstats-query: + update: runs-on: ubuntu-latest steps: - - uses: scientific-python/spec0-action@main + - uses: scientific-python/spec0-action@main # when this is merged and released, this should turn to @v1 + with: + token: ${{ secrets.GH_PAT }} + target_branch: main + tool: pixi ``` -The above would produce an artifact named `spec-zero-versions`, the following files: `schedule.yaml`,`schedule.md` and `chart.md`. +Whenever the action is triggered it will open a PR in your repository that will update the dependencies of SPEC 0 to the new lower bound. For this you will have to provide it with a PAT that has write permissions in the `contents` and `pull request` scopes. Please refer to the GitHub documentation for instructions on how to do this [here](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens). To help projects stay compliant with SPEC-0, we provide a `schedule.json` file that can be used by CI systems to determine new version boundaries. -The structure of the file is as follows: - -```json -[ - { - "start_date": "iso8601_timestamp", - "packages": { - "package_name": "version" - } - } -] -``` -All information in the json file is in a string format that should be easy to use. -The date is the first timestamp of the relevant quarter. -Thus a workflow for using this file could be: +Currently the action can take the following inputs: -1. Fetch `schedule.json` -2. Determine maximum date that is smaller than current date -3. Update packages listed with new minimum versions +| Name | Description | Required | +| --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | +| `token` | The token that the action will use to create and update the pull request. See [token](https://github.com/marketplace/actions/create-pull-request#token). | Yes | +| `tool` | Which tool to use for managing your dependencies. Currently `pixi` is the only option. | No | +| `target_branch` | The branch to open a PR against with the updated versions. Defaults to `main`. | No | -You can obtain the new versions you should set by using this `jq` expression: +## Limitations -```sh -jq 'map(select(.start_date |fromdateiso8601 |tonumber < now))| sort_by("start_date") | reverse | .[0].packages ' schedule.json -``` +This project is still in progress and thus it comes with some limitations we are working on. Hopefully this will be gone by the time you read this, but currently the limitations are: -If you use a package manager like pixi you could update the dependencies with a bash script like this (untested): - -```sh -curl -Ls -o schedule.json https://raw.githubusercontent.com/scientific-python/specs/main/spec-0000/schedule.json -for line in $(jq 'map(select(.start_date |fromdateiso8601 |tonumber < now))| sort_by("start_date") | reverse | .[0].packages | to_entries | map(.key + ":" + .value)[]' --raw-output schedule.json); do - package=$(echo "$line" | cut -d ':' -f 1) - version=$(echo "$line" | cut -d ':' -f 2) - if pixi list -x "^$package" &>/dev/null| grep "No packages" -q; then - pixi add "$package>=$version"; - fi -done -``` +- Only `pixi` is supported +- if you have a higher bound than the one listed in SPEC 0 this is overwritten +- higher bounds are deleted instead of maintained. +- dependency groups are not yet supported diff --git a/update_pixi.sh b/update_pixi.sh new file mode 100755 index 0000000..e7fbe95 --- /dev/null +++ b/update_pixi.sh @@ -0,0 +1,13 @@ +#!/bin/bash + + +for line in $(jq 'map(select(.start_date |fromdateiso8601 |tonumber < now))| sort_by("start_date") | reverse | .[0].packages | to_entries | map(.key + ":" + .value)[]' --raw-output schedule.json); do + + package=$(echo "$line" | cut -d ':' -f 1) + spec_0_version=$(echo "$line" | cut -d ':' -f 2) + + if pixi list -x "^$package" 2> /dev/null | grep "No packages" -q -v; then + echo "Updating $package" + pixi add "$package>=$spec_0_version" + fi +done