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
36 changes: 36 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,46 @@ and this project adheres to

## Unreleased

### Added

* New `secrets` task group, defined via `RakeGithub.define_secrets_tasks`, for
managing GitHub repository secrets. It exposes `provision`, `destroy` and
`ensure` tasks. Each secret is written to the Actions secret store, and
additionally to the Dependabot secret store when it sets `dependabot: true`,
so that Dependabot-triggered workflow runs can read the secrets they need.

Secrets are supplied as an array of hashes, e.g.
`[{ name: 'SOME_SECRET', value: 'plaintext' }]`, and are encrypted
client-side before being sent to GitHub.

* The `secrets` task group is also included in the tasks defined by
`RakeGithub.define_repository_tasks`.

* New `environments` task group, defined via
`RakeGithub.define_environments_tasks`, for managing GitHub deployment
environments. It exposes `provision`, `destroy` and `ensure` tasks, and
supports protection rules including required reviewers.

Environments are supplied as an array of hashes, e.g.
`[{ name: 'release', reviewers: [{ team: 'maintainers' }] }]`. Only `name`
is required; team and user reviewers are resolved to their numeric ids
before being sent to GitHub.

* The `environments` task group is also included in the tasks defined by
`RakeGithub.define_repository_tasks`.

### Changed

* The `pull_requests:merge` task no longer requires setting the branch name and
commit message provide via arguments as parameters within the task definition.
* The `octokit` dependency lower bound has been raised from `>= 4.16` to
`>= 7.0`, as the Dependabot secret methods used by the `secrets` task group
were introduced in octokit 7.0. Consumers pinning octokit below 7.0 will need
to relax that constraint.
* Added a new runtime dependency on `rbnacl` (`~> 7.1`), used to encrypt
secrets client-side. `rbnacl` requires the native libsodium library to be
installed on the host (see the Installation section of the README); this is
only needed when using the `secrets` task group.

## [0.9.0] 2022-01-28

Expand Down
8 changes: 6 additions & 2 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ PATH
specs:
rake_github (0.16.0.pre.3)
colored2 (~> 3.1)
octokit (>= 4.16, < 11.0)
octokit (>= 7.0, < 11.0)
rake_factory (~> 0.33)
rbnacl (~> 7.1)
sshkey (~> 2.0)

GEM
Expand Down Expand Up @@ -42,6 +43,7 @@ GEM
logger
faraday-net_http (3.4.0)
net-http (>= 0.5.0)
ffi (1.17.4)
gem-release (2.2.4)
git (1.19.1)
addressable (~> 2.8)
Expand Down Expand Up @@ -100,6 +102,8 @@ GEM
colored2 (~> 3.1)
rake_factory (~> 0.33)
sshkey (~> 2.0)
rbnacl (7.1.2)
ffi (~> 1)
rchardet (1.8.0)
regexp_parser (2.10.0)
rspec (3.13.1)
Expand Down Expand Up @@ -157,7 +161,7 @@ GEM
unicode-display_width (3.1.4)
unicode-emoji (~> 4.0, >= 4.0.4)
unicode-emoji (4.0.4)
uri (1.0.3)
uri (1.1.1)

PLATFORMS
ruby
Expand Down
170 changes: 170 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,21 @@ Or install it yourself as:

$ gem install rake_github

### System dependencies

