Skip to content

Commit

Permalink
Add src code
Browse files Browse the repository at this point in the history
  • Loading branch information
charleskawczynski committed Mar 11, 2022
1 parent e093d89 commit ea78062
Show file tree
Hide file tree
Showing 11 changed files with 431 additions and 1 deletion.
11 changes: 11 additions & 0 deletions .github/codecov.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
comment: false
coverage:
status:
project:
default:
target: auto
# this allows a 10% drop from the previous base commit coverage
threshold: 10%

github_checks:
annotations: false
44 changes: 44 additions & 0 deletions .github/workflows/CodeCov.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: CodeCov

on:
push:
branches:
- main
- trying
- staging
tags: '*'
pull_request:

jobs:
codecov:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2.2.0

- name: Set up Julia
uses: julia-actions/setup-julia@latest
with:
version: 1.7.0

- name: Test with coverage
env:
JULIA_PROJECT: "@."
run: |
julia --project=@. -e 'using Pkg; Pkg.instantiate()'
julia --project=@. -e 'using Pkg; Pkg.test(coverage=true)'
- name: Generate coverage file
env:
JULIA_PROJECT: "@."
run: julia --project=@. -e 'using Pkg; Pkg.add("Coverage");
using Coverage;
LCOV.writefile("coverage-lcov.info", Codecov.process_folder())'
if: success()

- name: Submit coverage
uses: codecov/codecov-action@v1.0.7
with:
token: ${{secrets.CODECOV_TOKEN}}
if: success()

16 changes: 16 additions & 0 deletions .github/workflows/CompatHelper.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
name: CompatHelper
on:
schedule:
- cron: '00 00 * * *'
workflow_dispatch:
jobs:
CompatHelper:
runs-on: ubuntu-latest
steps:
- name: Pkg.add("CompatHelper")
run: julia -e 'using Pkg; Pkg.add("CompatHelper")'
- name: CompatHelper.main()
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
COMPATHELPER_PRIV: ${{ secrets.COMPATHELPER_PRIV }} # optional
run: julia -e 'using CompatHelper; CompatHelper.main()'
15 changes: 15 additions & 0 deletions .github/workflows/TagBot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
name: TagBot
on:
issue_comment:
types:
- created
workflow_dispatch:
jobs:
TagBot:
if: github.event_name == 'workflow_dispatch' || github.actor == 'JuliaTagBot'
runs-on: ubuntu-latest
steps:
- uses: JuliaRegistries/TagBot@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
ssh: ${{ secrets.DOCUMENTER_KEY }}
49 changes: 49 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: ci
on:
push:
branches:
- main
- trying
- staging
tags: '*'
pull_request:

jobs:
test:
name: ci ${{ matrix.version }} - ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
version:
- '1.4'
- '1.5'
- '1.6.0'
os:
- ubuntu-latest
- macOS-latest
- windows-latest
arch:
- x64
steps:
- uses: actions/checkout@v2
- uses: julia-actions/setup-julia@v1
with:
version: ${{ matrix.version }}
arch: ${{ matrix.arch }}
- uses: actions/cache@v1
env:
cache-name: cache-artifacts
with:
path: ~/.julia/artifacts
key: ${{ runner.os }}-test-${{ env.cache-name }}-${{ hashFiles('**/Project.toml') }}
restore-keys: |
${{ runner.os }}-test-${{ env.cache-name }}-
${{ runner.os }}-test-
${{ runner.os }}-
- uses: julia-actions/julia-buildpkg@v1
- uses: julia-actions/julia-runtest@v1
- uses: julia-actions/julia-processcoverage@v1
- uses: codecov/codecov-action@v1
with:
file: lcov.info
12 changes: 12 additions & 0 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
name = "CompatDevTools"
uuid = "732b9ffd-ba4a-45cb-82b2-a390f71ea5ac"
authors = ["Charles Kawczynski <kawczynski.charles@gmail.com>"]
version = "0.1.0"

[deps]
OrderedCollections = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"
REPL = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb"

