|
| 1 | +import Git as G |
| 2 | + |
| 3 | +using PkgTemplates |
| 4 | +import PkgTemplates |
| 5 | + |
| 6 | +using TOML |
| 7 | + |
| 8 | +struct SemanticReleaseBadge <: PkgTemplates.BadgePlugin end |
| 9 | + |
| 10 | +""" |
| 11 | +Badge for semantic release |
| 12 | +""" |
| 13 | +function PkgTemplates.badges(::SemanticReleaseBadge) |
| 14 | + return PkgTemplates.Badge( |
| 15 | + "semantic-release", |
| 16 | + "https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg", |
| 17 | + "https://github.com/semantic-release/semantic-release", |
| 18 | + ) |
| 19 | +end |
| 20 | + |
| 21 | +PkgTemplates.badges(::Documenter{<:PkgTemplates.GitHubPagesStyle}) = [ |
| 22 | + PkgTemplates.Badge( |
| 23 | + "Latest", |
| 24 | + "https://img.shields.io/badge/docs-latest-purple.svg", |
| 25 | + "https://{{{USER}}}.github.io/{{{PKG}}}.jl/latest/", |
| 26 | + ), |
| 27 | +] |
| 28 | + |
| 29 | +PkgTemplates.badges(::Coveralls) = PkgTemplates.Badge( |
| 30 | + "Coverage Status", |
| 31 | + "https://img.shields.io/coveralls/github/{{{USER}}}/{{{PKG}}}.jl/badge.svg?branch={{{BRANCH}}}", |
| 32 | + "https://coveralls.io/github/{{{USER}}}/{{{PKG}}}.jl?branch={{{BRANCH}}}", |
| 33 | +) |
| 34 | + |
| 35 | +""" |
| 36 | + createpackage(path::AbstractString) |
| 37 | +
|
| 38 | +Create a package with semantic release using the configuration in the TOML file at `path` |
| 39 | +
|
| 40 | +Run using `julia -e 'include("setup.jl"); createpackage(path)'` |
| 41 | +""" |
| 42 | +function createpackage(path::AbstractString) |
| 43 | + config = TOML.parsefile(path) |
| 44 | + createpackage(; |
| 45 | + name=config["name"], |
| 46 | + user=config["user"], |
| 47 | + authors=config["authors"], |
| 48 | + julia=VersionNumber(config["julia"]...), |
| 49 | + dir=config["dir"], |
| 50 | + license=config["license"] |
| 51 | + ) |
| 52 | +end |
| 53 | + |
| 54 | +""" |
| 55 | + createpackage(;name="MyProject.jl", user="anirudh2", authors="Anirudh A. Patel", julia=v"1.8", dir="~/projects/", licensetype="MIT") |
| 56 | +
|
| 57 | +Create a package with semantic release. |
| 58 | +
|
| 59 | +Run using `julia -e 'include("setup.jl"); createpackage(;kwargs)'` |
| 60 | +
|
| 61 | +- `user` is the part of the GitHub URL that comes after github.com. E.g., github.com/anirudh2 => user="anirudh2" |
| 62 | +- `license` can be "MIT", "ASL" (Apache 2), "GPL", etc. A full list is available on [github](https://github.com/JuliaCI/PkgTemplates.jl/tree/master/templates/licenses) |
| 63 | +""" |
| 64 | +function createpackage(; name, user, authors, julia, dir, license) |
| 65 | + @info "Creating Package" |
| 66 | + t = PkgTemplates.Template(; |
| 67 | + user=user, |
| 68 | + authors=authors, |
| 69 | + julia=julia, |
| 70 | + dir="~/projects/", |
| 71 | + plugins=[ |
| 72 | + Git(; gpgsign=true, ssh=true), |
| 73 | + GitHubActions(; extra_versions=String[], coverage=true), |
| 74 | + Coveralls(), |
| 75 | + Documenter{PkgTemplates.GitHubActions}(), |
| 76 | + BlueStyleBadge(), |
| 77 | + Citation(), |
| 78 | + License(; name=license), |
| 79 | + Tests(; project=true), |
| 80 | + SrcDir(), |
| 81 | + ProjectFile(), |
| 82 | + SemanticReleaseBadge(), |
| 83 | + CompatHelper(), |
| 84 | + !TagBot, |
| 85 | + ]) |
| 86 | + t(name) |
| 87 | + |
| 88 | + @info "Copying Relevant Files To Package Repo" |
| 89 | + namesplit = name |> splitext |> first |
| 90 | + fulldir = dir |> expanduser |> realpath |
| 91 | + path = joinpath(fulldir, namesplit) |
| 92 | + cp("Release.yml", joinpath(path, ".github", "workflows", "Release.yml")) |
| 93 | + cp(".releaserc", joinpath(path, ".releaserc")) |
| 94 | + cp("CHANGELOG.md", joinpath(path, "CHANGELOG.md")) |
| 95 | + |
| 96 | + @info "Correcting initial version" |
| 97 | + tomlpath = joinpath(path, "Project.toml") |
| 98 | + modfile(tomlpath, x -> x == "version = \"0.1.0\"\n", "version = \"0.0.0\"\n") |
| 99 | + |
| 100 | + @info "Setting correct devurl for Documentation" |
| 101 | + makedocpath = joinpath(path, "docs", "make.jl") |
| 102 | + # \t is 8 spaces, so just use 4 spaces manually |
| 103 | + modfile(makedocpath, x -> contains(x, "devbranch"), " devbranch=\"main\",\n devurl=\"latest\",\n") |
| 104 | + |
| 105 | + @info "Setting git repo for semantic release" |
| 106 | + releasercpath = joinpath(path, ".releaserc") |
| 107 | + modfile(releasercpath, x -> contains(x, "repositoryUrl"), " \"repositoryUrl\": \"git@github.com:$user/$name.git\"") |
| 108 | + |
| 109 | + @info "Setting up coveralls" |
| 110 | + ciymlpath = joinpath(path, ".github", "workflows", "CI.yml") |
| 111 | + modfile(ciymlpath, x -> contains(x, "julia-runtest"), " - uses: julia-actions/julia-runtest@v1\n - uses: julia-actions/julia-processcoverage@v1\n") |
| 112 | + modfile(ciymlpath, x -> contains(x, "COVERALLS_TOKEN"), " COVERALLS_TOKEN: \${{ secrets.GITHUB_TOKEN }}\n") |
| 113 | + |
| 114 | + @info "Appending post-setup instructions to README" |
| 115 | + open(joinpath(path, "README.md"), "a") do io |
| 116 | + lines = [ |
| 117 | + "\n## TODO\n", |
| 118 | + "\n I generally recommend doing step 1 running this script, but it's not a big deal if you do it after.\n", |
| 119 | + "\n1. Go to [Coveralls](https://coveralls.io/) and activate this repo.", |
| 120 | + "\n2. Once CI finishes running for the first time, go to Settings, Pages, and select the branch `gh-pages`", |
| 121 | + "\n3. Once you've done these things, delete this TODO section and commit the change with the message `chore: finished repo setup`" |
| 122 | + ] |
| 123 | + for line in lines |
| 124 | + write(io, line) |
| 125 | + end |
| 126 | + end |
| 127 | + |
| 128 | + @info "Creating initial commit and tag" |
| 129 | + @warn "This will fail if you have not created the upstream repo on GitHub at the correct URL." |
| 130 | + @warn "You must also have gpg commit signing set up." |
| 131 | + cd(path) |
| 132 | + run(`$(G.git()) add .`) |
| 133 | + run(`$(G.git()) commit -m "chore: Set up project"`) |
| 134 | + run(`$(G.git()) tag v0.0.0 -m "Set up project"`) |
| 135 | + run(`$(G.git()) push --set-upstream origin main v0.0.0`) |
| 136 | +end |
| 137 | + |
| 138 | +""" |
| 139 | +Modify the file at `path` at lines that match `predicate`, replacing the lines with |
| 140 | +`replacement` |
| 141 | +""" |
| 142 | +function modfile(path::String, predicate::F, replacement::String) where {F<:Function} |
| 143 | + # https://stackoverflow.com/questions/58013970/how-to-edit-a-line-of-a-file-in-julia |
| 144 | + (tmppath, tmpio) = mktemp() |
| 145 | + open(path) do io |
| 146 | + for line in eachline(io; keep=true) |
| 147 | + if predicate(line) |
| 148 | + line = replacement |
| 149 | + end |
| 150 | + write(tmpio, line) |
| 151 | + end |
| 152 | + end |
| 153 | + close(tmpio) |
| 154 | + mv(tmppath, path, force=true) |
| 155 | + return nothing |
| 156 | +end |
0 commit comments