diff options
author | Christian Segundo | 2024-12-24 19:17:41 +0100 |
---|---|---|
committer | Christian Segundo | 2024-12-24 19:17:41 +0100 |
commit | 06562c5fe484eba954770819a56dc4227a78aa44 (patch) | |
tree | 79f8e877581abd4f529b613266a0a9fa691a2401 | |
parent | f71ff745bd50609bd0ed02d8617834b209a45edb (diff) | |
download | slack2gitlab-emoji-sync-06562c5fe484eba954770819a56dc4227a78aa44.tar.gz |
First commit 🌲
-rw-r--r-- | .envrc | 1 | ||||
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Dockerfile | 23 | ||||
-rw-r--r-- | Makefile.PL | 7 | ||||
-rw-r--r-- | app.nix | 10 | ||||
-rw-r--r-- | flake.lock | 61 | ||||
-rw-r--r-- | flake.nix | 29 | ||||
-rwxr-xr-x | sync | 135 |
8 files changed, 267 insertions, 0 deletions
@@ -0,0 +1 @@ +use flake . diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..92b2793 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.direnv diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..55d7385 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,23 @@ +FROM nixos/nix:latest AS builder + +COPY . /tmp/build +WORKDIR /tmp/build + +RUN nix \ + --extra-experimental-features "nix-command flakes" \ + --option filter-syscalls false \ + build -L .#docker + +# no quotes, we actually want to split +RUN mkdir /tmp/nix-store-closure && \ + cp -R $(nix-store -qR result/) /tmp/nix-store-closure + +WORKDIR /tmp/app + +FROM scratch + +COPY --from=builder /tmp/nix-store-closure /nix/store +COPY --from=builder /tmp/build/result / +USER 1000 +ENV PATH=/bin +ENTRYPOINT ["perl", "/bin/sync"] diff --git a/Makefile.PL b/Makefile.PL new file mode 100644 index 0000000..167d52e --- /dev/null +++ b/Makefile.PL @@ -0,0 +1,7 @@ +#!perl +use ExtUtils::MakeMaker; + +WriteMakefile( + NAME => 'slack2gitlab-emoji-sync', + EXE_FILES => [ 'sync' ], +); @@ -0,0 +1,10 @@ +{ pkgs }: with pkgs; with perlPackages; +buildPerlPackage { + pname = "slack2gitlab-emoji-sync"; + version = "0.000"; + src = ./.; + propagatedBuildInputs = [ JSON LWP LWPProtocolHttps PathTiny ]; + outputs = [ "out" ]; +} + + diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..8be89b0 --- /dev/null +++ b/flake.lock @@ -0,0 +1,61 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1734820311, + "narHash": "sha256-YsLK4ZiGY5CZmmgzsfU76OHVUTDeZJgirKzNO+et0UQ=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "7e4a1594489d41bf8e16046b28e14a0e264c9baa", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..b616a91 --- /dev/null +++ b/flake.nix @@ -0,0 +1,29 @@ +{ + inputs = { + nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + }; + outputs = + { self + , nixpkgs + , flake-utils + }: + flake-utils.lib.eachDefaultSystem ( + system: + let + pkgs = import nixpkgs { inherit system; }; + app = pkgs.callPackage ./app.nix { inherit pkgs; }; + deps = with pkgs; with perlPackages; [ + perl JSON LWP LWPProtocolHttps PathTiny + ]; + in + with pkgs; { + packages.docker = symlinkJoin { + name = "docker"; + paths = [ perl app ]; + meta.priority = 5; + }; + devShells.default = mkShell { buildInputs = deps; }; + } + ); +} @@ -0,0 +1,135 @@ +#!perl +use strict; +use warnings; +use autodie; + +use JSON qw(decode_json encode_json); +use LWP::UserAgent qw(); +use Path::Tiny qw(path); + +$| = 1; + +my $gitlab_group_path = $ENV{GITLAB_GROUP_PATH} or die "GITLAB_GROUP_PATH is not set"; +my $gitlab_url = $ENV{GITLAB_URL} or die "GITLAB_URL is not set"; +my $gitlab_token = $ENV{GITLAB_TOKEN} or die "GITLAB_TOKEN is not set"; +my $slack_workspace = $ENV{SLACK_WORKSPACE} or die "SLACK_WORKSPACE is not set"; +my $slack_logs_dir = $ENV{SLACK_LOGS_DIR} // q{}; +my $gitlab_graphql_api = "${gitlab_url}/api/graphql"; + +die "Usage: $0 <filter>" if scalar @ARGV != 1; +my $filter = qr/$ARGV[0]/; + +my %slack_emojis; +my %gitlab_emojis; + +my $ua = LWP::UserAgent->new(timeout => 5); +$ua->default_header('Authorization' => "Bearer $gitlab_token"); +$ua->default_header('Content-Type' => 'application/json; charset=utf-8'); + +if (!$slack_logs_dir) { + if ($^O eq "darwin") { + my $username = $ENV{LOGNAME} || $ENV{USER} || getpwuid($<); + $slack_logs_dir = "/Users/$username/Library/Application Support/Slack/logs/default"; + } else { + die "SLACK_LOGS_DIR is not set"; + } +} + +if (!path($slack_logs_dir)->exists or !path($slack_logs_dir)->is_dir) { + die "Slack logs directory not found: $slack_logs_dir"; +} + +foreach (path($slack_logs_dir)->children(qr/\.log$/)) { + open my ($log_file), $_; + foreach (<$log_file>) { + if (m{fetch (https://emoji\.slack-edge\.com/$slack_workspace/([a-zA-Z-_0-9]+)\/\w+\.(png|gif|jpg))}gm) { + $slack_emojis{$2} = $1; + } + } + close $log_file; +} + +{ + my $next_cursor = ""; + my $has_next_page = 1; + while($has_next_page) { + my $content = encode_json({ + query => qq{ + { + group(fullPath: "$gitlab_group_path") { + customEmoji(first: 50, after: "$next_cursor") { + nodes { id name url } + pageInfo { endCursor hasNextPage } + } + } + } + } + }); + + my $res = $ua->post( $gitlab_graphql_api, Content => $content ); + die "failed" if $res->is_error or $res->code != 200; + + my $data = decode_json($res->decoded_content); + $next_cursor = $data->{data}{group}{customEmoji}{pageInfo}{endCursor}; + $has_next_page = $data->{data}{group}{customEmoji}{pageInfo}{hasNextPage}; + foreach(@{$data->{data}{group}{customEmoji}{nodes}}) { + $gitlab_emojis{$_->{name}} = { + url => $_->{url}, + id => $_->{id}, + }; + } + } +} + +foreach (sort keys %slack_emojis) { + next if $_ !~ $filter; + print "Emoji: $_\n"; + if (exists $gitlab_emojis{$_}) { + print " - already exists in GitLab\n"; + if ($slack_emojis{$_} eq $gitlab_emojis{$_}{url}) { + print " - skipping, URL is the same\n"; + next; + } + my $content = encode_json({ + query => qq{ + mutation { + destroyCustomEmoji(input: { + id: "$gitlab_emojis{$_}{id}" + }) { errors } + } + } + }); + my $res = $ua->post( $gitlab_graphql_api, Content => $content ); + if ($res->is_error or $res->code != 200) { + print " - failed to delete\n"; + next; + } + my $data = decode_json($res->decoded_content); + if ($data->{errors}) { + print " - failed to delete\n"; + next; + } + } + my $content = encode_json({ + query => qq{ + mutation { + createCustomEmoji(input: { + groupPath: "$gitlab_group_path", + name: "$_", + url: "$slack_emojis{$_}" + }) { errors } + } + } + }); + my $res = $ua->post( $gitlab_graphql_api, Content => $content ); + if ($res->is_error or $res->code != 200) { + print " - failed to create\n"; + } else { + my $data = decode_json($res->decoded_content); + if ($data->{errors}) { + print " - failed to create\n"; + } else { + print " - created\n"; + } + } +} |