From aa163350958e30b2696af6fe031b5c86f8580745 Mon Sep 17 00:00:00 2001 From: Aaron Bieber Date: Mon, 22 May 2023 19:12:52 -0600 Subject: [PATCH] initial --- .envrc | 1 + .gitignore | 4 ++ LICENSE | 15 ++++++ Makefile.PL | 24 +++++++++ flake.lock | 26 ++++++++++ flake.nix | 55 ++++++++++++++++++++ pr-status.pl | 139 +++++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 264 insertions(+) create mode 100644 .envrc create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 Makefile.PL create mode 100644 flake.lock create mode 100644 flake.nix create mode 100755 pr-status.pl diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..499addc --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.direnv +*.bak +result +.pls_cache diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..a272d20 --- /dev/null +++ b/LICENSE @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2023 Aaron Bieber + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ diff --git a/Makefile.PL b/Makefile.PL new file mode 100644 index 0000000..9e02c95 --- /dev/null +++ b/Makefile.PL @@ -0,0 +1,24 @@ +use ExtUtils::MakeMaker; + +WriteMakefile( + NAME => 'pr-status', + VERSION_FROM => 'pr-status.pl', + EXE_FILES => [qw(pr-status.pl)], + LICENSE => 'ISC', + MIN_PERL_VERSION => '5.006', + META_MERGE => { + 'meta-spec' => { version => 2 }, + resources => { + repository => { + type => 'git', + url => 'https://github.com/qbit/pr-status.git', + web => 'https://github.com/qbit/pr-status', + }, + }, + }, + PREREQ_PM => { + 'JSON' => '0', + 'Mojolicious' => '0', + 'Git' => '0', + }, +); diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..21287b7 --- /dev/null +++ b/flake.lock @@ -0,0 +1,26 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1684580438, + "narHash": "sha256-LUPswmDn6fXP3lEBJFA2Id8PkcYDgzUilevWackYVvQ=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "7dc71aef32e8faf065cb171700792cf8a65c152d", + "type": "github" + }, + "original": { + "id": "nixpkgs", + "ref": "nixos-22.11", + "type": "indirect" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..7eec506 --- /dev/null +++ b/flake.nix @@ -0,0 +1,55 @@ +{ + description = "pr-status: a tool to query NixOS/nixpkgs pull request status as they move along the build chain"; + + inputs.nixpkgs.url = "nixpkgs/nixos-22.11"; + + outputs = { self, nixpkgs }: + let + supportedSystems = + [ "x86_64-linux" "x86_64-darwin" "aarch64-linux" "aarch64-darwin" ]; + forAllSystems = nixpkgs.lib.genAttrs supportedSystems; + nixpkgsFor = forAllSystems (system: import nixpkgs { inherit system; }); + in { + packages = forAllSystems (system: + let pkgs = nixpkgsFor.${system}; + in { + pr-status = pkgs.stdenv.mkDerivation { + pname = "pr-status"; + version = "v0.0.1"; + src = ./.; + buildInputs = with pkgs.perlPackages; [ PerlTidy ]; + nativeBuildInputs = with pkgs.perlPackages; [ perl ]; + + propagatedBuildInputs = with pkgs.perlPackages; [ + Mojolicious + JSON + Git + ]; + + outputs = [ "out" "dev" ]; + }; + }); + + defaultPackage = forAllSystems (system: self.packages.${system}.pr-status); + devShells = forAllSystems (system: + let pkgs = nixpkgsFor.${system}; + in { + default = pkgs.mkShell { + shellHook = '' + PS1='\u@\h:\@; ' + nix flake run github:qbit/xin#flake-warn + echo "Perl `${pkgs.perl}/bin/perl --version`" + ''; + buildInputs = with pkgs.perlPackages; [ + Git + JSON + Mojolicious + perl + PerlCritic + PerlTidy + ]; + }; + }); + }; +} + diff --git a/pr-status.pl b/pr-status.pl new file mode 100755 index 0000000..820a198 --- /dev/null +++ b/pr-status.pl @@ -0,0 +1,139 @@ +#!/usr/bin/env perl + +# vim: set ts=4 sw=4 tw=0: +# vim: set expandtab: + +use strict; +use warnings; +use v5.32; + +use Git; +use JSON qw( from_json ); +use Mojolicious::Lite -signatures; +use Time::HiRes qw( time ); + +my $VERSION = 'v0.0.1'; + +my $repo_dir = "/home/qbit/gostart_nixpkgs"; + +$ENV{"GIT_CONFIG_SYSTEM"} = ""; # Ignore insteadOf rules +$ENV{"HOME"} = "/tmp"; # Ignore ~/.netrc + +Git::command( 'clone', 'https://github.com/nixos/nixpkgs', $repo_dir ) + if !-e $repo_dir; +my $repo = Git->repository( Directory => $repo_dir ); + +my $lock = 0; + +sub get_commit { + my $pr = shift; + $repo->command( 'fetch', 'origin', "pull/${pr}/head:pr-status-${pr}" ); + $repo->command( 'checkout', "pr-status-$pr" ); + my $commit = $repo->command( 'rev-parse', 'HEAD' ); + $repo->command( 'checkout', 'master' ); + + chomp $commit; + + return $commit; +} + +sub check_nixpkg_branches { + my $commit = shift; + my $list = []; + + return $list if $commit eq ""; + + my $branches = $repo->command( 'branch', '-r', '--contains', $commit ); + + foreach my $b ( split( '\n', $branches ) ) { + $b =~ s/^\s+origin\///g; + push( @$list, $b ) if $b =~ m/nixos|nixpkgs|staging|master/; + } + + return $list; +} + +sub figure_status { + my $list = shift; + my $release = shift; + my $status = { + state => "complete", + info => {} + }; + + my @unstable = + qw/ nixos-unstable nixos-unstable-small nixpkgs-unstable staging staging-next /; + my @stable = qw/ release-22.11 nixos-22.11-small nixos-22.11 /; + my @other = qw / master /; + + if ( $release eq "stable" ) { + foreach my $s (@stable) { + $status->{info}->{$s} = grep /$s/, @{$list}; + } + } + if ( $release eq "unstable" ) { + foreach my $s (@unstable) { + $status->{info}->{$s} = grep /^$s$/, @{$list}; + } + } + + foreach my $b ( keys %{ $status->{info} } ) { + if ( !$status->{info}->{$b} ) { + $status->{state} = "open"; + last; + } + } + + return $status; +} + +get '/gc' => sub ($c) { + my $start = time; + $repo->command('gc'); + my $end = time; + $c->render( + json => { + updateTime => sprintf( "%2f", $end - $start ), + action => 'gc' + } + ); +}; + +get '/update' => sub ($c) { + my $start = time; + $repo->command('fetch'); + my $end = time; + $c->render( + json => { + updateTime => sprintf( "%2f", $end - $start ), + action => 'update' + } + ); +}; + +get '/:release/:pr' => sub ($c) { + my $pr = $c->param('pr'); + my $release = $c->param('release'); + + return unless $pr =~ m/^\d+$/; + + my $commit = get_commit($pr); + + my $start = time; + my $list = check_nixpkg_branches $commit; + my $end = time; + + my $status = figure_status( $list, $release ); + + my $result = { + branches => $list, + pull_request => $pr, + status => $status->{state}, + status_info => $status->{info}, + queryTime => sprintf( "%2f", $end - $start ) + }; + + $c->render( json => $result ); +}; + +app->start;