Skip to content

Commit

Permalink
Merge pull request #429 from yakatz/hashed_repos
Browse files Browse the repository at this point in the history
Improve support for hooks in `@hashed` storage
  • Loading branch information
bastelfreak committed Feb 15, 2024
2 parents c94ddb5 + 6059809 commit 49f1f60
Show file tree
Hide file tree
Showing 3 changed files with 200 additions and 22 deletions.
49 changes: 36 additions & 13 deletions REFERENCE.md
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
@@ -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
@@ -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

0 comments on commit 49f1f60

Please sign in to comment.