The `secrets` task group encrypts secrets client-side using `rbnacl`, which
requires the native [libsodium](https://libsodium.org) library to be present on
the host. Install it before running any `secrets` task:

# macOS
$ brew install libsodium

# Debian/Ubuntu
$ apt-get install libsodium23

libsodium is only required when using the `secrets` tasks; the other task groups
have no additional system dependencies.

## Usage

### define_deploy_keys_tasks
Expand Down Expand Up @@ -52,6 +67,16 @@ end
| deploy_keys_destroy_task_name | symbol | N | Option to change the destroy task name | :obliterate | :destroy |
| deploy_keys_provision_task_name | symbol | N | Option to change the provision task name | :add | :provision |
| deploy_keys_ensure_task_name | symbol | N | Option to change the ensure task name | :destroy_and_provision | :ensure |
| secrets | array | N | Secrets to provision on the repository | { name: string, value: string, dependabot: bool } | [ ] |
| secrets_namespace | symbol | N | Namespace to contain secrets tasks | :repository_secrets | :secrets |
| secrets_destroy_task_name | symbol | N | Option to change the secrets destroy task name | :obliterate | :destroy |
| secrets_provision_task_name | symbol | N | Option to change the secrets provision task name | :add | :provision |
| secrets_ensure_task_name | symbol | N | Option to change the secrets ensure task name | :destroy_and_provision | :ensure |
| environments | array | N | Environments to provision on the repository | { name: string, reviewers: array } | [ ] |
| environments_namespace | symbol | N | Namespace to contain environments tasks | :repository_environments | :environments |
| environments_destroy_task_name | symbol | N | Option to change the environments destroy task name | :obliterate | :destroy |
| environments_provision_task_name| symbol | N | Option to change the environments provision task name | :add | :provision |
| environments_ensure_task_name | symbol | N | Option to change the environments ensure task name | :destroy_and_provision | :ensure |
| namespace | symbol | N | Namespace for tasks to live in, defaults to root namespace | :rake_github | N/A |

Exposes tasks:
Expand All @@ -62,6 +87,12 @@ $ rake -T
rake github:deploy_keys:destroy
rake github:deploy_keys:ensure
rake github:deploy_keys:provision
rake github:secrets:destroy
rake github:secrets:ensure
rake github:secrets:provision
rake github:environments:destroy
rake github:environments:ensure
rake github:environments:provision
rake github:pull_requests:merge[branch_name,commit_message]
```

Expand All @@ -84,6 +115,145 @@ Merges the PR associated with the `branch_name`. Branch name is required.
`commit_message` is optional, and can contain the original commit message with
the `%s` placeholder, e.g. `pull_requests:merge[new_feature,"%s [skip ci]"]`.

### define_secrets_tasks

Sets up rake tasks for managing repository secrets. Each secret is written to
the Actions secret store by default. A secret can additionally be written to the
Dependabot secret store by setting `dependabot: true`, so that
Dependabot-triggered workflow runs can read the secrets they need. Secrets are
encrypted client-side before being sent to GitHub.

These tasks require the native libsodium library to be installed on the host —
see [System dependencies](#system-dependencies) above.

```ruby
require 'rake_github'

RakeGithub.define_secrets_tasks(
namespace: :secrets,
repository: 'org/repo', # required
) do |t|
t.access_token = "your_github_access_token" # required
t.secrets = [
{
name: 'SOME_SECRET',
value: 'some-plaintext-value'
},
{
name: 'SHARED_SECRET',
value: 'another-plaintext-value',
dependabot: true # also write to the Dependabot store
}
]
end
```

| Parameter | Type | Required | Description | Example | Default |
|----------------------|--------|----------|------------------------------------------------------------|---------------------------------------------|------------|
| repository | string | Y | Repository to perform tasks upon | 'organisation/repository_name' | N/A |
| access_token | string | Y | Github token for authorisation | 'ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' | N/A |
| secrets | array | N | Secrets to provision on the repository | { name: string, value: string, dependabot: bool } | [ ] |
| destroy_task_name | symbol | N | Option to change the destroy task name | :obliterate | :destroy |
| provision_task_name | symbol | N | Option to change the provision task name | :add | :provision |
| ensure_task_name | symbol | N | Option to change the ensure task name | :destroy_and_provision | :ensure |
| namespace | symbol | N | Namespace for tasks to live in, defaults to root namespace | :secrets | N/A |

Exposes tasks:

```shell
$ rake -T

rake secrets:destroy
rake secrets:ensure
rake secrets:provision
```

#### secrets:provision

Provisions the specified secrets to the repository, writing each one to the
Actions secret store and, for secrets marked `dependabot: true`, also to the
Dependabot secret store.

#### secrets:destroy

Destroys the specified secrets from the repository, removing each one from both
the Actions and Dependabot secret stores.

#### secrets:ensure

Destroys and then provisions the specified secrets on the repository.

### define_environments_tasks

Sets up rake tasks for managing GitHub deployment environments, including
protection rules such as required reviewers. Team and user reviewers are
resolved to their numeric ids before being sent to GitHub.

```ruby
require 'rake_github'

RakeGithub.define_environments_tasks(
namespace: :environments,
repository: 'org/repo', # required
) do |t|
t.access_token = "your_github_access_token" # required
t.environments = [
{
name: 'release',
wait_timer: 0,
prevent_self_review: false,
reviewers: [
{ team: 'maintainers' },
{ user: 'someone' }
],
deployment_branch_policy: {
protected_branches: true,
custom_branch_policies: false
}
}
]
end
```

Only `name` is required for each environment; every other key is optional and
is omitted from the GitHub API payload when absent.

| Parameter | Type | Required | Description | Example | Default |
|----------------------|--------|----------|------------------------------------------------------------|---------------------------------------------|----------------|
| repository | string | Y | Repository to perform tasks upon | 'organisation/repository_name' | N/A |
| access_token | string | Y | Github token for authorisation | 'ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' | N/A |
| environments | array | N | Environments to provision on the repository | { name: string, reviewers: array } | [ ] |
| destroy_task_name | symbol | N | Option to change the destroy task name | :obliterate | :destroy |
| provision_task_name | symbol | N | Option to change the provision task name | :add | :provision |
| ensure_task_name | symbol | N | Option to change the ensure task name | :destroy_and_provision | :ensure |
| namespace | symbol | N | Namespace for tasks to live in, defaults to root namespace | :environments | N/A |

Exposes tasks:

```shell
$ rake -T

rake environments:destroy
rake environments:ensure
rake environments:provision
```

#### environments:provision

Provisions the specified environments on the repository, resolving any team
and user reviewers to their numeric ids.

#### environments:destroy

Destroys the specified environments from the repository. This is irreversible
and also discards each environment's protection rules, environment secrets and
deployment history. `environments:ensure` therefore fully recreates each
environment rather than patching it in place.

#### environments:ensure

Destroys and then provisions the specified environments on the repository.

### define_release_task

## Development
Expand Down
8 changes: 8 additions & 0 deletions lib/rake_github.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ def self.define_deploy_keys_tasks(opts = {}, &)
RakeGithub::TaskSets::DeployKeys.define(opts, &)
end

def self.define_secrets_tasks(opts = {}, &)
RakeGithub::TaskSets::Secrets.define(opts, &)
end

def self.define_environments_tasks(opts = {}, &)
RakeGithub::TaskSets::Environments.define(opts, &)
end

def self.define_repository_tasks(opts = {}, &)
RakeGithub::TaskSets::Repository.define(opts, &)
end
Expand Down
2 changes: 2 additions & 0 deletions lib/rake_github/task_sets.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# frozen_string_literal: true

require_relative 'task_sets/deploy_keys'
require_relative 'task_sets/secrets'
require_relative 'task_sets/environments'
require_relative 'task_sets/repository'
34 changes: 34 additions & 0 deletions lib/rake_github/task_sets/environments.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# frozen_string_literal: true

require 'rake_factory'

require_relative '../tasks'

module RakeGithub
module TaskSets
class Environments < RakeFactory::TaskSet
prepend RakeFactory::Namespaceable

parameter :repository, required: true
parameter :access_token, required: true
parameter :environments, default: []

parameter :destroy_task_name, default: :destroy
parameter :provision_task_name, default: :provision
parameter :ensure_task_name, default: :ensure

task Tasks::Environments::Provision,
name: RakeFactory::DynamicValue.new { |ts|
ts.provision_task_name
}
task Tasks::Environments::Destroy,
name: RakeFactory::DynamicValue.new { |ts|
ts.destroy_task_name
}
task Tasks::Environments::Ensure,
name: RakeFactory::DynamicValue.new { |ts|
ts.ensure_task_name
}
end
end
end
Loading