diff --git a/.github/workflows/version_check.yml b/.github/workflows/version_check.yml index b76714019..caebdffd6 100644 --- a/.github/workflows/version_check.yml +++ b/.github/workflows/version_check.yml @@ -1,4 +1,4 @@ -name: Check Turing.jl version +name: Check Turing.jl version consistency on: push: branches: @@ -14,10 +14,16 @@ jobs: check-version: runs-on: ubuntu-latest - # Determine whether the target branch is master. If so, also make sure to check that the - # version matches the latest release of Turing.jl. + permissions: + contents: write + pull-requests: write + env: + # Determine whether the target branch is master (i.e. this is a push to + # master or a PR to master). TARGET_IS_MASTER: ${{ (github.event_name == 'push' && github.ref_name == 'master') || (github.event_name == 'pull_request' && github.base_ref == 'master') }} + # Disable precompilation as it takes a long time and is not needed for this workflow + JULIA_PKG_PRECOMPILE_AUTO: 0 steps: - name: Checkout @@ -33,7 +39,7 @@ jobs: echo github.base_ref: ${{ github.base_ref }} echo TARGET_IS_MASTER: ${{ env.TARGET_IS_MASTER }} - - name: Check version consistency between Project.toml / _quarto.yml ${{ env.TARGET_IS_MASTER && ' / latest release' || '' }} + - name: Check version consistency shell: julia --color=yes --project=. {0} run: | using Pkg @@ -44,6 +50,10 @@ jobs: import JSON import HTTP + PROJECT_TOML_PATH = "Project.toml" + QUARTO_YML_PATH = "_quarto.yml" + MANIFEST_TOML_PATH = "Manifest.toml" + function major_minor_match(vs...) for v in vs if v.:major != vs[1].:major || v.:minor != vs[1].:minor @@ -62,40 +72,114 @@ jobs: return true end - quarto_yaml = YAML.load_file("_quarto.yml") - quarto_version = VersionNumber(quarto_yaml["website"]["navbar"]["right"][1]["text"]) - println("_quarto.yml version: ", quarto_version) + function update_project_toml(fname, target_version) + # Don't deserialise/serialise as this will scramble lines + lines = readlines(fname) + open(fname, "w") do io + for line in lines + if occursin(r"^Turing\s*=\s*\"\d+\.\d+\"\s*$", line) + println(io, "Turing = \"$(target_version.:major).$(target_version.:minor)\"") + else + println(io, line) + end + end + end + end + + function update_quarto_yml(fname, target_version) + # Don't deserialise/serialise as this will scramble lines + lines = readlines(fname) + open(fname, "w") do io + for line in lines + m = match(r"^(\s+)- text:\s*\"v\d+\.\d+\"\s*$", line) + if m !== nothing + println(io, "$(m[1])- text: \"v$(target_version.:major).$(target_version.:minor)\"") + else + println(io, line) + end + end + end + end + + # Retain the original version number string for error messages, as + # VersionNumber() will tack on a patch version of 0 + quarto_yaml = YAML.load_file(QUARTO_YML_PATH) + quarto_version_str = quarto_yaml["website"]["navbar"]["right"][1]["text"] + quarto_version = VersionNumber(quarto_version_str) + println("_quarto.yml version: ", quarto_version_str) - project_toml = TOML.parsefile("Project.toml") - project_version = VersionNumber(project_toml["compat"]["Turing"]) - println("Project.toml version: ", project_version) + project_toml = TOML.parsefile(PROJECT_TOML_PATH) + project_version_str = project_toml["compat"]["Turing"] + project_version = VersionNumber(project_version_str) + println("Project.toml version: ", project_version_str) - manifest_toml = TOML.parsefile("Manifest.toml") + manifest_toml = TOML.parsefile(MANIFEST_TOML_PATH) manifest_version = VersionNumber(manifest_toml["deps"]["Turing"][1]["version"]) println("Manifest.toml version: ", manifest_version) - if "--check-latest-version" in ARGS - # Fetch latest GitHub release + if ENV["TARGET_IS_MASTER"] == "true" + # Fetch the latest version from GitHub and update files to match this version + # if necessary. + resp = HTTP.get("https://api.github.com/repos/TuringLang/Turing.jl/releases/latest") latest_version = VersionNumber(JSON.parse(String(resp.body))["tag_name"]) println("Latest Turing.jl version: ", latest_version) - # Latest release; check that everything inside matches - if !major_minor_match(latest_version, project_version, quarto_version) - error("The latest version of Turing.jl (as determined from GitHub releases) is $latest_version. - * Please update Project.toml and/or _quarto.yml to match this version.") + if !major_minor_match(latest_version, project_version) + println("$(PROJECT_TOML_PATH) is out of date; updating") + update_project_toml(PROJECT_TOML_PATH, latest_version) + end + + if !major_minor_match(latest_version, quarto_version) + println("$(QUARTO_YML_PATH) is out of date; updating") + update_quarto_yml(QUARTO_YML_PATH, latest_version) end + if !major_minor_patch_match(latest_version, manifest_version) - error("The latest version of Turing.jl (as determined from GitHub releases) is $latest_version. - * Please update Manifest.toml to match this version.") + # Attempt to automatically update Manifest + println("$(MANIFEST_TOML_PATH) is out of date; updating") + old_env = Pkg.project().path + Pkg.activate(".") + Pkg.update() + # Check if versions match now, error if not + Pkg.activate(old_env) + manifest_toml = TOML.parsefile(MANIFEST_TOML_PATH) + manifest_version = VersionNumber(manifest_toml["deps"]["Turing"][1]["version"]) + if !major_minor_patch_match(latest_version, manifest_version) + error("Failed to update Manifest.toml to match latest Turing.jl version") + end end + else - # Not the latest release; just check for consistency + # Don't attempt to fetch the latest version; just check for consistency + # and error if versions don't match. if !major_minor_match(quarto_version, project_version, manifest_version) error("The minor versions of Turing.jl in _quarto.yml, Project.toml, and Manifest.toml are inconsistent: - - _quarto.yml: $quarto_version - - Project.toml: $project_version - - Manifest.toml: $manifest_version + - _quarto.yml: $quarto_version_str + - Project.toml: $project_version_str + - Manifest.toml: $manifest_version ") end end + + - name: Create a PR with suggested changes + id: create_pr + if: env.TARGET_IS_MASTER + uses: peter-evans/create-pull-request@v6 + with: + base: ${{ github.event_name == 'pull_request' && github.head_ref || github.ref_name }} + branch: update-turing-version/${{ github.event_name == 'pull_request' && github.head_ref || github.ref_name }} + commit-message: "Update Turing.jl version to match latest release" + body: "This PR is automatically generated by the `version_check.yml` GitHub Action." + title: "Update Turing.jl version to match latest release" + + - name: Comment on PR about suggested changes + if: ${{ github.event_name == 'pull_request' }} && ${{ steps.create_pr.outputs.pull-request-operation == 'created' }} + uses: thollander/actions-comment-pull-request@v2 + with: + message: | + Hello! The versions of Turing.jl in your `Project.toml`, `_quarto.yml`, and/or `Manifest.toml` did not match the latest release version found on GitHub (https://github.com/TuringLang/Turing.jl/releases/latest). + + I've made a PR to update these files to match the latest release: ${{ steps.create_pr.outputs.pull-request-url }} + + Please review the changes and merge the PR if they look good.