Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve support for hooks in @hashed storage #429

Merged
merged 3 commits into from
Feb 15, 2024
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
49 changes: 36 additions & 13 deletions REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

### Defined types

* [`gitlab::custom_hook`](#gitlab--custom_hook): Manage custom hook files within a GitLab project. Custom hooks can be created as a pre-receive, post-receive, or update hook. It's possible to create different custom hook types for the same project - one each for pre-receive, post-receive and update.
* [`gitlab::custom_hook`](#gitlab--custom_hook): Manage custom hook files within a GitLab project. Custom hooks can be created as a pre-receive, post-receive, or update hook. Only one of each is currently supported by this module.
* [`gitlab::global_hook`](#gitlab--global_hook): Manage global chain loaded hook files for all GitLab projects. Hooks can be created as a pre-receive, post-receive, or update hook. It's possible to create multipe hooks per type as long as their names are unique. Support for chained (global) hooks is introduced in GitLab Shell 4.1.0 and GitLab 8.15.
* [`gitlab::system_hook`](#gitlab--system_hook): A file hook will run on each event so it's up to you to filter events or projects

Expand Down Expand Up @@ -1185,43 +1185,58 @@ Default value: `$gitlab::skip_post_deployment_migrations`

### <a name="gitlab--custom_hook"></a>`gitlab::custom_hook`

Manage custom hook files within a GitLab project. Custom hooks can be created as a pre-receive, post-receive, or update hook. It's possible to create different custom hook types for the same project - one each for pre-receive, post-receive and update.
Manage custom hook files within a GitLab project. Custom hooks can be created as a pre-receive, post-receive, or update hook. Only one of each is currently supported by this module.

#### Examples

##### Custom hook usage

```puppet
gitlab::custom_hook { 'my_custom_hook':
namespace => 'my_group',
project => 'my_project',
type => 'post-receive',
source => 'puppet:///modules/my_module/post-receive',
namespace => 'my_group',
project => 'my_project',
type => 'post-receive',
source => 'puppet:///modules/my_module/post-receive',
}
```

##### Calculate hashed storage path

```puppet
gitlab::custom_hook { 'my_custom_hook':
project => 93,
hashed_storage => true,
type => 'post-receive',
source => 'puppet:///modules/my_module/post-receive',
}
# Hook path will be `@hashed/6e/40/6e4001871c0cf27c7634ef1dc478408f642410fd3a444e2a88e301f5c4a35a4d`
```

#### Parameters

The following parameters are available in the `gitlab::custom_hook` defined type:

* [`namespace`](#-gitlab--custom_hook--namespace)
* [`project`](#-gitlab--custom_hook--project)
* [`namespace`](#-gitlab--custom_hook--namespace)
* [`type`](#-gitlab--custom_hook--type)
* [`content`](#-gitlab--custom_hook--content)
* [`source`](#-gitlab--custom_hook--source)
* [`repos_path`](#-gitlab--custom_hook--repos_path)
* [`hashed_storage`](#-gitlab--custom_hook--hashed_storage)

##### <a name="-gitlab--custom_hook--namespace"></a>`namespace`
##### <a name="-gitlab--custom_hook--project"></a>`project`

Data type: `String`
Data type: `Variant[String,Integer]`

The GitLab group namespace for the project.
The GitLab project name, or the hashed directory name or project ID number

##### <a name="-gitlab--custom_hook--project"></a>`project`
##### <a name="-gitlab--custom_hook--namespace"></a>`namespace`

Data type: `String`
Data type: `Optional[String]`

The GitLab project name.
The GitLab group namespace for the project.

Default value: `undef`

##### <a name="-gitlab--custom_hook--type"></a>`type`

Expand Down Expand Up @@ -1253,6 +1268,14 @@ The GitLab shell repos path. This defaults to '/var/opt/gitlab/git-data/reposito

Default value: `undef`

##### <a name="-gitlab--custom_hook--hashed_storage"></a>`hashed_storage`

Data type: `Boolean`

Whether to treat the project name as a hashed storage directory name or ID number

Default value: `false`

### <a name="gitlab--global_hook"></a>`gitlab::global_hook`

Manage global chain loaded hook files for all GitLab projects. Hooks can be created as a pre-receive, post-receive, or update hook. It's possible to create multipe hooks per type as long as their names are unique. Support for chained (global) hooks is introduced in GitLab Shell 4.1.0 and GitLab 8.15.
Expand Down
52 changes: 43 additions & 9 deletions manifests/custom_hook.pp
Original file line number Diff line number Diff line change
@@ -1,26 +1,38 @@
# @summary Manage custom hook files within a GitLab project. Custom hooks can be created as a pre-receive, post-receive, or update hook. It's possible to create different custom hook types for the same project - one each for pre-receive, post-receive and update.
# @summary Manage custom hook files within a GitLab project. Custom hooks can be created as a pre-receive, post-receive, or update hook. Only one of each is currently supported by this module.
#
# @example Custom hook usage
# gitlab::custom_hook { 'my_custom_hook':
# namespace => 'my_group',
# project => 'my_project',
# type => 'post-receive',
# source => 'puppet:///modules/my_module/post-receive',
# namespace => 'my_group',
# project => 'my_project',
# type => 'post-receive',
# source => 'puppet:///modules/my_module/post-receive',
# }
#
# @example Calculate hashed storage path
# gitlab::custom_hook { 'my_custom_hook':
# project => 93,
# hashed_storage => true,
# type => 'post-receive',
# source => 'puppet:///modules/my_module/post-receive',
# }
# # Hook path will be `@hashed/6e/40/6e4001871c0cf27c7634ef1dc478408f642410fd3a444e2a88e301f5c4a35a4d`
#
# @param project The GitLab project name, or the hashed directory name or project ID number
# @param namespace The GitLab group namespace for the project.
# @param project The GitLab project name.
# @param type The custom hook type. Should be one of pre-receive, post-receive, or update.
# @param content Specify the custom hook contents either as a string or using the template function. If this paramter is specified source parameter must not be present.
# @param source Specify a file source path to populate the custom hook contents. If this paramter is specified content parameter must not be present.
# @param repos_path The GitLab shell repos path. This defaults to '/var/opt/gitlab/git-data/repositories' if not present.
# @param hashed_storage Whether to treat the project name as a hashed storage directory name or ID number
#
define gitlab::custom_hook (
String $namespace,
String $project,
Variant[String,Integer] $project,
Enum['update', 'post-receive', 'pre-receive'] $type,
Optional[String] $namespace = undef,
Optional[String] $content = undef,
Optional[String] $source = undef,
Optional[Stdlib::Absolutepath] $repos_path = undef,
Boolean $hashed_storage = false,
) {
if $repos_path {
$_repos_path = $repos_path
Expand All @@ -38,7 +50,29 @@
fail("gitlab::custom_hook[${name}]: Must specify either content or source, but not both")
}

$hook_path = "${_repos_path}/${namespace}/${project}.git/custom_hooks"
if ! ($hashed_storage) and ! ($namespace) {
fail("gitlab::custom_hook[${name}]: Must specify either namespace or hashed_storage")
}

if ($hashed_storage) and ($namespace) {
fail("gitlab::custom_hook[${name}]: Must specify either namespace or hashed_storage, but not both")
}

if ($namespace) {
$hook_path = "${_repos_path}/${namespace}/${project}.git/custom_hooks"
} elsif ($hashed_storage) {
if ($project.is_a(Integer)) {
$_project_hash = sha256(String($project))
} else {
$_project_hash = $project
}

if ($_project_hash.length != 64) {
fail("gitlab::custom_hook[${name}]: Invalid project hash ${_project_hash}")
}

$hook_path = "${_repos_path}/@hashed/${_project_hash[0,2]}/${_project_hash[2,2]}/${_project_hash}.git/custom_hooks"
}

File {
owner => $gitlab::service_user,
Expand Down
121 changes: 121 additions & 0 deletions spec/defines/custom_hook_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# frozen_string_literal: true

require 'spec_helper'

describe 'gitlab::custom_hook' do
let(:title) { 'test-hook' }

let(:pre_condition) do
<<-MANIFEST
class { 'gitlab':
repository_configuration => {},
}
MANIFEST
end

['post-receive', 'pre-receive', 'update'].each do |type|
context "with type => #{type} and source" do
let(:source) { 'puppet:///modules/my_module/post-receive' }
let(:params) do
{
type: type,
repos_path: '/custom/hooks/dir',
source: source,
namespace: 'foo',
project: 'bar'
}
end

it { is_expected.to compile }

it do
is_expected.to contain_file('/custom/hooks/dir/foo/bar.git/custom_hooks').
with_ensure('directory')
end

it do
is_expected.to contain_file("/custom/hooks/dir/foo/bar.git/custom_hooks/#{type}").
with_ensure('file').
with_source(source)
end
end

context "with type => #{type} and content" do
let(:content) { "#!/usr/bin/env bash\ntest 0" }
let(:params) do
{
type: type,
repos_path: '/custom/hooks/dir',
content: content,
namespace: 'foo',
project: 'bar'
}
end

it { is_expected.to compile }

it do
is_expected.to contain_file('/custom/hooks/dir/foo/bar.git/custom_hooks').
with_ensure('directory')
end

it do
is_expected.to contain_file("/custom/hooks/dir/foo/bar.git/custom_hooks/#{type}").
with_ensure('file').
with_content(content)
end
end

context "with type => #{type} and project hash" do
let(:content) { "#!/usr/bin/env bash\ntest 0" }
let(:params) do
{
type: type,
repos_path: '/custom/hooks/dir',
content: content,
hashed_storage: true,
project: '6e4001871c0cf27c7634ef1dc478408f642410fd3a444e2a88e301f5c4a35a4d'
}
end

it { is_expected.to compile }

it do
is_expected.to contain_file('/custom/hooks/dir/@hashed/6e/40/6e4001871c0cf27c7634ef1dc478408f642410fd3a444e2a88e301f5c4a35a4d.git/custom_hooks').
with_ensure('directory')
end

it do
is_expected.to contain_file("/custom/hooks/dir/@hashed/6e/40/6e4001871c0cf27c7634ef1dc478408f642410fd3a444e2a88e301f5c4a35a4d.git/custom_hooks/#{type}").
with_ensure('file').
with_content(content)
end
end

context "with type => #{type} and project id" do
let(:content) { "#!/usr/bin/env bash\ntest 0" }
let(:params) do
{
type: type,
repos_path: '/custom/hooks/dir',
content: content,
hashed_storage: true,
project: 93
}
end

it { is_expected.to compile }

it do
is_expected.to contain_file('/custom/hooks/dir/@hashed/6e/40/6e4001871c0cf27c7634ef1dc478408f642410fd3a444e2a88e301f5c4a35a4d.git/custom_hooks').
with_ensure('directory')
end

it do
is_expected.to contain_file("/custom/hooks/dir/@hashed/6e/40/6e4001871c0cf27c7634ef1dc478408f642410fd3a444e2a88e301f5c4a35a4d.git/custom_hooks/#{type}").
with_ensure('file').
with_content(content)
end
end
end
end