-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Automate publishing new releases on crates.io
These scripts will help automate the steps required to publish new releases on crates.io: - update version number in `Cargo.toml`, `README.md`, and `src/lib.rs` - update changelog in `README.md` - run `cargo publish` if all tests pass
- Loading branch information
Showing
2 changed files
with
216 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
name: Prepare Release PR | ||
|
||
on: | ||
push: | ||
branches: | ||
- 'release-*' | ||
|
||
jobs: | ||
setup: | ||
runs-on: ubuntu-latest | ||
outputs: | ||
name: ${{ steps.vars.outputs.name }} | ||
old-version: ${{ steps.vars.outputs.old-version }} | ||
new-version: ${{ steps.vars.outputs.new-version }} | ||
steps: | ||
- name: Check out repository | ||
uses: actions/checkout@v2 | ||
|
||
- name: Set variables | ||
id: vars | ||
run: | | ||
NAME=$(cargo metadata -q --no-deps | jq -r '.packages[0].name') | ||
OLD_VERSION=$(cargo metadata -q --no-deps | jq -r '.packages[0].version') | ||
NEW_VERSION=$(echo ${{ github.ref }} | cut -d '-' -f 2-) | ||
echo "Version from Cargo: $OLD_VERSION" | ||
echo "Version from branch: $NEW_VERSION" | ||
echo "::set-output name=name::$NAME" | ||
echo "::set-output name=old-version::$OLD_VERSION" | ||
echo "::set-output name=new-version::$NEW_VERSION" | ||
- name: Verify version format | ||
run: | | ||
echo '${{ steps.vars.outputs.new-version }}' | grep -q '^[0-9]\+\.[0-9]\+\.[0-9]\+$' | ||
pull-request: | ||
needs: setup | ||
if: ${{ needs.setup.outputs.old-version != needs.setup.outputs.new-version }} | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Check out repository | ||
uses: actions/checkout@v2 | ||
|
||
- name: Configure Git user | ||
run: | | ||
git config user.name "Martin Geisler" | ||
git config user.email "martin@geisler.net" | ||
- name: Update changelog for version ${{ needs.setup.outputs.new-version }} | ||
id: changelog | ||
uses: actions/github-script@v2 | ||
with: | ||
script: | | ||
var fs = require('fs') | ||
const old_version = '${{ needs.setup.outputs.old-version }}' | ||
const new_version = '${{ needs.setup.outputs.new-version }}' | ||
let cutoff = '1970-01-01' | ||
const releases = await github.repos.listReleases(context.repo) | ||
for (const release of releases.data) { | ||
if (release.tag_name == old_version) { | ||
cutoff = release.published_at | ||
break | ||
} | ||
} | ||
core.info(`Finding merged PRs after ${cutoff}`) | ||
let q = [`repo:${context.repo.owner}/${context.repo.repo}`, | ||
'is:pr', 'is:merged', `merged:>${cutoff}`] | ||
const prs = await github.search.issuesAndPullRequests({ | ||
q: q.join(' '), | ||
sort: 'created', | ||
order: 'asc', | ||
}) | ||
core.info(`Found ${prs.data.items.length} merged PRs`) | ||
const changelog = prs.data.items.map( | ||
pr => `* [#${pr.number}](${pr.html_url}): ${pr.title}` | ||
).join('\n\n') | ||
core.exportVariable('CHANGELOG', changelog) | ||
var readme = fs.readFileSync('README.md', 'utf8') | ||
const today = new Date().toISOString().split('T')[0] | ||
const heading = `## Version ${new_version} (${today})\n` | ||
if (readme.match('## Unreleased')) { | ||
readme = readme.replace('## Unreleased', `${heading}\n${changelog}`) | ||
} else { | ||
readme = readme.replace('# Changelog', `# Changelog\n\n${heading}\n${changelog}`) | ||
} | ||
fs.writeFileSync('README.md', readme) | ||
- name: Commit changelog | ||
run: | | ||
git commit --all -m "Update changelog for version ${{ needs.setup.outputs.new-version }}" | ||
- name: Update TOML code blocks | ||
run: | | ||
import fileinput, re, sys | ||
NAME = '${{ needs.setup.outputs.name }}' | ||
NEW_VERSION = '${{ needs.setup.outputs.new-version }}' | ||
MAJOR_MINOR = '.'.join(NEW_VERSION.split('.')[:2]) | ||
for line in fileinput.input(inplace=True): | ||
line = re.sub(f'{NAME} = "[^"]+"', | ||
f'{NAME} = "{MAJOR_MINOR}"', line) | ||
line = re.sub(f'{NAME} = {{ version = "[^"]+"', | ||
f'{NAME} = {{ version = "{MAJOR_MINOR}"', line) | ||
sys.stdout.write(line) | ||
shell: python3 {0} README.md | ||
|
||
- name: Update html_root_url | ||
run: | | ||
import fileinput, re, sys | ||
NAME = '${{ needs.setup.outputs.name }}' | ||
NEW_VERSION = '${{ needs.setup.outputs.new-version }}' | ||
for line in fileinput.input(inplace=True): | ||
sys.stdout.write( | ||
re.sub(f'html_root_url = "https://docs.rs/{NAME}/[^"]+"', | ||
f'html_root_url = "https://docs.rs/{NAME}/{NEW_VERSION}"', line)) | ||
shell: python3 {0} src/lib.rs | ||
|
||
- name: Update crate version to ${{ needs.setup.outputs.new-version }} | ||
uses: thomaseizinger/set-crate-version@1.0.0 | ||
with: | ||
version: ${{ needs.setup.outputs.new-version }} | ||
|
||
- name: Build and test | ||
run: | | ||
cargo test | ||
- name: Commit version bump | ||
run: | | ||
git commit --all -m "Bump version to ${{ needs.setup.outputs.new-version }}" | ||
- name: Push version bump | ||
run: git push origin | ||
|
||
- name: Create pull request | ||
uses: actions/github-script@v2 | ||
with: | ||
script: | | ||
const pr = await github.pulls.create({ | ||
owner: context.repo.owner, | ||
repo: context.repo.repo, | ||
head: 'release-${{ needs.setup.outputs.new-version }}', | ||
base: 'master', | ||
title: 'Release ${{ needs.setup.outputs.new-version }}', | ||
body: process.env.CHANGELOG, | ||
}) | ||
core.info(`Created PR: ${pr.data.html_url}`) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
name: Publish Crate | ||
|
||
on: | ||
push: | ||
branches: | ||
- master | ||
paths: | ||
- Cargo.toml | ||
repository_dispatch: | ||
types: publish | ||
|
||
jobs: | ||
publish: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Check out repository | ||
uses: actions/checkout@v2 | ||
|
||
- name: Set variables | ||
id: vars | ||
run: | | ||
NAME=$(cargo metadata -q --no-deps | jq -r '.packages[0].name') | ||
VERSION=$(cargo metadata -q --no-deps | jq -r '.packages[0].version') | ||
CHANGELOG=$(awk '/^## Version/ {i++}; i==1 {print}; i>1 {exit}' README.md \ | ||
| python3 -c 'import sys, json; print(json.dumps(sys.stdin.read()))') | ||
echo "::set-output name=name::$NAME" | ||
echo "::set-output name=version::$VERSION" | ||
echo "::set-output name=changelog::$CHANGELOG" | ||
echo "Found $NAME-$VERSION" | ||
- name: Lookup ${{ steps.vars.outputs.version }} tag | ||
id: need-release | ||
uses: actions/github-script@v2 | ||
with: | ||
script: | | ||
const version = '${{ steps.vars.outputs.version }}' | ||
const tags = await github.repos.listTags(context.repo) | ||
if (tags.data.some(tag => tag.name == version)) { | ||
core.info(`Found ${version} tag -- will skip publish step`) | ||
return false | ||
} | ||
core.info(`Found no ${version} tag -- will proceed with publishing`) | ||
return true | ||
# The result from above is JSON-encoded, meaning that we | ||
# end up with the string 'true', not the Boolean true. | ||
- if: steps.need-release.outputs.result == 'true' | ||
name: Publish crate to crates.io | ||
run: | | ||
echo "Publishing ${{ steps.vars.outputs.name }}-${{ steps.vars.outputs.version }}" | ||
cargo publish --token ${{ secrets.CARGO_TOKEN }} | ||
- if: steps.need-release.outputs.result == 'true' | ||
name: Create GitHub release | ||
uses: actions/create-release@v1 | ||
env: | ||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
with: | ||
tag_name: ${{ steps.vars.outputs.version }} | ||
release_name: ${{ steps.vars.outputs.name }}-${{ steps.vars.outputs.version }} | ||
body: ${{ fromJson(steps.vars.outputs.changelog) }} | ||
draft: false | ||
prerelease: false |