Aprendizaje-como-código

usando herramientas CI/CD para evaluación automática de proyectos en informática

@jjmerelo | github.com/JJ

Imágenes y texto cc-by-sa

37 años programando

33 en la UGR

12 en GitHub

💘 Raku

DevOps es

Infraestructura como código

Configuración como código

Tests como código

Aprendizaje-como-código es

Codificar objetivos de aprendizaje como tests

¿Por qué?

① Se aprende haciendo

② Aprender es un proceso de mejora continua

③ La capacidad de corregir no puede limitar.

Curso 2015-16 📅 Asignatura infraestructura virtualcloud computing

Cambiemos la forma de hacer las cosas

OK, ¿cómo se hace eso?

Enseñanza basada en proyecto

Clase invertida

¿Dónde se hace?

En GitHub, claro

GitHub es la red social de la gente que programa

¡Es software libre!

+ buenas prácticas: revisión de código, búsqueda fácil de copieteo, y el propio uso de git.

Pero...

La corrección era manual

Corrigiendo hito 0

Lo que está hecho, está hecho

2017 📅 Tiempo de cambios

se acabó la OSL

Toda la información necesaria para testear un proyecto está en

El cuerpo del pull request

El README.md

GitHub

Algún fichero adicional de configuración

Si GitHub lo sabe

Que GitHub lo testee

Analiza el PR: Perl FTW

my $repo = Git->repository ( Directory => '.' );
my $diff = $repo->command('diff','HEAD^1','HEAD');
my $diff_regex = qr/a\/proyectos\/hito-(\d)\.md/;
my $github;

SKIP: {
  my ($this_hito) = ($diff =~ $diff_regex);
  skip "No hay envío de proyecto", 5 unless defined $this_hito;  my @files = split(/diff --git/,$diff);
  my ($diff_hito) = grep( /$diff_regex/, @files);
  say "Tratando diff\n\t$diff_hito";
  my @lines = split("\n",$diff_hito);
  my @adds = grep(/^\+[^+]/,@lines);
  is( $#adds, 0, "Añade sólo una línea");
  my $url_repo;
  if ( $adds[0] =~ /\(http/ ) {
    ($url_repo) = ($adds[0] =~ /\((http\S+)\)/);
  } else {
    ($url_repo) = ($adds[0] =~ /^\+.+(http\S+)/s);
  }

Scraping FTW

sub closed_issues {
  my ($user,$repo) = @_;
  my $page = get( "https://github.com/$user/$repo".'/issues?q=is%3Aissue+is%3Aclosed' );
  my (@closed_issues ) = ( $page =~ m{<li\s+(id=.+?)}gs );
  return @closed_issues;
}

sub closes_from_commit {
  my ($user,$repo,$issue) = @_;
  my $page = get( "https://github.com/$user/$repo/issues/$issue" );
  return $page =~ /closed\s+this\s+in/gs ;

}

Aderezado con Travis.

branches:
  except:
    - gh-pages
language: perl
perl:
  - "5.16"
before_install:
install: cpanm Test::More Test::Harness Git File::Slurper JSON \
  Net::Ping TAP::Formatter::Color Term::ANSIColor
script: prove -c

Prueba hasta que funcione.

imagen de travis

Cambio fundamental: aprende mientras envías

Cambio más fundamental:

Aprendizaje como código

    doing("hito 5");
    my ($deployment_url) = ($README =~ /Despliegue final:\s+(\S+)\b/);
    if ( $deployment_url ) {
      diag "☑ Detectada IP de despliegue $deployment_url";
    } else {
      diag "✗ Problemas detectando IP de despliegue";
    }
    unlike( $deployment_url, qr/(heroku|now)/, "Despliegue efectivamente hecho en IaaS" );
    isnt( $deployment_url, "", "URL de despliegue hito 5");
    check_ip($deployment_url);
    my $status = get "http://$deployment_url/status";
    isnt( $status, undef, "Despliegue correcto en $deployment_url/status" );
    my $status_ref = from_json( $status );
    like ( $status_ref->{'status'}, qr/[Oo][Kk]/, "Status de $deployment_url correcto");
          

2019 📅 El escrapear se va a acabar

🚫 usar secretos en PRs

Presentando GitHub Actions

name: "Comprueba hitos y milestones"
on:
  pull_request:
    paths:
      - 'proyectos/hito-[1234567].md'
      - '!objetivos/*.(md|org)'
jobs:
  obtain-repo:
    runs-on: ubuntu-latest
    steps:
      - name: Extrae URL del repositorio
        uses: JJ/github-pr-contains-action@releases/v1
        with:
          github-token: ${{github.token}}
          filesChanged: 1
      - name: Comprueba hitos e issues
        uses: JJ/repo-in-diff-gh-action@releases/v0
        with:
          github-token: ${{github.token}}
          minMilestones: 3

Usando el API de GitHub

const milestones = await github.issues.listMilestonesForRepo( { owner: user, repo: repo } )
 if ( ! milestones.data.length ) {
	core.setFailed("❌ There should be at least one milestone")
 }
 const minMilestones = +core.getInput('minMilestones')
 if ( minMilestones && milestones.data.length < minMilestones ) {
	core.setFailed( "❌ There should be more than " + minMilestones + " milestone(s)");
 }
 var totalIssues = 0
 var totalClosedIssues = 0
 milestones.data.forEach( async function( milestone ) {
	totalIssues += milestone.open_issues + milestone.closed_issues
	totalClosedIssues += milestone.closed_issues
 })
 console.log( "✅ There are " + totalIssues + "
            issues in your milestones  and " + totalClosedIssues + "
            closed issues ")

Comprobando lo comprobable

Usando GH actions +
                   Travis

Acelerando los tests → mejor aprendizaje

Velocidad de los
                    tests

Docker FTW

FROM perl:5.32-slim-threaded
LABEL version="1.5" maintainer="JJ Merelo " perl5version="5.28"

# Set up dir and download modules
RUN chmod o+r /etc/resolv.conf
RUN mkdir /test && apt-get update \
    && apt-get install -y git curl libio-socket-ssl-perl libnet-ssleay-perl gcc  \
    && cpanm Test::More Test::Harness Git File::Slurper JSON TAP::Formatter::Color Term::ANSIColor Mojo::UserAgent Net::Ping YAML
RUN perl --version
VOLUME /test
WORKDIR /test

ENTRYPOINT prove -I/usr/lib -c

2020 📅 github script + API v4 (GraphQL)

const query = `query($owner:String!, $name:String!, $issue:Int!) {
                            repository(name: $name , owner: $owner  ) {
                              issue(number: $issue) {
                                timelineItems(itemTypes: CLOSED_EVENT, last: 1) {
                                  nodes {
                                    ... on ClosedEvent {
                                      closer {
                                        __typename
                                      }
                                    }
                                  }
                                }
                              }
                            }
                          }`;

Los estudiantes son tus clientes.

Contestando un
                   issue

Si GitHub lo sabe...

pop-up de
              comprobaciones

¿Funciona?

Pregunta incorrecta.

¿El estudiante aprende más y mejor?

Discutiblemente,

Objetivos de aprendizaje de estudiante y profesores coinciden

Que es de lo que se trata

Muchas gracias.