Skip to content

Commit

Permalink
Merge pull request #2 from fac/devp/v1.1.0
Browse files Browse the repository at this point in the history
Devp/v1.1.0

See: fac/dev-platform#62
  • Loading branch information
markpitchless authored Apr 15, 2021
2 parents 81dca54 + 659a9b3 commit fbf77e0
Show file tree
Hide file tree
Showing 5 changed files with 192 additions and 15 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

## [Unreleased]

## [1.1.0] - 2021-04-15

- Add: input release: Whether to push release versions
- Add: input pre-release: Whether to push pre-release versions
- Add: input tag-release: After pushing a new gem version, git tag with the version string
- Add: output pushed-version: the version of the gem pushed to the repository

## [1.0.0] - 2021-04-15

- Add basic action that pushes gems to the repository
Expand Down
84 changes: 83 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,15 @@ If the gem version already exists in the repo the action will no-op and still se

## Usage

The action expects that you have already checked out your gem and setup your ruby environment (bundle installed), such that gem and ruby commands are availiable. The easiest way to do this is using `actions/checkout` and `ruby/setup-ruby` actions with a `.ruby-version` file. See example below.

### Basic Setup

Build and push all new version of the gem:

```yaml
steps:
# Setup ruby environment
- uses: actions/checkout@v2
- uses: ruby/setup-ruby@v1 # .ruby-version

Expand All @@ -36,6 +43,62 @@ If you want to use a different gem host or key:
gem_host_api_key: ${{ secrets.EXAMPLE_APYI_KEY }}
```
### Separate release and pre-release workflow
You probably don't want to push all versions from any branch. More likely you would want to push release versions from your default branch (e.g. main) and pre-release from PR builds. To help with this the release and pre-release inputs can be used:
```yaml
name: Gem Build and Release
on:
push:
branches:
- main
pull_request:

jobs:
test:
name: Gem / Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: ruby/setup-ruby@v1
- name: Test
run: bundle exec rake

release:
name: Gem / Release
needs: test
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- uses: ruby/setup-ruby@v1

- name: Build Gem
run: bundle exec rake build

- name: Setup GPR
uses: fac/rubygems-setup-gpr-action@v1
with:
token: ${{ secrets.github_token }}

# Release production gem version from default branch
- name: Push Release Gem
if: github.ref == 'refs/heads/main'
uses: fac/rubygems-push-action@v1

# PR branch builds will release pre-release gems
- name: Push Pre-Release Gem
if: github.ref != 'refs/heads/main'
uses: fac/rubygems-push-action@v1
with:
release: false
pre-release: true
```
Here we run the test on its own job, so that it gets it's own status on the PR, that you can require separately from the release job in your branch protection.
The release job runs if the tests pass, we always package the gem to test that works. For release we use a conditional along with the actions inputs to push release versions for the main branch only and push pre-releases for PR.
## Inputs
### package-glob
Expand All @@ -49,9 +112,28 @@ File glob to match the gem file to push. The default `pkg/*.gem` picks up gems b
package-glob: build/special.gem
```

### release

Whether to push new release versions of the gem. Defaults to true.

### pre-release

Whether to push new pre-release versions of the gem. Defaults to true.

### tag-release

When true (the default), after pushing a new gem version tag the repo with
the version number prefixed with `v`. e.g. after pushing version `0.1.0`, the
tag will be `v0.1.0`. This is the same behavior as `gem tag`, but internally
implemented to work with older gem versions.

The tag commit and push will be made as the author of the commit being tagged.

## Outputs

None.
### pushed-version

If we pushed a gem to the repository, this will be set to the version pushed.

## Environment Variables

Expand Down
36 changes: 22 additions & 14 deletions action.yml
Original file line number Diff line number Diff line change
@@ -1,29 +1,37 @@
# See: https://docs.github.com/en/actions/creating-actions
name: Gem Push
author: FreeAgent
description: Push gem packages to a rubygems compatible repo
description: Push gem packages to a rubygems compatible repository
inputs:
package-glob:
description: "File glob to match the .gem files to push"
description: File glob to match the .gem files to push
default: "pkg/*.gem"
release:
description: Whether to push release versions
default: true
pre-release:
description: Whether to push pre-release versions
default: true
tag-release:
description: After pushing a new gem version, git tag with the version string
default: true
outputs:
pushed-version:
description: "The version of the gem pushed to the repository"
value: ${{ steps.push-gem.outputs.pushed-version }}

runs:
using: "composite"
steps:
- name: Push Gem
id: push-gem
shell: bash
env:
# Expects GEM_HOST and GEM_HOST_API_KEY to be set
GEM_GLOB: ${{ inputs.package-glob }}
INPUT_PACKAGE_GLOB: ${{ inputs.package-glob }}
INPUT_RELEASE: ${{ inputs.release }}
INPUT_PRE_RELEASE: ${{ inputs.pre-release }}
INPUT_TAG_RELEASE: ${{ inputs.tag-release }}
run: |
if ! gem push --host "$GEM_HOST" $GEM_GLOB | tee push.out; then
gemerr=$?
if grep "has already been pushed" push.out; then
echo Gem Already Pushed
exit 0
fi
echo ::error::Gem Push Failed
cat push.out | sed 's/^/::error::/'
exit $gemerr
fi
exit 0
PATH="${{ github.action_path }}:$PATH"
gem-push-action
40 changes: 40 additions & 0 deletions gem-push-action
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#!/usr/bin/bash
set -e -o pipefail

if parse-gemspec --is-pre-release; then
if [[ $INPUT_PRE_RELEASE != true ]]; then
echo "Ignoring pre-release. To release, pass pre-release: true as an input"
exit 0
fi
elif [[ $INPUT_RELEASE != true ]]; then
echo "Ignoring release. To release, pass release: true as an input"
exit 0
fi

# tee the output to get it in the logs but capture as we can't tell why gem
# push failed from the exit code, so need to grep the output. Gem existing is
# ok, other errors not. Avoids playing games setting up auth differently for
# gem query.
# Note: the glob is intentially unquoted, we want a glob!
if ! gem push --host "$GEM_HOST" $INPUT_PACKAGE_GLOB | tee push.out; then
gemerr=$?
if grep -q "has already been pushed" push.out; then
echo Gem Already Pushed
exit 0
fi
echo ::error::Gem Push Failed
sed 's/^/::error::/' push.out
exit $gemerr
fi

echo "::set-output name=pushed-version::$( parse-gemspec --version )"

if [[ $INPUT_TAG_RELEASE == true ]]; then
tagname="v$( parse-gemspec --version )"
git config user.name "$(git log -1 --pretty=format:%an)"
git config user.email "$(git log -1 --pretty=format:%ae)"
git tag -a -m "Gem release $tagname" "$tagname"
git push origin "$tagname"
fi

exit 0
40 changes: 40 additions & 0 deletions parse-gemspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#!/usr/bin/env ruby

require 'optparse'

gemspecs = Dir["*.gemspec"]

if gemspecs.empty?
warn "No gemspec found"
exit 10
end

if gemspecs.count > 1
warn "More than one gemspec found"
exit 10
end

spec = Gem::Specification.load(gemspecs.first)
exit 10 unless spec

def puts!(msg)
puts msg
exit
end

OptionParser.new do |opts|
opts.banner = "Usage: #{File.basename($0)} [options]"
opts.on("-h", "--help", "Prints this help") do
puts! opts
end
opts.on("--name", "Output gemspec name") do |v|
puts! spec.name
end
opts.on("--version", "Output gemspec gem version") do |v|
puts! spec.version
end
opts.on("--is-pre-release", "Exit 0 if pre-release, 1 otherwise") do |v|
exit 0 if spec.version.prerelease?
exit 1
end
end.parse!

0 comments on commit fbf77e0

Please sign in to comment.