Skip to content

Commit

Permalink
Merge pull request #6 from fac/devp/v2
Browse files Browse the repository at this point in the history
Version v2

- Change: Don't pass the gem host around as an environment variable, extract from the gemspec.
- Change: Don't pass gem keys around in environment variables anymore. Use the installed creds by key name.
- Add: input key to set the key name in gem credentials to use.
- Change: Release/pre-release inputs collapsed into single pre-release input. Push is either release or pre-release version, can't do both (or none!) in the same call anymore.
- Add: Add linter for action code.
- Change: tag-release input renamed to just tag.
- Change: Use command line args instead of env variables for the internal command.
  • Loading branch information
markpitchless authored Apr 26, 2021
2 parents 3571ffe + c112604 commit 399af87
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 83 deletions.
26 changes: 26 additions & 0 deletions .github/workflows/linter.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Lint Code Base
# https://help.github.com/en/articles/workflow-syntax-for-github-actions

on:
pull_request:
push:
branches:
- main

jobs:
linter:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
ref: ${{ github.head_ref }}
fetch-depth: 0 # Full history to get a proper list of changed files within `super-linter`

- name: Lint Code Base
uses: github/super-linter@v3
env:
VALIDATE_ALL_CODEBASE: false
VALIDATE_BASH: true
VALIDATE_YAML: true
DEFAULT_BRANCH: main
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
# CHANGELOG

TODO: v2 changes

## [Unreleased]

## [2.0.0] - 2021-04-26

- Change: Don't pass the gem host around as an environment variable, extract from the gemspec.
- Change: Don't pass gem keys around in environment variables anymore. Use the installed creds by key name.
- Add: input `key` to set the key name in gem credentials to use.
- Change: Release/pre-release inputs collapsed into single pre-release input. Push is either release or pre-release version, can't do both (or none!) in the same call anymore.
- Add: Add linter for action code.
- Change: `tag-release` input renamed to just `tag`.
- Change: Use command line args instead of env variables for the internal command.

## [1.3.0] - 2021-04-16

- Fix: clean shell log handling for `gem push` call
Expand Down
82 changes: 31 additions & 51 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

## Description

