from __future__ import absolute_import

import json

from changes.config import db
from changes.constants import Result
from changes.models import FailureReason
from .base import ArtifactHandler


class ManifestJsonHandler(ArtifactHandler):
    """
    Artifact handler for manifest.json files. Makes sure their contents are valid.
    """
    FILENAMES = ('manifest.json',)

    def process(self, fp):
        try:
            contents = json.load(fp)
            if contents['job_step_id'] != self.step.id.hex:
                self.logger.warning('manifest.json had wrong step id (build=%s): expected %s but got %s',
                                    self.step.job.build_id.hex, self.step.id.hex, contents['job_step_id'])
                # TODO(nate): temporarily disabled
                # self._add_failure_reason()
        except Exception:
            self.logger.exception('Failed to parse manifest.json; (build=%s, step=%s)',
                                self.step.job.build_id.hex, self.step.id.hex)
            # TODO(nate): temporarily disabled
            # self._add_failure_reason()

    def _add_failure_reason(self):
        db.session.add(FailureReason(
            step_id=self.step.id,
            job_id=self.step.job_id,
            build_id=self.step.job.build_id,
            project_id=self.step.project_id,
            reason='malformed_manifest_json'
        ))
        self.step.result = Result.infra_failed
        db.session.add(self.step)
        db.session.commit()

from __future__ import absolute_import

import json

from changes.config import db
from changes.constants import Result
from changes.models import FailureReason
from .base import ArtifactHandler


class ManifestJsonHandler(ArtifactHandler):
    """
    Artifact handler for manifest.json files. Makes sure their contents are valid.
    """
    FILENAMES = ('manifest.json',)

    def process(self, fp):
        try:
            contents = json.load(fp)
            if contents['job_step_id'] != self.step.id.hex:
                self.logger.warning('manifest.json had wrong step id (build=%s): expected %s but got %s',
                                    self.step.job.build_id.hex, self.step.id.hex, contents['job_step_id'])
                self._add_failure_reason()
        except Exception:
            self.logger.warning('Failed to parse manifest.json; (build=%s, step=%s)',
                                self.step.job.build_id.hex, self.step.id.hex, exc_info=True)
            self._add_failure_reason()

    def _add_failure_reason(self):
        db.session.add(FailureReason(
            step_id=self.step.id,
            job_id=self.step.job_id,
            build_id=self.step.job.build_id,
            project_id=self.step.project_id,
            reason='malformed_manifest_json'
        ))
        self.step.result = Result.infra_failed
        db.session.add(self.step)
        db.session.commit()

Make malformed/mismatched manifest.json an infra failure
Make malformed/mismatched manifest.json an infra failure

Summary:
- This was disabled for a while due to problems with phased jobsteps, but
  Sentry shows that these errors occasionally still happen, but seem to be
  "real" errors now. Should almost certainly be marked infra failures.
- Also make malformed manifest a warning (and use exc_info=True) since
  malformed vs mismatched jobstep id seem like approximately the same severity.

Test Plan:
Sentry indicates these happen rarely and when they do are probably
legitimate infra failures.

Reviewers: paulruan

Reviewed By: paulruan

Subscribers: changesbot, kylec

Differential Revision: https://tails.corp.dropbox.com/D152534

  from __future__ import absolute_import
  
  import json
  
  from changes.config import db
  from changes.constants import Result
  from changes.models import FailureReason
  from .base import ArtifactHandler
  
  
  class ManifestJsonHandler(ArtifactHandler):
      """
      Artifact handler for manifest.json files. Makes sure their contents are valid.
      """
      FILENAMES = ('manifest.json',)
  
      def process(self, fp):
          try:
              contents = json.load(fp)
              if contents['job_step_id'] != self.step.id.hex:
                  self.logger.warning('manifest.json had wrong step id (build=%s): expected %s but got %s',
                                      self.step.job.build_id.hex, self.step.id.hex, contents['job_step_id'])
-                 # TODO(nate): temporarily disabled
-                 # self._add_failure_reason()
+                 self._add_failure_reason()
          except Exception:
-             self.logger.exception('Failed to parse manifest.json; (build=%s, step=%s)',
+             self.logger.warning('Failed to parse manifest.json; (build=%s, step=%s)',
-                                 self.step.job.build_id.hex, self.step.id.hex)
+                                 self.step.job.build_id.hex, self.step.id.hex, exc_info=True)
-             # TODO(nate): temporarily disabled
-             # self._add_failure_reason()
+             self._add_failure_reason()
  
      def _add_failure_reason(self):
          db.session.add(FailureReason(
              step_id=self.step.id,
              job_id=self.step.job_id,
              build_id=self.step.job.build_id,
              project_id=self.step.project_id,
              reason='malformed_manifest_json'
          ))
          self.step.result = Result.infra_failed
          db.session.add(self.step)
          db.session.commit()
  
Make malformed/mismatched manifest.json an infra failure
## Code Before:
from __future__ import absolute_import

import json

from changes.config import db
from changes.constants import Result
from changes.models import FailureReason
from .base import ArtifactHandler


class ManifestJsonHandler(ArtifactHandler):
    """
    Artifact handler for manifest.json files. Makes sure their contents are valid.
    """
    FILENAMES = ('manifest.json',)

    def process(self, fp):
        try:
            contents = json.load(fp)
            if contents['job_step_id'] != self.step.id.hex:
                self.logger.warning('manifest.json had wrong step id (build=%s): expected %s but got %s',
                                    self.step.job.build_id.hex, self.step.id.hex, contents['job_step_id'])
                # TODO(nate): temporarily disabled
                # self._add_failure_reason()
        except Exception:
            self.logger.exception('Failed to parse manifest.json; (build=%s, step=%s)',
                                self.step.job.build_id.hex, self.step.id.hex)
            # TODO(nate): temporarily disabled
            # self._add_failure_reason()

    def _add_failure_reason(self):
        db.session.add(FailureReason(
            step_id=self.step.id,
            job_id=self.step.job_id,
            build_id=self.step.job.build_id,
            project_id=self.step.project_id,
            reason='malformed_manifest_json'
        ))
        self.step.result = Result.infra_failed
        db.session.add(self.step)
        db.session.commit()

## Instruction:
Make malformed/mismatched manifest.json an infra failure
## Code After:
from __future__ import absolute_import

import json

from changes.config import db
from changes.constants import Result
from changes.models import FailureReason
from .base import ArtifactHandler


class ManifestJsonHandler(ArtifactHandler):
    """
    Artifact handler for manifest.json files. Makes sure their contents are valid.
    """
    FILENAMES = ('manifest.json',)

    def process(self, fp):
        try:
            contents = json.load(fp)
            if contents['job_step_id'] != self.step.id.hex:
                self.logger.warning('manifest.json had wrong step id (build=%s): expected %s but got %s',
                                    self.step.job.build_id.hex, self.step.id.hex, contents['job_step_id'])
                self._add_failure_reason()
        except Exception:
            self.logger.warning('Failed to parse manifest.json; (build=%s, step=%s)',
                                self.step.job.build_id.hex, self.step.id.hex, exc_info=True)
            self._add_failure_reason()

    def _add_failure_reason(self):
        db.session.add(FailureReason(
            step_id=self.step.id,
            job_id=self.step.job_id,
            build_id=self.step.job.build_id,
            project_id=self.step.project_id,
            reason='malformed_manifest_json'
        ))
        self.step.result = Result.infra_failed
        db.session.add(self.step)
        db.session.commit()