[compat]
OrderedCollections = "1.4"
julia = "1.4"
33 changes: 32 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,33 @@
# CompatDevTools.jl
Julia compat-related development tools

Julia compat-related development tools.

## Why was this developed?

[CompatHelper.jl](https://github.com/JuliaRegistries/CompatHelper.jl) does a great job of letting package maintainers know which compat entries should be updated to allow using the latest versions. However, managing many packages, or a package with many environments, requires keeping many compat entries up-to-date. In addition, package managers may want to keep these compat entries, between these many environments, synchronized to some extent. CompatDevTools.jl was developed to help ease this process.

## Features

The primary feature of CompatDevTools.jl is `synchronize_compats`:
```julia
synchronize_compats(code_dir::AbstractString)

This function
- Recursively finds all Project.toml files in `code_dir`
- Collects the compat entries
- Finds any inconsistent compat entries
- Asks the user (via `REPL.TerminalMenus`) which
version (if any) to update to, and modifies the
Project.toml files accordingly.
```

Another simple utility function, `compat_kick_start`, was added to this package:
```julia
compat_kick_start(code_dir::String, julia_version = "1")

Given a directory containing both a Project.toml and
Manifest.toml, print a string of a suggested compat
entry for all Project.toml dependencies.
```
This may be useful if you've started working on a new package which may have many dependencies and you need to generate your first set of compat entries. This function prints compat entries based on the existing Manifest.toml (and Project.toml) files.

16 changes: 16 additions & 0 deletions bors.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
status = [
"ci 1.4 - ubuntu-latest",
"ci 1.4 - windows-latest",
"ci 1.4 - macOS-latest",
"ci 1.5 - ubuntu-latest",
"ci 1.5 - windows-latest",
"ci 1.5 - macOS-latest",
"ci 1.6.0 - ubuntu-latest",
"ci 1.6.0 - windows-latest",
"ci 1.6.0 - macOS-latest",
"docbuild",
]
delete_merged_branches = true
timeout_sec = 10800
block_labels = [ "do-not-merge-yet" ]
cut_body_after = "<!--"
179 changes: 179 additions & 0 deletions src/CompatDevTools.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
"""
CompatDevTools
Featured functions:
- [`compat_kick_start`](@ref) kick-start compat entries from a directory
"""
module CompatDevTools

import OrderedCollections
import REPL.TerminalMenus

if VERSION >= v"1.6.0"
radio_menu(options; kwargs...) = TerminalMenus.RadioMenu(options; charset=:ascii, kwargs...)
else
radio_menu(options; kwargs...) = TerminalMenus.RadioMenu(options; kwargs...)
end

is_deps(x) = startswith(x, "[[deps.") || startswith(x, "[deps]")
dep_match(x, dep) = x == "[[$dep]]" || x == "[[deps.$dep]]"

"""
synchronize_compats(code_dir::AbstractString)
This function
- Recursively finds all Project.toml files in `code_dir`
- Collects the compat entries
- Finds any inconsistent compat entries
- Asks the user (via `REPL.TerminalMenus`) which
version (if any) to update to, and modifies the
Project.toml files accordingly.
"""
function synchronize_compats(code_dir::AbstractString)

project_toml_files = [joinpath(root, f) for (root, dirs, files) in Base.Filesystem.walkdir(code_dir) for f in files if endswith(f, "Project.toml")]

compat_entries = OrderedCollections.OrderedDict()
for project_toml in project_toml_files
contents = join(readlines(project_toml; keep=true))
if !occursin("[compat]", contents)
@warn "No compat entry found in $project_toml"
continue
end
if !occursin("[compat]\n", contents)
@warn "Compat header found, but no compat entry found in $project_toml"
continue
end
compat_section = last(split(contents, "[compat]\n"))
if occursin("\n\n", compat_section) # split by end of compat section
compat_section = first(split(compat_section, "\n\n"))
end
compats = split(compat_section, "\n")
filter!(x->!isempty(x), compats)
compats = map(compats) do compat
s = split(compat, "=")
(strip(first(s)), replace(strip(last(s)), "\"" => ""), compat)
end
dir = dirname(project_toml)
for (pkg, ver, line) in compats
if haskey(compat_entries, pkg)
ver in compat_entries[pkg] && continue
push!(compat_entries[pkg], (ver, dir, line))
else
compat_entries[pkg] = [(ver, dir, line)]
end
end
end

inconsistent_compat_entries = OrderedCollections.OrderedDict()
ice = inconsistent_compat_entries
for k in keys(compat_entries)
length(compat_entries[k]) == 1 && continue # only one env with this dep
if length(unique(first.(compat_entries[k]))) 1
ice[k] = compat_entries[k]
end
end
@debug begin
for k in keys(ice)
println("$k = $(ice[k])")
end
end
if length(keys(ice)) == 0
@info "All compat entries are consistent! 🎉"
return nothing
end
answers = OrderedCollections.OrderedDict()
@info "$(length(keys(ice))) inconsistent compat entries found across $(length(project_toml_files)) toml files."
for pkg in keys(ice)
versions = getindex.(ice[pkg], 1)
env_dirs = getindex.(ice[pkg], 2)
lines = getindex.(ice[pkg], 3)
entries = map(zip(versions, env_dirs)) do (ver, env_dir)
"$ver ($(env_dir))"
end
options = [entries..., "Leave alone."]
menu = radio_menu(options)
msg = "Inconsistent compat entries found for $pkg. Select a compat entry (or leave alone):"
choice = TerminalMenus.request(msg, menu)
if !(choice == length(options))
answers[pkg] = (env_dirs[choice], lines[choice], lines)
@info "Changing $(env_dirs[choice]) compat for $pkg to $(lines[choice])"
end
end

# Edit Project.toml files according to answers

for project_toml in project_toml_files
contents = join(readlines(project_toml; keep=true))
new_contents = contents
for pkg in keys(answers)
all_compat_lines = last(answers[pkg])
chosen_compat_line = getindex(answers[pkg], 2)
for compat_line in all_compat_lines
new_contents = replace(new_contents, compat_line => chosen_compat_line)
end
end
open(project_toml, "w") do io
print(io, new_contents)
end
end


end

"""
compat_kick_start(code_dir::String, julia_version = "1.5.4")
Given a directory containing both a Project.toml and Manifest.toml,
print a string of a suggested compat entry for all Project.toml
dependencies.
"""
function compat_kick_start(code_dir::AbstractString, julia_version = "1")
project = joinpath(code_dir, "Project.toml");
manifest = joinpath(code_dir, "Manifest.toml");
@assert isfile(project)
@assert isfile(manifest)

project_contents = readlines(project)
deps = String[]
collect_deps = false
end_collection = false
for line in project_contents
end_collection && break
if is_deps(line)
collect_deps = true
end
if collect_deps
if line == ""
end_collection = true
end
end
if collect_deps && !is_deps(line) && line ""
push!(deps, first(split(line, " = ")))
end
end
compat_entries = String[]
manifest_contents = readlines(manifest)
for dep in deps
i = findfirst(x -> dep_match(x, dep), manifest_contents)
i == nothing && continue
j = findfirst(x -> x == "", manifest_contents[i:end])

contents_block = manifest_contents[i:i+j-1]
i_version_entry = findfirst(x->startswith(x, "version = "), contents_block)
if i_version_entry == nothing
continue # must be a stdlib
end
version_str = contents_block[i_version_entry]
version_num = last(split(version_str, "version = "))

push!(compat_entries, "$dep = $version_num")
end
push!(compat_entries, "julia = \"$julia_version\"")

str = "[compat]\n"*join(compat_entries, "\n")
print(str)
return str
end

end # module
2 changes: 2 additions & 0 deletions test/Project.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[deps]
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
Loading

2 comments on commit ea78062

@charleskawczynski
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Registration pull request created: JuliaRegistries/General/56431

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v0.1.0 -m "<description of version>" ea78062666d9d7c02580ed606bd6e000566182fe
git push origin v0.1.0

Please sign in to comment.