Action to push gems to a gem cutter compatible repository. Probably RubyGems or GitHub Packages. It expects the authentication to have already been setup, using the environment variables GEM_HOST and GEM_HOST_API_KEY. See [fac/ruby-gem-setup-github-packages-action](https://github.com/fac/ruby-gem-setup-github-packages-action) for an action to set this up for you to push to GitHub.
Action to push gems to a gem cutter compatible repository. Basically RubyGems or GitHub Packages. It expects the authentication to have already been setup, `~/.gem/credentials` contains a token for the repo and you know the name of the key.
See [fac/ruby-gem-setup-github-packages-action](https://github.com/fac/ruby-gem-setup-github-packages-action) for an action to set this up for you. It is actually pretty easy if pushing to the same repo.

If the gem version already exists in the repo the action will no-op and still set a success status. This makes it easier to integrate into workflows, safe to re-run (intentionally or accidentally) and wont push duplicate/replacement packages.
It will still raise an error visible in the summary, letting you know the version already exists.

## Usage

Expand All @@ -16,38 +18,28 @@ 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
with:
bundler-cache: true # bundle install and cache
bundler-cache: true # bundle install
- run: bundle exec rake build

- name: Build Gem
shell: bash
run: bundle exec rake build

- name: Setup GPR
uses: fac/ruby-gem-setup-github-packages-action@v1
- uses: fac/ruby-gem-setup-github-packages-action@v2
with:
token: ${{ secrets.github_token }}

- name: Push Gem
uses: fac/ruby-gem-push-action@v1
- uses: fac/ruby-gem-push-action@v2
with:
key: github
```
If you want to use a different gem host or key:
```yaml
- name: Push Gem
uses: fac/ruby-gem-push-action@v1
env:
gem_host: http://gems.example.com
gem_host_api_key: ${{ secrets.EXAMPLE_API_KEY }}
```
Note that the ruby-gem-push-action will push to the host given in the gemspec. The token needs to match. Trying to push to a different host will fail.
### 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:
By default, the action only acts on non-pre-release versions, and prints a message if it thinks the gem has a pre-release version number. If you set the input option `pre-release: true`, then it will only act on pre-release versions, and will skip over regular versions. That way, you can have 2 calls to the action, using the workflow to decide the logic.

Say you want to push release versions from your default branch (main) and pre-release versions from PR builds:

```yaml
name: Gem Build and Release
Expand All @@ -69,32 +61,32 @@ jobs:
release:
name: Gem / Release
needs: test
needs: test # Only release IF the tests pass
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: ruby/setup-ruby@v1
- run: bundle exec rake build
- name: Build Gem
run: bundle exec rake build

- name: Setup GPR
uses: fac/ruby-gem-setup-github-packages-action@v1
# Setup repo auth
- uses: fac/ruby-gem-setup-github-packages-action@v2
with:
token: ${{ secrets.github_token }}
# Release production gem version from default branch
- name: Push Release Gem
- name: Release Gem
if: github.ref == 'refs/heads/main'
uses: fac/ruby-gem-push-action@v1
uses: fac/ruby-gem-push-action@v2
with:
key: github
# PR branch builds will release pre-release gems
- name: Push Pre-Release Gem
- name: Pre-Release Gem
if: github.ref != 'refs/heads/main'
uses: fac/ruby-gem-push-action@v1
uses: fac/ruby-gem-push-action@v2
with:
release: false
key: github
pre-release: true
```

Expand All @@ -103,31 +95,26 @@ The release job runs if the tests pass, we always package the gem to test that w

## Inputs

### package-glob
### gem-glob

File glob to match the gem file to push. The default `pkg/*.gem` picks up gems built using `bundle exec rake build`. You may need to set this if your your gem builds another way.

```yaml
- name: Push Gem
uses: fac/ruby-gem-push-action@v1
with:
package-glob: build/special.gem
gem-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.
Whether to push new pre-release versions of the gem and ignore releases, instead of the normal, push prod releases but ignore pre-release.

### tag-release
### tag

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.
tag will be `v0.1.0`. This is the same behavior as `gem tag`. (Internally
implemented to work with older gem versions and around bugs that caused tags for failed pushes, which then blocked re-pushing.

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

Expand All @@ -139,14 +126,7 @@ If we pushed a gem to the repository, this will be set to the version pushed.

## Environment Variables

### GEM_HOST_API_KEY

Read to get the API key string (prefixed token with Bearer), to access the package repo. Used by `gem push`.

### GEM_HOST

The host URL for pushing gems to.

None.
## Authors

* FreeAgent <[email protected]>
Expand Down
24 changes: 10 additions & 14 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@ name: Gem Push
author: FreeAgent
description: Push gem packages to a rubygems compatible repository
inputs:
package-glob:
key:
description: "Name of credentials key to use from ~/.gem/credentials."
default: ""
gem-glob:
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: Whether to push pre-release versions, instead of release versions (the default).
default: false
tag:
description: After pushing a new gem version, git tag with the version string
default: true
outputs:
Expand All @@ -26,12 +26,8 @@ runs:
- name: Push Gem
id: push-gem
shell: bash
env:
# Expects GEM_HOST and GEM_HOST_API_KEY to be set
INPUT_PACKAGE_GLOB: ${{ inputs.package-glob }}
INPUT_RELEASE: ${{ inputs.release }}
INPUT_PRE_RELEASE: ${{ inputs.pre-release }}
INPUT_TAG_RELEASE: ${{ inputs.tag-release }}
run: |
PATH="${{ github.action_path }}:$PATH"
gem-push-action
args=""
[ '${{ inputs.tag }}' == true ] && args="$args -t"
gem-push-action -k "${{inputs.key}}" $args ${{inputs.gem-glob}}
54 changes: 44 additions & 10 deletions gem-push-action
Original file line number Diff line number Diff line change
@@ -1,21 +1,55 @@
#!/usr/bin/bash
#!/usr/bin/env bash
set -e -o pipefail

if parse-gemspec --is-pre-release; then
if [[ $INPUT_PRE_RELEASE != true ]]; then
KEY=""
PRE_RELEASE=false
TAG_RELEASE=false

usage() {
echo "Usage: $0 [-k KEY] [-p] GEMFILE"
echo
echo Options:
echo " GEMFILE The pre-built .gem pkg you want to push"
echo " -k KEY Set the gem host credentials key name. Default: '$KEY'"
echo " -p Do a pre-release, ignore otherwise. Default: $PRE_RELEASE"
echo " -t After pushing a new version, git tag the current ref. Default: $TAG_RELEASE"
echo " -h Show this help"
exit 0
}

while getopts ":hk:pt" opt; do
case ${opt} in
h ) usage
;;
k ) KEY=$OPTARG
;;
p ) PRE_RELEASE=true
;;
t ) TAG_RELEASE=true
;;
\? ) usage
;;
esac
done
shift $((OPTIND -1))

GEM_FILE="$1"

# By default read the gem host from the gemspec, if they dont match the push
# will fail! Allow override if GEM_HOST is already exported.
push_host="$(parse-gemspec --push-host)"
GEM_HOST="${GEM_HOST:-$push_host}"

if parse-gemspec --is-pre-release && [[ $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

# Capture as we can't tell why gem push failed from the exit code and it logs
# everything to stdout, 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 >push.out; then
if ! gem push --key="$KEY" --host "$GEM_HOST" "$GEM_FILE" >push.out; then
gemerr=$?
sed 's/^Error:/::error::/' push.out
if grep -q "has already been pushed" push.out; then
Expand All @@ -26,7 +60,7 @@ fi

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

if [[ $INPUT_TAG_RELEASE == true ]]; then
if [[ $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)"
Expand Down
16 changes: 8 additions & 8 deletions parse-gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ 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
opts.on("-h", "--help", "Prints this help") do puts! opts end

opts.on("--name", "Output name") do |v| puts! spec.name end
opts.on("--version", "Output gem version") do |v| puts! spec.version end
opts.on("--metadata", "Output metadata") do |v| puts! spec.metadata end
opts.on("--push-host", "Output metadata.allowed_push_host") do |v|
puts! spec.metadata.dig "allowed_push_host"
end

opts.on("--is-pre-release", "Exit 0 if pre-release, 1 otherwise") do |v|
exit 0 if spec.version.prerelease?
exit 1
Expand Down

0 comments on commit 399af87

Please sign in to comment.