Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 37 additions & 17 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: CI

on:
push:
branches: [main, develop, 'release/**']
branches: [main, develop, release/**]
pull_request:
branches: [main, develop]

Expand Down Expand Up @@ -74,11 +74,11 @@ jobs:
bundle audit --update || true
continue-on-error: true

publish:
build:
runs-on: ubuntu-latest
needs: [test, security]
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop' || startsWith(github.ref, 'refs/heads/release/'))
if: github.event_name == 'push'

steps:
- uses: actions/checkout@v4

Expand All @@ -91,25 +91,45 @@ jobs:
- name: Modify version for develop branch
if: github.ref == 'refs/heads/develop'
run: |
sed -i "s/VERSION = '\([^']*\)'/VERSION = '\1.dev'/" lib/sudo/constants.rb
SHORT_SHA=$(git rev-parse --short HEAD)
sed -i "s/VERSION = '\([^']*\)'/VERSION = '\1.dev.${SHORT_SHA}'/" lib/sudo/constants.rb
echo "VERSION_SUFFIX=.dev.${SHORT_SHA}" >> $GITHUB_ENV

- name: Modify version for release branch
if: startsWith(github.ref, 'refs/heads/release/')
run: |
sed -i "s/VERSION = '\([^']*\)'/VERSION = '\1.rc'/" lib/sudo/constants.rb
SHORT_SHA=$(git rev-parse --short HEAD)
sed -i "s/VERSION = '\([^']*\)'/VERSION = '\1.rc.${SHORT_SHA}'/" lib/sudo/constants.rb
echo "VERSION_SUFFIX=.rc.${SHORT_SHA}" >> $GITHUB_ENV

- name: Set version suffix for main
if: github.ref == 'refs/heads/main'
run: echo "VERSION_SUFFIX=" >> $GITHUB_ENV

- name: Build gem
run: gem build sudo.gemspec

- name: Publish to GitHub Packages
- name: Get gem info
id: gem_info
run: |
GEM_FILE=$(ls *.gem)
GEM_VERSION=$(echo $GEM_FILE | sed 's/sudo-\(.*\)\.gem/\1/')
echo "gem_file=$GEM_FILE" >> $GITHUB_OUTPUT
echo "gem_version=$GEM_VERSION" >> $GITHUB_OUTPUT

- name: Store gem artifact
uses: actions/upload-artifact@v4
with:
name: gem-${{ steps.gem_info.outputs.gem_version }}
path: "*.gem"
retention-days: 30

- name: Create build summary
run: |
mkdir -p ~/.gem
cat << EOF > ~/.gem/credentials
---
:github: Bearer ${{ secrets.GITHUB_TOKEN }}
EOF
chmod 600 ~/.gem/credentials
# Temporarily remove allowed_push_host restriction for GitHub Packages
sed -i "s/spec.metadata\['allowed_push_host'\].*$//" sudo.gemspec
gem build sudo.gemspec
gem push --key github --host https://rubygems.pkg.github.com/TwilightCoders *.gem
echo "## Gem Built Successfully πŸ’Ž" >> $GITHUB_STEP_SUMMARY
echo "- **Version**: ${{ steps.gem_info.outputs.gem_version }}" >> $GITHUB_STEP_SUMMARY
echo "- **File**: ${{ steps.gem_info.outputs.gem_file }}" >> $GITHUB_STEP_SUMMARY
echo "- **Branch**: ${{ github.ref_name }}" >> $GITHUB_STEP_SUMMARY
echo "- **Commit**: ${{ github.sha }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "πŸš€ **Ready to publish!** Use the 'Manual Release' workflow to publish this gem." >> $GITHUB_STEP_SUMMARY
150 changes: 150 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
name: Manual Release

on:
workflow_dispatch:
inputs:
target:
description: 'Release target'
required: true
default: 'github'
type: choice
options:
- github
- rubygems
- both
run_id:
description: 'CI Run ID to use (optional - leave empty to build from current commit)'
required: false
type: string
version_override:
description: 'Version override (optional - leave empty to use VERSION constant)'
required: false
type: string
confirm:
description: 'Type "confirm" to proceed with release'
required: true
type: string

permissions:
actions: write
contents: read
id-token: write
packages: write

jobs:
validate:
runs-on: ubuntu-latest
steps:
- name: Validate confirmation
if: inputs.confirm != 'confirm'
run: |
echo "::error::You must type 'confirm' to proceed with release"
exit 1

release:
runs-on: ubuntu-latest
needs: validate

steps:
- uses: actions/checkout@v4

- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: "3.3"
bundler-cache: true

- name: Download gem artifact
if: inputs.run_id != ''
uses: actions/download-artifact@v4
with:
run-id: ${{ inputs.run_id }}
pattern: gem-*
merge-multiple: true

- name: Build gem from current commit
if: inputs.run_id == ''
run: |
# Override version if specified
if [ "${{ inputs.version_override }}" != "" ]; then
sed -i "s/VERSION = '\([^']*\)'/VERSION = '${{ inputs.version_override }}'/" lib/sudo/constants.rb
echo "Version overridden to: ${{ inputs.version_override }}"
fi

# Run tests first
bundle exec rspec

# Build gem
gem build sudo.gemspec

- name: Show gem info and get publish details
id: gem_details
run: |
echo "Available gems:"
ls -la *.gem
echo ""

# Get the gem file (assuming single gem)
GEM_FILE=$(ls *.gem | head -1)
GEM_VERSION=$(echo $GEM_FILE | sed 's/sudo-\(.*\)\.gem/\1/')

echo "gem_file=$GEM_FILE" >> $GITHUB_OUTPUT
echo "gem_version=$GEM_VERSION" >> $GITHUB_OUTPUT

echo "## πŸ’Ž PUBLISHING CONFIRMATION"
echo "**Gem Name:** sudo"
echo "**Version:** $GEM_VERSION"
echo "**File:** $GEM_FILE"
echo "**Target:** ${{ inputs.target }}"
echo "**Size:** $(ls -lh $GEM_FILE | awk '{print $5}')"
echo ""
echo "Gem contents preview:"
gem contents "$GEM_FILE" | head -10
echo "... (and $(gem contents "$GEM_FILE" | wc -l) total files)"

- name: Confirm publication details
run: |
echo "## πŸš€ READY TO PUBLISH" >> $GITHUB_STEP_SUMMARY
echo "- **Gem**: sudo" >> $GITHUB_STEP_SUMMARY
echo "- **Version**: ${{ steps.gem_details.outputs.gem_version }}" >> $GITHUB_STEP_SUMMARY
echo "- **File**: ${{ steps.gem_details.outputs.gem_file }}" >> $GITHUB_STEP_SUMMARY
echo "- **Target**: ${{ inputs.target }}" >> $GITHUB_STEP_SUMMARY
echo "- **Commit**: ${{ github.sha }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Publishing in 5 seconds..." >> $GITHUB_STEP_SUMMARY
sleep 5

- name: Publish to GitHub Packages
if: inputs.target == 'github' || inputs.target == 'both'
run: |
mkdir -p ~/.gem
cat << EOF > ~/.gem/credentials
---
:github: Bearer ${{ secrets.GITHUB_TOKEN }}
EOF
chmod 600 ~/.gem/credentials
# Temporarily remove allowed_push_host restriction for GitHub Packages
sed -i "s/spec.metadata\['allowed_push_host'\].*$//" sudo.gemspec
gem build sudo.gemspec
gem push --key github --host https://rubygems.pkg.github.com/TwilightCoders *.gem

- name: Publish to RubyGems.org
if: inputs.target == 'rubygems' || inputs.target == 'both'
env:
GEM_HOST_API_KEY: ${{ secrets.RUBYGEMS_API_KEY }}
run: |
mkdir -p ~/.gem
cat << EOF > ~/.gem/credentials
---
:rubygems_api_key: ${{ secrets.RUBYGEMS_API_KEY }}
EOF
chmod 600 ~/.gem/credentials
gem push *.gem

- name: Create release summary
run: |
echo "## Release Summary" >> $GITHUB_STEP_SUMMARY
echo "- **Target**: ${{ inputs.target }}" >> $GITHUB_STEP_SUMMARY
echo "- **Version**: $(ls *.gem | sed 's/sudo-\(.*\)\.gem/\1/')" >> $GITHUB_STEP_SUMMARY
echo "- **Branch**: ${{ github.ref_name }}" >> $GITHUB_STEP_SUMMARY
echo "- **Commit**: ${{ github.sha }}" >> $GITHUB_STEP_SUMMARY
22 changes: 9 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
[![CI](https://github.com/TwilightCoders/rubysu/actions/workflows/ci.yml/badge.svg)](https://github.com/TwilightCoders/rubysu/actions/workflows/ci.yml)
[![Maintainability](https://qlty.sh/badges/e63e40be-4d72-4519-ad77-d4f94803a7b9/maintainability.svg)](https://qlty.sh/TwilightCoders/rubysu)
[![Test Coverage](https://qlty.sh/badges/e63e40be-4d72-4519-ad77-d4f94803a7b9/test_coverage.svg)](https://qlty.sh/TwilightCoders/rubysu)
![GitHub License](https://img.shields.io/github/license/twilightcoders/rubysu)

# Ruby Sudo

Expand Down Expand Up @@ -139,27 +140,22 @@ end

Guido De Rosa ([@gderosa](http://github.com/gderosa/)).

See LICENSE.
See ([LICENSE](https://github.com/TwilightCoders/rubysu/blob/main/LICENSE)).

### Contributors

Dale Stevens ([@voltechs](https://github.com/voltechs))
- Dale Stevens ([@voltechs](https://github.com/voltechs))
- Robert M. Koch ([@threadmetal](https://github.com/threadmetal))
- Wolfgang Teuber ([@wteuber](https://github.com/wteuber))

Robert M. Koch ([@threadmetal](https://github.com/threadmetal))
### Acknowledgements

Wolfgang Teuber ([@wteuber](https://github.com/wteuber))

### Other acknowledgements


Thanks to Tony Arcieri and Brian Candler for suggestions on
[ruby-talk](http://www.ruby-forum.com/topic/262655).

Initially developed by G. D. while working at [@vemarsas](https://github.com/vemarsas).
- Thanks to Tony Arcieri and Brian Candler for suggestions on [ruby-talk](http://www.ruby-forum.com/topic/262655).
- Initially developed by Guido De Rosa while working at [@vemarsas](https://github.com/vemarsas).

## Contributing

1. Fork it ( https://github.com/TwilightCoders/rubysu/fork )
1. Fork it ( <https://github.com/TwilightCoders/rubysu/fork> )
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
Expand Down
45 changes: 45 additions & 0 deletions spec/lib/sudo/proxy_spec.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,44 @@
require 'spec_helper'

describe Sudo::MethodProxy do
let(:object) { double('test_object') }
let(:proxy) { double('proxy') }
subject { described_class.new(object, proxy) }

describe '#initialize' do
it 'stores object and proxy references' do
method_proxy = described_class.new(object, proxy)
expect(method_proxy.instance_variable_get(:@object)).to eq(object)
expect(method_proxy.instance_variable_get(:@proxy)).to eq(proxy)
end
end

describe '#method_missing' do
it 'delegates method calls to proxy' do
expect(proxy).to receive(:proxy).with(object, :test_method, 'arg1', 'arg2')
subject.test_method('arg1', 'arg2')
end

it 'supports blocks' do
block = proc { 'test' }
expect(proxy).to receive(:proxy).with(object, :test_method, &block)
subject.test_method(&block)
end
end

describe '#respond_to_missing?' do
it 'returns true if object responds to method' do
allow(object).to receive(:respond_to?).with(:test_method, false).and_return(true)
expect(subject.respond_to?(:test_method)).to be true
end

it 'returns false if object does not respond to method' do
allow(object).to receive(:respond_to?).with(:unknown_method, false).and_return(false)
expect(subject.respond_to?(:unknown_method)).to be false
end
end
end

describe Sudo::Proxy do
it 'proxies the call' do
expect(subject.proxy(Kernel)).to eq(Kernel)
Expand All @@ -11,6 +50,12 @@
expect(subject.loaded_specs).to_not be_empty
expect(subject.loaded_specs).to all(be_a(String))
end

it 'handles errors gracefully' do
allow(Gem).to receive(:loaded_specs).and_raise(StandardError.new('test error'))
allow(subject).to receive(:warn) # Suppress warning output in tests
expect(subject.loaded_specs).to eq([])
end
end

context '#load_path' do
Expand Down
Loading